We still compile with JSCRE immediately, instead of at the first use.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 31 Oct 2008 09:45:00 +0000 (09:45 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 31 Oct 2008 09:45:00 +0000 (09:45 +0000)
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@666 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

580 files changed:
regexp2000/AUTHORS [new file with mode: 0644]
regexp2000/ChangeLog [new file with mode: 0644]
regexp2000/LICENSE [new file with mode: 0644]
regexp2000/SConstruct [new file with mode: 0644]
regexp2000/benchmarks/README.txt [new file with mode: 0644]
regexp2000/benchmarks/base.js [new file with mode: 0644]
regexp2000/benchmarks/crypto.js [new file with mode: 0644]
regexp2000/benchmarks/deltablue.js [new file with mode: 0644]
regexp2000/benchmarks/earley-boyer.js [new file with mode: 0644]
regexp2000/benchmarks/raytrace.js [new file with mode: 0644]
regexp2000/benchmarks/richards.js [new file with mode: 0644]
regexp2000/benchmarks/run.html [new file with mode: 0644]
regexp2000/benchmarks/run.js [new file with mode: 0644]
regexp2000/benchmarks/v8-logo.png [new file with mode: 0644]
regexp2000/include/v8-debug.h [new file with mode: 0644]
regexp2000/include/v8.h [new file with mode: 0644]
regexp2000/samples/SConscript [new file with mode: 0644]
regexp2000/samples/count-hosts.js [new file with mode: 0644]
regexp2000/samples/process.cc [new file with mode: 0644]
regexp2000/samples/shell.cc [new file with mode: 0644]
regexp2000/src/SConscript [new file with mode: 0644]
regexp2000/src/accessors.cc [new file with mode: 0644]
regexp2000/src/accessors.h [new file with mode: 0644]
regexp2000/src/allocation.cc [new file with mode: 0644]
regexp2000/src/allocation.h [new file with mode: 0644]
regexp2000/src/api.cc [new file with mode: 0644]
regexp2000/src/api.h [new file with mode: 0644]
regexp2000/src/apinatives.js [new file with mode: 0644]
regexp2000/src/arguments.h [new file with mode: 0644]
regexp2000/src/array.js [new file with mode: 0644]
regexp2000/src/assembler-arm-inl.h [new file with mode: 0644]
regexp2000/src/assembler-arm.cc [new file with mode: 0644]
regexp2000/src/assembler-arm.h [new file with mode: 0644]
regexp2000/src/assembler-ia32-inl.h [new file with mode: 0644]
regexp2000/src/assembler-ia32.cc [new file with mode: 0644]
regexp2000/src/assembler-ia32.h [new file with mode: 0644]
regexp2000/src/assembler.cc [new file with mode: 0644]
regexp2000/src/assembler.h [new file with mode: 0644]
regexp2000/src/ast.cc [new file with mode: 0644]
regexp2000/src/ast.h [new file with mode: 0644]
regexp2000/src/bootstrapper.cc [new file with mode: 0644]
regexp2000/src/bootstrapper.h [new file with mode: 0644]
regexp2000/src/builtins-arm.cc [new file with mode: 0644]
regexp2000/src/builtins-ia32.cc [new file with mode: 0644]
regexp2000/src/builtins.cc [new file with mode: 0644]
regexp2000/src/builtins.h [new file with mode: 0644]
regexp2000/src/char-predicates-inl.h [new file with mode: 0644]
regexp2000/src/char-predicates.h [new file with mode: 0644]
regexp2000/src/checks.cc [new file with mode: 0644]
regexp2000/src/checks.h [new file with mode: 0644]
regexp2000/src/code-stubs.cc [new file with mode: 0644]
regexp2000/src/code-stubs.h [new file with mode: 0644]
regexp2000/src/code.h [new file with mode: 0644]
regexp2000/src/codegen-arm.cc [new file with mode: 0644]
regexp2000/src/codegen-arm.h [new file with mode: 0644]
regexp2000/src/codegen-ia32.cc [new file with mode: 0644]
regexp2000/src/codegen-ia32.h [new file with mode: 0644]
regexp2000/src/codegen-inl.h [new file with mode: 0644]
regexp2000/src/codegen.cc [new file with mode: 0644]
regexp2000/src/codegen.h [new file with mode: 0644]
regexp2000/src/compilation-cache.cc [new file with mode: 0644]
regexp2000/src/compilation-cache.h [new file with mode: 0644]
regexp2000/src/compiler.cc [new file with mode: 0644]
regexp2000/src/compiler.h [new file with mode: 0644]
regexp2000/src/constants-arm.h [new file with mode: 0644]
regexp2000/src/contexts.cc [new file with mode: 0644]
regexp2000/src/contexts.h [new file with mode: 0644]
regexp2000/src/conversions-inl.h [new file with mode: 0644]
regexp2000/src/conversions.cc [new file with mode: 0644]
regexp2000/src/conversions.h [new file with mode: 0644]
regexp2000/src/counters.cc [new file with mode: 0644]
regexp2000/src/counters.h [new file with mode: 0644]
regexp2000/src/cpu-arm.cc [new file with mode: 0644]
regexp2000/src/cpu-ia32.cc [new file with mode: 0644]
regexp2000/src/cpu.h [new file with mode: 0644]
regexp2000/src/d8-readline.cc [new file with mode: 0644]
regexp2000/src/d8.cc [new file with mode: 0644]
regexp2000/src/d8.h [new file with mode: 0644]
regexp2000/src/d8.js [new file with mode: 0644]
regexp2000/src/date-delay.js [new file with mode: 0644]
regexp2000/src/dateparser.cc [new file with mode: 0644]
regexp2000/src/dateparser.h [new file with mode: 0644]
regexp2000/src/debug-delay.js [new file with mode: 0644]
regexp2000/src/debug.cc [new file with mode: 0644]
regexp2000/src/debug.h [new file with mode: 0644]
regexp2000/src/disasm-arm.cc [new file with mode: 0644]
regexp2000/src/disasm-ia32.cc [new file with mode: 0644]
regexp2000/src/disasm.h [new file with mode: 0644]
regexp2000/src/disassembler.cc [new file with mode: 0644]
regexp2000/src/disassembler.h [new file with mode: 0644]
regexp2000/src/dtoa-config.c [new file with mode: 0644]
regexp2000/src/execution.cc [new file with mode: 0644]
regexp2000/src/execution.h [new file with mode: 0644]
regexp2000/src/factory.cc [new file with mode: 0644]
regexp2000/src/factory.h [new file with mode: 0644]
regexp2000/src/flag-definitions.h [new file with mode: 0644]
regexp2000/src/flags.cc [new file with mode: 0644]
regexp2000/src/flags.h [new file with mode: 0644]
regexp2000/src/frames-arm.cc [new file with mode: 0644]
regexp2000/src/frames-arm.h [new file with mode: 0644]
regexp2000/src/frames-ia32.cc [new file with mode: 0644]
regexp2000/src/frames-ia32.h [new file with mode: 0644]
regexp2000/src/frames-inl.h [new file with mode: 0644]
regexp2000/src/frames.cc [new file with mode: 0644]
regexp2000/src/frames.h [new file with mode: 0644]
regexp2000/src/global-handles.cc [new file with mode: 0644]
regexp2000/src/global-handles.h [new file with mode: 0644]
regexp2000/src/globals.h [new file with mode: 0644]
regexp2000/src/handles-inl.h [new file with mode: 0644]
regexp2000/src/handles.cc [new file with mode: 0644]
regexp2000/src/handles.h [new file with mode: 0644]
regexp2000/src/hashmap.cc [new file with mode: 0644]
regexp2000/src/hashmap.h [new file with mode: 0644]
regexp2000/src/heap-inl.h [new file with mode: 0644]
regexp2000/src/heap.cc [new file with mode: 0644]
regexp2000/src/heap.h [new file with mode: 0644]
regexp2000/src/ic-arm.cc [new file with mode: 0644]
regexp2000/src/ic-ia32.cc [new file with mode: 0644]
regexp2000/src/ic-inl.h [new file with mode: 0644]
regexp2000/src/ic.cc [new file with mode: 0644]
regexp2000/src/ic.h [new file with mode: 0644]
regexp2000/src/jsregexp.cc [new file with mode: 0644]
regexp2000/src/jsregexp.h [new file with mode: 0644]
regexp2000/src/list-inl.h [new file with mode: 0644]
regexp2000/src/list.h [new file with mode: 0644]
regexp2000/src/log.cc [new file with mode: 0644]
regexp2000/src/log.h [new file with mode: 0644]
regexp2000/src/macro-assembler-arm.cc [new file with mode: 0644]
regexp2000/src/macro-assembler-arm.h [new file with mode: 0644]
regexp2000/src/macro-assembler-ia32.cc [new file with mode: 0644]
regexp2000/src/macro-assembler-ia32.h [new file with mode: 0644]
regexp2000/src/macro-assembler.h [new file with mode: 0644]
regexp2000/src/macros.py [new file with mode: 0644]
regexp2000/src/mark-compact.cc [new file with mode: 0644]
regexp2000/src/mark-compact.h [new file with mode: 0644]
regexp2000/src/math.js [new file with mode: 0644]
regexp2000/src/memory.h [new file with mode: 0644]
regexp2000/src/messages.cc [new file with mode: 0644]
regexp2000/src/messages.h [new file with mode: 0644]
regexp2000/src/messages.js [new file with mode: 0644]
regexp2000/src/mirror-delay.js [new file with mode: 0644]
regexp2000/src/mksnapshot.cc [new file with mode: 0644]
regexp2000/src/natives.h [new file with mode: 0644]
regexp2000/src/objects-debug.cc [new file with mode: 0644]
regexp2000/src/objects-inl.h [new file with mode: 0644]
regexp2000/src/objects.cc [new file with mode: 0644]
regexp2000/src/objects.h [new file with mode: 0644]
regexp2000/src/parser.cc [new file with mode: 0644]
regexp2000/src/parser.h [new file with mode: 0644]
regexp2000/src/platform-linux.cc [new file with mode: 0644]
regexp2000/src/platform-macos.cc [new file with mode: 0644]
regexp2000/src/platform-nullos.cc [new file with mode: 0644]
regexp2000/src/platform-win32.cc [new file with mode: 0644]
regexp2000/src/platform.h [new file with mode: 0644]
regexp2000/src/prettyprinter.cc [new file with mode: 0644]
regexp2000/src/prettyprinter.h [new file with mode: 0644]
regexp2000/src/property.cc [new file with mode: 0644]
regexp2000/src/property.h [new file with mode: 0644]
regexp2000/src/regexp-delay.js [new file with mode: 0644]
regexp2000/src/rewriter.cc [new file with mode: 0644]
regexp2000/src/rewriter.h [new file with mode: 0644]
regexp2000/src/runtime.cc [new file with mode: 0644]
regexp2000/src/runtime.h [new file with mode: 0644]
regexp2000/src/runtime.js [new file with mode: 0644]
regexp2000/src/scanner.cc [new file with mode: 0644]
regexp2000/src/scanner.h [new file with mode: 0644]
regexp2000/src/scopeinfo.cc [new file with mode: 0644]
regexp2000/src/scopeinfo.h [new file with mode: 0644]
regexp2000/src/scopes.cc [new file with mode: 0644]
regexp2000/src/scopes.h [new file with mode: 0644]
regexp2000/src/serialize.cc [new file with mode: 0644]
regexp2000/src/serialize.h [new file with mode: 0644]
regexp2000/src/shell.h [new file with mode: 0644]
regexp2000/src/simulator-arm.cc [new file with mode: 0644]
regexp2000/src/simulator-arm.h [new file with mode: 0644]
regexp2000/src/simulator-ia32.cc [new file with mode: 0644]
regexp2000/src/simulator-ia32.h [new file with mode: 0644]
regexp2000/src/smart-pointer.h [new file with mode: 0644]
regexp2000/src/snapshot-common.cc [new file with mode: 0644]
regexp2000/src/snapshot-empty.cc [new file with mode: 0644]
regexp2000/src/snapshot.h [new file with mode: 0644]
regexp2000/src/spaces-inl.h [new file with mode: 0644]
regexp2000/src/spaces.cc [new file with mode: 0644]
regexp2000/src/spaces.h [new file with mode: 0644]
regexp2000/src/string-stream.cc [new file with mode: 0644]
regexp2000/src/string-stream.h [new file with mode: 0644]
regexp2000/src/string.js [new file with mode: 0644]
regexp2000/src/stub-cache-arm.cc [new file with mode: 0644]
regexp2000/src/stub-cache-ia32.cc [new file with mode: 0644]
regexp2000/src/stub-cache.cc [new file with mode: 0644]
regexp2000/src/stub-cache.h [new file with mode: 0644]
regexp2000/src/third_party/dtoa/COPYING [new file with mode: 0644]
regexp2000/src/third_party/dtoa/dtoa.c [new file with mode: 0644]
regexp2000/src/third_party/jscre/ASCIICType.h [new file with mode: 0644]
regexp2000/src/third_party/jscre/AUTHORS [new file with mode: 0644]
regexp2000/src/third_party/jscre/COPYING [new file with mode: 0644]
regexp2000/src/third_party/jscre/LICENSE [new file with mode: 0644]
regexp2000/src/third_party/jscre/config.h [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre.h [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre_chartables.c [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre_compile.cpp [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre_exec.cpp [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre_internal.h [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre_tables.cpp [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre_ucp_searchfuncs.cpp [new file with mode: 0644]
regexp2000/src/third_party/jscre/pcre_xclass.cpp [new file with mode: 0644]
regexp2000/src/third_party/jscre/ucpinternal.h [new file with mode: 0644]
regexp2000/src/third_party/jscre/ucptable.cpp [new file with mode: 0644]
regexp2000/src/token.cc [new file with mode: 0644]
regexp2000/src/token.h [new file with mode: 0644]
regexp2000/src/top.cc [new file with mode: 0644]
regexp2000/src/top.h [new file with mode: 0644]
regexp2000/src/unicode-inl.h [new file with mode: 0644]
regexp2000/src/unicode.cc [new file with mode: 0644]
regexp2000/src/unicode.h [new file with mode: 0644]
regexp2000/src/uri.js [new file with mode: 0644]
regexp2000/src/usage-analyzer.cc [new file with mode: 0644]
regexp2000/src/usage-analyzer.h [new file with mode: 0644]
regexp2000/src/utils.cc [new file with mode: 0644]
regexp2000/src/utils.h [new file with mode: 0644]
regexp2000/src/v8-counters.cc [new file with mode: 0644]
regexp2000/src/v8-counters.h [new file with mode: 0644]
regexp2000/src/v8.cc [new file with mode: 0644]
regexp2000/src/v8.h [new file with mode: 0644]
regexp2000/src/v8natives.js [new file with mode: 0644]
regexp2000/src/v8threads.cc [new file with mode: 0644]
regexp2000/src/v8threads.h [new file with mode: 0644]
regexp2000/src/variables.cc [new file with mode: 0644]
regexp2000/src/variables.h [new file with mode: 0644]
regexp2000/src/zone-inl.h [new file with mode: 0644]
regexp2000/src/zone.cc [new file with mode: 0644]
regexp2000/src/zone.h [new file with mode: 0644]
regexp2000/test/cctest/SConscript [new file with mode: 0644]
regexp2000/test/cctest/cctest.cc [new file with mode: 0644]
regexp2000/test/cctest/cctest.h [new file with mode: 0644]
regexp2000/test/cctest/cctest.status [new file with mode: 0644]
regexp2000/test/cctest/test-api.cc [new file with mode: 0644]
regexp2000/test/cctest/test-assembler-arm.cc [new file with mode: 0644]
regexp2000/test/cctest/test-assembler-ia32.cc [new file with mode: 0644]
regexp2000/test/cctest/test-ast.cc [new file with mode: 0644]
regexp2000/test/cctest/test-compiler.cc [new file with mode: 0644]
regexp2000/test/cctest/test-conversions.cc [new file with mode: 0644]
regexp2000/test/cctest/test-debug.cc [new file with mode: 0644]
regexp2000/test/cctest/test-decls.cc [new file with mode: 0644]
regexp2000/test/cctest/test-disasm-arm.cc [new file with mode: 0644]
regexp2000/test/cctest/test-disasm-ia32.cc [new file with mode: 0644]
regexp2000/test/cctest/test-flags.cc [new file with mode: 0644]
regexp2000/test/cctest/test-hashmap.cc [new file with mode: 0644]
regexp2000/test/cctest/test-heap.cc [new file with mode: 0644]
regexp2000/test/cctest/test-lock.cc [new file with mode: 0644]
regexp2000/test/cctest/test-mark-compact.cc [new file with mode: 0644]
regexp2000/test/cctest/test-platform-linux.cc [new file with mode: 0644]
regexp2000/test/cctest/test-platform-macos.cc [new file with mode: 0644]
regexp2000/test/cctest/test-platform-nullos.cc [new file with mode: 0644]
regexp2000/test/cctest/test-platform-win32.cc [new file with mode: 0644]
regexp2000/test/cctest/test-regexp.cc [new file with mode: 0644]
regexp2000/test/cctest/test-serialize.cc [new file with mode: 0644]
regexp2000/test/cctest/test-spaces.cc [new file with mode: 0644]
regexp2000/test/cctest/test-strings.cc [new file with mode: 0644]
regexp2000/test/cctest/test-utils.cc [new file with mode: 0644]
regexp2000/test/cctest/testcfg.py [new file with mode: 0644]
regexp2000/test/message/message.status [new file with mode: 0644]
regexp2000/test/message/regress/regress-73.js [new file with mode: 0644]
regexp2000/test/message/regress/regress-73.out [new file with mode: 0644]
regexp2000/test/message/regress/regress-75.js [new file with mode: 0644]
regexp2000/test/message/regress/regress-75.out [new file with mode: 0644]
regexp2000/test/message/simple-throw.js [new file with mode: 0644]
regexp2000/test/message/simple-throw.out [new file with mode: 0644]
regexp2000/test/message/testcfg.py [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-no-message.js [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-no-message.out [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-throw-in-catch-and-finally.js [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-throw-in-catch-and-finally.out [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-throw-in-catch.js [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-throw-in-catch.out [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-throw-in-finally.js [new file with mode: 0644]
regexp2000/test/message/try-catch-finally-throw-in-finally.out [new file with mode: 0644]
regexp2000/test/message/try-finally-throw-in-finally.js [new file with mode: 0644]
regexp2000/test/message/try-finally-throw-in-finally.out [new file with mode: 0644]
regexp2000/test/message/try-finally-throw-in-try-and-finally.js [new file with mode: 0644]
regexp2000/test/message/try-finally-throw-in-try-and-finally.out [new file with mode: 0644]
regexp2000/test/message/try-finally-throw-in-try.js [new file with mode: 0644]
regexp2000/test/message/try-finally-throw-in-try.out [new file with mode: 0644]
regexp2000/test/mjsunit/api-call-after-bypassed-exception.js [new file with mode: 0644]
regexp2000/test/mjsunit/apply.js [new file with mode: 0644]
regexp2000/test/mjsunit/arguments-call-apply.js [new file with mode: 0644]
regexp2000/test/mjsunit/arguments-enum.js [new file with mode: 0644]
regexp2000/test/mjsunit/arguments-indirect.js [new file with mode: 0644]
regexp2000/test/mjsunit/arguments-opt.js [new file with mode: 0644]
regexp2000/test/mjsunit/arguments.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-concat.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-functions-prototype.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-indexing.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-iteration.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-join.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-length.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-sort.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-splice-webkit.js [new file with mode: 0644]
regexp2000/test/mjsunit/array-splice.js [new file with mode: 0644]
regexp2000/test/mjsunit/array_length.js [new file with mode: 0644]
regexp2000/test/mjsunit/ascii-regexp-subject.js [new file with mode: 0644]
regexp2000/test/mjsunit/binary-operation-overwrite.js [new file with mode: 0644]
regexp2000/test/mjsunit/body-not-visible.js [new file with mode: 0644]
regexp2000/test/mjsunit/bugs/bug-1231206.js [new file with mode: 0644]
regexp2000/test/mjsunit/bugs/bug-1344252.js [new file with mode: 0644]
regexp2000/test/mjsunit/bugs/bug-87.js [new file with mode: 0644]
regexp2000/test/mjsunit/bugs/bug-900066.js [new file with mode: 0644]
regexp2000/test/mjsunit/bugs/bug-941049.js [new file with mode: 0644]
regexp2000/test/mjsunit/call-non-function-call.js [new file with mode: 0644]
regexp2000/test/mjsunit/call-non-function.js [new file with mode: 0644]
regexp2000/test/mjsunit/call.js [new file with mode: 0644]
regexp2000/test/mjsunit/char-escape.js [new file with mode: 0644]
regexp2000/test/mjsunit/class-of-builtins.js [new file with mode: 0644]
regexp2000/test/mjsunit/closure.js [new file with mode: 0644]
regexp2000/test/mjsunit/compare-nan.js [new file with mode: 0644]
regexp2000/test/mjsunit/const-redecl.js [new file with mode: 0644]
regexp2000/test/mjsunit/const.js [new file with mode: 0644]
regexp2000/test/mjsunit/context-variable-assignments.js [new file with mode: 0644]
regexp2000/test/mjsunit/cyclic-array-to-string.js [new file with mode: 0644]
regexp2000/test/mjsunit/date-parse.js [new file with mode: 0644]
regexp2000/test/mjsunit/date.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-backtrace-text.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-backtrace.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-breakpoints.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-changebreakpoint.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-clearbreakpoint.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-conditional-breakpoints.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-constructed-by.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-constructor.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-continue.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-enable-disable-breakpoints.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-evaluate-arguments.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-evaluate-locals.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-evaluate-recursive.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-evaluate-with.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-evaluate.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-event-listener.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-ignore-breakpoints.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-multiple-breakpoints.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-referenced-by.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-script-breakpoints.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-script.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-scripts-request.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-setbreakpoint.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-sourceinfo.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-sourceslice.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-step-stub-callfunction.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-step.js [new file with mode: 0644]
regexp2000/test/mjsunit/debug-stepin-constructor.js [new file with mode: 0644]
regexp2000/test/mjsunit/declare-locally.js [new file with mode: 0644]
regexp2000/test/mjsunit/deep-recursion.js [new file with mode: 0644]
regexp2000/test/mjsunit/delay-syntax-error.js [new file with mode: 0644]
regexp2000/test/mjsunit/delete-global-properties.js [new file with mode: 0644]
regexp2000/test/mjsunit/delete-in-eval.js [new file with mode: 0644]
regexp2000/test/mjsunit/delete-in-with.js [new file with mode: 0644]
regexp2000/test/mjsunit/delete-vars-from-eval.js [new file with mode: 0644]
regexp2000/test/mjsunit/delete.js [new file with mode: 0644]
regexp2000/test/mjsunit/do-not-strip-fc.js [new file with mode: 0644]
regexp2000/test/mjsunit/dont-enum-array-holes.js [new file with mode: 0644]
regexp2000/test/mjsunit/dont-reinit-global-var.js [new file with mode: 0644]
regexp2000/test/mjsunit/double-equals.js [new file with mode: 0644]
regexp2000/test/mjsunit/dtoa.js [new file with mode: 0644]
regexp2000/test/mjsunit/enumeration_order.js [new file with mode: 0644]
regexp2000/test/mjsunit/escape.js [new file with mode: 0644]
regexp2000/test/mjsunit/eval-typeof-non-existing.js [new file with mode: 0644]
regexp2000/test/mjsunit/execScript-case-insensitive.js [new file with mode: 0644]
regexp2000/test/mjsunit/extra-arguments.js [new file with mode: 0644]
regexp2000/test/mjsunit/extra-commas.js [new file with mode: 0644]
regexp2000/test/mjsunit/for-in-null-or-undefined.js [new file with mode: 0644]
regexp2000/test/mjsunit/for-in-special-cases.js [new file with mode: 0644]
regexp2000/test/mjsunit/for-in.js [new file with mode: 0644]
regexp2000/test/mjsunit/fun-as-prototype.js [new file with mode: 0644]
regexp2000/test/mjsunit/fun_name.js [new file with mode: 0644]
regexp2000/test/mjsunit/function-arguments-null.js [new file with mode: 0644]
regexp2000/test/mjsunit/function-caller.js [new file with mode: 0644]
regexp2000/test/mjsunit/function-names.js [new file with mode: 0644]
regexp2000/test/mjsunit/function-property.js [new file with mode: 0644]
regexp2000/test/mjsunit/function-prototype.js [new file with mode: 0644]
regexp2000/test/mjsunit/function-source.js [new file with mode: 0644]
regexp2000/test/mjsunit/function.js [new file with mode: 0644]
regexp2000/test/mjsunit/fuzz-accessors.js [new file with mode: 0644]
regexp2000/test/mjsunit/fuzz-natives.js [new file with mode: 0644]
regexp2000/test/mjsunit/getter-in-value-prototype.js [new file with mode: 0644]
regexp2000/test/mjsunit/global-const-var-conflicts.js [new file with mode: 0644]
regexp2000/test/mjsunit/global-vars-eval.js [new file with mode: 0644]
regexp2000/test/mjsunit/global-vars-with.js [new file with mode: 0644]
regexp2000/test/mjsunit/greedy.js [new file with mode: 0644]
regexp2000/test/mjsunit/has-own-property.js [new file with mode: 0644]
regexp2000/test/mjsunit/html-comments.js [new file with mode: 0644]
regexp2000/test/mjsunit/html-string-funcs.js [new file with mode: 0644]
regexp2000/test/mjsunit/if-in-undefined.js [new file with mode: 0644]
regexp2000/test/mjsunit/in.js [new file with mode: 0644]
regexp2000/test/mjsunit/instanceof.js [new file with mode: 0644]
regexp2000/test/mjsunit/integer-to-string.js [new file with mode: 0644]
regexp2000/test/mjsunit/invalid-lhs.js [new file with mode: 0644]
regexp2000/test/mjsunit/keyed-ic.js [new file with mode: 0644]
regexp2000/test/mjsunit/keyed-storage-extend.js [new file with mode: 0644]
regexp2000/test/mjsunit/large-object-allocation.js [new file with mode: 0644]
regexp2000/test/mjsunit/large-object-literal.js [new file with mode: 0644]
regexp2000/test/mjsunit/lazy-load.js [new file with mode: 0644]
regexp2000/test/mjsunit/leakcheck.js [new file with mode: 0644]
regexp2000/test/mjsunit/length.js [new file with mode: 0644]
regexp2000/test/mjsunit/math-min-max.js [new file with mode: 0644]
regexp2000/test/mjsunit/megamorphic-callbacks.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-array.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-boolean.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-date.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-error.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-function.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-null.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-number.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-object.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-regexp.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-string.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-undefined.js [new file with mode: 0644]
regexp2000/test/mjsunit/mirror-unresolved-function.js [new file with mode: 0644]
regexp2000/test/mjsunit/mjsunit.js [new file with mode: 0644]
regexp2000/test/mjsunit/mjsunit.status [new file with mode: 0644]
regexp2000/test/mjsunit/mul-exhaustive.js [new file with mode: 0644]
regexp2000/test/mjsunit/negate-zero.js [new file with mode: 0644]
regexp2000/test/mjsunit/negate.js [new file with mode: 0644]
regexp2000/test/mjsunit/nested-repetition-count-overflow.js [new file with mode: 0644]
regexp2000/test/mjsunit/new.js [new file with mode: 0644]
regexp2000/test/mjsunit/newline-in-string.js [new file with mode: 0644]
regexp2000/test/mjsunit/no-branch-elimination.js [new file with mode: 0644]
regexp2000/test/mjsunit/no-octal-constants-above-256.js [new file with mode: 0644]
regexp2000/test/mjsunit/no-semicolon.js [new file with mode: 0644]
regexp2000/test/mjsunit/non-ascii-replace.js [new file with mode: 0644]
regexp2000/test/mjsunit/nul-characters.js [new file with mode: 0644]
regexp2000/test/mjsunit/number-limits.js [new file with mode: 0644]
regexp2000/test/mjsunit/number-string-index-call.js [new file with mode: 0644]
regexp2000/test/mjsunit/number-tostring-small.js [new file with mode: 0644]
regexp2000/test/mjsunit/number-tostring.js [new file with mode: 0644]
regexp2000/test/mjsunit/obj-construct.js [new file with mode: 0644]
regexp2000/test/mjsunit/parse-int-float.js [new file with mode: 0644]
regexp2000/test/mjsunit/property-object-key.js [new file with mode: 0644]
regexp2000/test/mjsunit/proto.js [new file with mode: 0644]
regexp2000/test/mjsunit/prototype.js [new file with mode: 0644]
regexp2000/test/mjsunit/regexp-indexof.js [new file with mode: 0644]
regexp2000/test/mjsunit/regexp-multiline-stack-trace.js [new file with mode: 0644]
regexp2000/test/mjsunit/regexp-multiline.js [new file with mode: 0644]
regexp2000/test/mjsunit/regexp-standalones.js [new file with mode: 0644]
regexp2000/test/mjsunit/regexp-static.js [new file with mode: 0644]
regexp2000/test/mjsunit/regexp.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1030466.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1036894.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1039610.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1050043.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1062422.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1066899.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1081309.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1102760.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1110164.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1112051.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1114040.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1134697.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-114.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-116.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1170187.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1173979.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1175390.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1177518.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1177809.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1178598.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1182832.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1187524.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1199401.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1199637.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1200351.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1201933.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1203459.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1207276.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1213516.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1213575.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1215653.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-124.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1254366.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1327557.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1341167.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1346700.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-1439135.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-20070207.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-35.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-57.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-588599.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-662254.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-666721.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-667061.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-670147.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-674753.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-676025.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-678525.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-682649.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-69.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-734862.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-737588.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-780423.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-799761.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-806473.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-842017.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-86.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-874178.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-875031.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-877615.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-892742.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-900055.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-900966.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-925537.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-937896.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-990205.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-992733.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-996542.js [new file with mode: 0644]
regexp2000/test/mjsunit/regress/regress-998565.js [new file with mode: 0644]
regexp2000/test/mjsunit/scanner.js [new file with mode: 0644]
regexp2000/test/mjsunit/smi-negative-zero.js [new file with mode: 0644]
regexp2000/test/mjsunit/smi-ops.js [new file with mode: 0644]
regexp2000/test/mjsunit/sparse-array-reverse.js [new file with mode: 0644]
regexp2000/test/mjsunit/sparse-array.js [new file with mode: 0644]
regexp2000/test/mjsunit/str-to-num.js [new file with mode: 0644]
regexp2000/test/mjsunit/stress-array-push.js [new file with mode: 0644]
regexp2000/test/mjsunit/strict-equals.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-case.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-charat.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-charcodeat.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-flatten.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-index.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-indexof.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-lastindexof.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-localecompare.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-search.js [new file with mode: 0644]
regexp2000/test/mjsunit/string-split.js [new file with mode: 0644]
regexp2000/test/mjsunit/substr.js [new file with mode: 0644]
regexp2000/test/mjsunit/switch.js [new file with mode: 0644]
regexp2000/test/mjsunit/testcfg.py [new file with mode: 0644]
regexp2000/test/mjsunit/this-in-callbacks.js [new file with mode: 0644]
regexp2000/test/mjsunit/this.js [new file with mode: 0644]
regexp2000/test/mjsunit/throw-exception-for-null-access.js [new file with mode: 0644]
regexp2000/test/mjsunit/to-precision.js [new file with mode: 0644]
regexp2000/test/mjsunit/tobool.js [new file with mode: 0644]
regexp2000/test/mjsunit/toint32.js [new file with mode: 0644]
regexp2000/test/mjsunit/touint32.js [new file with mode: 0644]
regexp2000/test/mjsunit/try-finally-nested.js [new file with mode: 0644]
regexp2000/test/mjsunit/try.js [new file with mode: 0644]
regexp2000/test/mjsunit/try_catch_scopes.js [new file with mode: 0644]
regexp2000/test/mjsunit/unicode-string-to-number.js [new file with mode: 0644]
regexp2000/test/mjsunit/unicode-test.js [new file with mode: 0644]
regexp2000/test/mjsunit/unusual-constructor.js [new file with mode: 0644]
regexp2000/test/mjsunit/uri.js [new file with mode: 0644]
regexp2000/test/mjsunit/value-callic-prototype-change.js [new file with mode: 0644]
regexp2000/test/mjsunit/var.js [new file with mode: 0644]
regexp2000/test/mjsunit/with-function-expression.js [new file with mode: 0644]
regexp2000/test/mjsunit/with-leave.js [new file with mode: 0644]
regexp2000/test/mjsunit/with-parameter-access.js [new file with mode: 0644]
regexp2000/test/mjsunit/with-value.js [new file with mode: 0644]
regexp2000/test/mozilla/mozilla.status [new file with mode: 0644]
regexp2000/test/mozilla/testcfg.py [new file with mode: 0644]
regexp2000/tools/js2c.py [new file with mode: 0755]
regexp2000/tools/linux-tick-processor.py [new file with mode: 0755]
regexp2000/tools/presubmit.py [new file with mode: 0755]
regexp2000/tools/splaytree.py [new file with mode: 0644]
regexp2000/tools/test.py [new file with mode: 0755]
regexp2000/tools/tickprocessor.py [new file with mode: 0644]
regexp2000/tools/utils.py [new file with mode: 0644]
regexp2000/tools/v8.xcodeproj/project.pbxproj [new file with mode: 0644]
regexp2000/tools/visual_studio/README.txt [new file with mode: 0644]
regexp2000/tools/visual_studio/common.vsprops [new file with mode: 0644]
regexp2000/tools/visual_studio/d8.vcproj [new file with mode: 0644]
regexp2000/tools/visual_studio/d8js2c.cmd [new file with mode: 0644]
regexp2000/tools/visual_studio/debug.vsprops [new file with mode: 0644]
regexp2000/tools/visual_studio/js2c.cmd [new file with mode: 0644]
regexp2000/tools/visual_studio/release.vsprops [new file with mode: 0644]
regexp2000/tools/visual_studio/v8.sln [new file with mode: 0644]
regexp2000/tools/visual_studio/v8.vcproj [new file with mode: 0644]
regexp2000/tools/visual_studio/v8_base.vcproj [new file with mode: 0644]
regexp2000/tools/visual_studio/v8_cctest.vcproj [new file with mode: 0644]
regexp2000/tools/visual_studio/v8_mksnapshot.vcproj [new file with mode: 0644]
regexp2000/tools/visual_studio/v8_process_sample.vcproj [new file with mode: 0644]
regexp2000/tools/visual_studio/v8_shell_sample.vcproj [new file with mode: 0644]
regexp2000/tools/visual_studio/v8_snapshot.vcproj [new file with mode: 0644]
regexp2000/tools/windows-tick-processor.py [new file with mode: 0755]

diff --git a/regexp2000/AUTHORS b/regexp2000/AUTHORS
new file mode 100644 (file)
index 0000000..596cc58
--- /dev/null
@@ -0,0 +1,13 @@
+# Below is a list of people and organizations that have contributed
+# to the V8 project.  Names should be added to the list like so:
+#
+#   Name/Organization <email address>
+
+Google Inc.
+
+Rene Rebe <rene@exactcode.de>
+Rafal Krypa <rafal@krypa.net>
+Jay Freeman <saurik@saurik.com>
+Daniel James <dnljms@gmail.com>
+Paolo Giarrusso <p.giarrusso@gmail.com>
+Daniel Andersson <kodandersson@gmail.com>
diff --git a/regexp2000/ChangeLog b/regexp2000/ChangeLog
new file mode 100644 (file)
index 0000000..95d3202
--- /dev/null
@@ -0,0 +1,403 @@
+2008-10-23: Version 0.4.0
+
+        Split the global object into two parts: The state holding global
+        object and the global object proxy.
+
+        Fixed bug that affected the value of an assignment to an element
+        in certain cases (issue 116).
+
+        Added GetPropertyNames functionality (issue 33) and extra Date
+        functions (issue 77) to the API.
+
+        Changed WeakReferenceCallback to take a Persistent<Value> instead
+        of a Persistent<Object> (issue 101).
+
+        Fixed issues with message reporting for exceptions in try-finally
+        blocks (issues 73 and 75).
+
+        Optimized flattening of strings and string equality checking. 
+
+        Improved Boyer-Moore implementation for faster indexOf operations.
+
+        Added development shell (d8) which includes counters and
+        completion support.
+
+        Fixed problem with the receiver passed to functions called from
+        eval (issue 124).
+
+
+2008-10-16: Version 0.3.5
+
+        Improved string hash-code distribution by excluding bit-field bits
+        from the hash-code.
+
+        Changed string search algorithm used in indexOf from KMP to
+        Boyer-Moore.
+
+        Improved the generated code for the instanceof operator.
+
+        Improved performance of slow-case string equality checks by
+        specializing the code based on the string representation.
+
+        Improve the handling of out-of-memory situations (issue 70).
+
+        Improved performance of strict equality checks.
+
+        Improved profiler output to make it easier to see anonymous
+        functions.
+
+        Improved performance of slow-case keyed loads.
+
+        Improved property access performance by allocating a number of
+        properties in the front object.
+
+        Changed the toString behavior on the built-in object constructors
+        to print [native code] instead of the actual source.  Some web
+        applications do not like constructors with complex toString
+        results.
+        
+
+2008-10-06: Version 0.3.4
+
+        Changed Array.prototype.sort to use quick sort.
+
+        Fixed code generation issue where leaving a finally block with
+        break or continue would accumulate elements on the expression
+        stack (issue 86).
+
+        Made sure that the name accessor on functions returns the expected
+        names for builtin JavaScript functions and C++ callback functions.
+
+        Added fast case code for extending the property storage array of
+        JavaScript objects.
+
+        Ported switch statement optimizations introduced in version 0.3.3
+        to the ARM code generator.
+
+        Allowed GCC to use strict-aliasing rules when compiling.
+
+        Improved performance of arguments object allocation by taking care
+        of arguments adaptor frames in the generated code.
+
+        Updated the V8 benchmark suite to version 2.
+
+
+2008-09-25: Version 0.3.3
+
+        Improved handling of relocation information to enable more
+        peep-hole optimizations.
+
+        Optimized switch statements where all labels are constant small
+        integers.
+
+        Optimized String.prototype.indexOf for common cases.
+
+        Fixed more build issues (issue 80).
+
+        Fixed a couple of profiler issues.
+
+        Fixed bug where the body of a function created using the Function
+        constructor was not allowed to end with a single-line comment
+        (issue 85).
+
+        Improved handling of object literals by canonicalizing object
+        literal maps.  This will allow JSON objects with the same set of
+        properties to share the same map making inline caching work better
+        for JSON objects.
+        
+
+2008-09-17: Version 0.3.2
+
+        Generalized the EvalCache into a CompilationCache and enabled it
+        for scripts too.  The current strategy is to retire all entries
+        whenever a mark-sweep collection is started.
+
+        Fixed bug where switch statements containing only a default case
+        would lead to an unbalanced stack (issue 69).
+
+        Fixed bug that made access to the function in a named function
+        expression impossible in certain situations (issue 24).
+
+        Fixed even more build issues.
+
+        Optimized calling conventions on ARM.  The conventions on ARM and
+        IA-32 now match.
+
+        Removed static initializers for flags and counters.
+
+        Improved inline caching behavior for uncommon cases where lazily
+        loading Date and RegExp code could force certain code paths go
+        megamorphic.
+
+        Removed arguments adaption for builtins written in C++.  This
+        makes Array.prototype.push and Array.prototype.pop slightly
+        faster.
+
+
+2008-09-11: Version 0.3.1
+
+        Fixed a number of build issues.
+
+        Fixed problem with missing I-cache flusing on ARM.
+
+        Changed space layout in memory management by splitting up
+        code space into old data space and code space.
+
+        Added utf-8 conversion support to the API (issue 57).
+
+        Optimized repeated calls to eval with the same strings.  These
+        repeated calls are common in web applications.
+
+        Added Xcode project file.
+
+        Optimized a couple of Array operation.
+
+        Fixed parser bug by checking for end-of-string when parsing break
+        and continue (issue 35).
+
+        Fixed problem where asian characters were not categorized as
+        letters.
+
+        Fixed bug that disallowed calling functions fetched from an array
+        using a string as an array index (issue 32).
+
+        Fixed bug where the internal field count on object templates were
+        sometimes ignored (issue 54).
+
+        Added -f option to the shell sample for compatibility with other
+        engines (issue 18).
+
+        Added source info to TryCatches in the API.
+
+        Fixed problem where the seed for the random number generator was
+        clipped in a double to unsigned int conversion.
+
+        Fixed bug where cons string symbols were sometimes converted to
+        non-symbol flat strings during GC.
+
+        Fixed bug in error reporting when attempting to convert null to an
+        object.
+        
+        
+2008-09-04: Version 0.3.0
+
+        Added support for running tests on the ARM simulator.
+
+        Fixed bug in the 'in' operator where negative indices were not
+        treated correctly.
+
+        Fixed build issues on gcc-4.3.1.
+
+        Changed Date.prototype.toLocaleTimeString to not print the
+        timezone part of the time.
+
+        Renamed debug.h to v8-debug.h to reduce the risk of name conflicts
+        with user code.
+
+
+2008-09-02: Version 0.2.5
+
+        Renamed the top level directory 'public' to 'include'.
+
+        Added 'env' option to the SCons build scripts to support
+        overriding the ENV part of the build environment.  This is mostly
+        to support Windows builds in cases where SCons cannot find the
+        correct paths to the Windows SDK, as these paths cannot be passed
+        through shell environment variables.
+
+        Enabled "Buffer Security Check" on for the Windows SCons build and
+        added the linker option /OPT:ICF as an optimization.
+
+        Added the V8 benchmark suite to the repository.
+
+
+2008-09-01: Version 0.2.4
+
+        Included mjsunit JavaScript test suite and C++ unit tests.
+
+        Changed the shell sample to not print the result of executing a
+        script provided on the command line.
+
+        Fixed issue when building samples on Windows using a shared V8
+        library.  Added visibility option on Linux build which makes the
+        generated library 18% smaller.
+
+        Changed build system to accept multiple build modes in one build
+        and generate separate objects, libraries and executables for each
+        mode.
+
+        Removed deferred negation optimization (a * -b => -(a * b)) since
+        this visibly changes operand conversion order.
+
+        Improved parsing performance by introducing stack guard in
+        preparsing.  Without a stack guard preparsing always bails out
+        with stack overflow.
+
+        Changed shell sample to take flags directly from the command-line.
+        Added API call that implements this.
+
+        Added load, quit and version functions to the shell sample so it's
+        easier to run benchmarks and tests.
+
+        Fixed issue with building samples and cctests on 64-bit machines.
+
+        Fixed bug in the runtime system where the prototype chain was not
+        always searched for a setter when setting a property that does not
+        exist locally.
+        
+
+2008-08-14: Version 0.2.3
+
+        Improved performance of garbage collection by moving the
+        function that updates pointers during compacting collection
+        into the updating visitor.  This gives the compiler a better
+        chance to inline and avoid a function call per (potential)
+        pointer.
+
+        Extended the shell sample with a --runtime-flags option.
+
+        Added Visual Studio project files for the shell.cc and
+        process.cc samples.
+
+
+2008-08-13: Version 0.2.2
+
+        Improved performance of garbage collection by changing the way
+        we use the marking stack in the event of stack overflow during
+        full garbage collection and by changing the way we mark roots.
+
+        Cleaned up ARM version by removing top of stack caching and by
+        introducing push/pop elimination.
+
+        Cleaned up the way runtime functions are called to allow
+        runtime calls with no arguments.
+
+        Changed Windows build options to make sure that exceptions are
+        disabled and that optimization flags are enabled.
+
+        Added first version of Visual Studio project files.
+
+
+2008-08-06: Version 0.2.1
+
+        Improved performance of unary addition by avoiding runtime calls.
+
+        Fixed the handling of '>' and '<=' to use right-to-left conversion
+        and left-to-right evaluation as specified by ECMA-262.
+
+        Fixed a branch elimination bug on the ARM platform where incorrect
+        code was generated because of overly aggressive branch
+        elimination.
+
+        Improved performance of code that repeatedly assigns the same
+        function to the same property of different objects with the same
+        map.
+
+        Untangled DEBUG and ENABLE_DISASSEMBLER defines.  The disassembler
+        no longer expects DEBUG to be defined.
+
+        Added platform-nullos.cc to serve as the basis for new platform
+        implementations.
+
+
+2008-07-30: Version 0.2.0
+
+        Changed all text files to have native svn:eol-style.
+
+        Added a few samples and support for building them. The samples
+        include a simple shell that can be used to benchmark and test V8.
+
+        Changed V8::GetVersion to return the version as a string.
+
+        Added source for lazily loaded scripts to snapshots and made
+        serialization non-destructive.
+
+        Improved ARM support by fixing the write barrier code to use
+        aligned loads and stores and by removing premature locals
+        optimization that relied on broken support for callee-saved
+        registers (removed).
+
+        Refactored the code for marking live objects during garbage
+        collection and the code for allocating objects in paged
+        spaces. Introduced an abstraction for the map word of a heap-
+        allocated object and changed the memory allocator to allocate
+        executable memory only for spaces that may contain code objects.
+
+        Moved StringBuilder to utils.h and ScopedLock to platform.h, where
+        they can be used by debugging and logging modules. Added
+        thread-safe message queues for dealing with debugger events.
+
+        Fixed the source code reported by toString for certain builtin
+        empty functions and made sure that the prototype property of a
+        function is enumerable.
+
+        Improved performance of converting values to condition flags in
+        generated code.
+
+        Merged disassembler-{arch} files.
+
+
+2008-07-28: Version 0.1.4
+
+        Added support for storing JavaScript stack traces in a stack
+        allocated buffer to make it visible in shallow core dumps.
+        Controlled by the --preallocate-message-memory flag which is
+        disabled by default.
+
+
+2008-07-25: Version 0.1.3
+
+        Fixed bug in JSObject::GetPropertyAttributePostInterceptor where
+        map transitions would count as properties.
+
+        Allowed aliased eval invocations by treating them as evals in the
+        global context. This may change in the future.
+
+        Added support for accessing the last entered context through the
+        API and renamed Context::Current to Context::GetCurrent and
+        Context::GetSecurityContext to Context::GetCurrentSecurityContext.
+
+        Fixed bug in the debugger that would cause the debugger scripts to
+        be recursively loaded and changed all disabling of interrupts to
+        be block-structured.
+
+        Made snapshot data read-only to allow it to be more easily shared
+        across multiple users of V8 when linked as a shared library.
+
+
+2008-07-16: Version 0.1.2
+
+        Fixed building on Mac OS X by recognizing i386 and friends as
+        IA-32 platforms.
+
+        Added propagation of stack overflow exceptions that occur while
+        compiling nested functions.
+
+        Improved debugger with support for recursive break points and
+        handling of exceptions that occur in the debugger JavaScript code.
+
+        Renamed GetInternal to GetInternalField and SetInternal to
+        SetInternalField in the API and moved InternalFieldCount and
+        SetInternalFieldCount from FunctionTemplate to ObjectTemplate.
+
+
+2008-07-09: Version 0.1.1
+
+        Fixed bug in stack overflow check code for IA-32 targets where a
+        non-tagged value in register eax was pushed to the stack.
+
+        Fixed potential quadratic behavior when converting strings to
+        numbers.
+
+        Fixed bug where the return value from Object::SetProperty could
+        end up being the property holder instead of the written value.
+
+        Improved debugger support by allowing nested break points and by
+        dealing with stack-overflows when compiling functions before
+        setting break points in them.
+
+
+2008-07-03: Version 0.1.0
+
+        Initial export.
+
diff --git a/regexp2000/LICENSE b/regexp2000/LICENSE
new file mode 100644 (file)
index 0000000..2f61dc7
--- /dev/null
@@ -0,0 +1,46 @@
+This license applies to all parts of V8 that are not externally
+maintained libraries.  The externally maintained libraries used by V8
+are:
+
+  - Jscre, located under third_party/jscre.  This code is copyrighted
+    by the University of Cambridge and Apple Inc. and released under a
+    2-clause BSD license.
+
+  - Dtoa, located under third_party/dtoa.  This code is copyrighted by
+    David M. Gay and released under an MIT license.
+
+  - Strongtalk assembler, the basis of the files assembler-arm-inl.h,
+    assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h,
+    assembler-ia32.cc, assembler-ia32.h, assembler.cc and assembler.h.
+    This code is copyrighted by Sun Microsystems Inc. and released
+    under a 3-clause BSD license.
+
+These libraries have their own licenses; we recommend you read them,
+as their terms may differ from the terms below.
+
+Copyright 2006-2008, Google Inc. 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.
diff --git a/regexp2000/SConstruct b/regexp2000/SConstruct
new file mode 100644 (file)
index 0000000..6e5bc7a
--- /dev/null
@@ -0,0 +1,578 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import platform
+import re
+import sys
+import os
+from os.path import join, dirname, abspath
+from types import DictType, StringTypes
+root_dir = dirname(File('SConstruct').rfile().abspath)
+sys.path.append(join(root_dir, 'tools'))
+import js2c, utils
+
+
+LIBRARY_FLAGS = {
+  'all': {
+    'CPPDEFINES':   ['ENABLE_LOGGING_AND_PROFILING']
+  },
+  'gcc': {
+    'all': {
+      'DIALECTFLAGS': ['-ansi'],
+      'CCFLAGS':      ['$DIALECTFLAGS', '$WARNINGFLAGS'],
+      'CXXFLAGS':     ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'],
+      'LIBS':         ['pthread']
+    },
+    'mode:debug': {
+      'CCFLAGS':      ['-g', '-O0'],
+      'CPPDEFINES':   ['ENABLE_DISASSEMBLER', 'DEBUG']
+    },
+    'mode:release': {
+      'CCFLAGS':      ['-O3', '-fomit-frame-pointer']
+    },
+    'wordsize:64': {
+      'CCFLAGS':      ['-m32'],
+      'LINKFLAGS':    ['-m32']
+    }
+  },
+  'msvc': {
+    'all': {
+      'DIALECTFLAGS': ['/nologo'],
+      'CCFLAGS':      ['$DIALECTFLAGS', '$WARNINGFLAGS'],
+      'CXXFLAGS':     ['$CCFLAGS', '/GR-', '/Gy'],
+      'CPPDEFINES':   ['WIN32', '_USE_32BIT_TIME_T', 'PCRE_STATIC'],
+      'LINKFLAGS':    ['/NOLOGO', '/MACHINE:X86', '/INCREMENTAL:NO',
+          '/NXCOMPAT', '/IGNORE:4221'],
+      'ARFLAGS':      ['/NOLOGO'],
+      'CCPDBFLAGS':   ['/Zi']
+    },
+    'mode:debug': {
+      'CCFLAGS':      ['/Od', '/Gm', '/MTd'],
+      'CPPDEFINES':   ['_DEBUG', 'ENABLE_DISASSEMBLER', 'DEBUG'],
+      'LINKFLAGS':    ['/DEBUG']
+    },
+    'mode:release': {
+      'CCFLAGS':      ['/O2', '/MT', '/GL'],
+      'LINKFLAGS':    ['/OPT:REF', '/OPT:ICF', '/LTCG'],
+      'ARFLAGS':      ['/LTCG']
+    }
+  }
+}
+
+
+V8_EXTRA_FLAGS = {
+  'gcc': {
+    'all': {
+      'CXXFLAGS':     [], #['-fvisibility=hidden'],
+      'WARNINGFLAGS': ['-pedantic', '-Wall', '-Werror', '-W',
+          '-Wno-unused-parameter']
+    },
+    'arch:arm': {
+      'CPPDEFINES':   ['ARM']
+    },
+    'disassembler:on': {
+      'CPPDEFINES':   ['ENABLE_DISASSEMBLER']
+    }
+  },
+  'msvc': {
+    'all': {
+      'WARNINGFLAGS': ['/W3', '/WX', '/wd4355', '/wd4800']
+    },
+    'library:shared': {
+      'CPPDEFINES':   ['BUILDING_V8_SHARED']
+    },
+    'arch:arm': {
+      'CPPDEFINES':   ['ARM']
+    },
+    'disassembler:on': {
+      'CPPDEFINES':   ['ENABLE_DISASSEMBLER']
+    }
+  }
+}
+
+
+JSCRE_EXTRA_FLAGS = {
+  'gcc': {
+    'all': {
+      'CPPDEFINES':   ['SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
+      'WARNINGFLAGS': ['-w']
+    },
+  },
+  'msvc': {
+    'all': {
+      'CPPDEFINES':   ['SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
+      'WARNINGFLAGS': ['/W3', '/WX', '/wd4355', '/wd4800']
+    },
+    'library:shared': {
+      'CPPDEFINES':   ['BUILDING_V8_SHARED']
+    }
+  }
+}
+
+
+DTOA_EXTRA_FLAGS = {
+  'gcc': {
+    'all': {
+      'WARNINGFLAGS': ['-Werror']
+    }
+  },
+  'msvc': {
+    'all': {
+      'WARNINGFLAGS': ['/WX', '/wd4018', '/wd4244']
+    }
+  }
+}
+
+
+CCTEST_EXTRA_FLAGS = {
+  'all': {
+    'CPPPATH': [join(root_dir, 'src')],
+    'LIBS': ['$LIBRARY']
+  },
+  'gcc': {
+    'all': {
+      'LIBPATH': [abspath('.')]
+    },
+    'wordsize:64': {
+      'CCFLAGS':      ['-m32'],
+      'LINKFLAGS':    ['-m32']
+    },
+  },
+  'msvc': {
+    'all': {
+      'CPPDEFINES': ['_HAS_EXCEPTIONS=0']
+    },
+    'library:shared': {
+      'CPPDEFINES': ['USING_V8_SHARED']
+    }
+  }
+}
+
+
+SAMPLE_FLAGS = {
+  'all': {
+    'CPPPATH': [join(abspath('.'), 'include')],
+    'LIBS': ['$LIBRARY'],
+  },
+  'gcc': {
+    'all': {
+      'LIBS': ['pthread'],
+      'LIBPATH': ['.']
+    },
+    'wordsize:64': {
+      'CCFLAGS':      ['-m32'],
+      'LINKFLAGS':    ['-m32']
+    },
+    'mode:release': {
+      'CCFLAGS':      ['-O2']
+    },
+    'mode:debug': {
+      'CCFLAGS':      ['-g', '-O0']
+    }
+  },
+  'msvc': {
+    'all': {
+      'CCFLAGS': ['/nologo'],
+      'LINKFLAGS': ['/nologo'],
+    },
+    'library:shared': {
+      'CPPDEFINES': ['USING_V8_SHARED']
+    },
+    'prof:on': {
+      'LINKFLAGS': ['/MAP']
+    },
+    'mode:release': {
+      'CCFLAGS':   ['/O2', '/MT'],
+      'LINKFLAGS': ['/OPT:REF', '/OPT:ICF', '/LTCG']
+    },
+    'mode:debug': {
+      'CCFLAGS':   ['/Od', '/MTd'],
+      'LINKFLAGS': ['/DEBUG']
+    }
+  }
+}
+
+
+D8_FLAGS = {
+  'gcc': {
+    'console:readline': {
+      'LIBS': ['readline']
+    }
+  },
+  'msvc': { }
+}
+
+
+SUFFIXES = {
+  'release': '',
+  'debug': '_g'
+}
+
+
+def Abort(message):
+  print message
+  sys.exit(1)
+
+
+def GuessOS():
+  id = platform.system()
+  if id == 'Linux':
+    return 'linux'
+  elif id == 'Darwin':
+    return 'macos'
+  elif id == 'Windows':
+    return 'win32'
+  else:
+    return None
+
+
+def GuessWordsize():
+  if '64' in platform.machine():
+    return '64'
+  else:
+    return '32'
+
+
+def GuessToolchain(os):
+  tools = Environment()['TOOLS']
+  if 'gcc' in tools:
+    return 'gcc'
+  elif 'msvc' in tools:
+    return 'msvc'
+  else:
+    return None
+
+
+OS_GUESS = GuessOS()
+TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS)
+ARCH_GUESS = utils.GuessArchitecture()
+WORDSIZE_GUESS = GuessWordsize()
+
+
+SIMPLE_OPTIONS = {
+  'toolchain': {
+    'values': ['gcc', 'msvc'],
+    'default': TOOLCHAIN_GUESS,
+    'help': 'the toolchain to use'
+  },
+  'os': {
+    'values': ['linux', 'macos', 'win32'],
+    'default': OS_GUESS,
+    'help': 'the os to build for'
+  },
+  'arch': {
+    'values':['arm', 'ia32'],
+    'default': ARCH_GUESS,
+    'help': 'the architecture to build for'
+  },
+  'snapshot': {
+    'values': ['on', 'off'],
+    'default': 'off',
+    'help': 'build using snapshots for faster start-up'
+  },
+  'prof': {
+    'values': ['on', 'off'],
+    'default': 'off',
+    'help': 'enable profiling of build target'
+  },
+  'library': {
+    'values': ['static', 'shared'],
+    'default': 'static',
+    'help': 'the type of library to produce'
+  },
+  'wordsize': {
+    'values': ['64', '32'],
+    'default': WORDSIZE_GUESS,
+    'help': 'the word size'
+  },
+  'simulator': {
+    'values': ['arm', 'none'],
+    'default': 'none',
+    'help': 'build with simulator'
+  },
+  'disassembler': {
+    'values': ['on', 'off'],
+    'default': 'off',
+    'help': 'enable the disassembler to inspect generated code'
+  },
+  'sourcesignatures': {
+    'values': ['MD5', 'timestamp'],
+    'default': 'MD5',
+    'help': 'set how the build system detects file changes'
+  },
+  'console': {
+    'values': ['dumb', 'readline'],
+    'default': 'dumb',
+    'help': 'the console to use for the d8 shell'
+  }
+}
+
+
+def GetOptions():
+  result = Options()
+  result.Add('mode', 'compilation mode (debug, release)', 'release')
+  result.Add('sample', 'build sample (shell, process)', '')
+  result.Add('env', 'override environment settings (NAME1:value1,NAME2:value2)', '')
+  for (name, option) in SIMPLE_OPTIONS.iteritems():
+    help = '%s (%s)' % (name, ", ".join(option['values']))
+    result.Add(name, help, option.get('default'))
+  return result
+
+
+def SplitList(str):
+  return [ s for s in str.split(",") if len(s) > 0 ]
+
+
+def IsLegal(env, option, values):
+  str = env[option]
+  for s in SplitList(str):
+    if not s in values:
+      Abort("Illegal value for option %s '%s'." % (option, s))
+      return False
+  return True
+
+
+def VerifyOptions(env):
+  if not IsLegal(env, 'mode', ['debug', 'release']):
+    return False
+  if not IsLegal(env, 'sample', ["shell", "process"]):
+    return False
+  if env['os'] == 'win32' and env['library'] == 'shared' and env['prof'] == 'on':
+    Abort("Profiling on windows only supported for static library.")
+  for (name, option) in SIMPLE_OPTIONS.iteritems():
+    if (not option.get('default')) and (name not in ARGUMENTS):
+      message = ("A value for option %s must be specified (%s)." %
+          (name, ", ".join(option['values'])))
+      Abort(message)
+    if not env[name] in option['values']:
+      message = ("Unknown %s value '%s'.  Possible values are (%s)." %
+          (name, env[name], ", ".join(option['values'])))
+      Abort(message)
+
+
+class BuildContext(object):
+
+  def __init__(self, options, env_overrides, samples):
+    self.library_targets = []
+    self.cctest_targets = []
+    self.sample_targets = []
+    self.d8_targets = []
+    self.options = options
+    self.env_overrides = env_overrides
+    self.samples = samples
+    self.use_snapshot = (options['snapshot'] == 'on')
+    self.flags = None
+
+  def AddRelevantFlags(self, initial, flags):
+    result = initial.copy()
+    self.AppendFlags(result, flags.get('all'))
+    toolchain = self.options['toolchain']
+    self.AppendFlags(result, flags[toolchain].get('all'))
+    for option in sorted(self.options.keys()):
+      value = self.options[option]
+      self.AppendFlags(result, flags[toolchain].get(option + ':' + value))
+    return result
+
+  def GetRelevantSources(self, source):
+    result = []
+    result += source.get('all', [])
+    for (name, value) in self.options.iteritems():
+      result += source.get(name + ':' + value, [])
+    return sorted(result)
+
+  def AppendFlags(self, options, added):
+    if not added:
+      return
+    for (key, value) in added.iteritems():
+      if not key in options:
+        options[key] = value
+      else:
+        prefix = options[key]
+        if isinstance(prefix, StringTypes): prefix = prefix.split()
+        options[key] = prefix + value
+
+  def ConfigureObject(self, env, input, **kw):
+    if self.options['library'] == 'static':
+      return env.StaticObject(input, **kw)
+    else:
+      return env.SharedObject(input, **kw)
+
+  def ApplyEnvOverrides(self, env):
+    if not self.env_overrides:
+      return
+    if type(env['ENV']) == DictType:
+      env['ENV'].update(**self.env_overrides)
+    else:
+      env['ENV'] = self.env_overrides
+
+
+def PostprocessOptions(options):
+  # Adjust architecture if the simulator option has been set
+  if (options['simulator'] != 'none') and (options['arch'] != options['simulator']):
+    if 'arch' in ARGUMENTS:
+      # Print a warning if arch has explicitly been set
+      print "Warning: forcing architecture to match simulator (%s)" % options['simulator']
+    options['arch'] = options['simulator']
+
+
+def ParseEnvOverrides(arg):
+  # The environment overrides are in the format NAME1:value1,NAME2:value2
+  overrides = {}
+  for override in arg.split(','):
+    pos = override.find(':')
+    if pos == -1:
+      continue
+    overrides[override[:pos].strip()] = override[pos+1:].strip()
+  return overrides
+
+
+def BuildSpecific(env, mode, env_overrides):
+  options = {'mode': mode}
+  for option in SIMPLE_OPTIONS:
+    options[option] = env[option]
+  PostprocessOptions(options)
+
+  context = BuildContext(options, env_overrides, samples=SplitList(env['sample']))
+
+  library_flags = context.AddRelevantFlags(os.environ, LIBRARY_FLAGS)
+  v8_flags = context.AddRelevantFlags(library_flags, V8_EXTRA_FLAGS)
+  jscre_flags = context.AddRelevantFlags(library_flags, JSCRE_EXTRA_FLAGS)
+  dtoa_flags = context.AddRelevantFlags(library_flags, DTOA_EXTRA_FLAGS)
+  cctest_flags = context.AddRelevantFlags(v8_flags, CCTEST_EXTRA_FLAGS)
+  sample_flags = context.AddRelevantFlags(os.environ, SAMPLE_FLAGS)
+  d8_flags = context.AddRelevantFlags(library_flags, D8_FLAGS)
+
+  context.flags = {
+    'v8': v8_flags,
+    'jscre': jscre_flags,
+    'dtoa': dtoa_flags,
+    'cctest': cctest_flags,
+    'sample': sample_flags,
+    'd8': d8_flags
+  }
+
+  target_id = mode
+  suffix = SUFFIXES[target_id]
+  library_name = 'v8' + suffix
+  env['LIBRARY'] = library_name
+
+  # Build the object files by invoking SCons recursively.  
+  (object_files, shell_files) = env.SConscript(
+    join('src', 'SConscript'),
+    build_dir=join('obj', target_id),
+    exports='context',
+    duplicate=False
+  )
+
+  # Link the object files into a library.
+  env.Replace(**context.flags['v8'])
+  context.ApplyEnvOverrides(env)
+  if context.options['library'] == 'static':
+    library = env.StaticLibrary(library_name, object_files)
+  else:
+    # There seems to be a glitch in the way scons decides where to put
+    # PDB files when compiling using MSVC so we specify it manually.
+    # This should not affect any other platforms.
+    pdb_name = library_name + '.dll.pdb'
+    library = env.SharedLibrary(library_name, object_files, PDB=pdb_name)
+  context.library_targets.append(library)
+  
+  d8_env = Environment()
+  d8_env.Replace(**context.flags['d8'])
+  shell = d8_env.Program('d8' + suffix, object_files + shell_files)
+  context.d8_targets.append(shell)
+
+  for sample in context.samples:
+    sample_env = Environment(LIBRARY=library_name)
+    sample_env.Replace(**context.flags['sample'])
+    context.ApplyEnvOverrides(sample_env)
+    sample_object = sample_env.SConscript(
+      join('samples', 'SConscript'),
+      build_dir=join('obj', 'sample', sample, target_id),
+      exports='sample context',
+      duplicate=False
+    )
+    sample_name = sample + suffix
+    sample_program = sample_env.Program(sample_name, sample_object)
+    sample_env.Depends(sample_program, library)
+    context.sample_targets.append(sample_program)
+  
+  cctest_program = env.SConscript(
+    join('test', 'cctest', 'SConscript'),
+    build_dir=join('obj', 'test', target_id),
+    exports='context object_files',
+    duplicate=False
+  )
+  context.cctest_targets.append(cctest_program)
+  
+  return context
+
+
+def Build():
+  opts = GetOptions()
+  env = Environment(options=opts)
+  Help(opts.GenerateHelpText(env))
+  VerifyOptions(env)
+  env_overrides = ParseEnvOverrides(env['env'])
+
+  SourceSignatures(env['sourcesignatures'])
+
+  libraries = []
+  cctests = []
+  samples = []
+  d8s = []
+  modes = SplitList(env['mode'])
+  for mode in modes:
+    context = BuildSpecific(env.Copy(), mode, env_overrides)
+    libraries += context.library_targets
+    cctests += context.cctest_targets
+    samples += context.sample_targets
+    d8s += context.d8_targets
+
+  env.Alias('library', libraries)
+  env.Alias('cctests', cctests)
+  env.Alias('sample', samples)
+  env.Alias('d8', d8s)
+  
+  if env['sample']:
+    env.Default('sample')
+  else:
+    env.Default('library')
+
+
+# We disable deprecation warnings because we need to be able to use
+# env.Copy without getting warnings for compatibility with older
+# version of scons.  Also, there's a bug in some revisions that
+# doesn't allow this flag to be set, so we swallow any exceptions.
+# Lovely.
+try:
+  SetOption('warn', 'no-deprecated')
+except:
+  pass
+
+
+Build()
diff --git a/regexp2000/benchmarks/README.txt b/regexp2000/benchmarks/README.txt
new file mode 100644 (file)
index 0000000..7058212
--- /dev/null
@@ -0,0 +1,29 @@
+V8 Benchmark Suite
+==================
+
+This is the V8 benchmark suite: A collection of pure JavaScript
+benchmarks that we have used to tune V8. The licenses for the
+individual benchmarks are included in the JavaScript files.
+
+In addition to the benchmarks, the suite consists of the benchmark
+framework (base.js), which must be loaded before any of the individual
+benchmark files, and two benchmark runners: An HTML version (run.html)
+and a standalone JavaScript version (run.js).
+
+
+Changes From Version 1 To Version 2
+===================================
+
+For version 2 the crypto benchmark was fixed.  Previously, the
+decryption stage was given plaintext as input, which resulted in an
+error.  Now, the decryption stage is given the output of the
+encryption stage as input.  The result is checked against the original
+plaintext.  For this to give the correct results the crypto objects
+are reset for each iteration of the benchmark.  In addition, the size
+of the plain text has been increased a little and the use of
+Math.random() and new Date() to build an RNG pool has been removed.
+
+Other benchmarks were fixed to do elementary verification of the
+results of their calculations.  This is to avoid accidentally
+obtaining scores that are the result of an incorrect JavaScript engine
+optimization.
diff --git a/regexp2000/benchmarks/base.js b/regexp2000/benchmarks/base.js
new file mode 100644 (file)
index 0000000..2c26132
--- /dev/null
@@ -0,0 +1,221 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Simple framework for running the benchmark suites and
+// computing a score based on the timing measurements.
+
+
+// A benchmark has a name (string) and a function that will be run to
+// do the performance measurement.
+function Benchmark(name, run) {
+  this.name = name;
+  this.run = run;
+}
+
+
+// Benchmark results hold the benchmark and the measured time used to
+// run the benchmark. The benchmark score is computed later once a
+// full benchmark suite has run to completion.
+function BenchmarkResult(benchmark, time) {
+  this.benchmark = benchmark;
+  this.time = time;
+}
+
+
+// Automatically convert results to numbers. Used by the geometric
+// mean computation.
+BenchmarkResult.prototype.valueOf = function() {
+  return this.time;
+}
+
+
+// Suites of benchmarks consist of a name and the set of benchmarks in
+// addition to the reference timing that the final score will be based
+// on. This way, all scores are relative to a reference run and higher
+// scores implies better performance.
+function BenchmarkSuite(name, reference, benchmarks) {
+  this.name = name;
+  this.reference = reference;
+  this.benchmarks = benchmarks;
+  BenchmarkSuite.suites.push(this);
+}
+
+
+// Keep track of all declared benchmark suites.
+BenchmarkSuite.suites = [];
+
+
+// Scores are not comparable across versions. Bump the version if
+// you're making changes that will affect that scores, e.g. if you add
+// a new benchmark or change an existing one.
+BenchmarkSuite.version = '2';
+
+
+// To make the benchmark results predictable, we replace Math.random
+// with a 100% deterministic alternative.
+Math.random = (function() {
+  var seed = 49734321;
+  return function() {
+    // Robert Jenkins' 32 bit integer hash function.
+    seed = ((seed + 0x7ed55d16) + (seed << 12))  & 0xffffffff;
+    seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
+    seed = ((seed + 0x165667b1) + (seed << 5))   & 0xffffffff;
+    seed = ((seed + 0xd3a2646c) ^ (seed << 9))   & 0xffffffff;
+    seed = ((seed + 0xd3a2646c) ^ (seed << 9))   & 0xffffffff;
+    seed = ((seed + 0xfd7046c5) + (seed << 3))   & 0xffffffff;
+    seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
+    return (seed & 0xfffffff) / 0x10000000;
+  };
+})();
+
+
+// Runs all registered benchmark suites and optionally yields between
+// each individual benchmark to avoid running for too long in the
+// context of browsers. Once done, the final score is reported to the
+// runner.
+BenchmarkSuite.RunSuites = function(runner) {
+  var continuation = null;
+  var suites = BenchmarkSuite.suites;
+  var length = suites.length;
+  BenchmarkSuite.scores = [];
+  var index = 0;
+  function RunStep() {
+    while (continuation || index < length) {
+      if (continuation) {
+        continuation = continuation();
+      } else {
+        var suite = suites[index++];
+        if (runner.NotifyStart) runner.NotifyStart(suite.name);
+        continuation = suite.RunStep(runner);
+      }
+      if (continuation && typeof window != 'undefined' && window.setTimeout) {
+        window.setTimeout(RunStep, 100);
+        return;
+      }
+    }
+    if (runner.NotifyScore) {
+      var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);
+      runner.NotifyScore(Math.round(100 * score));
+    }
+  }
+  RunStep();
+}
+
+
+// Counts the total number of registered benchmarks. Useful for
+// showing progress as a percentage.
+BenchmarkSuite.CountBenchmarks = function() {
+  var result = 0;
+  var suites = BenchmarkSuite.suites;
+  for (var i = 0; i < suites.length; i++) {
+    result += suites[i].benchmarks.length;
+  }
+  return result;
+}
+
+
+// Computes the geometric mean of a set of numbers.
+BenchmarkSuite.GeometricMean = function(numbers) {
+  var log = 0;
+  for (var i = 0; i < numbers.length; i++) {
+    log += Math.log(numbers[i]);
+  }
+  return Math.pow(Math.E, log / numbers.length);
+}
+
+
+// Notifies the runner that we're done running a single benchmark in
+// the benchmark suite. This can be useful to report progress.
+BenchmarkSuite.prototype.NotifyStep = function(result) {
+  this.results.push(result);
+  if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);
+}
+
+
+// Notifies the runner that we're done with running a suite and that
+// we have a result which can be reported to the user if needed.
+BenchmarkSuite.prototype.NotifyResult = function() {
+  var mean = BenchmarkSuite.GeometricMean(this.results);
+  var score = this.reference / mean;
+  BenchmarkSuite.scores.push(score);
+  if (this.runner.NotifyResult) {
+    this.runner.NotifyResult(this.name, Math.round(100 * score));
+  }
+}
+
+
+// Notifies the runner that running a benchmark resulted in an error.
+BenchmarkSuite.prototype.NotifyError = function(error) {
+  if (this.runner.NotifyError) {
+    this.runner.NotifyError(this.name, error);
+  }
+  if (this.runner.NotifyStep) {
+    this.runner.NotifyStep(this.name);
+  }
+}
+
+
+// Runs a single benchmark for at least a second and computes the
+// average time it takes to run a single iteration.
+BenchmarkSuite.prototype.RunSingle = function(benchmark) {
+  var elapsed = 0;
+  var start = new Date();
+  for (var n = 0; elapsed < 1000; n++) {
+    benchmark.run();
+    elapsed = new Date() - start;
+  }
+  var usec = (elapsed * 1000) / n;
+  this.NotifyStep(new BenchmarkResult(benchmark, usec));
+}
+
+
+// This function starts running a suite, but stops between each
+// individual benchmark in the suite and returns a continuation
+// function which can be invoked to run the next benchmark. Once the
+// last benchmark has been executed, null is returned.
+BenchmarkSuite.prototype.RunStep = function(runner) {
+  this.results = [];
+  this.runner = runner;
+  var length = this.benchmarks.length;
+  var index = 0;
+  var suite = this;
+  function RunNext() {
+    if (index < length) {
+      try {
+        suite.RunSingle(suite.benchmarks[index++]);
+      } catch (e) {
+        suite.NotifyError(e);
+        return null;
+      }
+      return RunNext;
+    }
+    suite.NotifyResult();
+    return null;
+  }
+  return RunNext();
+}
diff --git a/regexp2000/benchmarks/crypto.js b/regexp2000/benchmarks/crypto.js
new file mode 100644 (file)
index 0000000..12b88ef
--- /dev/null
@@ -0,0 +1,1698 @@
+/*
+ * Copyright (c) 2003-2005  Tom Wu
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following condition applies:
+ *
+ * All redistributions must retain an intact copy of this copyright notice
+ * and disclaimer.
+ */
+
+
+// The code has been adapted for use as a benchmark by Google.
+var Crypto = new BenchmarkSuite('Crypto', 203037, [
+  new Benchmark("Encrypt", encrypt),
+  new Benchmark("Decrypt", decrypt)
+]);
+
+
+// Basic JavaScript BN library - subset useful for RSA encryption.
+
+// Bits per digit
+var dbits;
+var BI_DB;
+var BI_DM;
+var BI_DV;
+
+var BI_FP;
+var BI_FV;
+var BI_F1;
+var BI_F2;
+
+// JavaScript engine analysis
+var canary = 0xdeadbeefcafe;
+var j_lm = ((canary&0xffffff)==0xefcafe);
+
+// (public) Constructor
+function BigInteger(a,b,c) {
+  this.array = new Array();
+  if(a != null)
+    if("number" == typeof a) this.fromNumber(a,b,c);
+    else if(b == null && "string" != typeof a) this.fromString(a,256);
+    else this.fromString(a,b);
+}
+
+// return new, unset BigInteger
+function nbi() { return new BigInteger(null); }
+
+// am: Compute w_j += (x*this_i), propagate carries,
+// c is initial carry, returns final carry.
+// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+// We need to select the fastest one that works in this environment.
+
+// am1: use a single mult and divide to get the high bits,
+// max digit bits should be 26 because
+// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+function am1(i,x,w,j,c,n) {
+  var this_array = this.array;
+  var w_array    = w.array;
+  while(--n >= 0) {
+    var v = x*this_array[i++]+w_array[j]+c;
+    c = Math.floor(v/0x4000000);
+    w_array[j++] = v&0x3ffffff;
+  }
+  return c;
+}
+
+// am2 avoids a big mult-and-extract completely.
+// Max digit bits should be <= 30 because we do bitwise ops
+// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+function am2(i,x,w,j,c,n) {
+  var this_array = this.array;
+  var w_array    = w.array;
+  var xl = x&0x7fff, xh = x>>15;
+  while(--n >= 0) {
+    var l = this_array[i]&0x7fff;
+    var h = this_array[i++]>>15;
+    var m = xh*l+h*xl;
+    l = xl*l+((m&0x7fff)<<15)+w_array[j]+(c&0x3fffffff);
+    c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
+    w_array[j++] = l&0x3fffffff;
+  }
+  return c;
+}
+
+// Alternately, set max digit bits to 28 since some
+// browsers slow down when dealing with 32-bit numbers.
+function am3(i,x,w,j,c,n) {
+  var this_array = this.array;
+  var w_array    = w.array;
+
+  var xl = x&0x3fff, xh = x>>14;
+  while(--n >= 0) {
+    var l = this_array[i]&0x3fff;
+    var h = this_array[i++]>>14;
+    var m = xh*l+h*xl;
+    l = xl*l+((m&0x3fff)<<14)+w_array[j]+c;
+    c = (l>>28)+(m>>14)+xh*h;
+    w_array[j++] = l&0xfffffff;
+  }
+  return c;
+}
+
+// This is tailored to VMs with 2-bit tagging. It makes sure
+// that all the computations stay within the 29 bits available.
+function am4(i,x,w,j,c,n) {
+  var this_array = this.array;
+  var w_array    = w.array;
+
+  var xl = x&0x1fff, xh = x>>13;
+  while(--n >= 0) {
+    var l = this_array[i]&0x1fff;
+    var h = this_array[i++]>>13;
+    var m = xh*l+h*xl;
+    l = xl*l+((m&0x1fff)<<13)+w_array[j]+c;
+    c = (l>>26)+(m>>13)+xh*h;
+    w_array[j++] = l&0x3ffffff;
+  }
+  return c;
+}
+
+// am3/28 is best for SM, Rhino, but am4/26 is best for v8.
+// Kestrel (Opera 9.5) gets its best result with am4/26.
+// IE7 does 9% better with am3/28 than with am4/26.
+// Firefox (SM) gets 10% faster with am3/28 than with am4/26.
+
+setupEngine = function(fn, bits) {
+  BigInteger.prototype.am = fn;
+  dbits = bits;
+
+  BI_DB = dbits;
+  BI_DM = ((1<<dbits)-1);
+  BI_DV = (1<<dbits);
+
+  BI_FP = 52;
+  BI_FV = Math.pow(2,BI_FP);
+  BI_F1 = BI_FP-dbits;
+  BI_F2 = 2*dbits-BI_FP;
+}
+
+
+// Digit conversions
+var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+var BI_RC = new Array();
+var rr,vv;
+rr = "0".charCodeAt(0);
+for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
+rr = "a".charCodeAt(0);
+for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+rr = "A".charCodeAt(0);
+for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+
+function int2char(n) { return BI_RM.charAt(n); }
+function intAt(s,i) {
+  var c = BI_RC[s.charCodeAt(i)];
+  return (c==null)?-1:c;
+}
+
+// (protected) copy this to r
+function bnpCopyTo(r) {
+  var this_array = this.array;
+  var r_array    = r.array;
+
+  for(var i = this.t-1; i >= 0; --i) r_array[i] = this_array[i];
+  r.t = this.t;
+  r.s = this.s;
+}
+
+// (protected) set from integer value x, -DV <= x < DV
+function bnpFromInt(x) {
+  var this_array = this.array;
+  this.t = 1;
+  this.s = (x<0)?-1:0;
+  if(x > 0) this_array[0] = x;
+  else if(x < -1) this_array[0] = x+DV;
+  else this.t = 0;
+}
+
+// return bigint initialized to value
+function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
+
+// (protected) set from string and radix
+function bnpFromString(s,b) {
+  var this_array = this.array;
+  var k;
+  if(b == 16) k = 4;
+  else if(b == 8) k = 3;
+  else if(b == 256) k = 8; // byte array
+  else if(b == 2) k = 1;
+  else if(b == 32) k = 5;
+  else if(b == 4) k = 2;
+  else { this.fromRadix(s,b); return; }
+  this.t = 0;
+  this.s = 0;
+  var i = s.length, mi = false, sh = 0;
+  while(--i >= 0) {
+    var x = (k==8)?s[i]&0xff:intAt(s,i);
+    if(x < 0) {
+      if(s.charAt(i) == "-") mi = true;
+      continue;
+    }
+    mi = false;
+    if(sh == 0)
+      this_array[this.t++] = x;
+    else if(sh+k > BI_DB) {
+      this_array[this.t-1] |= (x&((1<<(BI_DB-sh))-1))<<sh;
+      this_array[this.t++] = (x>>(BI_DB-sh));
+    }
+    else
+      this_array[this.t-1] |= x<<sh;
+    sh += k;
+    if(sh >= BI_DB) sh -= BI_DB;
+  }
+  if(k == 8 && (s[0]&0x80) != 0) {
+    this.s = -1;
+    if(sh > 0) this_array[this.t-1] |= ((1<<(BI_DB-sh))-1)<<sh;
+  }
+  this.clamp();
+  if(mi) BigInteger.ZERO.subTo(this,this);
+}
+
+// (protected) clamp off excess high words
+function bnpClamp() {
+  var this_array = this.array;
+  var c = this.s&BI_DM;
+  while(this.t > 0 && this_array[this.t-1] == c) --this.t;
+}
+
+// (public) return string representation in given radix
+function bnToString(b) {
+  var this_array = this.array;
+  if(this.s < 0) return "-"+this.negate().toString(b);
+  var k;
+  if(b == 16) k = 4;
+  else if(b == 8) k = 3;
+  else if(b == 2) k = 1;
+  else if(b == 32) k = 5;
+  else if(b == 4) k = 2;
+  else return this.toRadix(b);
+  var km = (1<<k)-1, d, m = false, r = "", i = this.t;
+  var p = BI_DB-(i*BI_DB)%k;
+  if(i-- > 0) {
+    if(p < BI_DB && (d = this_array[i]>>p) > 0) { m = true; r = int2char(d); }
+    while(i >= 0) {
+      if(p < k) {
+        d = (this_array[i]&((1<<p)-1))<<(k-p);
+        d |= this_array[--i]>>(p+=BI_DB-k);
+      }
+      else {
+        d = (this_array[i]>>(p-=k))&km;
+        if(p <= 0) { p += BI_DB; --i; }
+      }
+      if(d > 0) m = true;
+      if(m) r += int2char(d);
+    }
+  }
+  return m?r:"0";
+}
+
+// (public) -this
+function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
+
+// (public) |this|
+function bnAbs() { return (this.s<0)?this.negate():this; }
+
+// (public) return + if this > a, - if this < a, 0 if equal
+function bnCompareTo(a) {
+  var this_array = this.array;
+  var a_array = a.array;
+
+  var r = this.s-a.s;
+  if(r != 0) return r;
+  var i = this.t;
+  r = i-a.t;
+  if(r != 0) return r;
+  while(--i >= 0) if((r=this_array[i]-a_array[i]) != 0) return r;
+  return 0;
+}
+
+// returns bit length of the integer x
+function nbits(x) {
+  var r = 1, t;
+  if((t=x>>>16) != 0) { x = t; r += 16; }
+  if((t=x>>8) != 0) { x = t; r += 8; }
+  if((t=x>>4) != 0) { x = t; r += 4; }
+  if((t=x>>2) != 0) { x = t; r += 2; }
+  if((t=x>>1) != 0) { x = t; r += 1; }
+  return r;
+}
+
+// (public) return the number of bits in "this"
+function bnBitLength() {
+  var this_array = this.array;
+  if(this.t <= 0) return 0;
+  return BI_DB*(this.t-1)+nbits(this_array[this.t-1]^(this.s&BI_DM));
+}
+
+// (protected) r = this << n*DB
+function bnpDLShiftTo(n,r) {
+  var this_array = this.array;
+  var r_array = r.array;
+  var i;
+  for(i = this.t-1; i >= 0; --i) r_array[i+n] = this_array[i];
+  for(i = n-1; i >= 0; --i) r_array[i] = 0;
+  r.t = this.t+n;
+  r.s = this.s;
+}
+
+// (protected) r = this >> n*DB
+function bnpDRShiftTo(n,r) {
+  var this_array = this.array;
+  var r_array = r.array;
+  for(var i = n; i < this.t; ++i) r_array[i-n] = this_array[i];
+  r.t = Math.max(this.t-n,0);
+  r.s = this.s;
+}
+
+// (protected) r = this << n
+function bnpLShiftTo(n,r) {
+  var this_array = this.array;
+  var r_array = r.array;
+  var bs = n%BI_DB;
+  var cbs = BI_DB-bs;
+  var bm = (1<<cbs)-1;
+  var ds = Math.floor(n/BI_DB), c = (this.s<<bs)&BI_DM, i;
+  for(i = this.t-1; i >= 0; --i) {
+    r_array[i+ds+1] = (this_array[i]>>cbs)|c;
+    c = (this_array[i]&bm)<<bs;
+  }
+  for(i = ds-1; i >= 0; --i) r_array[i] = 0;
+  r_array[ds] = c;
+  r.t = this.t+ds+1;
+  r.s = this.s;
+  r.clamp();
+}
+
+// (protected) r = this >> n
+function bnpRShiftTo(n,r) {
+  var this_array = this.array;
+  var r_array = r.array;
+  r.s = this.s;
+  var ds = Math.floor(n/BI_DB);
+  if(ds >= this.t) { r.t = 0; return; }
+  var bs = n%BI_DB;
+  var cbs = BI_DB-bs;
+  var bm = (1<<bs)-1;
+  r_array[0] = this_array[ds]>>bs;
+  for(var i = ds+1; i < this.t; ++i) {
+    r_array[i-ds-1] |= (this_array[i]&bm)<<cbs;
+    r_array[i-ds] = this_array[i]>>bs;
+  }
+  if(bs > 0) r_array[this.t-ds-1] |= (this.s&bm)<<cbs;
+  r.t = this.t-ds;
+  r.clamp();
+}
+
+// (protected) r = this - a
+function bnpSubTo(a,r) {
+  var this_array = this.array;
+  var r_array = r.array;
+  var a_array = a.array;
+  var i = 0, c = 0, m = Math.min(a.t,this.t);
+  while(i < m) {
+    c += this_array[i]-a_array[i];
+    r_array[i++] = c&BI_DM;
+    c >>= BI_DB;
+  }
+  if(a.t < this.t) {
+    c -= a.s;
+    while(i < this.t) {
+      c += this_array[i];
+      r_array[i++] = c&BI_DM;
+      c >>= BI_DB;
+    }
+    c += this.s;
+  }
+  else {
+    c += this.s;
+    while(i < a.t) {
+      c -= a_array[i];
+      r_array[i++] = c&BI_DM;
+      c >>= BI_DB;
+    }
+    c -= a.s;
+  }
+  r.s = (c<0)?-1:0;
+  if(c < -1) r_array[i++] = BI_DV+c;
+  else if(c > 0) r_array[i++] = c;
+  r.t = i;
+  r.clamp();
+}
+
+// (protected) r = this * a, r != this,a (HAC 14.12)
+// "this" should be the larger one if appropriate.
+function bnpMultiplyTo(a,r) {
+  var this_array = this.array;
+  var r_array = r.array;
+  var x = this.abs(), y = a.abs();
+  var y_array = y.array;
+
+  var i = x.t;
+  r.t = i+y.t;
+  while(--i >= 0) r_array[i] = 0;
+  for(i = 0; i < y.t; ++i) r_array[i+x.t] = x.am(0,y_array[i],r,i,0,x.t);
+  r.s = 0;
+  r.clamp();
+  if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
+}
+
+// (protected) r = this^2, r != this (HAC 14.16)
+function bnpSquareTo(r) {
+  var x = this.abs();
+  var x_array = x.array;
+  var r_array = r.array;
+
+  var i = r.t = 2*x.t;
+  while(--i >= 0) r_array[i] = 0;
+  for(i = 0; i < x.t-1; ++i) {
+    var c = x.am(i,x_array[i],r,2*i,0,1);
+    if((r_array[i+x.t]+=x.am(i+1,2*x_array[i],r,2*i+1,c,x.t-i-1)) >= BI_DV) {
+      r_array[i+x.t] -= BI_DV;
+      r_array[i+x.t+1] = 1;
+    }
+  }
+  if(r.t > 0) r_array[r.t-1] += x.am(i,x_array[i],r,2*i,0,1);
+  r.s = 0;
+  r.clamp();
+}
+
+// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+// r != q, this != m.  q or r may be null.
+function bnpDivRemTo(m,q,r) {
+  var pm = m.abs();
+  if(pm.t <= 0) return;
+  var pt = this.abs();
+  if(pt.t < pm.t) {
+    if(q != null) q.fromInt(0);
+    if(r != null) this.copyTo(r);
+    return;
+  }
+  if(r == null) r = nbi();
+  var y = nbi(), ts = this.s, ms = m.s;
+  var pm_array = pm.array;
+  var nsh = BI_DB-nbits(pm_array[pm.t-1]);     // normalize modulus
+  if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
+  else { pm.copyTo(y); pt.copyTo(r); }
+  var ys = y.t;
+
+  var y_array = y.array;
+  var y0 = y_array[ys-1];
+  if(y0 == 0) return;
+  var yt = y0*(1<<BI_F1)+((ys>1)?y_array[ys-2]>>BI_F2:0);
+  var d1 = BI_FV/yt, d2 = (1<<BI_F1)/yt, e = 1<<BI_F2;
+  var i = r.t, j = i-ys, t = (q==null)?nbi():q;
+  y.dlShiftTo(j,t);
+
+  var r_array = r.array;
+  if(r.compareTo(t) >= 0) {
+    r_array[r.t++] = 1;
+    r.subTo(t,r);
+  }
+  BigInteger.ONE.dlShiftTo(ys,t);
+  t.subTo(y,y);        // "negative" y so we can replace sub with am later
+  while(y.t < ys) y_array[y.t++] = 0;
+  while(--j >= 0) {
+    // Estimate quotient digit
+    var qd = (r_array[--i]==y0)?BI_DM:Math.floor(r_array[i]*d1+(r_array[i-1]+e)*d2);
+    if((r_array[i]+=y.am(0,qd,r,j,0,ys)) < qd) {       // Try it out
+      y.dlShiftTo(j,t);
+      r.subTo(t,r);
+      while(r_array[i] < --qd) r.subTo(t,r);
+    }
+  }
+  if(q != null) {
+    r.drShiftTo(ys,q);
+    if(ts != ms) BigInteger.ZERO.subTo(q,q);
+  }
+  r.t = ys;
+  r.clamp();
+  if(nsh > 0) r.rShiftTo(nsh,r);       // Denormalize remainder
+  if(ts < 0) BigInteger.ZERO.subTo(r,r);
+}
+
+// (public) this mod a
+function bnMod(a) {
+  var r = nbi();
+  this.abs().divRemTo(a,null,r);
+  if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
+  return r;
+}
+
+// Modular reduction using "classic" algorithm
+function Classic(m) { this.m = m; }
+function cConvert(x) {
+  if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
+  else return x;
+}
+function cRevert(x) { return x; }
+function cReduce(x) { x.divRemTo(this.m,null,x); }
+function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+Classic.prototype.convert = cConvert;
+Classic.prototype.revert = cRevert;
+Classic.prototype.reduce = cReduce;
+Classic.prototype.mulTo = cMulTo;
+Classic.prototype.sqrTo = cSqrTo;
+
+// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+// justification:
+//         xy == 1 (mod m)
+//         xy =  1+km
+//   xy(2-xy) = (1+km)(1-km)
+// x[y(2-xy)] = 1-k^2m^2
+// x[y(2-xy)] == 1 (mod m^2)
+// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+// JS multiply "overflows" differently from C/C++, so care is needed here.
+function bnpInvDigit() {
+  var this_array = this.array;
+  if(this.t < 1) return 0;
+  var x = this_array[0];
+  if((x&1) == 0) return 0;
+  var y = x&3;         // y == 1/x mod 2^2
+  y = (y*(2-(x&0xf)*y))&0xf;   // y == 1/x mod 2^4
+  y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
+  y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff;  // y == 1/x mod 2^16
+  // last step - calculate inverse mod DV directly;
+  // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+  y = (y*(2-x*y%BI_DV))%BI_DV;         // y == 1/x mod 2^dbits
+  // we really want the negative inverse, and -DV < y < DV
+  return (y>0)?BI_DV-y:-y;
+}
+
+// Montgomery reduction
+function Montgomery(m) {
+  this.m = m;
+  this.mp = m.invDigit();
+  this.mpl = this.mp&0x7fff;
+  this.mph = this.mp>>15;
+  this.um = (1<<(BI_DB-15))-1;
+  this.mt2 = 2*m.t;
+}
+
+// xR mod m
+function montConvert(x) {
+  var r = nbi();
+  x.abs().dlShiftTo(this.m.t,r);
+  r.divRemTo(this.m,null,r);
+  if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
+  return r;
+}
+
+// x/R mod m
+function montRevert(x) {
+  var r = nbi();
+  x.copyTo(r);
+  this.reduce(r);
+  return r;
+}
+
+// x = x/R mod m (HAC 14.32)
+function montReduce(x) {
+  var x_array = x.array;
+  while(x.t <= this.mt2)       // pad x so am has enough room later
+    x_array[x.t++] = 0;
+  for(var i = 0; i < this.m.t; ++i) {
+    // faster way of calculating u0 = x[i]*mp mod DV
+    var j = x_array[i]&0x7fff;
+    var u0 = (j*this.mpl+(((j*this.mph+(x_array[i]>>15)*this.mpl)&this.um)<<15))&BI_DM;
+    // use am to combine the multiply-shift-add into one call
+    j = i+this.m.t;
+    x_array[j] += this.m.am(0,u0,x,i,0,this.m.t);
+    // propagate carry
+    while(x_array[j] >= BI_DV) { x_array[j] -= BI_DV; x_array[++j]++; }
+  }
+  x.clamp();
+  x.drShiftTo(this.m.t,x);
+  if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+}
+
+// r = "x^2/R mod m"; x != r
+function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+// r = "xy/R mod m"; x,y != r
+function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+Montgomery.prototype.convert = montConvert;
+Montgomery.prototype.revert = montRevert;
+Montgomery.prototype.reduce = montReduce;
+Montgomery.prototype.mulTo = montMulTo;
+Montgomery.prototype.sqrTo = montSqrTo;
+
+// (protected) true iff this is even
+function bnpIsEven() {
+  var this_array = this.array;
+  return ((this.t>0)?(this_array[0]&1):this.s) == 0;
+}
+
+// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+function bnpExp(e,z) {
+  if(e > 0xffffffff || e < 1) return BigInteger.ONE;
+  var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
+  g.copyTo(r);
+  while(--i >= 0) {
+    z.sqrTo(r,r2);
+    if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
+    else { var t = r; r = r2; r2 = t; }
+  }
+  return z.revert(r);
+}
+
+// (public) this^e % m, 0 <= e < 2^32
+function bnModPowInt(e,m) {
+  var z;
+  if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
+  return this.exp(e,z);
+}
+
+// protected
+BigInteger.prototype.copyTo = bnpCopyTo;
+BigInteger.prototype.fromInt = bnpFromInt;
+BigInteger.prototype.fromString = bnpFromString;
+BigInteger.prototype.clamp = bnpClamp;
+BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
+BigInteger.prototype.drShiftTo = bnpDRShiftTo;
+BigInteger.prototype.lShiftTo = bnpLShiftTo;
+BigInteger.prototype.rShiftTo = bnpRShiftTo;
+BigInteger.prototype.subTo = bnpSubTo;
+BigInteger.prototype.multiplyTo = bnpMultiplyTo;
+BigInteger.prototype.squareTo = bnpSquareTo;
+BigInteger.prototype.divRemTo = bnpDivRemTo;
+BigInteger.prototype.invDigit = bnpInvDigit;
+BigInteger.prototype.isEven = bnpIsEven;
+BigInteger.prototype.exp = bnpExp;
+
+// public
+BigInteger.prototype.toString = bnToString;
+BigInteger.prototype.negate = bnNegate;
+BigInteger.prototype.abs = bnAbs;
+BigInteger.prototype.compareTo = bnCompareTo;
+BigInteger.prototype.bitLength = bnBitLength;
+BigInteger.prototype.mod = bnMod;
+BigInteger.prototype.modPowInt = bnModPowInt;
+
+// "constants"
+BigInteger.ZERO = nbv(0);
+BigInteger.ONE = nbv(1);
+// Copyright (c) 2005  Tom Wu
+// All Rights Reserved.
+// See "LICENSE" for details.
+
+// Extended JavaScript BN functions, required for RSA private ops.
+
+// (public)
+function bnClone() { var r = nbi(); this.copyTo(r); return r; }
+
+// (public) return value as integer
+function bnIntValue() {
+  var this_array = this.array;
+  if(this.s < 0) {
+    if(this.t == 1) return this_array[0]-BI_DV;
+    else if(this.t == 0) return -1;
+  }
+  else if(this.t == 1) return this_array[0];
+  else if(this.t == 0) return 0;
+  // assumes 16 < DB < 32
+  return ((this_array[1]&((1<<(32-BI_DB))-1))<<BI_DB)|this_array[0];
+}
+
+// (public) return value as byte
+function bnByteValue() {
+  var this_array = this.array;
+  return (this.t==0)?this.s:(this_array[0]<<24)>>24;
+}
+
+// (public) return value as short (assumes DB>=16)
+function bnShortValue() {
+  var this_array = this.array;
+  return (this.t==0)?this.s:(this_array[0]<<16)>>16;
+}
+
+// (protected) return x s.t. r^x < DV
+function bnpChunkSize(r) { return Math.floor(Math.LN2*BI_DB/Math.log(r)); }
+
+// (public) 0 if this == 0, 1 if this > 0
+function bnSigNum() {
+  var this_array = this.array;
+  if(this.s < 0) return -1;
+  else if(this.t <= 0 || (this.t == 1 && this_array[0] <= 0)) return 0;
+  else return 1;
+}
+
+// (protected) convert to radix string
+function bnpToRadix(b) {
+  if(b == null) b = 10;
+  if(this.signum() == 0 || b < 2 || b > 36) return "0";
+  var cs = this.chunkSize(b);
+  var a = Math.pow(b,cs);
+  var d = nbv(a), y = nbi(), z = nbi(), r = "";
+  this.divRemTo(d,y,z);
+  while(y.signum() > 0) {
+    r = (a+z.intValue()).toString(b).substr(1) + r;
+    y.divRemTo(d,y,z);
+  }
+  return z.intValue().toString(b) + r;
+}
+
+// (protected) convert from radix string
+function bnpFromRadix(s,b) {
+  this.fromInt(0);
+  if(b == null) b = 10;
+  var cs = this.chunkSize(b);
+  var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
+  for(var i = 0; i < s.length; ++i) {
+    var x = intAt(s,i);
+    if(x < 0) {
+      if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
+      continue;
+    }
+    w = b*w+x;
+    if(++j >= cs) {
+      this.dMultiply(d);
+      this.dAddOffset(w,0);
+      j = 0;
+      w = 0;
+    }
+  }
+  if(j > 0) {
+    this.dMultiply(Math.pow(b,j));
+    this.dAddOffset(w,0);
+  }
+  if(mi) BigInteger.ZERO.subTo(this,this);
+}
+
+// (protected) alternate constructor
+function bnpFromNumber(a,b,c) {
+  if("number" == typeof b) {
+    // new BigInteger(int,int,RNG)
+    if(a < 2) this.fromInt(1);
+    else {
+      this.fromNumber(a,c);
+      if(!this.testBit(a-1))   // force MSB set
+        this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
+      if(this.isEven()) this.dAddOffset(1,0); // force odd
+      while(!this.isProbablePrime(b)) {
+        this.dAddOffset(2,0);
+        if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
+      }
+    }
+  }
+  else {
+    // new BigInteger(int,RNG)
+    var x = new Array(), t = a&7;
+    x.length = (a>>3)+1;
+    b.nextBytes(x);
+    if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
+    this.fromString(x,256);
+  }
+}
+
+// (public) convert to bigendian byte array
+function bnToByteArray() {
+  var this_array = this.array;
+  var i = this.t, r = new Array();
+  r[0] = this.s;
+  var p = BI_DB-(i*BI_DB)%8, d, k = 0;
+  if(i-- > 0) {
+    if(p < BI_DB && (d = this_array[i]>>p) != (this.s&BI_DM)>>p)
+      r[k++] = d|(this.s<<(BI_DB-p));
+    while(i >= 0) {
+      if(p < 8) {
+        d = (this_array[i]&((1<<p)-1))<<(8-p);
+        d |= this_array[--i]>>(p+=BI_DB-8);
+      }
+      else {
+        d = (this_array[i]>>(p-=8))&0xff;
+        if(p <= 0) { p += BI_DB; --i; }
+      }
+      if((d&0x80) != 0) d |= -256;
+      if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
+      if(k > 0 || d != this.s) r[k++] = d;
+    }
+  }
+  return r;
+}
+
+function bnEquals(a) { return(this.compareTo(a)==0); }
+function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
+function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
+
+// (protected) r = this op a (bitwise)
+function bnpBitwiseTo(a,op,r) {
+  var this_array = this.array;
+  var a_array    = a.array;
+  var r_array    = r.array;
+  var i, f, m = Math.min(a.t,this.t);
+  for(i = 0; i < m; ++i) r_array[i] = op(this_array[i],a_array[i]);
+  if(a.t < this.t) {
+    f = a.s&BI_DM;
+    for(i = m; i < this.t; ++i) r_array[i] = op(this_array[i],f);
+    r.t = this.t;
+  }
+  else {
+    f = this.s&BI_DM;
+    for(i = m; i < a.t; ++i) r_array[i] = op(f,a_array[i]);
+    r.t = a.t;
+  }
+  r.s = op(this.s,a.s);
+  r.clamp();
+}
+
+// (public) this & a
+function op_and(x,y) { return x&y; }
+function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
+
+// (public) this | a
+function op_or(x,y) { return x|y; }
+function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
+
+// (public) this ^ a
+function op_xor(x,y) { return x^y; }
+function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
+
+// (public) this & ~a
+function op_andnot(x,y) { return x&~y; }
+function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
+
+// (public) ~this
+function bnNot() {
+  var this_array = this.array;
+  var r = nbi();
+  var r_array = r.array;
+
+  for(var i = 0; i < this.t; ++i) r_array[i] = BI_DM&~this_array[i];
+  r.t = this.t;
+  r.s = ~this.s;
+  return r;
+}
+
+// (public) this << n
+function bnShiftLeft(n) {
+  var r = nbi();
+  if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
+  return r;
+}
+
+// (public) this >> n
+function bnShiftRight(n) {
+  var r = nbi();
+  if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
+  return r;
+}
+
+// return index of lowest 1-bit in x, x < 2^31
+function lbit(x) {
+  if(x == 0) return -1;
+  var r = 0;
+  if((x&0xffff) == 0) { x >>= 16; r += 16; }
+  if((x&0xff) == 0) { x >>= 8; r += 8; }
+  if((x&0xf) == 0) { x >>= 4; r += 4; }
+  if((x&3) == 0) { x >>= 2; r += 2; }
+  if((x&1) == 0) ++r;
+  return r;
+}
+
+// (public) returns index of lowest 1-bit (or -1 if none)
+function bnGetLowestSetBit() {
+  var this_array = this.array;
+  for(var i = 0; i < this.t; ++i)
+    if(this_array[i] != 0) return i*BI_DB+lbit(this_array[i]);
+  if(this.s < 0) return this.t*BI_DB;
+  return -1;
+}
+
+// return number of 1 bits in x
+function cbit(x) {
+  var r = 0;
+  while(x != 0) { x &= x-1; ++r; }
+  return r;
+}
+
+// (public) return number of set bits
+function bnBitCount() {
+  var r = 0, x = this.s&BI_DM;
+  for(var i = 0; i < this.t; ++i) r += cbit(this_array[i]^x);
+  return r;
+}
+
+// (public) true iff nth bit is set
+function bnTestBit(n) {
+  var this_array = this.array;
+  var j = Math.floor(n/BI_DB);
+  if(j >= this.t) return(this.s!=0);
+  return((this_array[j]&(1<<(n%BI_DB)))!=0);
+}
+
+// (protected) this op (1<<n)
+function bnpChangeBit(n,op) {
+  var r = BigInteger.ONE.shiftLeft(n);
+  this.bitwiseTo(r,op,r);
+  return r;
+}
+
+// (public) this | (1<<n)
+function bnSetBit(n) { return this.changeBit(n,op_or); }
+
+// (public) this & ~(1<<n)
+function bnClearBit(n) { return this.changeBit(n,op_andnot); }
+
+// (public) this ^ (1<<n)
+function bnFlipBit(n) { return this.changeBit(n,op_xor); }
+
+// (protected) r = this + a
+function bnpAddTo(a,r) {
+  var this_array = this.array;
+  var a_array = a.array;
+  var r_array = r.array;
+  var i = 0, c = 0, m = Math.min(a.t,this.t);
+  while(i < m) {
+    c += this_array[i]+a_array[i];
+    r_array[i++] = c&BI_DM;
+    c >>= BI_DB;
+  }
+  if(a.t < this.t) {
+    c += a.s;
+    while(i < this.t) {
+      c += this_array[i];
+      r_array[i++] = c&BI_DM;
+      c >>= BI_DB;
+    }
+    c += this.s;
+  }
+  else {
+    c += this.s;
+    while(i < a.t) {
+      c += a_array[i];
+      r_array[i++] = c&BI_DM;
+      c >>= BI_DB;
+    }
+    c += a.s;
+  }
+  r.s = (c<0)?-1:0;
+  if(c > 0) r_array[i++] = c;
+  else if(c < -1) r_array[i++] = BI_DV+c;
+  r.t = i;
+  r.clamp();
+}
+
+// (public) this + a
+function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
+
+// (public) this - a
+function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
+
+// (public) this * a
+function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
+
+// (public) this / a
+function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
+
+// (public) this % a
+function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
+
+// (public) [this/a,this%a]
+function bnDivideAndRemainder(a) {
+  var q = nbi(), r = nbi();
+  this.divRemTo(a,q,r);
+  return new Array(q,r);
+}
+
+// (protected) this *= n, this >= 0, 1 < n < DV
+function bnpDMultiply(n) {
+  var this_array = this.array;
+  this_array[this.t] = this.am(0,n-1,this,0,0,this.t);
+  ++this.t;
+  this.clamp();
+}
+
+// (protected) this += n << w words, this >= 0
+function bnpDAddOffset(n,w) {
+  var this_array = this.array;
+  while(this.t <= w) this_array[this.t++] = 0;
+  this_array[w] += n;
+  while(this_array[w] >= BI_DV) {
+    this_array[w] -= BI_DV;
+    if(++w >= this.t) this_array[this.t++] = 0;
+    ++this_array[w];
+  }
+}
+
+// A "null" reducer
+function NullExp() {}
+function nNop(x) { return x; }
+function nMulTo(x,y,r) { x.multiplyTo(y,r); }
+function nSqrTo(x,r) { x.squareTo(r); }
+
+NullExp.prototype.convert = nNop;
+NullExp.prototype.revert = nNop;
+NullExp.prototype.mulTo = nMulTo;
+NullExp.prototype.sqrTo = nSqrTo;
+
+// (public) this^e
+function bnPow(e) { return this.exp(e,new NullExp()); }
+
+// (protected) r = lower n words of "this * a", a.t <= n
+// "this" should be the larger one if appropriate.
+function bnpMultiplyLowerTo(a,n,r) {
+  var r_array = r.array;
+  var a_array = a.array;
+  var i = Math.min(this.t+a.t,n);
+  r.s = 0; // assumes a,this >= 0
+  r.t = i;
+  while(i > 0) r_array[--i] = 0;
+  var j;
+  for(j = r.t-this.t; i < j; ++i) r_array[i+this.t] = this.am(0,a_array[i],r,i,0,this.t);
+  for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a_array[i],r,i,0,n-i);
+  r.clamp();
+}
+
+// (protected) r = "this * a" without lower n words, n > 0
+// "this" should be the larger one if appropriate.
+function bnpMultiplyUpperTo(a,n,r) {
+  var r_array = r.array;
+  var a_array = a.array;
+  --n;
+  var i = r.t = this.t+a.t-n;
+  r.s = 0; // assumes a,this >= 0
+  while(--i >= 0) r_array[i] = 0;
+  for(i = Math.max(n-this.t,0); i < a.t; ++i)
+    r_array[this.t+i-n] = this.am(n-i,a_array[i],r,0,0,this.t+i-n);
+  r.clamp();
+  r.drShiftTo(1,r);
+}
+
+// Barrett modular reduction
+function Barrett(m) {
+  // setup Barrett
+  this.r2 = nbi();
+  this.q3 = nbi();
+  BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
+  this.mu = this.r2.divide(m);
+  this.m = m;
+}
+
+function barrettConvert(x) {
+  if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
+  else if(x.compareTo(this.m) < 0) return x;
+  else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
+}
+
+function barrettRevert(x) { return x; }
+
+// x = x mod m (HAC 14.42)
+function barrettReduce(x) {
+  x.drShiftTo(this.m.t-1,this.r2);
+  if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
+  this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
+  this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
+  while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
+  x.subTo(this.r2,x);
+  while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+}
+
+// r = x^2 mod m; x != r
+function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+// r = x*y mod m; x,y != r
+function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+Barrett.prototype.convert = barrettConvert;
+Barrett.prototype.revert = barrettRevert;
+Barrett.prototype.reduce = barrettReduce;
+Barrett.prototype.mulTo = barrettMulTo;
+Barrett.prototype.sqrTo = barrettSqrTo;
+
+// (public) this^e % m (HAC 14.85)
+function bnModPow(e,m) {
+  var e_array = e.array;
+  var i = e.bitLength(), k, r = nbv(1), z;
+  if(i <= 0) return r;
+  else if(i < 18) k = 1;
+  else if(i < 48) k = 3;
+  else if(i < 144) k = 4;
+  else if(i < 768) k = 5;
+  else k = 6;
+  if(i < 8)
+    z = new Classic(m);
+  else if(m.isEven())
+    z = new Barrett(m);
+  else
+    z = new Montgomery(m);
+
+  // precomputation
+  var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
+  g[1] = z.convert(this);
+  if(k > 1) {
+    var g2 = nbi();
+    z.sqrTo(g[1],g2);
+    while(n <= km) {
+      g[n] = nbi();
+      z.mulTo(g2,g[n-2],g[n]);
+      n += 2;
+    }
+  }
+
+  var j = e.t-1, w, is1 = true, r2 = nbi(), t;
+  i = nbits(e_array[j])-1;
+  while(j >= 0) {
+    if(i >= k1) w = (e_array[j]>>(i-k1))&km;
+    else {
+      w = (e_array[j]&((1<<(i+1))-1))<<(k1-i);
+      if(j > 0) w |= e_array[j-1]>>(BI_DB+i-k1);
+    }
+
+    n = k;
+    while((w&1) == 0) { w >>= 1; --n; }
+    if((i -= n) < 0) { i += BI_DB; --j; }
+    if(is1) {  // ret == 1, don't bother squaring or multiplying it
+      g[w].copyTo(r);
+      is1 = false;
+    }
+    else {
+      while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
+      if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
+      z.mulTo(r2,g[w],r);
+    }
+
+    while(j >= 0 && (e_array[j]&(1<<i)) == 0) {
+      z.sqrTo(r,r2); t = r; r = r2; r2 = t;
+      if(--i < 0) { i = BI_DB-1; --j; }
+    }
+  }
+  return z.revert(r);
+}
+
+// (public) gcd(this,a) (HAC 14.54)
+function bnGCD(a) {
+  var x = (this.s<0)?this.negate():this.clone();
+  var y = (a.s<0)?a.negate():a.clone();
+  if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
+  var i = x.getLowestSetBit(), g = y.getLowestSetBit();
+  if(g < 0) return x;
+  if(i < g) g = i;
+  if(g > 0) {
+    x.rShiftTo(g,x);
+    y.rShiftTo(g,y);
+  }
+  while(x.signum() > 0) {
+    if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
+    if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
+    if(x.compareTo(y) >= 0) {
+      x.subTo(y,x);
+      x.rShiftTo(1,x);
+    }
+    else {
+      y.subTo(x,y);
+      y.rShiftTo(1,y);
+    }
+  }
+  if(g > 0) y.lShiftTo(g,y);
+  return y;
+}
+
+// (protected) this % n, n < 2^26
+function bnpModInt(n) {
+  var this_array = this.array;
+  if(n <= 0) return 0;
+  var d = BI_DV%n, r = (this.s<0)?n-1:0;
+  if(this.t > 0)
+    if(d == 0) r = this_array[0]%n;
+    else for(var i = this.t-1; i >= 0; --i) r = (d*r+this_array[i])%n;
+  return r;
+}
+
+// (public) 1/this % m (HAC 14.61)
+function bnModInverse(m) {
+  var ac = m.isEven();
+  if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
+  var u = m.clone(), v = this.clone();
+  var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
+  while(u.signum() != 0) {
+    while(u.isEven()) {
+      u.rShiftTo(1,u);
+      if(ac) {
+        if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
+        a.rShiftTo(1,a);
+      }
+      else if(!b.isEven()) b.subTo(m,b);
+      b.rShiftTo(1,b);
+    }
+    while(v.isEven()) {
+      v.rShiftTo(1,v);
+      if(ac) {
+        if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
+        c.rShiftTo(1,c);
+      }
+      else if(!d.isEven()) d.subTo(m,d);
+      d.rShiftTo(1,d);
+    }
+    if(u.compareTo(v) >= 0) {
+      u.subTo(v,u);
+      if(ac) a.subTo(c,a);
+      b.subTo(d,b);
+    }
+    else {
+      v.subTo(u,v);
+      if(ac) c.subTo(a,c);
+      d.subTo(b,d);
+    }
+  }
+  if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
+  if(d.compareTo(m) >= 0) return d.subtract(m);
+  if(d.signum() < 0) d.addTo(m,d); else return d;
+  if(d.signum() < 0) return d.add(m); else return d;
+}
+
+var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509];
+var lplim = (1<<26)/lowprimes[lowprimes.length-1];
+
+// (public) test primality with certainty >= 1-.5^t
+function bnIsProbablePrime(t) {
+  var i, x = this.abs();
+  var x_array = x.array;
+  if(x.t == 1 && x_array[0] <= lowprimes[lowprimes.length-1]) {
+    for(i = 0; i < lowprimes.length; ++i)
+      if(x_array[0] == lowprimes[i]) return true;
+    return false;
+  }
+  if(x.isEven()) return false;
+  i = 1;
+  while(i < lowprimes.length) {
+    var m = lowprimes[i], j = i+1;
+    while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
+    m = x.modInt(m);
+    while(i < j) if(m%lowprimes[i++] == 0) return false;
+  }
+  return x.millerRabin(t);
+}
+
+// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
+function bnpMillerRabin(t) {
+  var n1 = this.subtract(BigInteger.ONE);
+  var k = n1.getLowestSetBit();
+  if(k <= 0) return false;
+  var r = n1.shiftRight(k);
+  t = (t+1)>>1;
+  if(t > lowprimes.length) t = lowprimes.length;
+  var a = nbi();
+  for(var i = 0; i < t; ++i) {
+    a.fromInt(lowprimes[i]);
+    var y = a.modPow(r,this);
+    if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
+      var j = 1;
+      while(j++ < k && y.compareTo(n1) != 0) {
+        y = y.modPowInt(2,this);
+        if(y.compareTo(BigInteger.ONE) == 0) return false;
+      }
+      if(y.compareTo(n1) != 0) return false;
+    }
+  }
+  return true;
+}
+
+// protected
+BigInteger.prototype.chunkSize = bnpChunkSize;
+BigInteger.prototype.toRadix = bnpToRadix;
+BigInteger.prototype.fromRadix = bnpFromRadix;
+BigInteger.prototype.fromNumber = bnpFromNumber;
+BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
+BigInteger.prototype.changeBit = bnpChangeBit;
+BigInteger.prototype.addTo = bnpAddTo;
+BigInteger.prototype.dMultiply = bnpDMultiply;
+BigInteger.prototype.dAddOffset = bnpDAddOffset;
+BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
+BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
+BigInteger.prototype.modInt = bnpModInt;
+BigInteger.prototype.millerRabin = bnpMillerRabin;
+
+// public
+BigInteger.prototype.clone = bnClone;
+BigInteger.prototype.intValue = bnIntValue;
+BigInteger.prototype.byteValue = bnByteValue;
+BigInteger.prototype.shortValue = bnShortValue;
+BigInteger.prototype.signum = bnSigNum;
+BigInteger.prototype.toByteArray = bnToByteArray;
+BigInteger.prototype.equals = bnEquals;
+BigInteger.prototype.min = bnMin;
+BigInteger.prototype.max = bnMax;
+BigInteger.prototype.and = bnAnd;
+BigInteger.prototype.or = bnOr;
+BigInteger.prototype.xor = bnXor;
+BigInteger.prototype.andNot = bnAndNot;
+BigInteger.prototype.not = bnNot;
+BigInteger.prototype.shiftLeft = bnShiftLeft;
+BigInteger.prototype.shiftRight = bnShiftRight;
+BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
+BigInteger.prototype.bitCount = bnBitCount;
+BigInteger.prototype.testBit = bnTestBit;
+BigInteger.prototype.setBit = bnSetBit;
+BigInteger.prototype.clearBit = bnClearBit;
+BigInteger.prototype.flipBit = bnFlipBit;
+BigInteger.prototype.add = bnAdd;
+BigInteger.prototype.subtract = bnSubtract;
+BigInteger.prototype.multiply = bnMultiply;
+BigInteger.prototype.divide = bnDivide;
+BigInteger.prototype.remainder = bnRemainder;
+BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
+BigInteger.prototype.modPow = bnModPow;
+BigInteger.prototype.modInverse = bnModInverse;
+BigInteger.prototype.pow = bnPow;
+BigInteger.prototype.gcd = bnGCD;
+BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
+
+// BigInteger interfaces not implemented in jsbn:
+
+// BigInteger(int signum, byte[] magnitude)
+// double doubleValue()
+// float floatValue()
+// int hashCode()
+// long longValue()
+// static BigInteger valueOf(long val)
+// prng4.js - uses Arcfour as a PRNG
+
+function Arcfour() {
+  this.i = 0;
+  this.j = 0;
+  this.S = new Array();
+}
+
+// Initialize arcfour context from key, an array of ints, each from [0..255]
+function ARC4init(key) {
+  var i, j, t;
+  for(i = 0; i < 256; ++i)
+    this.S[i] = i;
+  j = 0;
+  for(i = 0; i < 256; ++i) {
+    j = (j + this.S[i] + key[i % key.length]) & 255;
+    t = this.S[i];
+    this.S[i] = this.S[j];
+    this.S[j] = t;
+  }
+  this.i = 0;
+  this.j = 0;
+}
+
+function ARC4next() {
+  var t;
+  this.i = (this.i + 1) & 255;
+  this.j = (this.j + this.S[this.i]) & 255;
+  t = this.S[this.i];
+  this.S[this.i] = this.S[this.j];
+  this.S[this.j] = t;
+  return this.S[(t + this.S[this.i]) & 255];
+}
+
+Arcfour.prototype.init = ARC4init;
+Arcfour.prototype.next = ARC4next;
+
+// Plug in your RNG constructor here
+function prng_newstate() {
+  return new Arcfour();
+}
+
+// Pool size must be a multiple of 4 and greater than 32.
+// An array of bytes the size of the pool will be passed to init()
+var rng_psize = 256;
+// Random number generator - requires a PRNG backend, e.g. prng4.js
+
+// For best results, put code like
+// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'>
+// in your main HTML document.
+
+var rng_state;
+var rng_pool;
+var rng_pptr;
+
+// Mix in a 32-bit integer into the pool
+function rng_seed_int(x) {
+  rng_pool[rng_pptr++] ^= x & 255;
+  rng_pool[rng_pptr++] ^= (x >> 8) & 255;
+  rng_pool[rng_pptr++] ^= (x >> 16) & 255;
+  rng_pool[rng_pptr++] ^= (x >> 24) & 255;
+  if(rng_pptr >= rng_psize) rng_pptr -= rng_psize;
+}
+
+// Mix in the current time (w/milliseconds) into the pool
+function rng_seed_time() {
+  // Use pre-computed date to avoid making the benchmark 
+  // results dependent on the current date.
+  rng_seed_int(1122926989487);
+}
+
+// Initialize the pool with junk if needed.
+if(rng_pool == null) {
+  rng_pool = new Array();
+  rng_pptr = 0;
+  var t;
+  while(rng_pptr < rng_psize) {  // extract some randomness from Math.random()
+    t = Math.floor(65536 * Math.random());
+    rng_pool[rng_pptr++] = t >>> 8;
+    rng_pool[rng_pptr++] = t & 255;
+  }
+  rng_pptr = 0;
+  rng_seed_time();
+  //rng_seed_int(window.screenX);
+  //rng_seed_int(window.screenY);
+}
+
+function rng_get_byte() {
+  if(rng_state == null) {
+    rng_seed_time();
+    rng_state = prng_newstate();
+    rng_state.init(rng_pool);
+    for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr)
+      rng_pool[rng_pptr] = 0;
+    rng_pptr = 0;
+    //rng_pool = null;
+  }
+  // TODO: allow reseeding after first request
+  return rng_state.next();
+}
+
+function rng_get_bytes(ba) {
+  var i;
+  for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte();
+}
+
+function SecureRandom() {}
+
+SecureRandom.prototype.nextBytes = rng_get_bytes;
+// Depends on jsbn.js and rng.js
+
+// convert a (hex) string to a bignum object
+function parseBigInt(str,r) {
+  return new BigInteger(str,r);
+}
+
+function linebrk(s,n) {
+  var ret = "";
+  var i = 0;
+  while(i + n < s.length) {
+    ret += s.substring(i,i+n) + "\n";
+    i += n;
+  }
+  return ret + s.substring(i,s.length);
+}
+
+function byte2Hex(b) {
+  if(b < 0x10)
+    return "0" + b.toString(16);
+  else
+    return b.toString(16);
+}
+
+// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
+function pkcs1pad2(s,n) {
+  if(n < s.length + 11) {
+    alert("Message too long for RSA");
+    return null;
+  }
+  var ba = new Array();
+  var i = s.length - 1;
+  while(i >= 0 && n > 0) ba[--n] = s.charCodeAt(i--);
+  ba[--n] = 0;
+  var rng = new SecureRandom();
+  var x = new Array();
+  while(n > 2) { // random non-zero pad
+    x[0] = 0;
+    while(x[0] == 0) rng.nextBytes(x);
+    ba[--n] = x[0];
+  }
+  ba[--n] = 2;
+  ba[--n] = 0;
+  return new BigInteger(ba);
+}
+
+// "empty" RSA key constructor
+function RSAKey() {
+  this.n = null;
+  this.e = 0;
+  this.d = null;
+  this.p = null;
+  this.q = null;
+  this.dmp1 = null;
+  this.dmq1 = null;
+  this.coeff = null;
+}
+
+// Set the public key fields N and e from hex strings
+function RSASetPublic(N,E) {
+  if(N != null && E != null && N.length > 0 && E.length > 0) {
+    this.n = parseBigInt(N,16);
+    this.e = parseInt(E,16);
+  }
+  else
+    alert("Invalid RSA public key");
+}
+
+// Perform raw public operation on "x": return x^e (mod n)
+function RSADoPublic(x) {
+  return x.modPowInt(this.e, this.n);
+}
+
+// Return the PKCS#1 RSA encryption of "text" as an even-length hex string
+function RSAEncrypt(text) {
+  var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3);
+  if(m == null) return null;
+  var c = this.doPublic(m);
+  if(c == null) return null;
+  var h = c.toString(16);
+  if((h.length & 1) == 0) return h; else return "0" + h;
+}
+
+// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
+//function RSAEncryptB64(text) {
+//  var h = this.encrypt(text);
+//  if(h) return hex2b64(h); else return null;
+//}
+
+// protected
+RSAKey.prototype.doPublic = RSADoPublic;
+
+// public
+RSAKey.prototype.setPublic = RSASetPublic;
+RSAKey.prototype.encrypt = RSAEncrypt;
+//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
+// Depends on rsa.js and jsbn2.js
+
+// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
+function pkcs1unpad2(d,n) {
+  var b = d.toByteArray();
+  var i = 0;
+  while(i < b.length && b[i] == 0) ++i;
+  if(b.length-i != n-1 || b[i] != 2)
+    return null;
+  ++i;
+  while(b[i] != 0)
+    if(++i >= b.length) return null;
+  var ret = "";
+  while(++i < b.length)
+    ret += String.fromCharCode(b[i]);
+  return ret;
+}
+
+// Set the private key fields N, e, and d from hex strings
+function RSASetPrivate(N,E,D) {
+  if(N != null && E != null && N.length > 0 && E.length > 0) {
+    this.n = parseBigInt(N,16);
+    this.e = parseInt(E,16);
+    this.d = parseBigInt(D,16);
+  }
+  else
+    alert("Invalid RSA private key");
+}
+
+// Set the private key fields N, e, d and CRT params from hex strings
+function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) {
+  if(N != null && E != null && N.length > 0 && E.length > 0) {
+    this.n = parseBigInt(N,16);
+    this.e = parseInt(E,16);
+    this.d = parseBigInt(D,16);
+    this.p = parseBigInt(P,16);
+    this.q = parseBigInt(Q,16);
+    this.dmp1 = parseBigInt(DP,16);
+    this.dmq1 = parseBigInt(DQ,16);
+    this.coeff = parseBigInt(C,16);
+  }
+  else
+    alert("Invalid RSA private key");
+}
+
+// Generate a new random private key B bits long, using public expt E
+function RSAGenerate(B,E) {
+  var rng = new SecureRandom();
+  var qs = B>>1;
+  this.e = parseInt(E,16);
+  var ee = new BigInteger(E,16);
+  for(;;) {
+    for(;;) {
+      this.p = new BigInteger(B-qs,1,rng);
+      if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
+    }
+    for(;;) {
+      this.q = new BigInteger(qs,1,rng);
+      if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
+    }
+    if(this.p.compareTo(this.q) <= 0) {
+      var t = this.p;
+      this.p = this.q;
+      this.q = t;
+    }
+    var p1 = this.p.subtract(BigInteger.ONE);
+    var q1 = this.q.subtract(BigInteger.ONE);
+    var phi = p1.multiply(q1);
+    if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
+      this.n = this.p.multiply(this.q);
+      this.d = ee.modInverse(phi);
+      this.dmp1 = this.d.mod(p1);
+      this.dmq1 = this.d.mod(q1);
+      this.coeff = this.q.modInverse(this.p);
+      break;
+    }
+  }
+}
+
+// Perform raw private operation on "x": return x^d (mod n)
+function RSADoPrivate(x) {
+  if(this.p == null || this.q == null)
+    return x.modPow(this.d, this.n);
+
+  // TODO: re-calculate any missing CRT params
+  var xp = x.mod(this.p).modPow(this.dmp1, this.p);
+  var xq = x.mod(this.q).modPow(this.dmq1, this.q);
+
+  while(xp.compareTo(xq) < 0)
+    xp = xp.add(this.p);
+  return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
+}
+
+// Return the PKCS#1 RSA decryption of "ctext".
+// "ctext" is an even-length hex string and the output is a plain string.
+function RSADecrypt(ctext) {
+  var c = parseBigInt(ctext, 16);
+  var m = this.doPrivate(c);
+  if(m == null) return null;
+  return pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
+}
+
+// Return the PKCS#1 RSA decryption of "ctext".
+// "ctext" is a Base64-encoded string and the output is a plain string.
+//function RSAB64Decrypt(ctext) {
+//  var h = b64tohex(ctext);
+//  if(h) return this.decrypt(h); else return null;
+//}
+
+// protected
+RSAKey.prototype.doPrivate = RSADoPrivate;
+
+// public
+RSAKey.prototype.setPrivate = RSASetPrivate;
+RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
+RSAKey.prototype.generate = RSAGenerate;
+RSAKey.prototype.decrypt = RSADecrypt;
+//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;
+
+
+nValue="a5261939975948bb7a58dffe5ff54e65f0498f9175f5a09288810b8975871e99af3b5dd94057b0fc07535f5f97444504fa35169d461d0d30cf0192e307727c065168c788771c561a9400fb49175e9e6aa4e23fe11af69e9412dd23b0cb6684c4c2429bce139e848ab26d0829073351f4acd36074eafd036a5eb83359d2a698d3";
+eValue="10001";
+dValue="8e9912f6d3645894e8d38cb58c0db81ff516cf4c7e5a14c7f1eddb1459d2cded4d8d293fc97aee6aefb861859c8b6a3d1dfe710463e1f9ddc72048c09751971c4a580aa51eb523357a3cc48d31cfad1d4a165066ed92d4748fb6571211da5cb14bc11b6e2df7c1a559e6d5ac1cd5c94703a22891464fba23d0d965086277a161";
+pValue="d090ce58a92c75233a6486cb0a9209bf3583b64f540c76f5294bb97d285eed33aec220bde14b2417951178ac152ceab6da7090905b478195498b352048f15e7d";
+qValue="cab575dc652bb66df15a0359609d51d1db184750c00c6698b90ef3465c99655103edbf0d54c56aec0ce3c4d22592338092a126a0cc49f65a4a30d222b411e58f";
+dmp1Value="1a24bca8e273df2f0e47c199bbf678604e7df7215480c77c8db39f49b000ce2cf7500038acfff5433b7d582a01f1826e6f4d42e1c57f5e1fef7b12aabc59fd25";
+dmq1Value="3d06982efbbe47339e1f6d36b1216b8a741d410b0c662f54f7118b27b9a4ec9d914337eb39841d8666f3034408cf94f5b62f11c402fc994fe15a05493150d9fd";
+coeffValue="3a3e731acd8960b7ff9eb81a7ff93bd1cfa74cbd56987db58b4594fb09c09084db1734c8143f98b602b981aaa9243ca28deb69b5b280ee8dcee0fd2625e53250";
+
+setupEngine(am3, 28);
+
+var TEXT = "The quick brown fox jumped over the extremely lazy frog! " +
+    "Now is the time for all good men to come to the party.";
+var encrypted;
+
+function encrypt() {
+  var RSA = new RSAKey();
+  RSA.setPublic(nValue, eValue);
+  RSA.setPrivateEx(nValue, eValue, dValue, pValue, qValue, dmp1Value, dmq1Value, coeffValue);
+  encrypted = RSA.encrypt(TEXT);
+}
+
+function decrypt() {
+  var RSA = new RSAKey();
+  RSA.setPublic(nValue, eValue);
+  RSA.setPrivateEx(nValue, eValue, dValue, pValue, qValue, dmp1Value, dmq1Value, coeffValue);
+  var decrypted = RSA.decrypt(encrypted);
+  if (decrypted != TEXT) {
+    throw new Error("Crypto operation failed");
+  }
+}
diff --git a/regexp2000/benchmarks/deltablue.js b/regexp2000/benchmarks/deltablue.js
new file mode 100644 (file)
index 0000000..b51afd1
--- /dev/null
@@ -0,0 +1,880 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 1996 John Maloney and Mario Wolczko.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+// This implementation of the DeltaBlue benchmark is derived 
+// from the Smalltalk implementation by John Maloney and Mario 
+// Wolczko. Some parts have been translated directly, whereas 
+// others have been modified more aggresively to make it feel 
+// more like a JavaScript program.
+
+
+var DeltaBlue = new BenchmarkSuite('DeltaBlue', 71104, [
+  new Benchmark('DeltaBlue', deltaBlue)
+]);
+
+
+/**
+ * A JavaScript implementation of the DeltaBlue constrain-solving
+ * algorithm, as described in:
+ *
+ * "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver"
+ *   Bjorn N. Freeman-Benson and John Maloney
+ *   January 1990 Communications of the ACM,
+ *   also available as University of Washington TR 89-08-06.
+ *
+ * Beware: this benchmark is written in a grotesque style where
+ * the constraint model is built by side-effects from constructors.
+ * I've kept it this way to avoid deviating too much from the original
+ * implementation.
+ */
+
+
+/* --- O b j e c t   M o d e l --- */
+
+Object.prototype.inherits = function (shuper) {
+  function Inheriter() { }
+  Inheriter.prototype = shuper.prototype;
+  this.prototype = new Inheriter();
+  this.superConstructor = shuper;
+}
+
+function OrderedCollection() {
+  this.elms = new Array();
+}
+
+OrderedCollection.prototype.add = function (elm) {
+  this.elms.push(elm);
+}
+
+OrderedCollection.prototype.at = function (index) {
+  return this.elms[index];
+}
+
+OrderedCollection.prototype.size = function () {
+  return this.elms.length;
+}
+
+OrderedCollection.prototype.removeFirst = function () {
+  return this.elms.pop();
+}
+
+OrderedCollection.prototype.remove = function (elm) {
+  var index = 0, skipped = 0;
+  for (var i = 0; i < this.elms.length; i++) {
+    var value = this.elms[i];
+    if (value != elm) {
+      this.elms[index] = value;
+      index++;
+    } else {
+      skipped++;
+    }
+  }
+  for (var i = 0; i < skipped; i++)
+    this.elms.pop();
+}
+
+/* --- *
+ * S t r e n g t h
+ * --- */
+
+/**
+ * Strengths are used to measure the relative importance of constraints.
+ * New strengths may be inserted in the strength hierarchy without
+ * disrupting current constraints.  Strengths cannot be created outside
+ * this class, so pointer comparison can be used for value comparison.
+ */
+function Strength(strengthValue, name) {
+  this.strengthValue = strengthValue;
+  this.name = name;
+}
+
+Strength.stronger = function (s1, s2) {
+  return s1.strengthValue < s2.strengthValue;
+}
+
+Strength.weaker = function (s1, s2) {
+  return s1.strengthValue > s2.strengthValue;
+}
+
+Strength.weakestOf = function (s1, s2) {
+  return this.weaker(s1, s2) ? s1 : s2;
+}
+
+Strength.strongest = function (s1, s2) {
+  return this.stronger(s1, s2) ? s1 : s2;
+}
+
+Strength.prototype.nextWeaker = function () {
+  switch (this.strengthValue) {
+    case 0: return Strength.WEAKEST;
+    case 1: return Strength.WEAK_DEFAULT;
+    case 2: return Strength.NORMAL;
+    case 3: return Strength.STRONG_DEFAULT;
+    case 4: return Strength.PREFERRED;
+    case 5: return Strength.REQUIRED;
+  }
+}
+
+// Strength constants.
+Strength.REQUIRED        = new Strength(0, "required");
+Strength.STONG_PREFERRED = new Strength(1, "strongPreferred");
+Strength.PREFERRED       = new Strength(2, "preferred");
+Strength.STRONG_DEFAULT  = new Strength(3, "strongDefault");
+Strength.NORMAL          = new Strength(4, "normal");
+Strength.WEAK_DEFAULT    = new Strength(5, "weakDefault");
+Strength.WEAKEST         = new Strength(6, "weakest");
+
+/* --- *
+ * C o n s t r a i n t
+ * --- */
+
+/**
+ * An abstract class representing a system-maintainable relationship
+ * (or "constraint") between a set of variables. A constraint supplies
+ * a strength instance variable; concrete subclasses provide a means
+ * of storing the constrained variables and other information required
+ * to represent a constraint.
+ */
+function Constraint(strength) {
+  this.strength = strength;
+}
+
+/**
+ * Activate this constraint and attempt to satisfy it.
+ */
+Constraint.prototype.addConstraint = function () {
+  this.addToGraph();
+  planner.incrementalAdd(this);
+}
+
+/**
+ * Attempt to find a way to enforce this constraint. If successful,
+ * record the solution, perhaps modifying the current dataflow
+ * graph. Answer the constraint that this constraint overrides, if
+ * there is one, or nil, if there isn't.
+ * Assume: I am not already satisfied.
+ */
+Constraint.prototype.satisfy = function (mark) {
+  this.chooseMethod(mark);
+  if (!this.isSatisfied()) {
+    if (this.strength == Strength.REQUIRED)
+      alert("Could not satisfy a required constraint!");
+    return null;
+  }
+  this.markInputs(mark);
+  var out = this.output();
+  var overridden = out.determinedBy;
+  if (overridden != null) overridden.markUnsatisfied();
+  out.determinedBy = this;
+  if (!planner.addPropagate(this, mark))
+    alert("Cycle encountered");
+  out.mark = mark;
+  return overridden;
+}
+
+Constraint.prototype.destroyConstraint = function () {
+  if (this.isSatisfied()) planner.incrementalRemove(this);
+  else this.removeFromGraph();
+}
+
+/**
+ * Normal constraints are not input constraints.  An input constraint
+ * is one that depends on external state, such as the mouse, the
+ * keybord, a clock, or some arbitraty piece of imperative code.
+ */
+Constraint.prototype.isInput = function () {
+  return false;
+}
+
+/* --- *
+ * U n a r y   C o n s t r a i n t
+ * --- */
+
+/**
+ * Abstract superclass for constraints having a single possible output
+ * variable.
+ */
+function UnaryConstraint(v, strength) {
+  UnaryConstraint.superConstructor.call(this, strength);
+  this.myOutput = v;
+  this.satisfied = false;
+  this.addConstraint();
+}
+
+UnaryConstraint.inherits(Constraint);
+
+/**
+ * Adds this constraint to the constraint graph
+ */
+UnaryConstraint.prototype.addToGraph = function () {
+  this.myOutput.addConstraint(this);
+  this.satisfied = false;
+}
+
+/**
+ * Decides if this constraint can be satisfied and records that
+ * decision.
+ */
+UnaryConstraint.prototype.chooseMethod = function (mark) {
+  this.satisfied = (this.myOutput.mark != mark)
+    && Strength.stronger(this.strength, this.myOutput.walkStrength);
+}
+
+/**
+ * Returns true if this constraint is satisfied in the current solution.
+ */
+UnaryConstraint.prototype.isSatisfied = function () {
+  return this.satisfied;
+}
+
+UnaryConstraint.prototype.markInputs = function (mark) {
+  // has no inputs
+}
+
+/**
+ * Returns the current output variable.
+ */
+UnaryConstraint.prototype.output = function () {
+  return this.myOutput;
+}
+
+/**
+ * Calculate the walkabout strength, the stay flag, and, if it is
+ * 'stay', the value for the current output of this constraint. Assume
+ * this constraint is satisfied.
+ */
+UnaryConstraint.prototype.recalculate = function () {
+  this.myOutput.walkStrength = this.strength;
+  this.myOutput.stay = !this.isInput();
+  if (this.myOutput.stay) this.execute(); // Stay optimization
+}
+
+/**
+ * Records that this constraint is unsatisfied
+ */
+UnaryConstraint.prototype.markUnsatisfied = function () {
+  this.satisfied = false;
+}
+
+UnaryConstraint.prototype.inputsKnown = function () {
+  return true;
+}
+
+UnaryConstraint.prototype.removeFromGraph = function () {
+  if (this.myOutput != null) this.myOutput.removeConstraint(this);
+  this.satisfied = false;
+}
+
+/* --- *
+ * S t a y   C o n s t r a i n t
+ * --- */
+
+/**
+ * Variables that should, with some level of preference, stay the same.
+ * Planners may exploit the fact that instances, if satisfied, will not
+ * change their output during plan execution.  This is called "stay
+ * optimization".
+ */
+function StayConstraint(v, str) {
+  StayConstraint.superConstructor.call(this, v, str);
+}
+
+StayConstraint.inherits(UnaryConstraint);
+
+StayConstraint.prototype.execute = function () {
+  // Stay constraints do nothing
+}
+
+/* --- *
+ * E d i t   C o n s t r a i n t
+ * --- */
+
+/**
+ * A unary input constraint used to mark a variable that the client
+ * wishes to change.
+ */
+function EditConstraint(v, str) {
+  EditConstraint.superConstructor.call(this, v, str);
+}
+
+EditConstraint.inherits(UnaryConstraint);
+
+/**
+ * Edits indicate that a variable is to be changed by imperative code.
+ */
+EditConstraint.prototype.isInput = function () {
+  return true;
+}
+
+EditConstraint.prototype.execute = function () {
+  // Edit constraints do nothing
+}
+
+/* --- *
+ * B i n a r y   C o n s t r a i n t
+ * --- */
+
+var Direction = new Object();
+Direction.NONE     = 0;
+Direction.FORWARD  = 1;
+Direction.BACKWARD = -1;
+
+/**
+ * Abstract superclass for constraints having two possible output
+ * variables.
+ */
+function BinaryConstraint(var1, var2, strength) {
+  BinaryConstraint.superConstructor.call(this, strength);
+  this.v1 = var1;
+  this.v2 = var2;
+  this.direction = Direction.NONE;
+  this.addConstraint();
+}
+
+BinaryConstraint.inherits(Constraint);
+
+/**
+ * Decides if this constratint can be satisfied and which way it
+ * should flow based on the relative strength of the variables related,
+ * and record that decision.
+ */
+BinaryConstraint.prototype.chooseMethod = function (mark) {
+  if (this.v1.mark == mark) {
+    this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v2.walkStrength))
+      ? Direction.FORWARD
+      : Direction.NONE;
+  }
+  if (this.v2.mark == mark) {
+    this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v1.walkStrength))
+      ? Direction.BACKWARD
+      : Direction.NONE;
+  }
+  if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) {
+    this.direction = Strength.stronger(this.strength, this.v1.walkStrength)
+      ? Direction.BACKWARD
+      : Direction.NONE;
+  } else {
+    this.direction = Strength.stronger(this.strength, this.v2.walkStrength)
+      ? Direction.FORWARD
+      : Direction.BACKWARD
+  }
+}
+
+/**
+ * Add this constraint to the constraint graph
+ */
+BinaryConstraint.prototype.addToGraph = function () {
+  this.v1.addConstraint(this);
+  this.v2.addConstraint(this);
+  this.direction = Direction.NONE;
+}
+
+/**
+ * Answer true if this constraint is satisfied in the current solution.
+ */
+BinaryConstraint.prototype.isSatisfied = function () {
+  return this.direction != Direction.NONE;
+}
+
+/**
+ * Mark the input variable with the given mark.
+ */
+BinaryConstraint.prototype.markInputs = function (mark) {
+  this.input().mark = mark;
+}
+
+/**
+ * Returns the current input variable
+ */
+BinaryConstraint.prototype.input = function () {
+  return (this.direction == Direction.FORWARD) ? this.v1 : this.v2;
+}
+
+/**
+ * Returns the current output variable
+ */
+BinaryConstraint.prototype.output = function () {
+  return (this.direction == Direction.FORWARD) ? this.v2 : this.v1;
+}
+
+/**
+ * Calculate the walkabout strength, the stay flag, and, if it is
+ * 'stay', the value for the current output of this
+ * constraint. Assume this constraint is satisfied.
+ */
+BinaryConstraint.prototype.recalculate = function () {
+  var ihn = this.input(), out = this.output();
+  out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength);
+  out.stay = ihn.stay;
+  if (out.stay) this.execute();
+}
+
+/**
+ * Record the fact that this constraint is unsatisfied.
+ */
+BinaryConstraint.prototype.markUnsatisfied = function () {
+  this.direction = Direction.NONE;
+}
+
+BinaryConstraint.prototype.inputsKnown = function (mark) {
+  var i = this.input();
+  return i.mark == mark || i.stay || i.determinedBy == null;
+}
+
+BinaryConstraint.prototype.removeFromGraph = function () {
+  if (this.v1 != null) this.v1.removeConstraint(this);
+  if (this.v2 != null) this.v2.removeConstraint(this);
+  this.direction = Direction.NONE;
+}
+
+/* --- *
+ * S c a l e   C o n s t r a i n t
+ * --- */
+
+/**
+ * Relates two variables by the linear scaling relationship: "v2 =
+ * (v1 * scale) + offset". Either v1 or v2 may be changed to maintain
+ * this relationship but the scale factor and offset are considered
+ * read-only.
+ */
+function ScaleConstraint(src, scale, offset, dest, strength) {
+  this.direction = Direction.NONE;
+  this.scale = scale;
+  this.offset = offset;
+  ScaleConstraint.superConstructor.call(this, src, dest, strength);
+}
+
+ScaleConstraint.inherits(BinaryConstraint);
+
+/**
+ * Adds this constraint to the constraint graph.
+ */
+ScaleConstraint.prototype.addToGraph = function () {
+  ScaleConstraint.superConstructor.prototype.addToGraph.call(this);
+  this.scale.addConstraint(this);
+  this.offset.addConstraint(this);
+}
+
+ScaleConstraint.prototype.removeFromGraph = function () {
+  ScaleConstraint.superConstructor.prototype.removeFromGraph.call(this);
+  if (this.scale != null) this.scale.removeConstraint(this);
+  if (this.offset != null) this.offset.removeConstraint(this);
+}
+
+ScaleConstraint.prototype.markInputs = function (mark) {
+  ScaleConstraint.superConstructor.prototype.markInputs.call(this, mark);
+  this.scale.mark = this.offset.mark = mark;
+}
+
+/**
+ * Enforce this constraint. Assume that it is satisfied.
+ */
+ScaleConstraint.prototype.execute = function () {
+  if (this.direction == Direction.FORWARD) {
+    this.v2.value = this.v1.value * this.scale.value + this.offset.value;
+  } else {
+    this.v1.value = (this.v2.value - this.offset.value) / this.scale.value;
+  }
+}
+
+/**
+ * Calculate the walkabout strength, the stay flag, and, if it is
+ * 'stay', the value for the current output of this constraint. Assume
+ * this constraint is satisfied.
+ */
+ScaleConstraint.prototype.recalculate = function () {
+  var ihn = this.input(), out = this.output();
+  out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength);
+  out.stay = ihn.stay && this.scale.stay && this.offset.stay;
+  if (out.stay) this.execute();
+}
+
+/* --- *
+ * E q u a l i t  y   C o n s t r a i n t
+ * --- */
+
+/**
+ * Constrains two variables to have the same value.
+ */
+function EqualityConstraint(var1, var2, strength) {
+  EqualityConstraint.superConstructor.call(this, var1, var2, strength);
+}
+
+EqualityConstraint.inherits(BinaryConstraint);
+
+/**
+ * Enforce this constraint. Assume that it is satisfied.
+ */
+EqualityConstraint.prototype.execute = function () {
+  this.output().value = this.input().value;
+}
+
+/* --- *
+ * V a r i a b l e
+ * --- */
+
+/**
+ * A constrained variable. In addition to its value, it maintain the
+ * structure of the constraint graph, the current dataflow graph, and
+ * various parameters of interest to the DeltaBlue incremental
+ * constraint solver.
+ **/
+function Variable(name, initialValue) {
+  this.value = initialValue || 0;
+  this.constraints = new OrderedCollection();
+  this.determinedBy = null;
+  this.mark = 0;
+  this.walkStrength = Strength.WEAKEST;
+  this.stay = true;
+  this.name = name;
+}
+
+/**
+ * Add the given constraint to the set of all constraints that refer
+ * this variable.
+ */
+Variable.prototype.addConstraint = function (c) {
+  this.constraints.add(c);
+}
+
+/**
+ * Removes all traces of c from this variable.
+ */
+Variable.prototype.removeConstraint = function (c) {
+  this.constraints.remove(c);
+  if (this.determinedBy == c) this.determinedBy = null;
+}
+
+/* --- *
+ * P l a n n e r
+ * --- */
+
+/**
+ * The DeltaBlue planner
+ */
+function Planner() {
+  this.currentMark = 0;
+}
+
+/**
+ * Attempt to satisfy the given constraint and, if successful,
+ * incrementally update the dataflow graph.  Details: If satifying
+ * the constraint is successful, it may override a weaker constraint
+ * on its output. The algorithm attempts to resatisfy that
+ * constraint using some other method. This process is repeated
+ * until either a) it reaches a variable that was not previously
+ * determined by any constraint or b) it reaches a constraint that
+ * is too weak to be satisfied using any of its methods. The
+ * variables of constraints that have been processed are marked with
+ * a unique mark value so that we know where we've been. This allows
+ * the algorithm to avoid getting into an infinite loop even if the
+ * constraint graph has an inadvertent cycle.
+ */
+Planner.prototype.incrementalAdd = function (c) {
+  var mark = this.newMark();
+  var overridden = c.satisfy(mark);
+  while (overridden != null)
+    overridden = overridden.satisfy(mark);
+}
+
+/**
+ * Entry point for retracting a constraint. Remove the given
+ * constraint and incrementally update the dataflow graph.
+ * Details: Retracting the given constraint may allow some currently
+ * unsatisfiable downstream constraint to be satisfied. We therefore collect
+ * a list of unsatisfied downstream constraints and attempt to
+ * satisfy each one in turn. This list is traversed by constraint
+ * strength, strongest first, as a heuristic for avoiding
+ * unnecessarily adding and then overriding weak constraints.
+ * Assume: c is satisfied.
+ */
+Planner.prototype.incrementalRemove = function (c) {
+  var out = c.output();
+  c.markUnsatisfied();
+  c.removeFromGraph();
+  var unsatisfied = this.removePropagateFrom(out);
+  var strength = Strength.REQUIRED;
+  do {
+    for (var i = 0; i < unsatisfied.size(); i++) {
+      var u = unsatisfied.at(i);
+      if (u.strength == strength)
+        this.incrementalAdd(u);
+    }
+    strength = strength.nextWeaker();
+  } while (strength != Strength.WEAKEST);
+}
+
+/**
+ * Select a previously unused mark value.
+ */
+Planner.prototype.newMark = function () {
+  return ++this.currentMark;
+}
+
+/**
+ * Extract a plan for resatisfaction starting from the given source
+ * constraints, usually a set of input constraints. This method
+ * assumes that stay optimization is desired; the plan will contain
+ * only constraints whose output variables are not stay. Constraints
+ * that do no computation, such as stay and edit constraints, are
+ * not included in the plan.
+ * Details: The outputs of a constraint are marked when it is added
+ * to the plan under construction. A constraint may be appended to
+ * the plan when all its input variables are known. A variable is
+ * known if either a) the variable is marked (indicating that has
+ * been computed by a constraint appearing earlier in the plan), b)
+ * the variable is 'stay' (i.e. it is a constant at plan execution
+ * time), or c) the variable is not determined by any
+ * constraint. The last provision is for past states of history
+ * variables, which are not stay but which are also not computed by
+ * any constraint.
+ * Assume: sources are all satisfied.
+ */
+Planner.prototype.makePlan = function (sources) {
+  var mark = this.newMark();
+  var plan = new Plan();
+  var todo = sources;
+  while (todo.size() > 0) {
+    var c = todo.removeFirst();
+    if (c.output().mark != mark && c.inputsKnown(mark)) {
+      plan.addConstraint(c);
+      c.output().mark = mark;
+      this.addConstraintsConsumingTo(c.output(), todo);
+    }
+  }
+  return plan;
+}
+
+/**
+ * Extract a plan for resatisfying starting from the output of the
+ * given constraints, usually a set of input constraints.
+ */
+Planner.prototype.extractPlanFromConstraints = function (constraints) {
+  var sources = new OrderedCollection();
+  for (var i = 0; i < constraints.size(); i++) {
+    var c = constraints.at(i);
+    if (c.isInput() && c.isSatisfied())
+      // not in plan already and eligible for inclusion
+      sources.add(c);
+  }
+  return this.makePlan(sources);
+}
+
+/**
+ * Recompute the walkabout strengths and stay flags of all variables
+ * downstream of the given constraint and recompute the actual
+ * values of all variables whose stay flag is true. If a cycle is
+ * detected, remove the given constraint and answer
+ * false. Otherwise, answer true.
+ * Details: Cycles are detected when a marked variable is
+ * encountered downstream of the given constraint. The sender is
+ * assumed to have marked the inputs of the given constraint with
+ * the given mark. Thus, encountering a marked node downstream of
+ * the output constraint means that there is a path from the
+ * constraint's output to one of its inputs.
+ */
+Planner.prototype.addPropagate = function (c, mark) {
+  var todo = new OrderedCollection();
+  todo.add(c);
+  while (todo.size() > 0) {
+    var d = todo.removeFirst();
+    if (d.output().mark == mark) {
+      this.incrementalRemove(c);
+      return false;
+    }
+    d.recalculate();
+    this.addConstraintsConsumingTo(d.output(), todo);
+  }
+  return true;
+}
+
+
+/**
+ * Update the walkabout strengths and stay flags of all variables
+ * downstream of the given constraint. Answer a collection of
+ * unsatisfied constraints sorted in order of decreasing strength.
+ */
+Planner.prototype.removePropagateFrom = function (out) {
+  out.determinedBy = null;
+  out.walkStrength = Strength.WEAKEST;
+  out.stay = true;
+  var unsatisfied = new OrderedCollection();
+  var todo = new OrderedCollection();
+  todo.add(out);
+  while (todo.size() > 0) {
+    var v = todo.removeFirst();
+    for (var i = 0; i < v.constraints.size(); i++) {
+      var c = v.constraints.at(i);
+      if (!c.isSatisfied())
+        unsatisfied.add(c);
+    }
+    var determining = v.determinedBy;
+    for (var i = 0; i < v.constraints.size(); i++) {
+      var next = v.constraints.at(i);
+      if (next != determining && next.isSatisfied()) {
+        next.recalculate();
+        todo.add(next.output());
+      }
+    }
+  }
+  return unsatisfied;
+}
+
+Planner.prototype.addConstraintsConsumingTo = function (v, coll) {
+  var determining = v.determinedBy;
+  var cc = v.constraints;
+  for (var i = 0; i < cc.size(); i++) {
+    var c = cc.at(i);
+    if (c != determining && c.isSatisfied())
+      coll.add(c);
+  }
+}
+
+/* --- *
+ * P l a n
+ * --- */
+
+/**
+ * A Plan is an ordered list of constraints to be executed in sequence
+ * to resatisfy all currently satisfiable constraints in the face of
+ * one or more changing inputs.
+ */
+function Plan() {
+  this.v = new OrderedCollection();
+}
+
+Plan.prototype.addConstraint = function (c) {
+  this.v.add(c);
+}
+
+Plan.prototype.size = function () {
+  return this.v.size();
+}
+
+Plan.prototype.constraintAt = function (index) {
+  return this.v.at(index);
+}
+
+Plan.prototype.execute = function () {
+  for (var i = 0; i < this.size(); i++) {
+    var c = this.constraintAt(i);
+    c.execute();
+  }
+}
+
+/* --- *
+ * M a i n
+ * --- */
+
+/**
+ * This is the standard DeltaBlue benchmark. A long chain of equality
+ * constraints is constructed with a stay constraint on one end. An
+ * edit constraint is then added to the opposite end and the time is
+ * measured for adding and removing this constraint, and extracting
+ * and executing a constraint satisfaction plan. There are two cases.
+ * In case 1, the added constraint is stronger than the stay
+ * constraint and values must propagate down the entire length of the
+ * chain. In case 2, the added constraint is weaker than the stay
+ * constraint so it cannot be accomodated. The cost in this case is,
+ * of course, very low. Typical situations lie somewhere between these
+ * two extremes.
+ */
+function chainTest(n) {
+  planner = new Planner();
+  var prev = null, first = null, last = null;
+
+  // Build chain of n equality constraints
+  for (var i = 0; i <= n; i++) {
+    var name = "v" + i;
+    var v = new Variable(name);
+    if (prev != null)
+      new EqualityConstraint(prev, v, Strength.REQUIRED);
+    if (i == 0) first = v;
+    if (i == n) last = v;
+    prev = v;
+  }
+
+  new StayConstraint(last, Strength.STRONG_DEFAULT);
+  var edit = new EditConstraint(first, Strength.PREFERRED);
+  var edits = new OrderedCollection();
+  edits.add(edit);
+  var plan = planner.extractPlanFromConstraints(edits);
+  for (var i = 0; i < 100; i++) {
+    first.value = i;
+    plan.execute();
+    if (last.value != i)
+      alert("Chain test failed.");
+  }
+}
+
+/**
+ * This test constructs a two sets of variables related to each
+ * other by a simple linear transformation (scale and offset). The
+ * time is measured to change a variable on either side of the
+ * mapping and to change the scale and offset factors.
+ */
+function projectionTest(n) {
+  planner = new Planner();
+  var scale = new Variable("scale", 10);
+  var offset = new Variable("offset", 1000);
+  var src = null, dst = null;
+
+  var dests = new OrderedCollection();
+  for (var i = 0; i < n; i++) {
+    src = new Variable("src" + i, i);
+    dst = new Variable("dst" + i, i);
+    dests.add(dst);
+    new StayConstraint(src, Strength.NORMAL);
+    new ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED);
+  }
+
+  change(src, 17);
+  if (dst.value != 1170) alert("Projection 1 failed");
+  change(dst, 1050);
+  if (src.value != 5) alert("Projection 2 failed");
+  change(scale, 5);
+  for (var i = 0; i < n - 1; i++) {
+    if (dests.at(i).value != i * 5 + 1000)
+      alert("Projection 3 failed");
+  }
+  change(offset, 2000);
+  for (var i = 0; i < n - 1; i++) {
+    if (dests.at(i).value != i * 5 + 2000)
+      alert("Projection 4 failed");
+  }
+}
+
+function change(v, newValue) {
+  var edit = new EditConstraint(v, Strength.PREFERRED);
+  var edits = new OrderedCollection();
+  edits.add(edit);
+  var plan = planner.extractPlanFromConstraints(edits);
+  for (var i = 0; i < 10; i++) {
+    v.value = newValue;
+    plan.execute();
+  }
+  edit.destroyConstraint();
+}
+
+// Global variable holding the current planner.
+var planner = null;
+
+function deltaBlue() {
+  chainTest(100);
+  projectionTest(100);
+}
diff --git a/regexp2000/benchmarks/earley-boyer.js b/regexp2000/benchmarks/earley-boyer.js
new file mode 100644 (file)
index 0000000..9016a13
--- /dev/null
@@ -0,0 +1,4685 @@
+// This file is automatically generated by scheme2js, except for the
+// benchmark harness code at the beginning and end of the file.
+
+var EarleyBoyer = new BenchmarkSuite('EarleyBoyer', 765819, [
+  new Benchmark("Earley", function () { BgL_earleyzd2benchmarkzd2(); }),
+  new Benchmark("Boyer", function () { BgL_nboyerzd2benchmarkzd2(); })
+]);
+
+
+/************* GENERATED FILE - DO NOT EDIT *************/
+/************* GENERATED FILE - DO NOT EDIT *************/
+/************* GENERATED FILE - DO NOT EDIT *************/
+/************* GENERATED FILE - DO NOT EDIT *************/
+/************* GENERATED FILE - DO NOT EDIT *************/
+/************* GENERATED FILE - DO NOT EDIT *************/
+/************* GENERATED FILE - DO NOT EDIT *************/
+/************* GENERATED FILE - DO NOT EDIT *************/
+/*
+ * To use write/prints/... the default-output port has to be set first.
+ * Simply setting SC_DEFAULT_OUT and SC_ERROR_OUT to the desired values
+ * should do the trick.
+ * In the following example the std-out and error-port are redirected to
+ * a DIV.
+function initRuntime() {
+    function escapeHTML(s) {
+       var tmp = s;
+       tmp = tmp.replace(/&/g, "&amp;");
+       tmp = tmp.replace(/</g, "&lt;");
+       tmp = tmp.replace(/>/g, "&gt;");
+       tmp = tmp.replace(/ /g, "&nbsp;");
+       tmp = tmp.replace(/\n/g, "<br />");
+       tmp = tmp.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp");
+       return tmp;
+       
+    }
+
+    document.write("<div id='stdout'></div>");
+    SC_DEFAULT_OUT = new sc_GenericOutputPort(
+       function(s) {
+           var stdout = document.getElementById('stdout');
+           stdout.innerHTML = stdout.innerHTML + escapeHTML(s);
+       });
+    SC_ERROR_OUT = SC_DEFAULT_OUT;
+}
+*/
+
+
+function sc_print_debug() {
+    sc_print.apply(null, arguments);
+}
+/*** META ((export *js*)) */
+var sc_JS_GLOBALS = this;
+
+var __sc_LINE=-1;
+var __sc_FILE="";
+
+/*** META ((export #t)) */
+function sc_alert() {
+   var len = arguments.length;
+   var s = "";
+   var i;
+
+   for( i = 0; i < len; i++ ) {
+       s += sc_toDisplayString(arguments[ i ]);
+   }
+
+   return alert( s );
+}
+
+/*** META ((export #t)) */
+function sc_typeof( x ) {
+   return typeof x;
+}
+
+/*** META ((export #t)) */
+function sc_error() {
+    var a = [sc_jsstring2symbol("*error*")];
+    for (var i = 0; i < arguments.length; i++) {
+       a[i+1] = arguments[i];
+    }
+    throw a;
+}
+
+/*** META ((export #t)
+           (peephole (prefix "throw ")))
+*/
+function sc_raise(obj) {
+    throw obj;
+}
+
+/*** META ((export with-handler-lambda)) */
+function sc_withHandlerLambda(handler, body) {
+    try {
+       return body();
+    } catch(e) {
+       if (!e._internalException)
+           return handler(e);
+       else
+           throw e;
+    }
+}
+
+var sc_properties = new Object();
+
+/*** META ((export #t)) */
+function sc_putpropBang(sym, key, val) {
+    var ht = sc_properties[sym];
+    if (!ht) {
+       ht = new Object();
+       sc_properties[sym] = ht;
+    }
+    ht[key] = val;
+}
+
+/*** META ((export #t)) */
+function sc_getprop(sym, key) {
+    var ht = sc_properties[sym];
+    if (ht) {
+       if (key in ht)
+           return ht[key];
+       else
+           return false;
+    } else
+       return false;
+}
+
+/*** META ((export #t)) */
+function sc_rempropBang(sym, key) {
+    var ht = sc_properties[sym];
+    if (ht)
+       delete ht[key];
+}
+
+/*** META ((export #t)) */
+function sc_any2String(o) {
+    return jsstring2string(sc_toDisplayString(o));
+}    
+
+/*** META ((export #t)
+           (peephole (infix 2 2 "==="))
+           (type bool))
+*/
+function sc_isEqv(o1, o2) {
+    return (o1 === o2);
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 "==="))
+           (type bool))
+*/
+function sc_isEq(o1, o2) {
+    return (o1 === o2);
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isNumber(n) {
+    return (typeof n === "number");
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isComplex(n) {
+    return sc_isNumber(n);
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isReal(n) {
+    return sc_isNumber(n);
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isRational(n) {
+    return sc_isReal(n);
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isInteger(n) {
+    return (parseInt(n) === n);
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix ", false")))
+*/
+// we don't have exact numbers...
+function sc_isExact(n) {
+    return false;
+}
+
+/*** META ((export #t)
+           (peephole (postfix ", true"))
+          (type bool))
+*/
+function sc_isInexact(n) {
+    return true;
+}
+
+/*** META ((export = =fx =fl)
+           (type bool)
+           (peephole (infix 2 2 "===")))
+*/
+function sc_equal(x) {
+    for (var i = 1; i < arguments.length; i++)
+       if (x !== arguments[i])
+           return false;
+    return true;
+}
+
+/*** META ((export < <fx <fl)
+           (type bool)
+           (peephole (infix 2 2 "<")))
+*/
+function sc_less(x) {
+    for (var i = 1; i < arguments.length; i++) {
+       if (x >= arguments[i])
+           return false;
+       x = arguments[i];
+    }
+    return true;
+}
+
+/*** META ((export > >fx >fl)
+           (type bool)
+           (peephole (infix 2 2 ">")))
+*/
+function sc_greater(x, y) {
+    for (var i = 1; i < arguments.length; i++) {
+       if (x <= arguments[i])
+           return false;
+       x = arguments[i];
+    }
+    return true;
+}
+
+/*** META ((export <= <=fx <=fl)
+           (type bool)
+           (peephole (infix 2 2 "<=")))
+*/
+function sc_lessEqual(x, y) {
+    for (var i = 1; i < arguments.length; i++) {
+       if (x > arguments[i])
+           return false;
+       x = arguments[i];
+    }
+    return true;
+}
+
+/*** META ((export >= >=fl >=fx)
+           (type bool)
+           (peephole (infix 2 2 ">=")))
+*/
+function sc_greaterEqual(x, y) {
+    for (var i = 1; i < arguments.length; i++) {
+       if (x < arguments[i])
+           return false;
+       x = arguments[i];
+    }
+    return true;
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix "=== 0")))
+*/
+function sc_isZero(x) {
+    return (x === 0);
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix "> 0")))
+*/
+function sc_isPositive(x) {
+    return (x > 0);
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix "< 0")))
+*/
+function sc_isNegative(x) {
+    return (x < 0);
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix "%2===1")))
+*/
+function sc_isOdd(x) {
+    return (x % 2 === 1);
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix "%2===0")))
+*/
+function sc_isEven(x) {
+    return (x % 2 === 0);
+}
+
+/*** META ((export #t)) */
+var sc_max = Math.max;
+/*** META ((export #t)) */
+var sc_min = Math.min;
+
+/*** META ((export + +fx +fl)
+           (peephole (infix 0 #f "+" "0")))
+*/
+function sc_plus() {
+    var sum = 0;
+    for (var i = 0; i < arguments.length; i++)
+       sum += arguments[i];
+    return sum;
+}
+
+/*** META ((export * *fx *fl)
+           (peephole (infix 0 #f "*" "1")))
+*/
+function sc_multi() {
+    var product = 1;
+    for (var i = 0; i < arguments.length; i++)
+       product *= arguments[i];
+    return product;
+}
+
+/*** META ((export - -fx -fl)
+           (peephole (minus)))
+*/
+function sc_minus(x) {
+    if (arguments.length === 1)
+       return -x;
+    else {
+       var res = x;
+       for (var i = 1; i < arguments.length; i++)
+           res -= arguments[i];
+       return res;
+    }
+}
+
+/*** META ((export / /fl)
+           (peephole (div)))
+*/
+function sc_div(x) {
+    if (arguments.length === 1)
+       return 1/x;
+    else {
+       var res = x;
+       for (var i = 1; i < arguments.length; i++)
+           res /= arguments[i];
+       return res;
+    }
+}
+
+/*** META ((export #t)) */
+var sc_abs = Math.abs;
+
+/*** META ((export quotient /fx)
+           (peephole (hole 2 "parseInt(" x "/" y ")")))
+*/
+function sc_quotient(x, y) {
+    return parseInt(x / y);
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 "%")))
+*/
+function sc_remainder(x, y) {
+    return x % y;
+}
+
+/*** META ((export #t)
+           (peephole (modulo)))
+*/
+function sc_modulo(x, y) {
+    var remainder = x % y;
+    // if they don't have the same sign
+    if ((remainder * y) < 0)
+       return remainder + y;
+    else
+       return remainder;
+}
+
+function sc_euclid_gcd(a, b) {
+    var temp;
+    if (a === 0) return b;
+    if (b === 0) return a;
+    if (a < 0) {a = -a;};
+    if (b < 0) {b = -b;};
+    if (b > a) {temp = a; a = b; b = temp;};
+    while (true) {
+       a %= b;
+       if(a === 0) {return b;};
+       b %= a;
+       if(b === 0) {return a;};
+    };
+    return b;
+}
+
+/*** META ((export #t)) */
+function sc_gcd() {
+    var gcd = 0;
+    for (var i = 0; i < arguments.length; i++)
+       gcd = sc_euclid_gcd(gcd, arguments[i]);
+    return gcd;
+}
+
+/*** META ((export #t)) */
+function sc_lcm() {
+    var lcm = 1;
+    for (var i = 0; i < arguments.length; i++) {
+       var f = Math.round(arguments[i] / sc_euclid_gcd(arguments[i], lcm));
+       lcm *= Math.abs(f);
+    }
+    return lcm;
+}
+
+// LIMITATION: numerator and denominator don't make sense in floating point world.
+//var SC_MAX_DECIMALS = 1000000
+//
+// function sc_numerator(x) {
+//     var rounded = Math.round(x * SC_MAX_DECIMALS);
+//     return Math.round(rounded / sc_euclid_gcd(rounded, SC_MAX_DECIMALS));
+// }
+
+// function sc_denominator(x) {
+//     var rounded = Math.round(x * SC_MAX_DECIMALS);
+//     return Math.round(SC_MAX_DECIMALS / sc_euclid_gcd(rounded, SC_MAX_DECIMALS));
+// }
+
+/*** META ((export #t)) */
+var sc_floor = Math.floor;
+/*** META ((export #t)) */
+var sc_ceiling = Math.ceil;
+/*** META ((export #t)) */
+var sc_truncate = parseInt;
+/*** META ((export #t)) */
+var sc_round = Math.round;
+
+// LIMITATION: sc_rationalize doesn't make sense in a floating point world.
+
+/*** META ((export #t)) */
+var sc_exp = Math.exp;
+/*** META ((export #t)) */
+var sc_log = Math.log;
+/*** META ((export #t)) */
+var sc_sin = Math.sin;
+/*** META ((export #t)) */
+var sc_cos = Math.cos;
+/*** META ((export #t)) */
+var sc_tan = Math.tan;
+/*** META ((export #t)) */
+var sc_asin = Math.asin;
+/*** META ((export #t)) */
+var sc_acos = Math.acos;
+/*** META ((export #t)) */
+var sc_atan = Math.atan;
+
+/*** META ((export #t)) */
+var sc_sqrt = Math.sqrt;
+/*** META ((export #t)) */
+var sc_expt = Math.pow;
+
+// LIMITATION: we don't have complex numbers.
+// LIMITATION: the following functions are hence not implemented.
+// LIMITATION: make-rectangular, make-polar, real-part, imag-part, magnitude, angle
+// LIMITATION: 2 argument atan
+
+/*** META ((export #t)
+           (peephole (id)))
+*/
+function sc_exact2inexact(x) {
+    return x;
+}
+
+/*** META ((export #t)
+           (peephole (id)))
+*/
+function sc_inexact2exact(x) {
+    return x;
+}
+
+function sc_number2jsstring(x, radix) {
+    if (radix)
+       return x.toString(radix);
+    else
+       return x.toString();
+}
+
+function sc_jsstring2number(s, radix) {
+    if (s === "") return false;
+
+    if (radix) {
+       var t = parseInt(s, radix);
+       if (!t && t !== 0) return false;
+       // verify that each char is in range. (parseInt ignores leading
+       // white and trailing chars)
+       var allowedChars = "01234567890abcdefghijklmnopqrstuvwxyz".substring(0, radix+1);
+       if ((new RegExp("^["+allowedChars+"]*$", "i")).test(s))
+           return t;
+       else return false;
+    } else {
+       var t = +s; // does not ignore trailing chars.
+       if (!t && t !== 0) return false;
+       // simply verify that first char is not whitespace.
+       var c = s.charAt(0);
+       // if +c is 0, but the char is not "0", then we have a whitespace.
+       if (+c === 0 && c !== "0") return false;
+       return t;
+    }
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (not)))
+*/
+function sc_not(b) {
+    return b === false;
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isBoolean(b) {
+    return (b === true) || (b === false);
+}
+
+function sc_Pair(car, cdr) {
+    this.car = car;
+    this.cdr = cdr;
+}
+
+sc_Pair.prototype.toString = function() {
+    return sc_toDisplayString(this);
+};
+sc_Pair.prototype.sc_toWriteOrDisplayString = function(writeOrDisplay) {
+    var current = this;
+
+    var res = "(";
+
+    while(true) {
+       res += writeOrDisplay(current.car);
+       if (sc_isPair(current.cdr)) {
+           res += " ";
+           current = current.cdr;
+       } else if (current.cdr !== null) {
+           res += " . " + writeOrDisplay(current.cdr);
+           break;
+       } else // current.cdr == null
+           break;
+    }
+       
+    res += ")";
+
+    return res;
+};
+sc_Pair.prototype.sc_toDisplayString = function() {
+    return this.sc_toWriteOrDisplayString(sc_toDisplayString);
+};
+sc_Pair.prototype.sc_toWriteString = function() {
+    return this.sc_toWriteOrDisplayString(sc_toWriteString);
+};
+// sc_Pair.prototype.sc_toWriteCircleString in IO.js
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix " instanceof sc_Pair")))
+*/
+function sc_isPair(p) {
+    return (p instanceof sc_Pair);
+}
+
+function sc_isPairEqual(p1, p2, comp) {
+    return (comp(p1.car, p2.car) && comp(p1.cdr, p2.cdr));
+}
+
+/*** META ((export #t)
+           (peephole (hole 2 "new sc_Pair(" car ", " cdr ")")))
+*/
+function sc_cons(car, cdr) {
+    return new sc_Pair(car, cdr);
+}
+
+/*** META ((export cons*)) */
+function sc_consStar() {
+    var res = arguments[arguments.length - 1];
+    for (var i = arguments.length-2; i >= 0; i--)
+       res = new sc_Pair(arguments[i], res);
+    return res;
+}
+
+/*** META ((export #t)
+           (peephole (postfix ".car")))
+*/
+function sc_car(p) {
+    return p.car;
+}
+
+/*** META ((export #t)
+           (peephole (postfix ".cdr")))
+*/
+function sc_cdr(p) {
+    return p.cdr;
+}
+
+/*** META ((export #t)
+           (peephole (hole 2 p ".car = " val)))
+*/
+function sc_setCarBang(p, val) {
+    p.car = val;
+}
+
+/*** META ((export #t)
+           (peephole (hole 2 p ".cdr = " val)))
+*/
+function sc_setCdrBang(p, val) {
+    p.cdr = val;
+}
+
+/*** META ((export #t)
+           (peephole (postfix ".car.car")))
+*/
+function sc_caar(p) { return p.car.car; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.car")))
+*/
+function sc_cadr(p) { return p.cdr.car; }
+/*** META ((export #t)
+           (peephole (postfix ".car.cdr")))
+*/
+function sc_cdar(p) { return p.car.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.cdr")))
+*/
+function sc_cddr(p) { return p.cdr.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".car.car.car")))
+*/
+function sc_caaar(p) { return p.car.car.car; }
+/*** META ((export #t)
+           (peephole (postfix ".car.cdr.car")))
+*/
+function sc_cadar(p) { return p.car.cdr.car; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.car.car")))
+*/
+function sc_caadr(p) { return p.cdr.car.car; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.cdr.car")))
+*/
+function sc_caddr(p) { return p.cdr.cdr.car; }
+/*** META ((export #t)
+           (peephole (postfix ".car.car.cdr")))
+*/
+function sc_cdaar(p) { return p.car.car.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.car.cdr")))
+*/
+function sc_cdadr(p) { return p.cdr.car.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".car.cdr.cdr")))
+*/
+function sc_cddar(p) { return p.car.cdr.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.cdr.cdr")))
+*/
+function sc_cdddr(p) { return p.cdr.cdr.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".car.car.car.car")))
+*/
+function sc_caaaar(p) { return p.car.car.car.car; }
+/*** META ((export #t)
+           (peephole (postfix ".car.cdr.car.car")))
+*/
+function sc_caadar(p) { return p.car.cdr.car.car; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.car.car.car")))
+*/
+function sc_caaadr(p) { return p.cdr.car.car.car; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.cdr.car.car")))
+*/
+function sc_caaddr(p) { return p.cdr.cdr.car.car; }
+/*** META ((export #t)
+           (peephole (postfix ".car.car.car.cdr")))
+*/
+function sc_cdaaar(p) { return p.car.car.car.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".car.cdr.car.cdr")))
+*/
+function sc_cdadar(p) { return p.car.cdr.car.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.car.car.cdr")))
+*/
+function sc_cdaadr(p) { return p.cdr.car.car.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.cdr.car.cdr")))
+*/
+function sc_cdaddr(p) { return p.cdr.cdr.car.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".car.car.cdr.car")))
+*/
+function sc_cadaar(p) { return p.car.car.cdr.car; }
+/*** META ((export #t)
+           (peephole (postfix ".car.cdr.cdr.car")))
+*/
+function sc_caddar(p) { return p.car.cdr.cdr.car; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.car.cdr.car")))
+*/
+function sc_cadadr(p) { return p.cdr.car.cdr.car; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.cdr.cdr.car")))
+*/
+function sc_cadddr(p) { return p.cdr.cdr.cdr.car; }
+/*** META ((export #t)
+           (peephole (postfix ".car.car.cdr.cdr")))
+*/
+function sc_cddaar(p) { return p.car.car.cdr.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".car.cdr.cdr.cdr")))
+*/
+function sc_cdddar(p) { return p.car.cdr.cdr.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.car.cdr.cdr")))
+*/
+function sc_cddadr(p) { return p.cdr.car.cdr.cdr; }
+/*** META ((export #t)
+           (peephole (postfix ".cdr.cdr.cdr.cdr")))
+*/
+function sc_cddddr(p) { return p.cdr.cdr.cdr.cdr; }
+
+/*** META ((export #t)) */
+function sc_lastPair(l) {
+    if (!sc_isPair(l)) sc_error("sc_lastPair: pair expected");
+    var res = l;
+    var cdr = l.cdr;
+    while (sc_isPair(cdr)) {
+       res = cdr;
+       cdr = res.cdr;
+    }
+    return res;
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix " === null")))
+*/
+function sc_isNull(o) {
+    return (o === null);
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isList(o) {
+    var rabbit;
+    var turtle;
+
+    var rabbit = o;
+    var turtle = o;
+    while (true) {
+       if (rabbit === null ||
+           (rabbit instanceof sc_Pair && rabbit.cdr === null))
+           return true;  // end of list
+       else if ((rabbit instanceof sc_Pair) &&
+                (rabbit.cdr instanceof sc_Pair)) {
+           rabbit = rabbit.cdr.cdr;
+           turtle = turtle.cdr;
+           if (rabbit === turtle) return false; // cycle
+       } else
+           return false; // not pair
+    }
+}
+
+/*** META ((export #t)) */
+function sc_list() {
+    var res = null;
+    var a = arguments;
+    for (var i = a.length-1; i >= 0; i--)
+       res = new sc_Pair(a[i], res);
+    return res;
+}
+
+/*** META ((export #t)) */
+function sc_iota(num, init) {
+   var res = null;
+   if (!init) init = 0;
+   for (var i = num - 1; i >= 0; i--)
+      res = new sc_Pair(i + init, res);
+   return res;
+}
+
+/*** META ((export #t)) */
+function sc_makeList(nbEls, fill) {
+    var res = null;
+    for (var i = 0; i < nbEls; i++)
+       res = new sc_Pair(fill, res);
+    return res;
+}
+
+/*** META ((export #t)) */
+function sc_length(l) {
+    var res = 0;
+    while (l !== null) {
+       res++;
+       l = l.cdr;
+    }
+    return res;
+}
+
+/*** META ((export #t)) */
+function sc_remq(o, l) {
+    var dummy = { cdr : null };
+    var tail = dummy;
+    while (l !== null) {
+       if (l.car !== o) {
+           tail.cdr = sc_cons(l.car, null);
+           tail = tail.cdr;
+       }
+       l = l.cdr;
+    }
+    return dummy.cdr;
+}
+
+/*** META ((export #t)) */
+function sc_remqBang(o, l) {
+    var dummy = { cdr : null };
+    var tail = dummy;
+    var needsAssig = true;
+    while (l !== null) {
+       if (l.car === o) {
+           needsAssig = true;
+       } else {
+           if (needsAssig) {
+               tail.cdr = l;
+               needsAssig = false;
+           }
+           tail = l;
+       }
+       l = l.cdr;
+    }
+    tail.cdr = null;
+    return dummy.cdr;
+}
+
+/*** META ((export #t)) */
+function sc_delete(o, l) {
+    var dummy = { cdr : null };
+    var tail = dummy;
+    while (l !== null) {
+       if (!sc_isEqual(l.car, o)) {
+           tail.cdr = sc_cons(l.car, null);
+           tail = tail.cdr;
+       }
+       l = l.cdr;
+    }
+    return dummy.cdr;
+}
+
+/*** META ((export #t)) */
+function sc_deleteBang(o, l) {
+    var dummy = { cdr : null };
+    var tail = dummy;
+    var needsAssig = true;
+    while (l !== null) {
+       if (sc_isEqual(l.car, o)) {
+           needsAssig = true;
+       } else {
+           if (needsAssig) {
+               tail.cdr = l;
+               needsAssig = false;
+           }
+           tail = l;
+       }
+       l = l.cdr;
+    }
+    tail.cdr = null;
+    return dummy.cdr;
+}
+
+function sc_reverseAppendBang(l1, l2) {
+    var res = l2;
+    while (l1 !== null) {
+       var tmp = res;
+       res = l1;
+       l1 = l1.cdr;
+       res.cdr = tmp;
+    }
+    return res;
+}
+       
+function sc_dualAppend(l1, l2) {
+    if (l1 === null) return l2;
+    if (l2 === null) return l1;
+    var rev = sc_reverse(l1);
+    return sc_reverseAppendBang(rev, l2);
+}
+
+/*** META ((export #t)) */
+function sc_append() {
+    if (arguments.length === 0)
+       return null;
+    var res = arguments[arguments.length - 1];
+    for (var i = arguments.length - 2; i >= 0; i--)
+       res = sc_dualAppend(arguments[i], res);
+    return res;
+}
+
+function sc_dualAppendBang(l1, l2) {
+    if (l1 === null) return l2;
+    if (l2 === null) return l1;
+    var tmp = l1;
+    while (tmp.cdr !== null) tmp=tmp.cdr;
+    tmp.cdr = l2;
+    return l1;
+}
+    
+/*** META ((export #t)) */
+function sc_appendBang() {
+    var res = null;
+    for (var i = 0; i < arguments.length; i++)
+       res = sc_dualAppendBang(res, arguments[i]);
+    return res;
+}
+
+/*** META ((export #t)) */
+function sc_reverse(l1) {
+    var res = null;
+    while (l1 !== null) {
+       res = sc_cons(l1.car, res);
+       l1 = l1.cdr;
+    }
+    return res;
+}
+
+/*** META ((export #t)) */
+function sc_reverseBang(l) {
+    return sc_reverseAppendBang(l, null);
+}
+
+/*** META ((export #t)) */
+function sc_listTail(l, k) {
+    var res = l;
+    for (var i = 0; i < k; i++) {
+       res = res.cdr;
+    }
+    return res;
+}
+
+/*** META ((export #t)) */
+function sc_listRef(l, k) {
+    return sc_listTail(l, k).car;
+}
+
+/* // unoptimized generic versions
+function sc_memX(o, l, comp) {
+    while (l != null) {
+       if (comp(l.car, o))
+           return l;
+       l = l.cdr;
+    }
+    return false;
+}
+function sc_memq(o, l) { return sc_memX(o, l, sc_isEq); }
+function sc_memv(o, l) { return sc_memX(o, l, sc_isEqv); }
+function sc_member(o, l) { return sc_memX(o, l, sc_isEqual); }
+*/
+
+/* optimized versions */
+/*** META ((export #t)) */
+function sc_memq(o, l) {
+    while (l !== null) {
+       if (l.car === o)
+           return l;
+       l = l.cdr;
+    }
+    return false;
+}
+/*** META ((export #t)) */
+function sc_memv(o, l) {
+    while (l !== null) {
+       if (l.car === o)
+           return l;
+       l = l.cdr;
+    }
+    return false;
+}
+/*** META ((export #t)) */
+function sc_member(o, l) {
+    while (l !== null) {
+       if (sc_isEqual(l.car,o))
+           return l;
+       l = l.cdr;
+    }
+    return false;
+}
+
+/* // generic unoptimized versions
+function sc_assX(o, al, comp) {
+    while (al != null) {
+       if (comp(al.car.car, o))
+           return al.car;
+       al = al.cdr;
+    }
+    return false;
+}
+function sc_assq(o, al) { return sc_assX(o, al, sc_isEq); }
+function sc_assv(o, al) { return sc_assX(o, al, sc_isEqv); }
+function sc_assoc(o, al) { return sc_assX(o, al, sc_isEqual); }
+*/
+// optimized versions
+/*** META ((export #t)) */
+function sc_assq(o, al) {
+    while (al !== null) {
+       if (al.car.car === o)
+           return al.car;
+       al = al.cdr;
+    }
+    return false;
+}
+/*** META ((export #t)) */
+function sc_assv(o, al) {
+    while (al !== null) {
+       if (al.car.car === o)
+           return al.car;
+       al = al.cdr;
+    }
+    return false;
+}
+/*** META ((export #t)) */
+function sc_assoc(o, al) {
+    while (al !== null) {
+       if (sc_isEqual(al.car.car, o))
+           return al.car;
+       al = al.cdr;
+    }
+    return false;
+}
+
+/* can be used for mutable strings and characters */
+function sc_isCharStringEqual(cs1, cs2) { return cs1.val === cs2.val; }
+function sc_isCharStringLess(cs1, cs2) { return cs1.val < cs2.val; }
+function sc_isCharStringGreater(cs1, cs2) { return cs1.val > cs2.val; }
+function sc_isCharStringLessEqual(cs1, cs2) { return cs1.val <= cs2.val; }
+function sc_isCharStringGreaterEqual(cs1, cs2) { return cs1.val >= cs2.val; }
+function sc_isCharStringCIEqual(cs1, cs2)
+    { return cs1.val.toLowerCase() === cs2.val.toLowerCase(); }
+function sc_isCharStringCILess(cs1, cs2)
+    { return cs1.val.toLowerCase() < cs2.val.toLowerCase(); }
+function sc_isCharStringCIGreater(cs1, cs2)
+    { return cs1.val.toLowerCase() > cs2.val.toLowerCase(); }
+function sc_isCharStringCILessEqual(cs1, cs2)
+    { return cs1.val.toLowerCase() <= cs2.val.toLowerCase(); }
+function sc_isCharStringCIGreaterEqual(cs1, cs2)
+    { return cs1.val.toLowerCase() >= cs2.val.toLowerCase(); }
+
+
+
+
+function sc_Char(c) {
+    var cached = sc_Char.lazy[c];
+    if (cached)
+       return cached;
+    this.val = c;
+    sc_Char.lazy[c] = this;
+    // add return, so FF does not complain.
+    return undefined;
+}
+sc_Char.lazy = new Object();
+// thanks to Eric
+sc_Char.char2readable = {
+    "\000": "#\\null",
+    "\007": "#\\bell",
+    "\010": "#\\backspace",
+    "\011": "#\\tab",
+    "\012": "#\\newline",
+    "\014": "#\\page",
+    "\015": "#\\return",
+    "\033": "#\\escape",
+    "\040": "#\\space",
+    "\177": "#\\delete",
+
+  /* poeticless names */
+    "\001": "#\\soh",
+    "\002": "#\\stx",
+    "\003": "#\\etx",
+    "\004": "#\\eot",
+    "\005": "#\\enq",
+    "\006": "#\\ack",
+
+    "\013": "#\\vt",
+    "\016": "#\\so",
+    "\017": "#\\si",
+
+    "\020": "#\\dle",
+    "\021": "#\\dc1",
+    "\022": "#\\dc2",
+    "\023": "#\\dc3",
+    "\024": "#\\dc4",
+    "\025": "#\\nak",
+    "\026": "#\\syn",
+    "\027": "#\\etb",
+
+    "\030": "#\\can",
+    "\031": "#\\em",
+    "\032": "#\\sub",
+    "\033": "#\\esc",
+    "\034": "#\\fs",
+    "\035": "#\\gs",
+    "\036": "#\\rs",
+    "\037": "#\\us"};
+
+sc_Char.readable2char = {
+    "null": "\000",
+    "bell": "\007",
+    "backspace": "\010",
+    "tab": "\011",
+    "newline": "\012",
+    "page": "\014",
+    "return": "\015",
+    "escape": "\033",
+    "space": "\040",
+    "delete": "\000",
+    "soh": "\001",
+    "stx": "\002",
+    "etx": "\003",
+    "eot": "\004",
+    "enq": "\005",
+    "ack": "\006",
+    "bel": "\007",
+    "bs": "\010",
+    "ht": "\011",
+    "nl": "\012",
+    "vt": "\013",
+    "np": "\014",
+    "cr": "\015",
+    "so": "\016",
+    "si": "\017",
+    "dle": "\020",
+    "dc1": "\021",
+    "dc2": "\022",
+    "dc3": "\023",
+    "dc4": "\024",
+    "nak": "\025",
+    "syn": "\026",
+    "etb": "\027",
+    "can": "\030",
+    "em": "\031",
+    "sub": "\032",
+    "esc": "\033",
+    "fs": "\034",
+    "gs": "\035",
+    "rs": "\036",
+    "us": "\037",
+    "sp": "\040",
+    "del": "\177"};
+    
+sc_Char.prototype.toString = function() {
+    return this.val;
+};
+// sc_toDisplayString == toString
+sc_Char.prototype.sc_toWriteString = function() {
+    var entry = sc_Char.char2readable[this.val];
+    if (entry)
+       return entry;
+    else
+       return "#\\" + this.val;
+};
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix "instanceof sc_Char")))
+*/
+function sc_isChar(c) {
+    return (c instanceof sc_Char);
+}
+
+/*** META ((export char=?)
+           (type bool)
+           (peephole (hole 2 c1 ".val === " c2 ".val")))
+*/
+var sc_isCharEqual = sc_isCharStringEqual;
+/*** META ((export char<?)
+           (type bool)
+           (peephole (hole 2 c1 ".val < " c2 ".val")))
+*/
+var sc_isCharLess = sc_isCharStringLess;
+/*** META ((export char>?)
+           (type bool)
+           (peephole (hole 2 c1 ".val > " c2 ".val")))
+*/
+var sc_isCharGreater = sc_isCharStringGreater;
+/*** META ((export char<=?)
+           (type bool)
+           (peephole (hole 2 c1 ".val <= " c2 ".val")))
+*/
+var sc_isCharLessEqual = sc_isCharStringLessEqual;
+/*** META ((export char>=?)
+           (type bool)
+           (peephole (hole 2 c1 ".val >= " c2 ".val")))
+*/
+var sc_isCharGreaterEqual = sc_isCharStringGreaterEqual;
+/*** META ((export char-ci=?)
+           (type bool)
+           (peephole (hole 2 c1 ".val.toLowerCase() === " c2 ".val.toLowerCase()")))
+*/
+var sc_isCharCIEqual = sc_isCharStringCIEqual;
+/*** META ((export char-ci<?)
+           (type bool)
+           (peephole (hole 2 c1 ".val.toLowerCase() < " c2 ".val.toLowerCase()")))
+*/
+var sc_isCharCILess = sc_isCharStringCILess;
+/*** META ((export char-ci>?)
+           (type bool)
+           (peephole (hole 2 c1 ".val.toLowerCase() > " c2 ".val.toLowerCase()")))
+*/
+var sc_isCharCIGreater = sc_isCharStringCIGreater;
+/*** META ((export char-ci<=?)
+           (type bool)
+           (peephole (hole 2 c1 ".val.toLowerCase() <= " c2 ".val.toLowerCase()")))
+*/
+var sc_isCharCILessEqual = sc_isCharStringCILessEqual;
+/*** META ((export char-ci>=?)
+           (type bool)
+           (peephole (hole 2 c1 ".val.toLowerCase() >= " c2 ".val.toLowerCase()")))
+*/
+var sc_isCharCIGreaterEqual = sc_isCharStringCIGreaterEqual;
+
+var SC_NUMBER_CLASS = "0123456789";
+var SC_WHITESPACE_CLASS = ' \r\n\t\f';
+var SC_LOWER_CLASS = 'abcdefghijklmnopqrstuvwxyz';
+var SC_UPPER_CLASS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+function sc_isCharOfClass(c, cl) { return (cl.indexOf(c) != -1); }
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isCharAlphabetic(c)
+    { return sc_isCharOfClass(c.val, SC_LOWER_CLASS) ||
+         sc_isCharOfClass(c.val, SC_UPPER_CLASS); }
+/*** META ((export #t)
+           (type bool)
+           (peephole (hole 1 "SC_NUMBER_CLASS.indexOf(" c ".val) != -1")))
+*/
+function sc_isCharNumeric(c)
+    { return sc_isCharOfClass(c.val, SC_NUMBER_CLASS); }
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isCharWhitespace(c) {
+    var tmp = c.val;
+    return tmp === " " || tmp === "\r" || tmp === "\n" || tmp === "\t" || tmp === "\f";
+}
+/*** META ((export #t)
+           (type bool)
+           (peephole (hole 1 "SC_UPPER_CLASS.indexOf(" c ".val) != -1")))
+*/
+function sc_isCharUpperCase(c)
+    { return sc_isCharOfClass(c.val, SC_UPPER_CLASS); }
+/*** META ((export #t)
+           (type bool)
+           (peephole (hole 1 "SC_LOWER_CLASS.indexOf(" c ".val) != -1")))
+*/
+function sc_isCharLowerCase(c)
+    { return sc_isCharOfClass(c.val, SC_LOWER_CLASS); }
+
+/*** META ((export #t)
+           (peephole (postfix ".val.charCodeAt(0)")))
+*/
+function sc_char2integer(c)
+    { return c.val.charCodeAt(0); }
+/*** META ((export #t)
+           (peephole (hole 1 "new sc_Char(String.fromCharCode(" n "))")))
+*/
+function sc_integer2char(n)
+    { return new sc_Char(String.fromCharCode(n)); }
+
+/*** META ((export #t)
+           (peephole (hole 1 "new sc_Char(" c ".val.toUpperCase())")))
+*/
+function sc_charUpcase(c)
+    { return new sc_Char(c.val.toUpperCase()); }
+/*** META ((export #t)
+           (peephole (hole 1 "new sc_Char(" c ".val.toLowerCase())")))
+*/
+function sc_charDowncase(c)
+    { return new sc_Char(c.val.toLowerCase()); }
+
+function sc_makeJSStringOfLength(k, c) {
+    var fill;
+    if (c === undefined)
+       fill = " ";
+    else
+       fill = c;
+    var res = "";
+    var len = 1;
+    // every round doubles the size of fill.
+    while (k >= len) {
+       if (k & len)
+           res = res.concat(fill);
+       fill = fill.concat(fill);
+       len *= 2;
+    }
+    return res;
+}
+
+function sc_makejsString(k, c) {
+    var fill;
+    if (c)
+       fill = c.val;
+    else
+       fill = " ";
+    return sc_makeJSStringOfLength(k, fill);
+}
+
+function sc_jsstring2list(s) {
+    var res = null;
+    for (var i = s.length - 1; i >= 0; i--)
+       res = sc_cons(new sc_Char(s.charAt(i)), res);
+    return res;
+}
+
+function sc_list2jsstring(l) {
+    var a = new Array();
+    while(l !== null) {
+       a.push(l.car.val);
+       l = l.cdr;
+    }
+    return "".concat.apply("", a);
+}
+
+var sc_Vector = Array;
+
+sc_Vector.prototype.sc_toWriteOrDisplayString = function(writeOrDisplay) {
+    if (this.length === 0) return "#()";
+
+    var res = "#(" + writeOrDisplay(this[0]);
+    for (var i = 1; i < this.length; i++)
+       res += " " + writeOrDisplay(this[i]);
+    res += ")";
+    return res;
+};
+sc_Vector.prototype.sc_toDisplayString = function() {
+    return this.sc_toWriteOrDisplayString(sc_toDisplayString);
+};
+sc_Vector.prototype.sc_toWriteString = function() {
+    return this.sc_toWriteOrDisplayString(sc_toWriteString);
+};
+
+/*** META ((export vector? array?)
+           (type bool)
+           (peephole (postfix " instanceof sc_Vector")))
+*/
+function sc_isVector(v) {
+    return (v instanceof sc_Vector);
+}
+
+// only applies to vectors
+function sc_isVectorEqual(v1, v2, comp) {
+    if (v1.length !== v2.length) return false;
+    for (var i = 0; i < v1.length; i++)
+       if (!comp(v1[i], v2[i])) return false;
+    return true;
+}
+
+/*** META ((export make-vector make-array)) */
+function sc_makeVector(size, fill) {
+    var a = new sc_Vector(size);
+    if (fill !== undefined)
+       sc_vectorFillBang(a, fill);
+    return a;
+}
+
+/*** META ((export vector array)
+           (peephole (vector)))
+*/
+function sc_vector() {
+    var a = new sc_Vector();
+    for (var i = 0; i < arguments.length; i++)
+       a.push(arguments[i]);
+    return a;
+}
+
+/*** META ((export vector-length array-length)
+           (peephole (postfix ".length")))
+*/
+function sc_vectorLength(v) {
+    return v.length;
+}
+
+/*** META ((export vector-ref array-ref)
+           (peephole (hole 2 v "[" pos "]")))
+*/
+function sc_vectorRef(v, pos) {
+    return v[pos];
+}
+
+/*** META ((export vector-set! array-set!)
+           (peephole (hole 3 v "[" pos "] = " val)))
+*/
+function sc_vectorSetBang(v, pos, val) {
+    v[pos] = val;
+}
+
+/*** META ((export vector->list array->list)) */
+function sc_vector2list(a) {
+    var res = null;
+    for (var i = a.length-1; i >= 0; i--)
+       res = sc_cons(a[i], res);
+    return res;
+}
+
+/*** META ((export list->vector list->array)) */
+function sc_list2vector(l) {
+    var a = new sc_Vector();
+    while(l !== null) {
+       a.push(l.car);
+       l = l.cdr;
+    }
+    return a;
+}
+
+/*** META ((export vector-fill! array-fill!)) */
+function sc_vectorFillBang(a, fill) {
+    for (var i = 0; i < a.length; i++)
+       a[i] = fill;
+}
+
+
+/*** META ((export #t)) */
+function sc_copyVector(a, len) {
+    if (len <= a.length)
+       return a.slice(0, len);
+    else {
+       var tmp = a.concat();
+       tmp.length = len;
+       return tmp;
+    }
+}
+
+/*** META ((export #t)
+           (peephole (hole 3 a ".slice(" start "," end ")")))
+*/
+function sc_vectorCopy(a, start, end) {
+    return a.slice(start, end);
+}
+
+/*** META ((export #t)) */
+function sc_vectorCopyBang(target, tstart, source, sstart, send) {
+    if (!sstart) sstart = 0;
+    if (!send) send = source.length;
+
+    // if target == source we don't want to overwrite not yet copied elements.
+    if (tstart <= sstart) {
+       for (var i = tstart, j = sstart; j < send; i++, j++) {
+           target[i] = source[j];
+       }
+    } else {
+       var diff = send - sstart;
+       for (var i = tstart + diff - 1, j = send - 1;
+            j >= sstart;
+            i--, j--) {
+           target[i] = source[j];
+       }
+    }
+    return target;
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (hole 1 "typeof " o " === 'function'")))
+*/
+function sc_isProcedure(o) {
+    return (typeof o === "function");
+}
+
+/*** META ((export #t)) */
+function sc_apply(proc) {
+    var args = new Array();
+    // first part of arguments are not in list-form.
+    for (var i = 1; i < arguments.length - 1; i++)
+       args.push(arguments[i]);
+    var l = arguments[arguments.length - 1];
+    while (l !== null) {
+       args.push(l.car);
+       l = l.cdr;
+    }
+    return proc.apply(null, args);
+}
+
+/*** META ((export #t)) */
+function sc_map(proc, l1) {
+    if (l1 === undefined)
+       return null;
+    // else
+    var nbApplyArgs = arguments.length - 1;
+    var applyArgs = new Array(nbApplyArgs);
+    var revres = null;
+    while (l1 !== null) {
+       for (var i = 0; i < nbApplyArgs; i++) {
+           applyArgs[i] = arguments[i + 1].car;
+           arguments[i + 1] = arguments[i + 1].cdr;
+       }
+       revres = sc_cons(proc.apply(null, applyArgs), revres);
+    }
+    return sc_reverseAppendBang(revres, null);
+}
+
+/*** META ((export #t)) */
+function sc_mapBang(proc, l1) {
+    if (l1 === undefined)
+       return null;
+    // else
+    var l1_orig = l1;
+    var nbApplyArgs = arguments.length - 1;
+    var applyArgs = new Array(nbApplyArgs);
+    while (l1 !== null) {
+       var tmp = l1;
+       for (var i = 0; i < nbApplyArgs; i++) {
+           applyArgs[i] = arguments[i + 1].car;
+           arguments[i + 1] = arguments[i + 1].cdr;
+       }
+       tmp.car = proc.apply(null, applyArgs);
+    }
+    return l1_orig;
+}
+     
+/*** META ((export #t)) */
+function sc_forEach(proc, l1) {
+    if (l1 === undefined)
+       return undefined;
+    // else
+    var nbApplyArgs = arguments.length - 1;
+    var applyArgs = new Array(nbApplyArgs);
+    while (l1 !== null) {
+       for (var i = 0; i < nbApplyArgs; i++) {
+           applyArgs[i] = arguments[i + 1].car;
+           arguments[i + 1] = arguments[i + 1].cdr;
+       }
+       proc.apply(null, applyArgs);
+    }
+    // add return so FF does not complain.
+    return undefined;
+}
+
+/*** META ((export #t)) */
+function sc_filter(proc, l1) {
+    var dummy = { cdr : null };
+    var tail = dummy;
+    while (l1 !== null) {
+       if (proc(l1.car) !== false) {
+           tail.cdr = sc_cons(l1.car, null);
+           tail = tail.cdr;
+       }
+       l1 = l1.cdr;
+    }
+    return dummy.cdr;
+}
+
+/*** META ((export #t)) */
+function sc_filterBang(proc, l1) {
+    var head = sc_cons("dummy", l1);
+    var it = head;
+    var next = l1;
+    while (next !== null) {
+        if (proc(next.car) !== false) {
+           it.cdr = next
+           it = next;
+       }
+       next = next.cdr;
+    }
+    it.cdr = null;
+    return head.cdr;
+}
+
+function sc_filterMap1(proc, l1) {
+    var revres = null;
+    while (l1 !== null) {
+        var tmp = proc(l1.car)
+        if (tmp !== false) revres = sc_cons(tmp, revres);
+        l1 = l1.cdr;
+    }
+    return sc_reverseAppendBang(revres, null);
+}
+function sc_filterMap2(proc, l1, l2) {
+    var revres = null;
+    while (l1 !== null) {
+        var tmp = proc(l1.car, l2.car);
+        if(tmp !== false) revres = sc_cons(tmp, revres);
+       l1 = l1.cdr;
+       l2 = l2.cdr
+    }
+    return sc_reverseAppendBang(revres, null);
+}
+
+/*** META ((export #t)) */
+function sc_filterMap(proc, l1, l2, l3) {
+    if (l2 === undefined)
+       return sc_filterMap1(proc, l1);
+    else if (l3 === undefined)
+       return sc_filterMap2(proc, l1, l2);
+    // else
+    var nbApplyArgs = arguments.length - 1;
+    var applyArgs = new Array(nbApplyArgs);
+    var revres = null;
+    while (l1 !== null) {
+       for (var i = 0; i < nbApplyArgs; i++) {
+           applyArgs[i] = arguments[i + 1].car;
+           arguments[i + 1] = arguments[i + 1].cdr;
+       }
+       var tmp = proc.apply(null, applyArgs);
+       if(tmp !== false) revres = sc_cons(tmp, revres);
+    }
+    return sc_reverseAppendBang(revres, null);
+}
+
+/*** META ((export #t)) */
+function sc_any(proc, l) {
+    var revres = null;
+    while (l !== null) {
+        var tmp = proc(l.car);
+        if(tmp !== false) return tmp;
+       l = l.cdr;
+    }
+    return false;
+}
+
+/*** META ((export any?)
+           (peephole (hole 2 "sc_any(" proc "," l ") !== false")))
+*/
+function sc_anyPred(proc, l) {
+    return sc_any(proc, l)!== false;
+}
+
+/*** META ((export #t)) */
+function sc_every(proc, l) {
+    var revres = null;
+    var tmp = true;
+    while (l !== null) {
+        tmp = proc(l.car);
+        if (tmp === false) return false;
+       l = l.cdr;
+    }
+    return tmp;
+}
+
+/*** META ((export every?)
+           (peephole (hole 2 "sc_every(" proc "," l ") !== false")))
+*/
+function sc_everyPred(proc, l) {
+    var tmp = sc_every(proc, l);
+    if (tmp !== false) return true;
+    return false;
+}
+
+/*** META ((export #t)
+           (peephole (postfix "()")))
+*/
+function sc_force(o) {
+    return o();
+}
+
+/*** META ((export #t)) */
+function sc_makePromise(proc) {
+    var isResultReady = false;
+    var result = undefined;
+    return function() {
+       if (!isResultReady) {
+           var tmp = proc();
+           if (!isResultReady) {
+               isResultReady = true;
+               result = tmp;
+           }
+       }
+       return result;
+    };
+}
+
+function sc_Values(values) {
+    this.values = values;
+}
+
+/*** META ((export #t)
+           (peephole (values)))
+*/
+function sc_values() {
+    if (arguments.length === 1)
+       return arguments[0];
+    else
+       return new sc_Values(arguments);
+}
+
+/*** META ((export #t)) */
+function sc_callWithValues(producer, consumer) {
+    var produced = producer();
+    if (produced instanceof sc_Values)
+       return consumer.apply(null, produced.values);
+    else
+       return consumer(produced);
+}
+
+/*** META ((export #t)) */
+function sc_dynamicWind(before, thunk, after) {
+    before();
+    try {
+       var res = thunk();
+       return res;
+    } finally {
+       after();
+    }
+}
+
+
+// TODO: eval/scheme-report-environment/null-environment/interaction-environment
+
+// LIMITATION: 'load' doesn't exist without files.
+// LIMITATION: transcript-on/transcript-off doesn't exist without files.
+
+
+function sc_Struct(name) {
+    this.name = name;
+}
+sc_Struct.prototype.sc_toDisplayString = function() {
+    return "#<struct" + sc_hash(this) + ">";
+};
+sc_Struct.prototype.sc_toWriteString = sc_Struct.prototype.sc_toDisplayString;
+
+/*** META ((export #t)
+           (peephole (hole 1 "new sc_Struct(" name ")")))
+*/
+function sc_makeStruct(name) {
+    return new sc_Struct(name);
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix " instanceof sc_Struct")))
+*/
+function sc_isStruct(o) {
+    return (o instanceof sc_Struct);
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (hole 2 "(" 1 " instanceof sc_Struct) && ( " 1 ".name === " 0 ")")))
+*/
+function sc_isStructNamed(name, s) {
+    return ((s instanceof sc_Struct) && (s.name === name));
+}
+
+/*** META ((export struct-field)
+           (peephole (hole 3 0 "[" 2 "]")))
+*/
+function sc_getStructField(s, name, field) {
+    return s[field];
+}
+
+/*** META ((export struct-field-set!)
+           (peephole (hole 4 0 "[" 2 "] = " 3)))
+*/
+function sc_setStructFieldBang(s, name, field, val) {
+    s[field] = val;
+}
+
+/*** META ((export #t)
+           (peephole (prefix "~")))
+*/
+function sc_bitNot(x) {
+    return ~x;
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 "&")))
+*/
+function sc_bitAnd(x, y) {
+    return x & y;
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 "|")))
+*/
+function sc_bitOr(x, y) {
+    return x | y;
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 "^")))
+*/
+function sc_bitXor(x, y) {
+    return x ^ y;
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 "<<")))
+*/
+function sc_bitLsh(x, y) {
+    return x << y;
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 ">>")))
+*/
+function sc_bitRsh(x, y) {
+    return x >> y;
+}
+
+/*** META ((export #t)
+           (peephole (infix 2 2 ">>>")))
+*/
+function sc_bitUrsh(x, y) {
+    return x >>> y;
+}
+
+/*** META ((export js-field js-property)
+           (peephole (hole 2 o "[" field "]")))
+*/
+function sc_jsField(o, field) {
+    return o[field];
+}
+
+/*** META ((export js-field-set! js-property-set!)
+           (peephole (hole 3 o "[" field "] = " val)))
+*/
+function sc_setJsFieldBang(o, field, val) {
+    return o[field] = val;
+}
+
+/*** META ((export js-field-delete! js-property-delete!)
+           (peephole (hole 2 "delete" o "[" field "]")))
+*/
+function sc_deleteJsFieldBang(o, field) {
+    delete o[field];
+}
+
+/*** META ((export #t)
+           (peephole (jsCall)))
+*/
+function sc_jsCall(o, fun) {
+    var args = new Array();
+    for (var i = 2; i < arguments.length; i++)
+       args[i-2] = arguments[i];
+    return fun.apply(o, args);
+}
+
+/*** META ((export #t)
+           (peephole (jsMethodCall)))
+*/
+function sc_jsMethodCall(o, field) {
+    var args = new Array();
+    for (var i = 2; i < arguments.length; i++)
+       args[i-2] = arguments[i];
+    return o[field].apply(o, args);
+}
+
+/*** META ((export new js-new)
+           (peephole (jsNew)))
+*/
+function sc_jsNew(c) {
+    var evalStr = "new c(";
+    evalStr +=arguments.length > 1? "arguments[1]": "";
+    for (var i = 2; i < arguments.length; i++)
+       evalStr += ", arguments[" + i + "]";
+    evalStr +=")";
+    return eval(evalStr);
+}    
+
+// ======================== RegExp ====================
+/*** META ((export #t)) */
+function sc_pregexp(re) {
+    return new RegExp(sc_string2jsstring(re));
+}
+
+/*** META ((export #t)) */
+function sc_pregexpMatch(re, s) {
+    var reg = (re instanceof RegExp) ? re : sc_pregexp(re);
+    var tmp = reg.exec(sc_string2jsstring(s));
+    
+    if (tmp == null) return false;
+    
+    var res = null;
+    for (var i = tmp.length-1; i >= 0; i--) {
+       if (tmp[i] !== null) {
+           res = sc_cons(sc_jsstring2string(tmp[i]), res);
+       } else {
+           res = sc_cons(false, res);
+       }
+    }
+    return res;
+}
+   
+/*** META ((export #t)) */
+function sc_pregexpReplace(re, s1, s2) {
+   var reg;
+   var jss1 = sc_string2jsstring(s1);
+   var jss2 = sc_string2jsstring(s2);
+
+   if (re instanceof RegExp) {
+       if (re.global)
+          reg = re;
+       else
+          reg = new RegExp(re.source);
+   } else {
+       reg = new RegExp(sc_string2jsstring(re));
+   }
+
+   return jss1.replace(reg, jss2);
+}
+   
+/*** META ((export pregexp-replace*)) */
+function sc_pregexpReplaceAll(re, s1, s2) {
+   var reg;
+   var jss1 = sc_string2jsstring(s1);
+   var jss2 = sc_string2jsstring(s2);
+
+   if (re instanceof RegExp) {
+      if (re.global)
+         reg = re;
+      else
+         reg = new RegExp(re.source, "g");
+   } else {
+       reg = new RegExp(sc_string2jsstring(re), "g");
+   }
+
+   return jss1.replace(reg, jss2);
+}
+
+/*** META ((export #t)) */
+function sc_pregexpSplit(re, s) {
+   var reg = ((re instanceof RegExp) ?
+             re :
+             new RegExp(sc_string2jsstring(re)));
+   var jss = sc_string2jsstring(s);
+   var tmp = jss.split(reg);
+
+   if (tmp == null) return false;
+
+   return sc_vector2list(tmp);
+}
+   
+
+/* =========================================================================== */
+/* Other library stuff */
+/* =========================================================================== */
+
+/*** META ((export #t)
+           (peephole (hole 1 "Math.floor(Math.random()*" 'n ")")))
+*/
+function sc_random(n) {
+    return Math.floor(Math.random()*n);
+}
+
+/*** META ((export current-date)
+           (peephole (hole 0 "new Date()")))
+*/
+function sc_currentDate() {
+   return new Date();
+}
+
+function sc_Hashtable() {
+}
+sc_Hashtable.prototype.toString = function() {
+    return "#{%hashtable}";
+};
+// sc_toWriteString == sc_toDisplayString == toString
+
+function sc_HashtableElement(key, val) {
+    this.key = key;
+    this.val = val;
+}
+
+/*** META ((export #t)
+           (peephole (hole 0 "new sc_Hashtable()")))
+*/
+function sc_makeHashtable() {
+    return new sc_Hashtable();
+}
+
+/*** META ((export #t)) */
+function sc_hashtablePutBang(ht, key, val) {
+    var hash = sc_hash(key);
+    ht[hash] = new sc_HashtableElement(key, val);
+}
+
+/*** META ((export #t)) */
+function sc_hashtableGet(ht, key) {
+    var hash = sc_hash(key);
+    if (hash in ht)
+       return ht[hash].val;
+    else
+       return false;
+}
+
+/*** META ((export #t)) */
+function sc_hashtableForEach(ht, f) {
+    for (var v in ht) {
+       if (ht[v] instanceof sc_HashtableElement)
+           f(ht[v].key, ht[v].val);
+    }
+}
+
+/*** META ((export hashtable-contains?)
+           (peephole (hole 2 "sc_hash(" 1 ") in " 0)))
+*/
+function sc_hashtableContains(ht, key) {
+    var hash = sc_hash(key);
+    if (hash in ht)
+       return true;
+    else
+       return false;
+}
+
+var SC_HASH_COUNTER = 0;
+
+function sc_hash(o) {
+    if (o === null)
+       return "null";
+    else if (o === undefined)
+       return "undefined";
+    else if (o === true)
+       return "true";
+    else if (o === false)
+       return "false";
+    else if (typeof o === "number")
+       return "num-" + o;
+    else if (typeof o === "string")
+       return "jsstr-" + o;
+    else if (o.sc_getHash)
+       return o.sc_getHash();
+    else
+       return sc_counterHash.call(o);
+}
+function sc_counterHash() {
+    if (!this.sc_hash) {
+       this.sc_hash = "hash-" + SC_HASH_COUNTER;
+       SC_HASH_COUNTER++;
+    }
+    return this.sc_hash;
+}
+
+function sc_Trampoline(args, maxTailCalls) {
+    this['__trampoline return__'] = true;
+    this.args = args;
+    this.MAX_TAIL_CALLs = maxTailCalls;
+}
+// TODO: call/cc stuff
+sc_Trampoline.prototype.restart = function() {
+    var o = this;
+    while (true) {
+       // set both globals.
+       SC_TAIL_OBJECT.calls = o.MAX_TAIL_CALLs-1;
+       var fun = o.args.callee;
+       var res = fun.apply(SC_TAIL_OBJECT, o.args);
+       if (res instanceof sc_Trampoline)
+           o = res;
+       else
+           return res;
+    }
+}
+
+/*** META ((export bind-exit-lambda)) */
+function sc_bindExitLambda(proc) {
+    var escape_obj = new sc_BindExitException();
+    var escape = function(res) {
+       escape_obj.res = res;
+       throw escape_obj;
+    };
+    try {
+       return proc(escape);
+    } catch(e) {
+       if (e === escape_obj) {
+           return e.res;
+       }
+       throw e;
+    }
+}
+function sc_BindExitException() {
+    this._internalException = true;
+}
+
+var SC_SCM2JS_GLOBALS = new Object();
+
+// default tail-call depth.
+// normally the program should set it again. but just in case...
+var SC_TAIL_OBJECT = new Object();
+SC_SCM2JS_GLOBALS.TAIL_OBJECT = SC_TAIL_OBJECT;
+// ======================== I/O =======================
+
+/*------------------------------------------------------------------*/
+
+function sc_EOF() {
+}
+var SC_EOF_OBJECT = new sc_EOF();
+
+function sc_Port() {
+}
+
+/* --------------- Input ports -------------------------------------*/
+
+function sc_InputPort() {
+}
+sc_InputPort.prototype = new sc_Port();
+
+sc_InputPort.prototype.peekChar = function() {
+    if (!("peeked" in this))
+       this.peeked = this.getNextChar();
+    return this.peeked;
+}
+sc_InputPort.prototype.readChar = function() {
+    var tmp = this.peekChar();
+    delete this.peeked;
+    return tmp;
+}
+sc_InputPort.prototype.isCharReady = function() {
+    return true;
+}
+sc_InputPort.prototype.close = function() {
+    // do nothing
+}
+
+/* .............. String port ..........................*/
+function sc_ErrorInputPort() {
+};
+sc_ErrorInputPort.prototype = new sc_InputPort();
+sc_ErrorInputPort.prototype.getNextChar = function() {
+    throw "can't read from error-port.";
+};
+sc_ErrorInputPort.prototype.isCharReady = function() {
+    return false;
+};
+    
+
+/* .............. String port ..........................*/
+
+function sc_StringInputPort(jsStr) {
+    // we are going to do some charAts on the str.
+    // instead of recreating all the time a String-object, we
+    // create one in the beginning. (not sure, if this is really an optim)
+    this.str = new String(jsStr);
+    this.pos = 0;
+}
+sc_StringInputPort.prototype = new sc_InputPort();
+sc_StringInputPort.prototype.getNextChar = function() {
+    if (this.pos >= this.str.length)
+       return SC_EOF_OBJECT;
+    return this.str.charAt(this.pos++);
+};
+
+/* ------------- Read and other lib-funs  -------------------------------*/
+function sc_Token(type, val, pos) {
+    this.type = type;
+    this.val = val;
+    this.pos = pos;
+}
+sc_Token.EOF = 0/*EOF*/;
+sc_Token.OPEN_PAR = 1/*OPEN_PAR*/;
+sc_Token.CLOSE_PAR = 2/*CLOSE_PAR*/;
+sc_Token.OPEN_BRACE = 3/*OPEN_BRACE*/;
+sc_Token.CLOSE_BRACE = 4/*CLOSE_BRACE*/;
+sc_Token.OPEN_BRACKET = 5/*OPEN_BRACKET*/;
+sc_Token.CLOSE_BRACKET = 6/*CLOSE_BRACKET*/;
+sc_Token.WHITESPACE = 7/*WHITESPACE*/;
+sc_Token.QUOTE = 8/*QUOTE*/;
+sc_Token.ID = 9/*ID*/;
+sc_Token.DOT = 10/*DOT*/;
+sc_Token.STRING = 11/*STRING*/;
+sc_Token.NUMBER = 12/*NUMBER*/;
+sc_Token.ERROR = 13/*ERROR*/;
+sc_Token.VECTOR_BEGIN = 14/*VECTOR_BEGIN*/;
+sc_Token.TRUE = 15/*TRUE*/;
+sc_Token.FALSE = 16/*FALSE*/;
+sc_Token.UNSPECIFIED = 17/*UNSPECIFIED*/;
+sc_Token.REFERENCE = 18/*REFERENCE*/;
+sc_Token.STORE = 19/*STORE*/;
+sc_Token.CHAR = 20/*CHAR*/;
+
+var SC_ID_CLASS = SC_LOWER_CLASS + SC_UPPER_CLASS + "!$%*+-./:<=>?@^_~";
+function sc_Tokenizer(port) {
+    this.port = port;
+}
+sc_Tokenizer.prototype.peekToken = function() {
+    if (this.peeked)
+       return this.peeked;
+    var newToken = this.nextToken();
+    this.peeked = newToken;
+    return newToken;
+};
+sc_Tokenizer.prototype.readToken = function() {
+    var tmp = this.peekToken();
+    delete this.peeked;
+    return tmp;
+};
+sc_Tokenizer.prototype.nextToken = function() {
+    var port = this.port;
+    
+    function isNumberChar(c) {
+       return (c >= "0" && c <= "9");
+    };
+    function isIdOrNumberChar(c) {
+       return SC_ID_CLASS.indexOf(c) != -1 || // ID-char
+           (c >= "0" && c <= "9");
+    }
+    function isWhitespace(c) {
+       return c === " " || c === "\r" || c === "\n" || c === "\t" || c === "\f";
+    };
+    function isWhitespaceOrEOF(c) {
+       return isWhitespace(c) || c === SC_EOF_OBJECT;
+    };
+
+    function readString() {
+       res = "";
+       while (true) {
+           var c = port.readChar();
+           switch (c) {
+           case '"':
+               return new sc_Token(11/*STRING*/, res);
+           case "\\":
+               var tmp = port.readChar();
+               switch (tmp) {
+               case '0': res += "\0"; break;
+               case 'a': res += "\a"; break;
+               case 'b': res += "\b"; break;
+               case 'f': res += "\f"; break;
+               case 'n': res += "\n"; break;
+               case 'r': res += "\r"; break;
+               case 't': res += "\t"; break;
+               case 'v': res += "\v"; break;
+               case '"': res += '"'; break;
+               case '\\': res += '\\'; break;
+               case 'x':
+                   /* hexa-number */
+                   var nb = 0;
+                   while (true) {
+                       var hexC = port.peekChar();
+                       if (hexC >= '0' && hexC <= '9') {
+                           port.readChar();
+                           nb = nb * 16 + hexC.charCodeAt(0) - '0'.charCodeAt(0);
+                       } else if (hexC >= 'a' && hexC <= 'f') {
+                           port.readChar();
+                           nb = nb * 16 + hexC.charCodeAt(0) - 'a'.charCodeAt(0);
+                       } else if (hexC >= 'A' && hexC <= 'F') {
+                           port.readChar();
+                           nb = nb * 16 + hexC.charCodeAt(0) - 'A'.charCodeAt(0);
+                       } else {
+                           // next char isn't part of hex.
+                           res += String.fromCharCode(nb);
+                           break;
+                       }
+                   }
+                   break;
+               default:
+                   if (tmp === SC_EOF_OBJECT) {
+                       return new sc_Token(13/*ERROR*/, "unclosed string-literal" + res);
+                   }
+                   res += tmp;
+               }
+               break;
+           default:
+               if (c === SC_EOF_OBJECT) {
+                   return new sc_Token(13/*ERROR*/, "unclosed string-literal" + res);
+               }
+               res += c;
+           }
+       }
+    };
+    function readIdOrNumber(firstChar) {
+       var res = firstChar;
+       while (isIdOrNumberChar(port.peekChar()))
+           res += port.readChar();
+       if (isNaN(res))
+           return new sc_Token(9/*ID*/, res);
+       else
+           return new sc_Token(12/*NUMBER*/, res - 0);
+    };
+    
+    function skipWhitespaceAndComments() {
+       var done = false;
+       while (!done) {
+           done = true;
+           while (isWhitespace(port.peekChar()))
+               port.readChar();
+           if (port.peekChar() === ';') {
+               port.readChar();
+               done = false;
+               while (true) {
+                   curChar = port.readChar();
+                   if (curChar === SC_EOF_OBJECT ||
+                       curChar === '\n')
+                       break;
+               }
+           }
+       }
+    };
+    
+    function readDot() {
+       if (isWhitespace(port.peekChar()))
+           return new sc_Token(10/*DOT*/);
+       else
+           return readIdOrNumber(".");
+    };
+
+    function readSharp() {
+       var c = port.readChar();
+       if (isWhitespace(c))
+           return new sc_Token(13/*ERROR*/, "bad #-pattern0.");
+
+       // reference
+       if (isNumberChar(c)) {
+           var nb = c - 0;
+           while (isNumberChar(port.peekChar()))
+               nb = nb*10 + (port.readChar() - 0);
+           switch (port.readChar()) {
+           case '#':
+               return new sc_Token(18/*REFERENCE*/, nb);
+           case '=':
+               return new sc_Token(19/*STORE*/, nb);
+           default:
+               return new sc_Token(13/*ERROR*/, "bad #-pattern1." + nb);
+           }
+       }
+
+       if (c === "(")
+           return new sc_Token(14/*VECTOR_BEGIN*/);
+       
+       if (c === "\\") { // character
+           var tmp = ""
+           while (!isWhitespaceOrEOF(port.peekChar()))
+               tmp += port.readChar();
+           switch (tmp.length) {
+           case 0: // it's escaping a whitespace char:
+               if (sc_isEOFObject(port.peekChar))
+                   return new sc_Token(13/*ERROR*/, "bad #-pattern2.");
+               else
+                   return new sc_Token(20/*CHAR*/, port.readChar());
+           case 1:
+               return new sc_Token(20/*CHAR*/, tmp);
+           default:
+               var entry = sc_Char.readable2char[tmp.toLowerCase()];
+               if (entry)
+                   return new sc_Token(20/*CHAR*/, entry);
+               else
+                   return new sc_Token(13/*ERROR*/, "unknown character description: #\\" + tmp);
+           }
+       }
+
+       // some constants (#t, #f, #unspecified)
+       var res;
+       var needing;
+       switch (c) {
+       case 't': res = new sc_Token(15/*TRUE*/, true); needing = ""; break;
+       case 'f': res = new sc_Token(16/*FALSE*/, false); needing = ""; break;
+       case 'u': res = new sc_Token(17/*UNSPECIFIED*/, undefined); needing = "nspecified"; break;
+       default:
+           return new sc_Token(13/*ERROR*/, "bad #-pattern3: " + c);
+       }
+       while(true) {
+           c = port.peekChar();
+           if ((isWhitespaceOrEOF(c) || c === ')') &&
+               needing == "")
+               return res;
+           else if (isWhitespace(c) || needing == "")
+               return new sc_Token(13/*ERROR*/, "bad #-pattern4 " + c + " " + needing);
+           else if (needing.charAt(0) == c) {
+               port.readChar(); // consume
+               needing = needing.slice(1);
+           } else
+               return new sc_Token(13/*ERROR*/, "bad #-pattern5");
+       }
+       
+    };
+
+    skipWhitespaceAndComments();
+    var curChar = port.readChar();
+    if (curChar === SC_EOF_OBJECT)
+       return new sc_Token(0/*EOF*/, curChar);
+    switch (curChar)
+    {
+    case " ":
+    case "\n":
+    case "\t":
+       return readWhitespace();
+    case "(":
+       return new sc_Token(1/*OPEN_PAR*/);
+    case ")":
+       return new sc_Token(2/*CLOSE_PAR*/);
+    case "{":
+       return new sc_Token(3/*OPEN_BRACE*/);
+    case "}":
+       return new sc_Token(4/*CLOSE_BRACE*/);
+    case "[":
+       return new sc_Token(5/*OPEN_BRACKET*/);
+    case "]":
+       return new sc_Token(6/*CLOSE_BRACKET*/);
+    case "'":
+       return new sc_Token(8/*QUOTE*/);
+    case "#":
+       return readSharp();
+    case ".":
+       return readDot();
+    case '"':
+       return readString();
+    default:
+       if (isIdOrNumberChar(curChar))
+           return readIdOrNumber(curChar);
+       throw "unexpected character: " + curChar;
+    }
+};
+
+function sc_Reader(tokenizer) {
+    this.tokenizer = tokenizer;
+    this.backref = new Array();
+}
+sc_Reader.prototype.read = function() {
+    function readList(listBeginType) {
+       function matchesPeer(open, close) {
+           return open === 1/*OPEN_PAR*/ && close === 2/*CLOSE_PAR*/
+               || open === 3/*OPEN_BRACE*/ && close === 4/*CLOSE_BRACE*/
+               || open === 5/*OPEN_BRACKET*/ && close === 6/*CLOSE_BRACKET*/;
+       };
+       var res = null;
+
+       while (true) {
+           var token = tokenizer.peekToken();
+           
+           switch (token.type) {
+           case 2/*CLOSE_PAR*/:
+           case 4/*CLOSE_BRACE*/:
+           case 6/*CLOSE_BRACKET*/:
+               if (matchesPeer(listBeginType, token.type)) {
+                   tokenizer.readToken(); // consume token
+                   return sc_reverseBang(res);
+               } else
+                   throw "closing par doesn't match: " + listBeginType
+                       + " " + listEndType;
+
+           case 0/*EOF*/:
+               throw "unexpected end of file";
+
+           case 10/*DOT*/:
+               tokenizer.readToken(); // consume token
+               var cdr = this.read();
+               var par = tokenizer.readToken();
+               if (!matchesPeer(listBeginType, par.type))
+                   throw "closing par doesn't match: " + listBeginType
+                       + " " + par.type;
+               else
+                   return sc_reverseAppendBang(res, cdr);
+               
+
+           default:
+               res = sc_cons(this.read(), res);
+           }
+       }
+    };
+    function readQuote() {
+       return sc_cons("quote", sc_cons(this.read(), null));
+    };
+    function readVector() {
+       // opening-parenthesis is already consumed
+       var a = new Array();
+       while (true) {
+           var token = tokenizer.peekToken();
+           switch (token.type) {
+           case 2/*CLOSE_PAR*/:
+               tokenizer.readToken();
+               return a;
+               
+           default:
+               a.push(this.read());
+           }
+       }
+    };
+
+    function storeRefence(nb) {
+       var tmp = this.read();
+       this.backref[nb] = tmp;
+       return tmp;
+    };
+       
+    function readReference(nb) {
+       if (nb in this.backref)
+           return this.backref[nb];
+       else
+           throw "bad reference: " + nb;
+    };
+    
+    var tokenizer = this.tokenizer;
+
+    var token = tokenizer.readToken();
+
+    // handle error
+    if (token.type === 13/*ERROR*/)
+       throw token.val;
+    
+    switch (token.type) {
+    case 1/*OPEN_PAR*/:
+    case 3/*OPEN_BRACE*/:
+    case 5/*OPEN_BRACKET*/:
+       return readList.call(this, token.type);
+    case 8/*QUOTE*/:
+       return readQuote.call(this);
+    case 11/*STRING*/:
+       return sc_jsstring2string(token.val);
+    case 20/*CHAR*/:
+       return new sc_Char(token.val);
+    case 14/*VECTOR_BEGIN*/:
+       return readVector.call(this);
+    case 18/*REFERENCE*/:
+       return readReference.call(this, token.val);
+    case 19/*STORE*/:
+       return storeRefence.call(this, token.val);
+    case 9/*ID*/:
+       return sc_jsstring2symbol(token.val);
+    case 0/*EOF*/:
+    case 12/*NUMBER*/:
+    case 15/*TRUE*/:
+    case 16/*FALSE*/:
+    case 17/*UNSPECIFIED*/:
+       return token.val;
+    default:
+       throw "unexpected token " + token.type + " " + token.val;
+    }
+};
+
+/*** META ((export #t)) */
+function sc_read(port) {
+    if (port === undefined) // we assume the port hasn't been given.
+       port = SC_DEFAULT_IN; // THREAD: shared var...
+    var reader = new sc_Reader(new sc_Tokenizer(port));
+    return reader.read();
+}
+/*** META ((export #t)) */
+function sc_readChar(port) {
+    if (port === undefined) // we assume the port hasn't been given.
+       port = SC_DEFAULT_IN; // THREAD: shared var...
+    var t = port.readChar();
+    return t === SC_EOF_OBJECT? t: new sc_Char(t);
+}
+/*** META ((export #t)) */
+function sc_peekChar(port) {
+    if (port === undefined) // we assume the port hasn't been given.
+       port = SC_DEFAULT_IN; // THREAD: shared var...
+    var t = port.peekChar();
+    return t === SC_EOF_OBJECT? t: new sc_Char(t);
+}    
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isCharReady(port) {
+    if (port === undefined) // we assume the port hasn't been given.
+       port = SC_DEFAULT_IN; // THREAD: shared var...
+    return port.isCharReady();
+}
+/*** META ((export #t)
+           (peephole (postfix ".close()")))
+*/
+function sc_closeInputPort(p) {
+    return p.close();
+}
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix " instanceof sc_InputPort")))
+*/
+function sc_isInputPort(o) {
+    return (o instanceof sc_InputPort);
+}
+
+/*** META ((export eof-object?)
+           (type bool)
+           (peephole (postfix " === SC_EOF_OBJECT")))
+*/
+function sc_isEOFObject(o) {
+    return o === SC_EOF_OBJECT;
+}
+
+/*** META ((export #t)
+           (peephole (hole 0 "SC_DEFAULT_IN")))
+*/
+function sc_currentInputPort() {
+    return SC_DEFAULT_IN;
+}
+
+/* ------------ file operations are not supported -----------*/
+/*** META ((export #t)) */
+function sc_callWithInputFile(s, proc) {
+    throw "can't open " + s;
+}
+
+/*** META ((export #t)) */
+function sc_callWithOutputFile(s, proc) {
+    throw "can't open " + s;
+}
+
+/*** META ((export #t)) */
+function sc_withInputFromFile(s, thunk) {
+    throw "can't open " + s;
+}
+
+/*** META ((export #t)) */
+function sc_withOutputToFile(s, thunk) {
+    throw "can't open " + s;
+}
+
+/*** META ((export #t)) */
+function sc_openInputFile(s) {
+    throw "can't open " + s;
+}
+
+/*** META ((export #t)) */
+function sc_openOutputFile(s) {
+    throw "can't open " + s;
+}
+
+/* ----------------------------------------------------------------------------*/
+/*** META ((export #t)) */
+function sc_basename(p) {
+   var i = p.lastIndexOf('/');
+
+   if(i >= 0)
+      return p.substring(i + 1, p.length);
+   else
+      return '';
+}
+
+/*** META ((export #t)) */
+function sc_dirname(p) {
+   var i = p.lastIndexOf('/');
+
+   if(i >= 0)
+      return p.substring(0, i);
+   else
+      return '';
+}
+
+/* ----------------------------------------------------------------------------*/
+
+/*** META ((export #t)) */
+function sc_withInputFromPort(p, thunk) {
+    try {
+       var tmp = SC_DEFAULT_IN; // THREAD: shared var.
+       SC_DEFAULT_IN = p;
+       return thunk();
+    } finally {
+       SC_DEFAULT_IN = tmp;
+    }
+}
+
+/*** META ((export #t)) */
+function sc_withInputFromString(s, thunk) {
+    return sc_withInputFromPort(new sc_StringInputPort(sc_string2jsstring(s)), thunk);
+}
+
+/*** META ((export #t)) */
+function sc_withOutputToPort(p, thunk) {
+    try {
+       var tmp = SC_DEFAULT_OUT; // THREAD: shared var.
+       SC_DEFAULT_OUT = p;
+       return thunk();
+    } finally {
+       SC_DEFAULT_OUT = tmp;
+    }
+}
+
+/*** META ((export #t)) */
+function sc_withOutputToString(thunk) {
+    var p = new sc_StringOutputPort();
+    sc_withOutputToPort(p, thunk);
+    return p.close();
+}
+
+/*** META ((export #t)) */
+function sc_withOutputToProcedure(proc, thunk) {
+    var t = function(s) { proc(sc_jsstring2string(s)); };
+    return sc_withOutputToPort(new sc_GenericOutputPort(t), thunk);
+}
+
+/*** META ((export #t)
+           (peephole (hole 0 "new sc_StringOutputPort()")))
+*/
+function sc_openOutputString() {
+    return new sc_StringOutputPort();
+}
+
+/*** META ((export #t)) */
+function sc_openInputString(str) {
+    return new sc_StringInputPort(sc_string2jsstring(str));
+}
+
+/* ----------------------------------------------------------------------------*/
+
+function sc_OutputPort() {
+}
+sc_OutputPort.prototype = new sc_Port();
+sc_OutputPort.prototype.appendJSString = function(obj) {
+    /* do nothing */
+}
+sc_OutputPort.prototype.close = function() {
+    /* do nothing */
+}
+
+function sc_StringOutputPort() {
+    this.res = "";
+}
+sc_StringOutputPort.prototype = new sc_OutputPort();
+sc_StringOutputPort.prototype.appendJSString = function(s) {
+    this.res += s;
+}
+sc_StringOutputPort.prototype.close = function() {
+    return sc_jsstring2string(this.res);
+}
+
+/*** META ((export #t)) */
+function sc_getOutputString(sp) {
+    return sc_jsstring2string(sp.res);
+}
+    
+
+function sc_ErrorOutputPort() {
+}
+sc_ErrorOutputPort.prototype = new sc_OutputPort();
+sc_ErrorOutputPort.prototype.appendJSString = function(s) {
+    throw "don't write on ErrorPort!";
+}
+sc_ErrorOutputPort.prototype.close = function() {
+    /* do nothing */
+}
+
+function sc_GenericOutputPort(appendJSString, close) {
+    this.appendJSString = appendJSString;
+    if (close)
+       this.close = close;
+}
+sc_GenericOutputPort.prototype = new sc_OutputPort();
+
+/*** META ((export #t)
+           (type bool)
+           (peephole (postfix " instanceof sc_OutputPort")))
+*/
+function sc_isOutputPort(o) {
+    return (o instanceof sc_OutputPort);
+}
+
+/*** META ((export #t)
+           (peephole (postfix ".close()")))
+*/
+function sc_closeOutputPort(p) {
+    return p.close();
+}
+
+/* ------------------ write ---------------------------------------------------*/
+
+/*** META ((export #t)) */
+function sc_write(o, p) {
+    if (p === undefined) // we assume not given
+       p = SC_DEFAULT_OUT;
+    p.appendJSString(sc_toWriteString(o));
+}
+
+function sc_toWriteString(o) {
+    if (o === null)
+       return "()";
+    else if (o === true)
+       return "#t";
+    else if (o === false)
+       return "#f";
+    else if (o === undefined)
+       return "#unspecified";
+    else if (typeof o === 'function')
+       return "#<procedure " + sc_hash(o) + ">";
+    else if (o.sc_toWriteString)
+       return o.sc_toWriteString();
+    else
+       return o.toString();
+}
+
+function sc_escapeWriteString(s) {
+    var res = "";
+    var j = 0;
+    for (i = 0; i < s.length; i++) {
+       switch (s.charAt(i)) {
+       case "\0": res += s.substring(j, i) + "\\0"; j = i + 1; break;
+       case "\b": res += s.substring(j, i) + "\\b"; j = i + 1; break;
+       case "\f": res += s.substring(j, i) + "\\f"; j = i + 1; break;
+       case "\n": res += s.substring(j, i) + "\\n"; j = i + 1; break;
+       case "\r": res += s.substring(j, i) + "\\r"; j = i + 1; break;
+       case "\t": res += s.substring(j, i) + "\\t"; j = i + 1; break;
+       case "\v": res += s.substring(j, i) + "\\v"; j = i + 1; break;
+       case '"': res += s.substring(j, i) + '\\"'; j = i + 1; break;
+       case "\\": res += s.substring(j, i) + "\\\\"; j = i + 1; break;
+       default:
+           var c = s.charAt(i);
+           if ("\a" !== "a" && c == "\a") {
+               res += s.substring(j, i) + "\\a"; j = i + 1; continue;
+           }
+           if ("\v" !== "v" && c == "\v") {
+               res += s.substring(j, i) + "\\v"; j = i + 1; continue;
+           }
+           //if (s.charAt(i) < ' ' || s.charCodeAt(i) > 127) {
+           // CARE: Manuel is this OK with HOP?
+           if (s.charAt(i) < ' ') {
+               /* non printable character and special chars */
+               res += s.substring(j, i) + "\\x" + s.charCodeAt(i).toString(16);
+               j = i + 1;
+           }
+           // else just let i increase...
+       }
+    }
+    res += s.substring(j, i);
+    return res;
+}
+
+/* ------------------ display ---------------------------------------------------*/
+
+/*** META ((export #t)) */
+function sc_display(o, p) {
+    if (p === undefined) // we assume not given
+       p = SC_DEFAULT_OUT;
+    p.appendJSString(sc_toDisplayString(o));
+}
+
+function sc_toDisplayString(o) {
+    if (o === null)
+       return "()";
+    else if (o === true)
+       return "#t";
+    else if (o === false)
+       return "#f";
+    else if (o === undefined)
+       return "#unspecified";
+    else if (typeof o === 'function')
+       return "#<procedure " + sc_hash(o) + ">";
+    else if (o.sc_toDisplayString)
+       return o.sc_toDisplayString();
+    else
+       return o.toString();
+}
+
+/* ------------------ newline ---------------------------------------------------*/
+
+/*** META ((export #t)) */
+function sc_newline(p) {
+    if (p === undefined) // we assume not given
+       p = SC_DEFAULT_OUT;
+    p.appendJSString("\n");
+}
+    
+/* ------------------ write-char ---------------------------------------------------*/
+
+/*** META ((export #t)) */
+function sc_writeChar(c, p) {
+    if (p === undefined) // we assume not given
+       p = SC_DEFAULT_OUT;
+    p.appendJSString(c.val);
+}
+
+/* ------------------ write-circle ---------------------------------------------------*/
+
+/*** META ((export #t)) */
+function sc_writeCircle(o, p) {
+    if (p === undefined) // we assume not given
+       p = SC_DEFAULT_OUT;
+    p.appendJSString(sc_toWriteCircleString(o));
+}
+
+function sc_toWriteCircleString(o) {
+    var symb = sc_gensym("writeCircle");
+    var nbPointer = new Object();
+    nbPointer.nb = 0;
+    sc_prepWriteCircle(o, symb, nbPointer);
+    return sc_genToWriteCircleString(o, symb);
+}
+
+function sc_prepWriteCircle(o, symb, nbPointer) {
+    // TODO sc_Struct
+    if (o instanceof sc_Pair ||
+       o instanceof sc_Vector) {
+       if (o[symb] !== undefined) {
+           // not the first visit.
+           o[symb]++;
+           // unless there is already a number, assign one.
+           if (!o[symb + "nb"]) o[symb + "nb"] = nbPointer.nb++;
+           return;
+       }
+       o[symb] = 0;
+       if (o instanceof sc_Pair) {
+           sc_prepWriteCircle(o.car, symb, nbPointer);
+           sc_prepWriteCircle(o.cdr, symb, nbPointer);
+       } else {
+           for (var i = 0; i < o.length; i++)
+               sc_prepWriteCircle(o[i], symb, nbPointer);
+       }
+    }
+}
+
+function sc_genToWriteCircleString(o, symb) {
+    if (!(o instanceof sc_Pair ||
+         o instanceof sc_Vector))
+       return sc_toWriteString(o);
+    return o.sc_toWriteCircleString(symb);
+}
+sc_Pair.prototype.sc_toWriteCircleString = function(symb, inList) {
+    if (this[symb + "use"]) { // use-flag is set. Just use it.
+       var nb = this[symb + "nb"];
+       if (this[symb]-- === 0) { // if we are the last use. remove all fields.
+           delete this[symb];
+           delete this[symb + "nb"];
+           delete this[symb + "use"];
+       }
+       if (inList)
+           return '. #' + nb + '#';
+       else
+           return '#' + nb + '#';
+    }
+    if (this[symb]-- === 0) { // if we are the last use. remove all fields.
+       delete this[symb];
+       delete this[symb + "nb"];
+       delete this[symb + "use"];
+    }
+
+    var res = "";
+    
+    if (this[symb] !== undefined) { // implies > 0
+       this[symb + "use"] = true;
+       if (inList)
+           res += '. #' + this[symb + "nb"] + '=';
+       else
+           res += '#' + this[symb + "nb"] + '=';
+       inList = false;
+    }
+
+    if (!inList)
+       res += "(";
+    
+    // print car
+    res += sc_genToWriteCircleString(this.car, symb);
+    
+    if (sc_isPair(this.cdr)) {
+       res += " " + this.cdr.sc_toWriteCircleString(symb, true);
+    } else if (this.cdr !== null) {
+       res += " . " + sc_genToWriteCircleString(this.cdr, symb);
+    }
+    if (!inList)
+       res += ")";
+    return res;
+};
+sc_Vector.prototype.sc_toWriteCircleString = function(symb) {
+    if (this[symb + "use"]) { // use-flag is set. Just use it.
+       var nb = this[symb + "nb"];
+       if (this[symb]-- === 0) { // if we are the last use. remove all fields.
+           delete this[symb];
+           delete this[symb + "nb"];
+           delete this[symb + "use"];
+       }
+       return '#' + nb + '#';
+    }
+    if (this[symb]-- === 0) { // if we are the last use. remove all fields.
+       delete this[symb];
+       delete this[symb + "nb"];
+       delete this[symb + "use"];
+    }
+
+    var res = "";
+    if (this[symb] !== undefined) { // implies > 0
+       this[symb + "use"] = true;
+       res += '#' + this[symb + "nb"] + '=';
+    }
+    res += "#(";
+    for (var i = 0; i < this.length; i++) {
+       res += sc_genToWriteCircleString(this[i], symb);
+       if (i < this.length - 1) res += " ";
+    }
+    res += ")";
+    return res;
+};
+
+
+/* ------------------ print ---------------------------------------------------*/
+
+/*** META ((export #t)) */
+function sc_print(s) {
+    if (arguments.length === 1) {
+       sc_display(s);
+       sc_newline();
+    }
+    else {
+       for (var i = 0; i < arguments.length; i++)
+           sc_display(arguments[i]);
+       sc_newline();
+    }
+}
+
+/* ------------------ format ---------------------------------------------------*/
+/*** META ((export #t)) */
+function sc_format(s, args) {
+   var len = s.length;
+   var p = new sc_StringOutputPort();
+   var i = 0, j = 1;
+
+   while( i < len ) {
+      var i2 = s.indexOf("~", i);
+
+      if (i2 == -1) {
+         p.appendJSString( s.substring( i, len ) );
+         return p.close();
+      } else {
+        if (i2 > i) {
+           if (i2 == (len - 1)) {
+               p.appendJSString(s.substring(i, len));
+               return p.close();
+           } else {
+              p.appendJSString(s.substring(i, i2));
+              i = i2;
+           }
+        }
+
+        switch(s.charCodeAt(i2 + 1)) {
+           case 65:
+           case 97:
+              // a
+              sc_display(arguments[j], p);
+              i += 2; j++;
+              break;
+
+           case 83:
+           case 115:
+              // s
+              sc_write(arguments[j], p);
+              i += 2; j++;
+              break;
+
+           case 86:
+           case 118:
+              // v
+              sc_display(arguments[j], p);
+              p.appendJSString("\n");
+              i += 2; j++;
+              break;
+
+           case 67:
+           case 99:
+              // c
+              p.appendJSString(String.fromCharCode(arguments[j]));
+              i += 2; j++;
+              break;
+
+           case 88:
+           case 120:
+              // x
+              p.appendJSString(arguments[j].toString(6));
+              i += 2; j++;
+              break;
+
+           case 79:
+           case 111:
+              // o
+              p.appendJSString(arguments[j].toString(8));
+              i += 2; j++;
+              break;
+
+           case 66:
+           case 98:
+              // b
+              p.appendJSString(arguments[j].toString(2));
+              i += 2; j++;
+              break;
+              
+           case 37:
+           case 110:
+              // %, n
+              p.appendJSString("\n");
+              i += 2; break;
+
+           case 114:
+              // r
+              p.appendJSString("\r");
+              i += 2; break;
+
+           case 126:
+              // ~
+              p.appendJSString("~");
+              i += 2; break;
+
+           default:
+              sc_error( "format: illegal ~"
+                        + String.fromCharCode(s.charCodeAt(i2 + 1))
+                        + " sequence" );
+              return "";
+        }
+      }
+   }
+
+   return p.close();
+}
+
+/* ------------------ global ports ---------------------------------------------------*/
+
+var SC_DEFAULT_IN = new sc_ErrorInputPort();
+var SC_DEFAULT_OUT = new sc_ErrorOutputPort();
+var SC_ERROR_OUT = new sc_ErrorOutputPort();
+
+var sc_SYMBOL_PREFIX = "\u1E9C";
+var sc_KEYWORD_PREFIX = "\u1E9D";
+
+/*** META ((export #t)
+           (peephole (id))) */
+function sc_jsstring2string(s) {
+    return s;
+}
+
+/*** META ((export #t)
+           (peephole (prefix "'\\u1E9C' +")))
+*/
+function sc_jsstring2symbol(s) {
+    return sc_SYMBOL_PREFIX + s;
+}
+
+/*** META ((export #t)
+           (peephole (id)))
+*/
+function sc_string2jsstring(s) {
+    return s;
+}
+
+/*** META ((export #t)
+           (peephole (symbol2jsstring_immutable)))
+*/
+function sc_symbol2jsstring(s) {
+    return s.slice(1);
+}
+
+/*** META ((export #t)
+           (peephole (postfix ".slice(1)")))
+*/
+function sc_keyword2jsstring(k) {
+    return k.slice(1);
+}
+
+/*** META ((export #t)
+           (peephole (prefix "'\\u1E9D' +")))
+*/
+function sc_jsstring2keyword(s) {
+    return sc_KEYWORD_PREFIX + s;
+}
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isKeyword(s) {
+    return (typeof s === "string") &&
+       (s.charAt(0) === sc_KEYWORD_PREFIX);
+}
+
+
+/*** META ((export #t)) */
+var sc_gensym = function() {
+    var counter = 1000;
+    return function(sym) {
+       counter++;
+       if (!sym) sym = sc_SYMBOL_PREFIX;
+       return sym + "s" + counter + "~" + "^sC-GeNsYm ";
+    };
+}();
+
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isEqual(o1, o2) {
+    return ((o1 === o2) ||
+           (sc_isPair(o1) && sc_isPair(o2)
+            && sc_isPairEqual(o1, o2, sc_isEqual)) ||
+           (sc_isVector(o1) && sc_isVector(o2)
+            && sc_isVectorEqual(o1, o2, sc_isEqual)));
+}
+
+/*** META ((export number->symbol integer->symbol)) */
+function sc_number2symbol(x, radix) {
+    return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix);
+}
+    
+/*** META ((export number->string integer->string)) */
+var sc_number2string = sc_number2jsstring;
+
+/*** META ((export #t)) */
+function sc_symbol2number(s, radix) {
+    return sc_jsstring2number(s.slice(1), radix);
+}
+
+/*** META ((export #t)) */
+var sc_string2number = sc_jsstring2number;
+
+/*** META ((export #t)
+           (peephole (prefix "+" s)))
+           ;; peephole will only apply if no radix is given.
+*/
+function sc_string2integer(s, radix) {
+    if (!radix) return +s;
+    return parseInt(s, radix);
+}
+
+/*** META ((export #t)
+           (peephole (prefix "+")))
+*/
+function sc_string2real(s) {
+    return +s;
+}
+
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isSymbol(s) {
+    return (typeof s === "string") &&
+       (s.charAt(0) === sc_SYMBOL_PREFIX);
+}
+
+/*** META ((export #t)
+           (peephole (symbol2string_immutable)))
+*/
+function sc_symbol2string(s) {
+    return s.slice(1);
+}
+
+/*** META ((export #t)
+           (peephole (prefix "'\\u1E9C' +")))
+*/
+function sc_string2symbol(s) {
+    return sc_SYMBOL_PREFIX + s;
+}
+
+/*** META ((export symbol-append)
+           (peephole (symbolAppend_immutable)))
+*/
+function sc_symbolAppend() {
+    var res = sc_SYMBOL_PREFIX;
+    for (var i = 0; i < arguments.length; i++)
+       res += arguments[i].slice(1);
+    return res;
+}
+
+/*** META ((export #t)
+           (peephole (postfix ".val")))
+*/
+function sc_char2string(c) { return c.val; }
+
+/*** META ((export #t)
+           (peephole (hole 1 "'\\u1E9C' + " c ".val")))
+*/
+function sc_char2symbol(c) { return sc_SYMBOL_PREFIX + c.val; }
+
+/*** META ((export #t)
+           (type bool))
+*/
+function sc_isString(s) {
+    return (typeof s === "string") &&
+       (s.charAt(0) !== sc_SYMBOL_PREFIX);
+}
+
+/*** META ((export #t)) */
+var sc_makeString = sc_makejsString;
+
+
+/*** META ((export #t)) */
+function sc_string() {
+    for (var i = 0; i < arguments.length; i++)
+       arguments[i] = arguments[i].val;
+    return "".concat.apply("", arguments);
+}
+
+/*** META ((export #t)
+           (peephole (postfix ".length")))
+*/
+function sc_stringLength(s) { return s.length; }
+
+/*** META ((export #t)) */
+function sc_stringRef(s, k) {
+    return new sc_Char(s.charAt(k));
+}
+
+/* there's no stringSet in the immutable version
+function sc_stringSet(s, k, c)
+*/
+
+
+/*** META ((export string=?)
+          (type bool)
+           (peephole (hole 2 str1 " === " str2)))
+*/
+function sc_isStringEqual(s1, s2) {
+    return s1 === s2;
+}
+/*** META ((export string<?)
+          (type bool)
+           (peephole (hole 2 str1 " < " str2)))
+*/
+function sc_isStringLess(s1, s2) {
+    return s1 < s2;
+}
+/*** META ((export string>?)
+          (type bool)
+           (peephole (hole 2 str1 " > " str2)))
+*/
+function sc_isStringGreater(s1, s2) {
+    return s1 > s2;
+}
+/*** META ((export string<=?)
+          (type bool)
+           (peephole (hole 2 str1 " <= " str2)))
+*/
+function sc_isStringLessEqual(s1, s2) {
+    return s1 <= s2;
+}
+/*** META ((export string>=?)
+          (type bool)
+           (peephole (hole 2 str1 " >= " str2)))
+*/
+function sc_isStringGreaterEqual(s1, s2) {
+    return s1 >= s2;
+}
+/*** META ((export string-ci=?)
+          (type bool)
+           (peephole (hole 2 str1 ".toLowerCase() === " str2 ".toLowerCase()")))
+*/
+function sc_isStringCIEqual(s1, s2) {
+    return s1.toLowerCase() === s2.toLowerCase();
+}
+/*** META ((export string-ci<?)
+          (type bool)
+           (peephole (hole 2 str1 ".toLowerCase() < " str2 ".toLowerCase()")))
+*/
+function sc_isStringCILess(s1, s2) {
+    return s1.toLowerCase() < s2.toLowerCase();
+}
+/*** META ((export string-ci>?)
+          (type bool)
+           (peephole (hole 2 str1 ".toLowerCase() > " str2 ".toLowerCase()")))
+*/
+function sc_isStringCIGreater(s1, s2) {
+    return s1.toLowerCase() > s2.toLowerCase();
+}
+/*** META ((export string-ci<=?)
+          (type bool)
+           (peephole (hole 2 str1 ".toLowerCase() <= " str2 ".toLowerCase()")))
+*/
+function sc_isStringCILessEqual(s1, s2) {
+    return s1.toLowerCase() <= s2.toLowerCase();
+}
+/*** META ((export string-ci>=?)
+          (type bool)
+           (peephole (hole 2 str1 ".toLowerCase() >= " str2 ".toLowerCase()")))
+*/
+function sc_isStringCIGreaterEqual(s1, s2) {
+    return s1.toLowerCase() >= s2.toLowerCase();
+}
+
+/*** META ((export #t)
+           (peephole (hole 3 s ".substring(" start ", " end ")")))
+*/
+function sc_substring(s, start, end) {
+    return s.substring(start, end);
+}
+
+/*** META ((export #t))
+*/
+function sc_isSubstring_at(s1, s2, i) {
+    return s2 == s1.substring(i, i+ s2.length);
+}
+
+/*** META ((export #t)
+           (peephole (infix 0 #f "+" "''")))
+*/
+function sc_stringAppend() {
+    return "".concat.apply("", arguments);
+}
+
+/*** META ((export #t)) */
+var sc_string2list = sc_jsstring2list;
+
+/*** META ((export #t)) */
+var sc_list2string = sc_list2jsstring;
+
+/*** META ((export #t)
+           (peephole (id)))
+*/
+function sc_stringCopy(s) {
+    return s;
+}
+
+/* there's no string-fill in the immutable version
+function sc_stringFill(s, c)
+*/
+
+/*** META ((export #t)
+           (peephole (postfix ".slice(1)")))
+*/
+function sc_keyword2string(o) {
+    return o.slice(1);
+}
+
+/*** META ((export #t)
+           (peephole (prefix "'\\u1E9D' +")))
+*/
+function sc_string2keyword(o) {
+    return sc_KEYWORD_PREFIX + o;
+}
+
+String.prototype.sc_toDisplayString = function() {
+    if (this.charAt(0) === sc_SYMBOL_PREFIX)
+       // TODO: care for symbols with spaces (escape-chars symbols).
+       return this.slice(1);
+    else if (this.charAt(0) === sc_KEYWORD_PREFIX)
+       return ":" + this.slice(1);
+    else
+       return this.toString();
+};
+
+String.prototype.sc_toWriteString = function() {
+    if (this.charAt(0) === sc_SYMBOL_PREFIX)
+       // TODO: care for symbols with spaces (escape-chars symbols).
+       return this.slice(1);
+    else if (this.charAt(0) === sc_KEYWORD_PREFIX)
+       return ":" + this.slice(1);
+    else
+       return '"' + sc_escapeWriteString(this) + '"';
+};
+/* Exported Variables */
+var BgL_testzd2boyerzd2;
+var BgL_nboyerzd2benchmarkzd2;
+var BgL_setupzd2boyerzd2;
+/* End Exports */
+
+var translate_term_nboyer;
+var translate_args_nboyer;
+var untranslate_term_nboyer;
+var BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer;
+var BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer;
+var translate_alist_nboyer;
+var apply_subst_nboyer;
+var apply_subst_lst_nboyer;
+var tautologyp_nboyer;
+var if_constructor_nboyer;
+var rewrite_count_nboyer;
+var rewrite_nboyer;
+var rewrite_args_nboyer;
+var unify_subst_nboyer;
+var one_way_unify1_nboyer;
+var false_term_nboyer;
+var true_term_nboyer;
+var trans_of_implies1_nboyer;
+var is_term_equal_nboyer;
+var is_term_member_nboyer;
+var const_nboyer;
+var sc_const_3_nboyer;
+var sc_const_4_nboyer;
+{
+    (sc_const_4_nboyer = (new sc_Pair("\u1E9Cimplies",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cu",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cu",(new sc_Pair("\u1E9Cw",null)))))),null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cw",null)))))),null)))))));
+    (sc_const_3_nboyer = sc_list((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccompile",(new sc_Pair("\u1E9Cform",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Ccodegen",(new sc_Pair((new sc_Pair("\u1E9Coptimize",(new sc_Pair("\u1E9Cform",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ceqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreaterp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clesseqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatereqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cboolean",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ciff",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ceven1",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Codd",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccountps-",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cpred",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccountps-loop",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cpred",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfact-",(new sc_Pair("\u1E9Ci",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfact-loop",(new sc_Pair("\u1E9Ci",(new sc_Pair((1),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdivides",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassume-true",(new sc_Pair("\u1E9Cvar",(new sc_Pair("\u1E9Calist",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cvar",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))),(new sc_Pair("\u1E9Calist",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassume-false",(new sc_Pair("\u1E9Cvar",(new sc_Pair("\u1E9Calist",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cvar",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))),(new sc_Pair("\u1E9Calist",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctautology-checker",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ctautologyp",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfalsify",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfalsify1",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cprime",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))),null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cprime1",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cx",null)))),null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair("\u1E9Cp",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))))),(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cb",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cc",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cplus-fringe",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Ca",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cpds",(new sc_Pair("\u1E9Cenvrn",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cpds",(new sc_Pair("\u1E9Cenvrn",null)))))))),(new sc_Pair("\u1E9Cenvrn",null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmc-flatten",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cb",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Cintersect",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ck",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Ck",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ck",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair("\u1E9Ck",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Csort-lp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus1",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair("\u1E9Ci",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cbase",null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ci",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cj",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cj",(new sc_Pair((1),null)))))),null)))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Ci",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus",(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Cbase",null)))))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Ca",null)))),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cw",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Cx",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cz",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cvalue",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cvalue",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnlistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csamefringe",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((1),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((1),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cz",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cw",(new sc_Pair((1),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatereqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((1),null)))))),(new sc_Pair(sc_list("\u1E9Cand", (new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))), (new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))), (new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Ca",null)))), (new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cb",null)))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cl",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair("\u1E9Cl",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdsort",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx1",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx2",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx3",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx4",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx5",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx6",(new sc_Pair("\u1E9Cx7",null)))))),null)))))),null)))))),null)))))),null)))))),null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((6),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cx7",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((2),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((2),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Cy",(new sc_Pair((2),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csigma",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Ci",null)))),null)))))),(new sc_Pair((2),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cz",null)))),null)))))),null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ci",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair("\u1E9Ca",null)))),null)))),(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair("\u1E9Cb",null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),(new sc_Pair("\u1E9Cz",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cassignedp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cb",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair((new sc_Pair("\u1E9Ccdr",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccdr",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cget",(new sc_Pair("\u1E9Cj",(new sc_Pair((new sc_Pair("\u1E9Cset",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cval",(new sc_Pair("\u1E9Cmem",null)))))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Ceqp",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair("\u1E9Cval",(new sc_Pair((new sc_Pair("\u1E9Cget",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Cmem",null)))))),null)))))))),null))))))));
+    (const_nboyer = (new sc_Pair((new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cc",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cd",null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cu",(new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cb",null)))),null)))))),null)))))))),null)))))))))));
+    BgL_nboyerzd2benchmarkzd2 = function() {
+        var args = null;
+        for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) {
+            args = sc_cons(arguments[sc_tmp], args);
+        }
+        var n;
+        return ((n = ((args === null)?(0):(args.car))), (BgL_setupzd2boyerzd2()), (BgL_runzd2benchmarkzd2(("nboyer"+(sc_number2string(n))), (1), function() {
+            return (BgL_testzd2boyerzd2(n));
+        }, function(rewrites) {
+            if ((sc_isNumber(rewrites)))
+                switch (n) {
+                case (0):
+                    return (rewrites===(95024));
+                    break;
+                case (1):
+                    return (rewrites===(591777));
+                    break;
+                case (2):
+                    return (rewrites===(1813975));
+                    break;
+                case (3):
+                    return (rewrites===(5375678));
+                    break;
+                case (4):
+                    return (rewrites===(16445406));
+                    break;
+                case (5):
+                    return (rewrites===(51507739));
+                    break;
+                default:
+                    return true;
+                    break;
+                }
+            else
+                return false;
+        })));
+    };
+    BgL_setupzd2boyerzd2 = function() {
+        return true;
+    };
+    BgL_testzd2boyerzd2 = function() {
+        return true;
+    };
+    translate_term_nboyer = function(term) {
+        var lst;
+        return (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), ((lst = (term.cdr)), ((lst === null)?null:(new sc_Pair((translate_term_nboyer((lst.car))), (translate_args_nboyer((lst.cdr))))))))));
+    };
+    translate_args_nboyer = function(lst) {
+        var sc_lst_5;
+        var term;
+        return ((lst === null)?null:(new sc_Pair(((term = (lst.car)), (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr))))))), ((sc_lst_5 = (lst.cdr)), ((sc_lst_5 === null)?null:(new sc_Pair((translate_term_nboyer((sc_lst_5.car))), (translate_args_nboyer((sc_lst_5.cdr))))))))));
+    };
+    untranslate_term_nboyer = function(term) {
+        var optrOpnd;
+        var tail1131;
+        var L1127;
+        var falseHead1130;
+        var symbol_record;
+        if (!(term instanceof sc_Pair))
+            return term;
+        else
+            {
+                (falseHead1130 = (new sc_Pair(null, null)));
+                (L1127 = (term.cdr));
+                (tail1131 = falseHead1130);
+                while (!(L1127 === null)) {
+                    {
+                        (tail1131.cdr = (new sc_Pair((untranslate_term_nboyer((L1127.car))), null)));
+                        (tail1131 = (tail1131.cdr));
+                        (L1127 = (L1127.cdr));
+                    }
+                }
+                (optrOpnd = (falseHead1130.cdr));
+                return (new sc_Pair(((symbol_record = (term.car)), (symbol_record[(0)])), optrOpnd));
+            }
+    };
+    BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer = function(sym) {
+        var r;
+        var x;
+        return ((x = (sc_assq(sym, BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer))), ((x!== false)?(x.cdr):((r = [sym, null]), (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = (new sc_Pair((new sc_Pair(sym, r)), BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer))), r)));
+    };
+    (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null);
+    translate_alist_nboyer = function(alist) {
+        var sc_alist_6;
+        var term;
+        return ((alist === null)?null:(new sc_Pair((new sc_Pair((alist.car.car), ((term = (alist.car.cdr)), (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr))))))))), ((sc_alist_6 = (alist.cdr)), ((sc_alist_6 === null)?null:(new sc_Pair((new sc_Pair((sc_alist_6.car.car), (translate_term_nboyer((sc_alist_6.car.cdr))))), (translate_alist_nboyer((sc_alist_6.cdr))))))))));
+    };
+    apply_subst_nboyer = function(alist, term) {
+        var lst;
+        var temp_temp;
+        return (!(term instanceof sc_Pair)?((temp_temp = (sc_assq(term, alist))), ((temp_temp!== false)?(temp_temp.cdr):term)):(new sc_Pair((term.car), ((lst = (term.cdr)), ((lst === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (lst.car))), (apply_subst_lst_nboyer(alist, (lst.cdr))))))))));
+    };
+    apply_subst_lst_nboyer = function(alist, lst) {
+        var sc_lst_7;
+        return ((lst === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (lst.car))), ((sc_lst_7 = (lst.cdr)), ((sc_lst_7 === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (sc_lst_7.car))), (apply_subst_lst_nboyer(alist, (sc_lst_7.cdr))))))))));
+    };
+    tautologyp_nboyer = function(sc_x_11, true_lst, false_lst) {
+        var tmp1125;
+        var x;
+        var tmp1126;
+        var sc_x_8;
+        var sc_tmp1125_9;
+        var sc_tmp1126_10;
+        var sc_x_11;
+        var true_lst;
+        var false_lst;
+        while (true) {
+            if ((((sc_tmp1126_10 = (is_term_equal_nboyer(sc_x_11, true_term_nboyer))), ((sc_tmp1126_10!== false)?sc_tmp1126_10:(is_term_member_nboyer(sc_x_11, true_lst))))!== false))
+                return true;
+            else
+                if ((((sc_tmp1125_9 = (is_term_equal_nboyer(sc_x_11, false_term_nboyer))), ((sc_tmp1125_9!== false)?sc_tmp1125_9:(is_term_member_nboyer(sc_x_11, false_lst))))!== false))
+                    return false;
+                else
+                    if (!(sc_x_11 instanceof sc_Pair))
+                        return false;
+                    else
+                        if (((sc_x_11.car)===if_constructor_nboyer))
+                            if ((((sc_x_8 = (sc_x_11.cdr.car)), (tmp1126 = (is_term_equal_nboyer(sc_x_8, true_term_nboyer))), ((tmp1126!== false)?tmp1126:(is_term_member_nboyer(sc_x_8, true_lst))))!== false))
+                                (sc_x_11 = (sc_x_11.cdr.cdr.car));
+                            else
+                                if ((((x = (sc_x_11.cdr.car)), (tmp1125 = (is_term_equal_nboyer(x, false_term_nboyer))), ((tmp1125!== false)?tmp1125:(is_term_member_nboyer(x, false_lst))))!== false))
+                                    (sc_x_11 = (sc_x_11.cdr.cdr.cdr.car));
+                                else
+                                    if (((tautologyp_nboyer((sc_x_11.cdr.cdr.car), (new sc_Pair((sc_x_11.cdr.car), true_lst)), false_lst))!== false))
+                                        {
+                                            (false_lst = (new sc_Pair((sc_x_11.cdr.car), false_lst)));
+                                            (sc_x_11 = (sc_x_11.cdr.cdr.cdr.car));
+                                        }
+                                    else
+                                        return false;
+                        else
+                            return false;
+        }
+    };
+    (if_constructor_nboyer = "\u1E9C*");
+    (rewrite_count_nboyer = (0));
+    rewrite_nboyer = function(term) {
+        var term2;
+        var sc_term_12;
+        var lst;
+        var symbol_record;
+        var sc_lst_13;
+        {
+            (++rewrite_count_nboyer);
+            if (!(term instanceof sc_Pair))
+                return term;
+            else
+                {
+                    (sc_term_12 = (new sc_Pair((term.car), ((sc_lst_13 = (term.cdr)), ((sc_lst_13 === null)?null:(new sc_Pair((rewrite_nboyer((sc_lst_13.car))), (rewrite_args_nboyer((sc_lst_13.cdr))))))))));
+                    (lst = ((symbol_record = (term.car)), (symbol_record[(1)])));
+                    while (true) {
+                        if ((lst === null))
+                            return sc_term_12;
+                        else
+                            if ((((term2 = ((lst.car).cdr.car)), (unify_subst_nboyer = null), (one_way_unify1_nboyer(sc_term_12, term2)))!== false))
+                                return (rewrite_nboyer((apply_subst_nboyer(unify_subst_nboyer, ((lst.car).cdr.cdr.car)))));
+                            else
+                                (lst = (lst.cdr));
+                    }
+                }
+        }
+    };
+    rewrite_args_nboyer = function(lst) {
+        var sc_lst_14;
+        return ((lst === null)?null:(new sc_Pair((rewrite_nboyer((lst.car))), ((sc_lst_14 = (lst.cdr)), ((sc_lst_14 === null)?null:(new sc_Pair((rewrite_nboyer((sc_lst_14.car))), (rewrite_args_nboyer((sc_lst_14.cdr))))))))));
+    };
+    (unify_subst_nboyer = "\u1E9C*");
+    one_way_unify1_nboyer = function(term1, term2) {
+        var lst1;
+        var lst2;
+        var temp_temp;
+        if (!(term2 instanceof sc_Pair))
+            {
+                (temp_temp = (sc_assq(term2, unify_subst_nboyer)));
+                if ((temp_temp!== false))
+                    return (is_term_equal_nboyer(term1, (temp_temp.cdr)));
+                else
+                    if ((sc_isNumber(term2)))
+                        return (sc_isEqual(term1, term2));
+                    else
+                        {
+                            (unify_subst_nboyer = (new sc_Pair((new sc_Pair(term2, term1)), unify_subst_nboyer)));
+                            return true;
+                        }
+            }
+        else
+            if (!(term1 instanceof sc_Pair))
+                return false;
+            else
+                if (((term1.car)===(term2.car)))
+                    {
+                        (lst1 = (term1.cdr));
+                        (lst2 = (term2.cdr));
+                        while (true) {
+                            if ((lst1 === null))
+                                return (lst2 === null);
+                            else
+                                if ((lst2 === null))
+                                    return false;
+                                else
+                                    if (((one_way_unify1_nboyer((lst1.car), (lst2.car)))!== false))
+                                        {
+                                            (lst1 = (lst1.cdr));
+                                            (lst2 = (lst2.cdr));
+                                        }
+                                    else
+                                        return false;
+                        }
+                    }
+                else
+                    return false;
+    };
+    (false_term_nboyer = "\u1E9C*");
+    (true_term_nboyer = "\u1E9C*");
+    trans_of_implies1_nboyer = function(n) {
+        var sc_n_15;
+        return ((sc_isEqual(n, (1)))?(sc_list("\u1E9Cimplies", (0), (1))):(sc_list("\u1E9Cand", (sc_list("\u1E9Cimplies", (n-(1)), n)), ((sc_n_15 = (n-(1))), ((sc_isEqual(sc_n_15, (1)))?(sc_list("\u1E9Cimplies", (0), (1))):(sc_list("\u1E9Cand", (sc_list("\u1E9Cimplies", (sc_n_15-(1)), sc_n_15)), (trans_of_implies1_nboyer((sc_n_15-(1)))))))))));
+    };
+    is_term_equal_nboyer = function(x, y) {
+        var lst1;
+        var lst2;
+        var r2;
+        var r1;
+        if ((x instanceof sc_Pair))
+            if ((y instanceof sc_Pair))
+                if ((((r1 = (x.car)), (r2 = (y.car)), (r1===r2))!== false))
+                    {
+                        (lst1 = (x.cdr));
+                        (lst2 = (y.cdr));
+                        while (true) {
+                            if ((lst1 === null))
+                                return (lst2 === null);
+                            else
+                                if ((lst2 === null))
+                                    return false;
+                                else
+                                    if (((is_term_equal_nboyer((lst1.car), (lst2.car)))!== false))
+                                        {
+                                            (lst1 = (lst1.cdr));
+                                            (lst2 = (lst2.cdr));
+                                        }
+                                    else
+                                        return false;
+                        }
+                    }
+                else
+                    return false;
+            else
+                return false;
+        else
+            return (sc_isEqual(x, y));
+    };
+    is_term_member_nboyer = function(x, lst) {
+        var x;
+        var lst;
+        while (true) {
+            if ((lst === null))
+                return false;
+            else
+                if (((is_term_equal_nboyer(x, (lst.car)))!== false))
+                    return true;
+                else
+                    (lst = (lst.cdr));
+        }
+    };
+    BgL_setupzd2boyerzd2 = function() {
+        var symbol_record;
+        var value;
+        var BgL_sc_symbolzd2record_16zd2;
+        var sym;
+        var sc_sym_17;
+        var term;
+        var lst;
+        var sc_term_18;
+        var sc_term_19;
+        {
+            (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null);
+            (if_constructor_nboyer = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer("\u1E9Cif")));
+            (false_term_nboyer = ((sc_term_19 = (new sc_Pair("\u1E9Cf",null))), (!(sc_term_19 instanceof sc_Pair)?sc_term_19:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_19.car))), (translate_args_nboyer((sc_term_19.cdr))))))));
+            (true_term_nboyer = ((sc_term_18 = (new sc_Pair("\u1E9Ct",null))), (!(sc_term_18 instanceof sc_Pair)?sc_term_18:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_18.car))), (translate_args_nboyer((sc_term_18.cdr))))))));
+            (lst = sc_const_3_nboyer);
+            while (!(lst === null)) {
+                {
+                    (term = (lst.car));
+                    if (((term instanceof sc_Pair)&&(((term.car)==="\u1E9Cequal")&&((term.cdr.car) instanceof sc_Pair))))
+                        {
+                            (sc_sym_17 = ((term.cdr.car).car));
+                            (value = (new sc_Pair((!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr)))))), ((sym = ((term.cdr.car).car)), (BgL_sc_symbolzd2record_16zd2 = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sym))), (BgL_sc_symbolzd2record_16zd2[(1)])))));
+                            (symbol_record = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sc_sym_17)));
+                            (symbol_record[(1)] = value);
+                        }
+                    else
+                        (sc_error("ADD-LEMMA did not like term:  ", term));
+                    (lst = (lst.cdr));
+                }
+            }
+            return true;
+        }
+    };
+    BgL_testzd2boyerzd2 = function(n) {
+        var optrOpnd;
+        var term;
+        var sc_n_20;
+        var answer;
+        var sc_term_21;
+        var sc_term_22;
+        {
+            (rewrite_count_nboyer = (0));
+            (term = sc_const_4_nboyer);
+            (sc_n_20 = n);
+            while (!(sc_n_20=== 0)) {
+                {
+                    (term = (sc_list("\u1E9Cor", term, (new sc_Pair("\u1E9Cf",null)))));
+                    (--sc_n_20);
+                }
+            }
+            (sc_term_22 = term);
+            if (!(sc_term_22 instanceof sc_Pair))
+                (optrOpnd = sc_term_22);
+            else
+                (optrOpnd = (new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_22.car))), (translate_args_nboyer((sc_term_22.cdr))))));
+            (sc_term_21 = (apply_subst_nboyer(((const_nboyer === null)?null:(new sc_Pair((new sc_Pair((const_nboyer.car.car), (translate_term_nboyer((const_nboyer.car.cdr))))), (translate_alist_nboyer((const_nboyer.cdr)))))), optrOpnd)));
+            (answer = (tautologyp_nboyer((rewrite_nboyer(sc_term_21)), null, null)));
+            (sc_write(rewrite_count_nboyer));
+            (sc_display(" rewrites"));
+            (sc_newline());
+            if ((answer!== false))
+                return rewrite_count_nboyer;
+            else
+                return false;
+        }
+    };
+}
+/* Exported Variables */
+var BgL_parsezd2ze3nbzd2treesze3;
+var BgL_earleyzd2benchmarkzd2;
+var BgL_parsezd2ze3parsedzf3zc2;
+var test;
+var BgL_parsezd2ze3treesz31;
+var BgL_makezd2parserzd2;
+/* End Exports */
+
+var const_earley;
+{
+    (const_earley = (new sc_Pair((new sc_Pair("\u1E9Cs",(new sc_Pair((new sc_Pair("\u1E9Ca",null)),(new sc_Pair((new sc_Pair("\u1E9Cs",(new sc_Pair("\u1E9Cs",null)))),null)))))),null)));
+    BgL_makezd2parserzd2 = function(grammar, lexer) {
+        var i;
+        var parser_descr;
+        var def_loop;
+        var nb_nts;
+        var names;
+        var steps;
+        var predictors;
+        var enders;
+        var starters;
+        var nts;
+        var sc_names_1;
+        var sc_steps_2;
+        var sc_predictors_3;
+        var sc_enders_4;
+        var sc_starters_5;
+        var nb_confs;
+        var BgL_sc_defzd2loop_6zd2;
+        var BgL_sc_nbzd2nts_7zd2;
+        var sc_nts_8;
+        var BgL_sc_defzd2loop_9zd2;
+        var ind;
+        {
+            ind = function(nt, sc_nts_10) {
+                var i;
+                {
+                    (i = ((sc_nts_10.length)-(1)));
+                    while (true) {
+                        if ((i>=(0)))
+                            if ((sc_isEqual((sc_nts_10[i]), nt)))
+                                return i;
+                            else
+                                (--i);
+                        else
+                            return false;
+                    }
+                }
+            };
+            (sc_nts_8 = ((BgL_sc_defzd2loop_9zd2 = function(defs, sc_nts_11) {
+                var rule_loop;
+                var head;
+                var def;
+                return ((defs instanceof sc_Pair)?((def = (defs.car)), (head = (def.car)), (rule_loop = function(rules, sc_nts_12) {
+                    var nt;
+                    var l;
+                    var sc_nts_13;
+                    var rule;
+                    if ((rules instanceof sc_Pair))
+                        {
+                            (rule = (rules.car));
+                            (l = rule);
+                            (sc_nts_13 = sc_nts_12);
+                            while ((l instanceof sc_Pair)) {
+                                {
+                                    (nt = (l.car));
+                                    (l = (l.cdr));
+                                    (sc_nts_13 = (((sc_member(nt, sc_nts_13))!== false)?sc_nts_13:(new sc_Pair(nt, sc_nts_13))));
+                                }
+                            }
+                            return (rule_loop((rules.cdr), sc_nts_13));
+                        }
+                    else
+                        return (BgL_sc_defzd2loop_9zd2((defs.cdr), sc_nts_12));
+                }), (rule_loop((def.cdr), (((sc_member(head, sc_nts_11))!== false)?sc_nts_11:(new sc_Pair(head, sc_nts_11)))))):(sc_list2vector((sc_reverse(sc_nts_11)))));
+            }), (BgL_sc_defzd2loop_9zd2(grammar, null))));
+            (BgL_sc_nbzd2nts_7zd2 = (sc_nts_8.length));
+            (nb_confs = (((BgL_sc_defzd2loop_6zd2 = function(defs, BgL_sc_nbzd2confs_14zd2) {
+                var rule_loop;
+                var def;
+                return ((defs instanceof sc_Pair)?((def = (defs.car)), (rule_loop = function(rules, BgL_sc_nbzd2confs_15zd2) {
+                    var l;
+                    var BgL_sc_nbzd2confs_16zd2;
+                    var rule;
+                    if ((rules instanceof sc_Pair))
+                        {
+                            (rule = (rules.car));
+                            (l = rule);
+                            (BgL_sc_nbzd2confs_16zd2 = BgL_sc_nbzd2confs_15zd2);
+                            while ((l instanceof sc_Pair)) {
+                                {
+                                    (l = (l.cdr));
+                                    (++BgL_sc_nbzd2confs_16zd2);
+                                }
+                            }
+                            return (rule_loop((rules.cdr), (BgL_sc_nbzd2confs_16zd2+(1))));
+                        }
+                    else
+                        return (BgL_sc_defzd2loop_6zd2((defs.cdr), BgL_sc_nbzd2confs_15zd2));
+                }), (rule_loop((def.cdr), BgL_sc_nbzd2confs_14zd2))):BgL_sc_nbzd2confs_14zd2);
+            }), (BgL_sc_defzd2loop_6zd2(grammar, (0))))+BgL_sc_nbzd2nts_7zd2));
+            (sc_starters_5 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null)));
+            (sc_enders_4 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null)));
+            (sc_predictors_3 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null)));
+            (sc_steps_2 = (sc_makeVector(nb_confs, false)));
+            (sc_names_1 = (sc_makeVector(nb_confs, false)));
+            (nts = sc_nts_8);
+            (starters = sc_starters_5);
+            (enders = sc_enders_4);
+            (predictors = sc_predictors_3);
+            (steps = sc_steps_2);
+            (names = sc_names_1);
+            (nb_nts = (sc_nts_8.length));
+            (i = (nb_nts-(1)));
+            while ((i>=(0))) {
+                {
+                    (sc_steps_2[i] = (i-nb_nts));
+                    (sc_names_1[i] = (sc_list((sc_nts_8[i]), (0))));
+                    (sc_enders_4[i] = (sc_list(i)));
+                    (--i);
+                }
+            }
+            def_loop = function(defs, conf) {
+                var rule_loop;
+                var head;
+                var def;
+                return ((defs instanceof sc_Pair)?((def = (defs.car)), (head = (def.car)), (rule_loop = function(rules, conf, rule_num) {
+                    var i;
+                    var sc_i_17;
+                    var nt;
+                    var l;
+                    var sc_conf_18;
+                    var sc_i_19;
+                    var rule;
+                    if ((rules instanceof sc_Pair))
+                        {
+                            (rule = (rules.car));
+                            (names[conf] = (sc_list(head, rule_num)));
+                            (sc_i_19 = (ind(head, nts)));
+                            (starters[sc_i_19] = (new sc_Pair(conf, (starters[sc_i_19]))));
+                            (l = rule);
+                            (sc_conf_18 = conf);
+                            while ((l instanceof sc_Pair)) {
+                                {
+                                    (nt = (l.car));
+                                    (steps[sc_conf_18] = (ind(nt, nts)));
+                                    (sc_i_17 = (ind(nt, nts)));
+                                    (predictors[sc_i_17] = (new sc_Pair(sc_conf_18, (predictors[sc_i_17]))));
+                                    (l = (l.cdr));
+                                    (++sc_conf_18);
+                                }
+                            }
+                            (steps[sc_conf_18] = ((ind(head, nts))-nb_nts));
+                            (i = (ind(head, nts)));
+                            (enders[i] = (new sc_Pair(sc_conf_18, (enders[i]))));
+                            return (rule_loop((rules.cdr), (sc_conf_18+(1)), (rule_num+(1))));
+                        }
+                    else
+                        return (def_loop((defs.cdr), conf));
+                }), (rule_loop((def.cdr), conf, (1)))):undefined);
+            };
+            (def_loop(grammar, (sc_nts_8.length)));
+            (parser_descr = [lexer, sc_nts_8, sc_starters_5, sc_enders_4, sc_predictors_3, sc_steps_2, sc_names_1]);
+            return function(input) {
+                var optrOpnd;
+                var sc_optrOpnd_20;
+                var sc_optrOpnd_21;
+                var sc_optrOpnd_22;
+                var loop1;
+                var BgL_sc_stateza2_23za2;
+                var toks;
+                var BgL_sc_nbzd2nts_24zd2;
+                var sc_steps_25;
+                var sc_enders_26;
+                var state_num;
+                var BgL_sc_statesza2_27za2;
+                var states;
+                var i;
+                var conf;
+                var l;
+                var tok_nts;
+                var sc_i_28;
+                var sc_i_29;
+                var l1;
+                var l2;
+                var tok;
+                var tail1129;
+                var L1125;
+                var goal_enders;
+                var BgL_sc_statesza2_30za2;
+                var BgL_sc_nbzd2nts_31zd2;
+                var BgL_sc_nbzd2confs_32zd2;
+                var nb_toks;
+                var goal_starters;
+                var sc_states_33;
+                var BgL_sc_nbzd2confs_34zd2;
+                var BgL_sc_nbzd2toks_35zd2;
+                var sc_toks_36;
+                var falseHead1128;
+                var sc_names_37;
+                var sc_steps_38;
+                var sc_predictors_39;
+                var sc_enders_40;
+                var sc_starters_41;
+                var sc_nts_42;
+                var lexer;
+                var sc_ind_43;
+                var make_states;
+                var BgL_sc_confzd2setzd2getza2_44za2;
+                var conf_set_merge_new_bang;
+                var conf_set_adjoin;
+                var BgL_sc_confzd2setzd2adjoinza2_45za2;
+                var BgL_sc_confzd2setzd2adjoinza2za2_46z00;
+                var conf_set_union;
+                var forw;
+                var is_parsed;
+                var deriv_trees;
+                var BgL_sc_derivzd2treesza2_47z70;
+                var nb_deriv_trees;
+                var BgL_sc_nbzd2derivzd2treesza2_48za2;
+                {
+                    sc_ind_43 = function(nt, sc_nts_49) {
+                        var i;
+                        {
+                            (i = ((sc_nts_49.length)-(1)));
+                            while (true) {
+                                if ((i>=(0)))
+                                    if ((sc_isEqual((sc_nts_49[i]), nt)))
+                                        return i;
+                                    else
+                                        (--i);
+                                else
+                                    return false;
+                            }
+                        }
+                    };
+                    make_states = function(BgL_sc_nbzd2toks_50zd2, BgL_sc_nbzd2confs_51zd2) {
+                        var v;
+                        var i;
+                        var sc_states_52;
+                        {
+                            (sc_states_52 = (sc_makeVector((BgL_sc_nbzd2toks_50zd2+(1)), false)));
+                            (i = BgL_sc_nbzd2toks_50zd2);
+                            while ((i>=(0))) {
+                                {
+                                    (v = (sc_makeVector((BgL_sc_nbzd2confs_51zd2+(1)), false)));
+                                    (v[(0)] = (-1));
+                                    (sc_states_52[i] = v);
+                                    (--i);
+                                }
+                            }
+                            return sc_states_52;
+                        }
+                    };
+                    BgL_sc_confzd2setzd2getza2_44za2 = function(state, BgL_sc_statezd2num_53zd2, sc_conf_54) {
+                        var conf_set;
+                        var BgL_sc_confzd2set_55zd2;
+                        return ((BgL_sc_confzd2set_55zd2 = (state[(sc_conf_54+(1))])), ((BgL_sc_confzd2set_55zd2!== false)?BgL_sc_confzd2set_55zd2:((conf_set = (sc_makeVector((BgL_sc_statezd2num_53zd2+(6)), false))), (conf_set[(1)] = (-3)), (conf_set[(2)] = (-1)), (conf_set[(3)] = (-1)), (conf_set[(4)] = (-1)), (state[(sc_conf_54+(1))] = conf_set), conf_set)));
+                    };
+                    conf_set_merge_new_bang = function(conf_set) {
+                        return ((conf_set[((conf_set[(1)])+(5))] = (conf_set[(4)])), (conf_set[(1)] = (conf_set[(3)])), (conf_set[(3)] = (-1)), (conf_set[(4)] = (-1)));
+                    };
+                    conf_set_adjoin = function(state, conf_set, sc_conf_56, i) {
+                        var tail;
+                        return ((tail = (conf_set[(3)])), (conf_set[(i+(5))] = (-1)), (conf_set[(tail+(5))] = i), (conf_set[(3)] = i), ((tail<(0))?((conf_set[(0)] = (state[(0)])), (state[(0)] = sc_conf_56)):undefined));
+                    };
+                    BgL_sc_confzd2setzd2adjoinza2_45za2 = function(sc_states_57, BgL_sc_statezd2num_58zd2, l, i) {
+                        var conf_set;
+                        var sc_conf_59;
+                        var l1;
+                        var state;
+                        {
+                            (state = (sc_states_57[BgL_sc_statezd2num_58zd2]));
+                            (l1 = l);
+                            while ((l1 instanceof sc_Pair)) {
+                                {
+                                    (sc_conf_59 = (l1.car));
+                                    (conf_set = (BgL_sc_confzd2setzd2getza2_44za2(state, BgL_sc_statezd2num_58zd2, sc_conf_59)));
+                                    if (((conf_set[(i+(5))])=== false))
+                                        {
+                                            (conf_set_adjoin(state, conf_set, sc_conf_59, i));
+                                            (l1 = (l1.cdr));
+                                        }
+                                    else
+                                        (l1 = (l1.cdr));
+                                }
+                            }
+                            return undefined;
+                        }
+                    };
+                    BgL_sc_confzd2setzd2adjoinza2za2_46z00 = function(sc_states_60, BgL_sc_statesza2_61za2, BgL_sc_statezd2num_62zd2, sc_conf_63, i) {
+                        var BgL_sc_confzd2setza2_64z70;
+                        var BgL_sc_stateza2_65za2;
+                        var conf_set;
+                        var state;
+                        return ((state = (sc_states_60[BgL_sc_statezd2num_62zd2])), ((((conf_set = (state[(sc_conf_63+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)?((BgL_sc_stateza2_65za2 = (BgL_sc_statesza2_61za2[BgL_sc_statezd2num_62zd2])), (BgL_sc_confzd2setza2_64z70 = (BgL_sc_confzd2setzd2getza2_44za2(BgL_sc_stateza2_65za2, BgL_sc_statezd2num_62zd2, sc_conf_63))), (((BgL_sc_confzd2setza2_64z70[(i+(5))])=== false)?(conf_set_adjoin(BgL_sc_stateza2_65za2, BgL_sc_confzd2setza2_64z70, sc_conf_63, i)):undefined), true):false));
+                    };
+                    conf_set_union = function(state, conf_set, sc_conf_66, other_set) {
+                        var i;
+                        {
+                            (i = (other_set[(2)]));
+                            while ((i>=(0))) {
+                                if (((conf_set[(i+(5))])=== false))
+                                    {
+                                        (conf_set_adjoin(state, conf_set, sc_conf_66, i));
+                                        (i = (other_set[(i+(5))]));
+                                    }
+                                else
+                                    (i = (other_set[(i+(5))]));
+                            }
+                            return undefined;
+                        }
+                    };
+                    forw = function(sc_states_67, BgL_sc_statezd2num_68zd2, sc_starters_69, sc_enders_70, sc_predictors_71, sc_steps_72, sc_nts_73) {
+                        var next_set;
+                        var next;
+                        var conf_set;
+                        var ender;
+                        var l;
+                        var starter_set;
+                        var starter;
+                        var sc_l_74;
+                        var sc_loop1_75;
+                        var head;
+                        var BgL_sc_confzd2set_76zd2;
+                        var BgL_sc_statezd2num_77zd2;
+                        var state;
+                        var sc_states_78;
+                        var preds;
+                        var BgL_sc_confzd2set_79zd2;
+                        var step;
+                        var sc_conf_80;
+                        var BgL_sc_nbzd2nts_81zd2;
+                        var sc_state_82;
+                        {
+                            (sc_state_82 = (sc_states_67[BgL_sc_statezd2num_68zd2]));
+                            (BgL_sc_nbzd2nts_81zd2 = (sc_nts_73.length));
+                            while (true) {
+                                {
+                                    (sc_conf_80 = (sc_state_82[(0)]));
+                                    if ((sc_conf_80>=(0)))
+                                        {
+                                            (step = (sc_steps_72[sc_conf_80]));
+                                            (BgL_sc_confzd2set_79zd2 = (sc_state_82[(sc_conf_80+(1))]));
+                                            (head = (BgL_sc_confzd2set_79zd2[(4)]));
+                                            (sc_state_82[(0)] = (BgL_sc_confzd2set_79zd2[(0)]));
+                                            (conf_set_merge_new_bang(BgL_sc_confzd2set_79zd2));
+                                            if ((step>=(0)))
+                                                {
+                                                    (sc_l_74 = (sc_starters_69[step]));
+                                                    while ((sc_l_74 instanceof sc_Pair)) {
+                                                        {
+                                                            (starter = (sc_l_74.car));
+                                                            (starter_set = (BgL_sc_confzd2setzd2getza2_44za2(sc_state_82, BgL_sc_statezd2num_68zd2, starter)));
+                                                            if (((starter_set[(BgL_sc_statezd2num_68zd2+(5))])=== false))
+                                                                {
+                                                                    (conf_set_adjoin(sc_state_82, starter_set, starter, BgL_sc_statezd2num_68zd2));
+                                                                    (sc_l_74 = (sc_l_74.cdr));
+                                                                }
+                                                            else
+                                                                (sc_l_74 = (sc_l_74.cdr));
+                                                        }
+                                                    }
+                                                    (l = (sc_enders_70[step]));
+                                                    while ((l instanceof sc_Pair)) {
+                                                        {
+                                                            (ender = (l.car));
+                                                            if ((((conf_set = (sc_state_82[(ender+(1))])), ((conf_set!== false)?(conf_set[(BgL_sc_statezd2num_68zd2+(5))]):false))!== false))
+                                                                {
+                                                                    (next = (sc_conf_80+(1)));
+                                                                    (next_set = (BgL_sc_confzd2setzd2getza2_44za2(sc_state_82, BgL_sc_statezd2num_68zd2, next)));
+                                                                    (conf_set_union(sc_state_82, next_set, next, BgL_sc_confzd2set_79zd2));
+                                                                    (l = (l.cdr));
+                                                                }
+                                                            else
+                                                                (l = (l.cdr));
+                                                        }
+                                                    }
+                                                }
+                                            else
+                                                {
+                                                    (preds = (sc_predictors_71[(step+BgL_sc_nbzd2nts_81zd2)]));
+                                                    (sc_states_78 = sc_states_67);
+                                                    (state = sc_state_82);
+                                                    (BgL_sc_statezd2num_77zd2 = BgL_sc_statezd2num_68zd2);
+                                                    (BgL_sc_confzd2set_76zd2 = BgL_sc_confzd2set_79zd2);
+                                                    sc_loop1_75 = function(l) {
+                                                        var sc_state_83;
+                                                        var BgL_sc_nextzd2set_84zd2;
+                                                        var sc_next_85;
+                                                        var pred_set;
+                                                        var i;
+                                                        var pred;
+                                                        if ((l instanceof sc_Pair))
+                                                            {
+                                                                (pred = (l.car));
+                                                                (i = head);
+                                                                while ((i>=(0))) {
+                                                                    {
+                                                                        (pred_set = ((sc_state_83 = (sc_states_78[i])), (sc_state_83[(pred+(1))])));
+                                                                        if ((pred_set!== false))
+                                                                            {
+                                                                                (sc_next_85 = (pred+(1)));
+                                                                                (BgL_sc_nextzd2set_84zd2 = (BgL_sc_confzd2setzd2getza2_44za2(state, BgL_sc_statezd2num_77zd2, sc_next_85)));
+                                                                                (conf_set_union(state, BgL_sc_nextzd2set_84zd2, sc_next_85, pred_set));
+                                                                            }
+                                                                        (i = (BgL_sc_confzd2set_76zd2[(i+(5))]));
+                                                                    }
+                                                                }
+                                                                return (sc_loop1_75((l.cdr)));
+                                                            }
+                                                        else
+                                                            return undefined;
+                                                    };
+                                                    (sc_loop1_75(preds));
+                                                }
+                                        }
+                                    else
+                                        return undefined;
+                                }
+                            }
+                        }
+                    };
+                    is_parsed = function(nt, i, j, sc_nts_86, sc_enders_87, sc_states_88) {
+                        var conf_set;
+                        var state;
+                        var sc_conf_89;
+                        var l;
+                        var BgL_sc_ntza2_90za2;
+                        {
+                            (BgL_sc_ntza2_90za2 = (sc_ind_43(nt, sc_nts_86)));
+                            if ((BgL_sc_ntza2_90za2!== false))
+                                {
+                                    (sc_nts_86.length);
+                                    (l = (sc_enders_87[BgL_sc_ntza2_90za2]));
+                                    while (true) {
+                                        if ((l instanceof sc_Pair))
+                                            {
+                                                (sc_conf_89 = (l.car));
+                                                if ((((state = (sc_states_88[j])), (conf_set = (state[(sc_conf_89+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false))
+                                                    return true;
+                                                else
+                                                    (l = (l.cdr));
+                                            }
+                                        else
+                                            return false;
+                                    }
+                                }
+                            else
+                                return false;
+                        }
+                    };
+                    deriv_trees = function(sc_conf_91, i, j, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2) {
+                        var sc_loop1_98;
+                        var prev;
+                        var name;
+                        return ((name = (sc_names_94[sc_conf_91])), ((name!== false)?((sc_conf_91<BgL_sc_nbzd2nts_97zd2)?(sc_list((sc_list(name, ((sc_toks_95[i]).car))))):(sc_list((sc_list(name))))):((prev = (sc_conf_91-(1))), (sc_loop1_98 = function(l1, l2) {
+                            var loop2;
+                            var ender_set;
+                            var state;
+                            var ender;
+                            var l1;
+                            var l2;
+                            while (true) {
+                                if ((l1 instanceof sc_Pair))
+                                    {
+                                        (ender = (l1.car));
+                                        (ender_set = ((state = (sc_states_96[j])), (state[(ender+(1))])));
+                                        if ((ender_set!== false))
+                                            {
+                                                loop2 = function(k, l2) {
+                                                    var loop3;
+                                                    var ender_trees;
+                                                    var prev_trees;
+                                                    var conf_set;
+                                                    var sc_state_99;
+                                                    var k;
+                                                    var l2;
+                                                    while (true) {
+                                                        if ((k>=(0)))
+                                                            if (((k>=i)&&(((sc_state_99 = (sc_states_96[k])), (conf_set = (sc_state_99[(prev+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)))
+                                                                {
+                                                                    (prev_trees = (deriv_trees(prev, i, k, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2)));
+                                                                    (ender_trees = (deriv_trees(ender, k, j, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2)));
+                                                                    loop3 = function(l3, l2) {
+                                                                        var l4;
+                                                                        var sc_l2_100;
+                                                                        var ender_tree;
+                                                                        if ((l3 instanceof sc_Pair))
+                                                                            {
+                                                                                (ender_tree = (sc_list((l3.car))));
+                                                                                (l4 = prev_trees);
+                                                                                (sc_l2_100 = l2);
+                                                                                while ((l4 instanceof sc_Pair)) {
+                                                                                    {
+                                                                                        (sc_l2_100 = (new sc_Pair((sc_append((l4.car), ender_tree)), sc_l2_100)));
+                                                                                        (l4 = (l4.cdr));
+                                                                                    }
+                                                                                }
+                                                                                return (loop3((l3.cdr), sc_l2_100));
+                                                                            }
+                                                                        else
+                                                                            return (loop2((ender_set[(k+(5))]), l2));
+                                                                    };
+                                                                    return (loop3(ender_trees, l2));
+                                                                }
+                                                            else
+                                                                (k = (ender_set[(k+(5))]));
+                                                        else
+                                                            return (sc_loop1_98((l1.cdr), l2));
+                                                    }
+                                                };
+                                                return (loop2((ender_set[(2)]), l2));
+                                            }
+                                        else
+                                            (l1 = (l1.cdr));
+                                    }
+                                else
+                                    return l2;
+                            }
+                        }), (sc_loop1_98((sc_enders_92[(sc_steps_93[prev])]), null)))));
+                    };
+                    BgL_sc_derivzd2treesza2_47z70 = function(nt, i, j, sc_nts_101, sc_enders_102, sc_steps_103, sc_names_104, sc_toks_105, sc_states_106) {
+                        var conf_set;
+                        var state;
+                        var sc_conf_107;
+                        var l;
+                        var trees;
+                        var BgL_sc_nbzd2nts_108zd2;
+                        var BgL_sc_ntza2_109za2;
+                        {
+                            (BgL_sc_ntza2_109za2 = (sc_ind_43(nt, sc_nts_101)));
+                            if ((BgL_sc_ntza2_109za2!== false))
+                                {
+                                    (BgL_sc_nbzd2nts_108zd2 = (sc_nts_101.length));
+                                    (l = (sc_enders_102[BgL_sc_ntza2_109za2]));
+                                    (trees = null);
+                                    while ((l instanceof sc_Pair)) {
+                                        {
+                                            (sc_conf_107 = (l.car));
+                                            if ((((state = (sc_states_106[j])), (conf_set = (state[(sc_conf_107+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false))
+                                                {
+                                                    (l = (l.cdr));
+                                                    (trees = (sc_append((deriv_trees(sc_conf_107, i, j, sc_enders_102, sc_steps_103, sc_names_104, sc_toks_105, sc_states_106, BgL_sc_nbzd2nts_108zd2)), trees)));
+                                                }
+                                            else
+                                                (l = (l.cdr));
+                                        }
+                                    }
+                                    return trees;
+                                }
+                            else
+                                return false;
+                        }
+                    };
+                    nb_deriv_trees = function(sc_conf_110, i, j, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2) {
+                        var sc_loop1_116;
+                        var tmp1124;
+                        var prev;
+                        return ((prev = (sc_conf_110-(1))), ((((tmp1124 = (sc_conf_110<BgL_sc_nbzd2nts_115zd2)), ((tmp1124!== false)?tmp1124:((sc_steps_112[prev])<(0))))!== false)?(1):((sc_loop1_116 = function(l, sc_n_118) {
+                            var nb_ender_trees;
+                            var nb_prev_trees;
+                            var conf_set;
+                            var state;
+                            var k;
+                            var n;
+                            var ender_set;
+                            var sc_state_117;
+                            var ender;
+                            var l;
+                            var sc_n_118;
+                            while (true) {
+                                if ((l instanceof sc_Pair))
+                                    {
+                                        (ender = (l.car));
+                                        (ender_set = ((sc_state_117 = (sc_states_114[j])), (sc_state_117[(ender+(1))])));
+                                        if ((ender_set!== false))
+                                            {
+                                                (k = (ender_set[(2)]));
+                                                (n = sc_n_118);
+                                                while ((k>=(0))) {
+                                                    if (((k>=i)&&(((state = (sc_states_114[k])), (conf_set = (state[(prev+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)))
+                                                        {
+                                                            (nb_prev_trees = (nb_deriv_trees(prev, i, k, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2)));
+                                                            (nb_ender_trees = (nb_deriv_trees(ender, k, j, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2)));
+                                                            (k = (ender_set[(k+(5))]));
+                                                            (n +=(nb_prev_trees*nb_ender_trees));
+                                                        }
+                                                    else
+                                                        (k = (ender_set[(k+(5))]));
+                                                }
+                                                return (sc_loop1_116((l.cdr), n));
+                                            }
+                                        else
+                                            (l = (l.cdr));
+                                    }
+                                else
+                                    return sc_n_118;
+                            }
+                        }), (sc_loop1_116((sc_enders_111[(sc_steps_112[prev])]), (0))))));
+                    };
+                    BgL_sc_nbzd2derivzd2treesza2_48za2 = function(nt, i, j, sc_nts_119, sc_enders_120, sc_steps_121, sc_toks_122, sc_states_123) {
+                        var conf_set;
+                        var state;
+                        var sc_conf_124;
+                        var l;
+                        var nb_trees;
+                        var BgL_sc_nbzd2nts_125zd2;
+                        var BgL_sc_ntza2_126za2;
+                        {
+                            (BgL_sc_ntza2_126za2 = (sc_ind_43(nt, sc_nts_119)));
+                            if ((BgL_sc_ntza2_126za2!== false))
+                                {
+                                    (BgL_sc_nbzd2nts_125zd2 = (sc_nts_119.length));
+                                    (l = (sc_enders_120[BgL_sc_ntza2_126za2]));
+                                    (nb_trees = (0));
+                                    while ((l instanceof sc_Pair)) {
+                                        {
+                                            (sc_conf_124 = (l.car));
+                                            if ((((state = (sc_states_123[j])), (conf_set = (state[(sc_conf_124+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false))
+                                                {
+                                                    (l = (l.cdr));
+                                                    (nb_trees = ((nb_deriv_trees(sc_conf_124, i, j, sc_enders_120, sc_steps_121, sc_toks_122, sc_states_123, BgL_sc_nbzd2nts_125zd2))+nb_trees));
+                                                }
+                                            else
+                                                (l = (l.cdr));
+                                        }
+                                    }
+                                    return nb_trees;
+                                }
+                            else
+                                return false;
+                        }
+                    };
+                    (lexer = (parser_descr[(0)]));
+                    (sc_nts_42 = (parser_descr[(1)]));
+                    (sc_starters_41 = (parser_descr[(2)]));
+                    (sc_enders_40 = (parser_descr[(3)]));
+                    (sc_predictors_39 = (parser_descr[(4)]));
+                    (sc_steps_38 = (parser_descr[(5)]));
+                    (sc_names_37 = (parser_descr[(6)]));
+                    (falseHead1128 = (new sc_Pair(null, null)));
+                    (L1125 = (lexer(input)));
+                    (tail1129 = falseHead1128);
+                    while (!(L1125 === null)) {
+                        {
+                            (tok = (L1125.car));
+                            (l1 = (tok.cdr));
+                            (l2 = null);
+                            while ((l1 instanceof sc_Pair)) {
+                                {
+                                    (sc_i_29 = (sc_ind_43((l1.car), sc_nts_42)));
+                                    if ((sc_i_29!== false))
+                                        {
+                                            (l1 = (l1.cdr));
+                                            (l2 = (new sc_Pair(sc_i_29, l2)));
+                                        }
+                                    else
+                                        (l1 = (l1.cdr));
+                                }
+                            }
+                            (sc_optrOpnd_22 = (new sc_Pair((tok.car), (sc_reverse(l2)))));
+                            (sc_optrOpnd_21 = (new sc_Pair(sc_optrOpnd_22, null)));
+                            (tail1129.cdr = sc_optrOpnd_21);
+                            (tail1129 = (tail1129.cdr));
+                            (L1125 = (L1125.cdr));
+                        }
+                    }
+                    (sc_optrOpnd_20 = (falseHead1128.cdr));
+                    (sc_toks_36 = (sc_list2vector(sc_optrOpnd_20)));
+                    (BgL_sc_nbzd2toks_35zd2 = (sc_toks_36.length));
+                    (BgL_sc_nbzd2confs_34zd2 = (sc_steps_38.length));
+                    (sc_states_33 = (make_states(BgL_sc_nbzd2toks_35zd2, BgL_sc_nbzd2confs_34zd2)));
+                    (goal_starters = (sc_starters_41[(0)]));
+                    (BgL_sc_confzd2setzd2adjoinza2_45za2(sc_states_33, (0), goal_starters, (0)));
+                    (forw(sc_states_33, (0), sc_starters_41, sc_enders_40, sc_predictors_39, sc_steps_38, sc_nts_42));
+                    (sc_i_28 = (0));
+                    while ((sc_i_28<BgL_sc_nbzd2toks_35zd2)) {
+                        {
+                            (tok_nts = ((sc_toks_36[sc_i_28]).cdr));
+                            (BgL_sc_confzd2setzd2adjoinza2_45za2(sc_states_33, (sc_i_28+(1)), tok_nts, sc_i_28));
+                            (forw(sc_states_33, (sc_i_28+(1)), sc_starters_41, sc_enders_40, sc_predictors_39, sc_steps_38, sc_nts_42));
+                            (++sc_i_28);
+                        }
+                    }
+                    (nb_toks = (sc_toks_36.length));
+                    (BgL_sc_nbzd2confs_32zd2 = (sc_steps_38.length));
+                    (BgL_sc_nbzd2nts_31zd2 = (sc_nts_42.length));
+                    (BgL_sc_statesza2_30za2 = (make_states(nb_toks, BgL_sc_nbzd2confs_32zd2)));
+                    (goal_enders = (sc_enders_40[(0)]));
+                    (l = goal_enders);
+                    while ((l instanceof sc_Pair)) {
+                        {
+                            (conf = (l.car));
+                            (BgL_sc_confzd2setzd2adjoinza2za2_46z00(sc_states_33, BgL_sc_statesza2_30za2, nb_toks, conf, (0)));
+                            (l = (l.cdr));
+                        }
+                    }
+                    (i = nb_toks);
+                    while ((i>=(0))) {
+                        {
+                            (states = sc_states_33);
+                            (BgL_sc_statesza2_27za2 = BgL_sc_statesza2_30za2);
+                            (state_num = i);
+                            (sc_enders_26 = sc_enders_40);
+                            (sc_steps_25 = sc_steps_38);
+                            (BgL_sc_nbzd2nts_24zd2 = BgL_sc_nbzd2nts_31zd2);
+                            (toks = sc_toks_36);
+                            (BgL_sc_stateza2_23za2 = (BgL_sc_statesza2_30za2[i]));
+                            loop1 = function() {
+                                var sc_loop1_127;
+                                var prev;
+                                var BgL_sc_statesza2_128za2;
+                                var sc_states_129;
+                                var j;
+                                var i;
+                                var sc_i_130;
+                                var head;
+                                var conf_set;
+                                var sc_conf_131;
+                                {
+                                    (sc_conf_131 = (BgL_sc_stateza2_23za2[(0)]));
+                                    if ((sc_conf_131>=(0)))
+                                        {
+                                            (conf_set = (BgL_sc_stateza2_23za2[(sc_conf_131+(1))]));
+                                            (head = (conf_set[(4)]));
+                                            (BgL_sc_stateza2_23za2[(0)] = (conf_set[(0)]));
+                                            (conf_set_merge_new_bang(conf_set));
+                                            (sc_i_130 = head);
+                                            while ((sc_i_130>=(0))) {
+                                                {
+                                                    (i = sc_i_130);
+                                                    (j = state_num);
+                                                    (sc_states_129 = states);
+                                                    (BgL_sc_statesza2_128za2 = BgL_sc_statesza2_27za2);
+                                                    (prev = (sc_conf_131-(1)));
+                                                    if (((sc_conf_131>=BgL_sc_nbzd2nts_24zd2)&&((sc_steps_25[prev])>=(0))))
+                                                        {
+                                                            sc_loop1_127 = function(l) {
+                                                                var k;
+                                                                var ender_set;
+                                                                var state;
+                                                                var ender;
+                                                                var l;
+                                                                while (true) {
+                                                                    if ((l instanceof sc_Pair))
+                                                                        {
+                                                                            (ender = (l.car));
+                                                                            (ender_set = ((state = (sc_states_129[j])), (state[(ender+(1))])));
+                                                                            if ((ender_set!== false))
+                                                                                {
+                                                                                    (k = (ender_set[(2)]));
+                                                                                    while ((k>=(0))) {
+                                                                                        {
+                                                                                            if ((k>=i))
+                                                                                                if (((BgL_sc_confzd2setzd2adjoinza2za2_46z00(sc_states_129, BgL_sc_statesza2_128za2, k, prev, i))!== false))
+                                                                                                    (BgL_sc_confzd2setzd2adjoinza2za2_46z00(sc_states_129, BgL_sc_statesza2_128za2, j, ender, k));
+                                                                                            (k = (ender_set[(k+(5))]));
+                                                                                        }
+                                                                                    }
+                                                                                    return (sc_loop1_127((l.cdr)));
+                                                                                }
+                                                                            else
+                                                                                (l = (l.cdr));
+                                                                        }
+                                                                    else
+                                                                        return undefined;
+                                                                }
+                                                            };
+                                                            (sc_loop1_127((sc_enders_26[(sc_steps_25[prev])])));
+                                                        }
+                                                    (sc_i_130 = (conf_set[(sc_i_130+(5))]));
+                                                }
+                                            }
+                                            return (loop1());
+                                        }
+                                    else
+                                        return undefined;
+                                }
+                            };
+                            (loop1());
+                            (--i);
+                        }
+                    }
+                    (optrOpnd = BgL_sc_statesza2_30za2);
+                    return [sc_nts_42, sc_starters_41, sc_enders_40, sc_predictors_39, sc_steps_38, sc_names_37, sc_toks_36, optrOpnd, is_parsed, BgL_sc_derivzd2treesza2_47z70, BgL_sc_nbzd2derivzd2treesza2_48za2];
+                }
+            };
+        }
+    };
+    BgL_parsezd2ze3parsedzf3zc2 = function(parse, nt, i, j) {
+        var is_parsed;
+        var states;
+        var enders;
+        var nts;
+        return ((nts = (parse[(0)])), (enders = (parse[(2)])), (states = (parse[(7)])), (is_parsed = (parse[(8)])), (is_parsed(nt, i, j, nts, enders, states)));
+    };
+    BgL_parsezd2ze3treesz31 = function(parse, nt, i, j) {
+        var BgL_sc_derivzd2treesza2_132z70;
+        var states;
+        var toks;
+        var names;
+        var steps;
+        var enders;
+        var nts;
+        return ((nts = (parse[(0)])), (enders = (parse[(2)])), (steps = (parse[(4)])), (names = (parse[(5)])), (toks = (parse[(6)])), (states = (parse[(7)])), (BgL_sc_derivzd2treesza2_132z70 = (parse[(9)])), (BgL_sc_derivzd2treesza2_132z70(nt, i, j, nts, enders, steps, names, toks, states)));
+    };
+    BgL_parsezd2ze3nbzd2treesze3 = function(parse, nt, i, j) {
+        var BgL_sc_nbzd2derivzd2treesza2_133za2;
+        var states;
+        var toks;
+        var steps;
+        var enders;
+        var nts;
+        return ((nts = (parse[(0)])), (enders = (parse[(2)])), (steps = (parse[(4)])), (toks = (parse[(6)])), (states = (parse[(7)])), (BgL_sc_nbzd2derivzd2treesza2_133za2 = (parse[(10)])), (BgL_sc_nbzd2derivzd2treesza2_133za2(nt, i, j, nts, enders, steps, toks, states)));
+    };
+    test = function(k) {
+        var x;
+        var p;
+        return ((p = (BgL_makezd2parserzd2(const_earley, function(l) {
+            var sc_x_134;
+            var tail1134;
+            var L1130;
+            var falseHead1133;
+            {
+                (falseHead1133 = (new sc_Pair(null, null)));
+                (tail1134 = falseHead1133);
+                (L1130 = l);
+                while (!(L1130 === null)) {
+                    {
+                        (tail1134.cdr = (new sc_Pair(((sc_x_134 = (L1130.car)), (sc_list(sc_x_134, sc_x_134))), null)));
+                        (tail1134 = (tail1134.cdr));
+                        (L1130 = (L1130.cdr));
+                    }
+                }
+                return (falseHead1133.cdr);
+            }
+        }))), (x = (p((sc_vector2list((sc_makeVector(k, "\u1E9Ca"))))))), (sc_length((BgL_parsezd2ze3treesz31(x, "\u1E9Cs", (0), k)))));
+    };
+    BgL_earleyzd2benchmarkzd2 = function() {
+        var args = null;
+        for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) {
+            args = sc_cons(arguments[sc_tmp], args);
+        }
+        var k;
+        return ((k = ((args === null)?(7):(args.car))), (BgL_runzd2benchmarkzd2("earley", (1), function() {
+            return (test(k));
+        }, function(result) {
+            return ((sc_display(result)), (sc_newline()), result == 132);
+        })));
+    };
+}
+
+
+/************* END OF GENERATED CODE *************/
+// Invoke this function to run a benchmark.
+// The first argument is a string identifying the benchmark.
+// The second argument is the number of times to run the benchmark.
+// The third argument is a function that runs the benchmark.
+// The fourth argument is a unary function that warns if the result
+// returned by the benchmark is incorrect.
+//
+// Example:
+// RunBenchmark("new Array()",
+//              1,
+//              function () { new Array(1000000); }
+//              function (v) {
+//                return (v instanceof Array) && (v.length == 1000000);
+//              });
+
+SC_DEFAULT_OUT = new sc_GenericOutputPort(function(s) {});
+SC_ERROR_OUT = SC_DEFAULT_OUT;
+
+function RunBenchmark(name, count, run, warn) {
+  for (var n = 0; n < count; ++n) {
+    result = run();
+    if (!warn(result)) {
+      throw new Error("Earley or Boyer did incorrect number of rewrites");
+    }
+  }
+}
+
+var BgL_runzd2benchmarkzd2 = RunBenchmark;
+
diff --git a/regexp2000/benchmarks/raytrace.js b/regexp2000/benchmarks/raytrace.js
new file mode 100644 (file)
index 0000000..925d0ed
--- /dev/null
@@ -0,0 +1,3434 @@
+// The ray tracer code in this file is written by Adam Burmister. It
+// is available in its original form from:
+//
+//   http://labs.flog.nz.co/raytracer/
+//
+// It has been modified slightly by Google to work as a standalone
+// benchmark, but the all the computational code remains
+// untouched. This file also contains a copy of the Prototype
+// JavaScript framework which is used by the ray tracer.
+
+var RayTrace = new BenchmarkSuite('RayTrace', 932666, [
+  new Benchmark('RayTrace', renderScene)
+]);
+
+
+var checkNumber;
+
+// Create dummy objects if we're not running in a browser.
+if (typeof document == 'undefined') {
+  document = { };
+  window = { opera: null };
+  navigator = { userAgent: null, appVersion: "" };
+}
+
+
+// ------------------------------------------------------------------------
+// ------------------------------------------------------------------------
+
+
+/*  Prototype JavaScript framework, version 1.5.0
+ *  (c) 2005-2007 Sam Stephenson
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+//--------------------
+var Prototype = {
+  Version: '1.5.0',
+  BrowserFeatures: {
+    XPath: !!document.evaluate
+  },
+
+  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+  emptyFunction: function() {},
+  K: function(x) { return x }
+}
+
+var Class = {
+  create: function() {
+    return function() {
+      this.initialize.apply(this, arguments);
+    }
+  }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+  for (var property in source) {
+    destination[property] = source[property];
+  }
+  return destination;
+}
+
+Object.extend(Object, {
+  inspect: function(object) {
+    try {
+      if (object === undefined) return 'undefined';
+      if (object === null) return 'null';
+      return object.inspect ? object.inspect() : object.toString();
+    } catch (e) {
+      if (e instanceof RangeError) return '...';
+      throw e;
+    }
+  },
+
+  keys: function(object) {
+    var keys = [];
+    for (var property in object)
+      keys.push(property);
+    return keys;
+  },
+
+  values: function(object) {
+    var values = [];
+    for (var property in object)
+      values.push(object[property]);
+    return values;
+  },
+
+  clone: function(object) {
+    return Object.extend({}, object);
+  }
+});
+
+Function.prototype.bind = function() {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function() {
+    return __method.apply(object, args.concat($A(arguments)));
+  }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function(event) {
+    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
+  }
+}
+
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    var digits = this.toString(16);
+    if (this < 16) return '0' + digits;
+    return digits;
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator) {
+    $R(0, this, true).each(iterator);
+    return this;
+  }
+});
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
+
+    return returnValue;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  stop: function() {
+    if (!this.timer) return;
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.callback(this);
+      } finally {
+        this.currentlyExecuting = false;
+      }
+    }
+  }
+}
+String.interpret = function(value){
+  return value == null ? '' : String(value);
+}
+
+Object.extend(String.prototype, {
+  gsub: function(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = arguments.callee.prepareReplacement(replacement);
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  },
+
+  sub: function(pattern, replacement, count) {
+    replacement = this.gsub.prepareReplacement(replacement);
+    count = count === undefined ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  },
+
+  scan: function(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return this;
+  },
+
+  truncate: function(length, truncation) {
+    length = length || 30;
+    truncation = truncation === undefined ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : this;
+  },
+
+  strip: function() {
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');
+  },
+
+  stripTags: function() {
+    return this.replace(/<\/?[^>]+>/gi, '');
+  },
+
+  stripScripts: function() {
+    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+  },
+
+  extractScripts: function() {
+    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+    return (this.match(matchAll) || []).map(function(scriptTag) {
+      return (scriptTag.match(matchOne) || ['', ''])[1];
+    });
+  },
+
+  evalScripts: function() {
+    return this.extractScripts().map(function(script) { return eval(script) });
+  },
+
+  escapeHTML: function() {
+    var div = document.createElement('div');
+    var text = document.createTextNode(this);
+    div.appendChild(text);
+    return div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = document.createElement('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? (div.childNodes.length > 1 ?
+      $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
+      div.childNodes[0].nodeValue) : '';
+  },
+
+  toQueryParams: function(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return {};
+
+    return match[1].split(separator || '&').inject({}, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var name = decodeURIComponent(pair[0]);
+        var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+
+        if (hash[name] !== undefined) {
+          if (hash[name].constructor != Array)
+            hash[name] = [hash[name]];
+          if (value) hash[name].push(value);
+        }
+        else hash[name] = value;
+      }
+      return hash;
+    });
+  },
+
+  toArray: function() {
+    return this.split('');
+  },
+
+  succ: function() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  },
+
+  camelize: function() {
+    var parts = this.split('-'), len = parts.length;
+    if (len == 1) return parts[0];
+
+    var camelized = this.charAt(0) == '-'
+      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+      : parts[0];
+
+    for (var i = 1; i < len; i++)
+      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+    return camelized;
+  },
+
+  capitalize: function(){
+    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+  },
+
+  underscore: function() {
+    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+  },
+
+  dasherize: function() {
+    return this.gsub(/_/,'-');
+  },
+
+  inspect: function(useDoubleQuotes) {
+    var escapedString = this.replace(/\\/g, '\\\\');
+    if (useDoubleQuotes)
+      return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    else
+      return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+  if (typeof replacement == 'function') return replacement;
+  var template = new Template(replacement);
+  return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+  initialize: function(template, pattern) {
+    this.template = template.toString();
+    this.pattern  = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    return this.template.gsub(this.pattern, function(match) {
+      var before = match[1];
+      if (before == '\\') return match[2];
+      return before + String.interpret(object[match[3]]);
+    });
+  }
+}
+
+var $break    = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+  each: function(iterator) {
+    var index = 0;
+    try {
+      this._each(function(value) {
+        try {
+          iterator(value, index++);
+        } catch (e) {
+          if (e != $continue) throw e;
+        }
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  },
+
+  eachSlice: function(number, iterator) {
+    var index = -number, slices = [], array = this.toArray();
+    while ((index += number) < array.length)
+      slices.push(array.slice(index, index+number));
+    return slices.map(iterator);
+  },
+
+  all: function(iterator) {
+    var result = true;
+    this.each(function(value, index) {
+      result = result && !!(iterator || Prototype.K)(value, index);
+      if (!result) throw $break;
+    });
+    return result;
+  },
+
+  any: function(iterator) {
+    var result = false;
+    this.each(function(value, index) {
+      if (result = !!(iterator || Prototype.K)(value, index))
+        throw $break;
+    });
+    return result;
+  },
+
+  collect: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      results.push((iterator || Prototype.K)(value, index));
+    });
+    return results;
+  },
+
+  detect: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      if (iterator(value, index)) {
+        result = value;
+        throw $break;
+      }
+    });
+    return result;
+  },
+
+  findAll: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      if (iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  grep: function(pattern, iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      var stringValue = value.toString();
+      if (stringValue.match(pattern))
+        results.push((iterator || Prototype.K)(value, index));
+    })
+    return results;
+  },
+
+  include: function(object) {
+    var found = false;
+    this.each(function(value) {
+      if (value == object) {
+        found = true;
+        throw $break;
+      }
+    });
+    return found;
+  },
+
+  inGroupsOf: function(number, fillWith) {
+    fillWith = fillWith === undefined ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  },
+
+  inject: function(memo, iterator) {
+    this.each(function(value, index) {
+      memo = iterator(memo, value, index);
+    });
+    return memo;
+  },
+
+  invoke: function(method) {
+    var args = $A(arguments).slice(1);
+    return this.map(function(value) {
+      return value[method].apply(value, args);
+    });
+  },
+
+  max: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (result == undefined || value >= result)
+        result = value;
+    });
+    return result;
+  },
+
+  min: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (result == undefined || value < result)
+        result = value;
+    });
+    return result;
+  },
+
+  partition: function(iterator) {
+    var trues = [], falses = [];
+    this.each(function(value, index) {
+      ((iterator || Prototype.K)(value, index) ?
+        trues : falses).push(value);
+    });
+    return [trues, falses];
+  },
+
+  pluck: function(property) {
+    var results = [];
+    this.each(function(value, index) {
+      results.push(value[property]);
+    });
+    return results;
+  },
+
+  reject: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      if (!iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  sortBy: function(iterator) {
+    return this.map(function(value, index) {
+      return {value: value, criteria: iterator(value, index)};
+    }).sort(function(left, right) {
+      var a = left.criteria, b = right.criteria;
+      return a < b ? -1 : a > b ? 1 : 0;
+    }).pluck('value');
+  },
+
+  toArray: function() {
+    return this.map();
+  },
+
+  zip: function() {
+    var iterator = Prototype.K, args = $A(arguments);
+    if (typeof args.last() == 'function')
+      iterator = args.pop();
+
+    var collections = [this].concat(args).map($A);
+    return this.map(function(value, index) {
+      return iterator(collections.pluck(index));
+    });
+  },
+
+  size: function() {
+    return this.toArray().length;
+  },
+
+  inspect: function() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+}
+
+Object.extend(Enumerable, {
+  map:     Enumerable.collect,
+  find:    Enumerable.detect,
+  select:  Enumerable.findAll,
+  member:  Enumerable.include,
+  entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+  if (!iterable) return [];
+  if (iterable.toArray) {
+    return iterable.toArray();
+  } else {
+    var results = [];
+    for (var i = 0, length = iterable.length; i < length; i++)
+      results.push(iterable[i]);
+    return results;
+  }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse)
+  Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0, length = this.length; i < length; i++)
+      iterator(this[i]);
+  },
+
+  clear: function() {
+    this.length = 0;
+    return this;
+  },
+
+  first: function() {
+    return this[0];
+  },
+
+  last: function() {
+    return this[this.length - 1];
+  },
+
+  compact: function() {
+    return this.select(function(value) {
+      return value != null;
+    });
+  },
+
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(value && value.constructor == Array ?
+        value.flatten() : [value]);
+    });
+  },
+
+  without: function() {
+    var values = $A(arguments);
+    return this.select(function(value) {
+      return !values.include(value);
+    });
+  },
+
+  indexOf: function(object) {
+    for (var i = 0, length = this.length; i < length; i++)
+      if (this[i] == object) return i;
+    return -1;
+  },
+
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  reduce: function() {
+    return this.length > 1 ? this : this[0];
+  },
+
+  uniq: function() {
+    return this.inject([], function(array, value) {
+      return array.include(value) ? array : array.concat([value]);
+    });
+  },
+
+  clone: function() {
+    return [].concat(this);
+  },
+
+  size: function() {
+    return this.length;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  }
+});
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string){
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
+
+if(window.opera){
+  Array.prototype.concat = function(){
+    var array = [];
+    for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+    for(var i = 0, length = arguments.length; i < length; i++) {
+      if(arguments[i].constructor == Array) {
+        for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+          array.push(arguments[i][j]);
+      } else {
+        array.push(arguments[i]);
+      }
+    }
+    return array;
+  }
+}
+var Hash = function(obj) {
+  Object.extend(this, obj || {});
+};
+
+Object.extend(Hash, {
+  toQueryString: function(obj) {
+    var parts = [];
+
+         this.prototype._each.call(obj, function(pair) {
+      if (!pair.key) return;
+
+      if (pair.value && pair.value.constructor == Array) {
+        var values = pair.value.compact();
+        if (values.length < 2) pair.value = values.reduce();
+        else {
+               key = encodeURIComponent(pair.key);
+          values.each(function(value) {
+            value = value != undefined ? encodeURIComponent(value) : '';
+            parts.push(key + '=' + encodeURIComponent(value));
+          });
+          return;
+        }
+      }
+      if (pair.value == undefined) pair[1] = '';
+      parts.push(pair.map(encodeURIComponent).join('='));
+         });
+
+    return parts.join('&');
+  }
+});
+
+Object.extend(Hash.prototype, Enumerable);
+Object.extend(Hash.prototype, {
+  _each: function(iterator) {
+    for (var key in this) {
+      var value = this[key];
+      if (value && value == Hash.prototype[key]) continue;
+
+      var pair = [key, value];
+      pair.key = key;
+      pair.value = value;
+      iterator(pair);
+    }
+  },
+
+  keys: function() {
+    return this.pluck('key');
+  },
+
+  values: function() {
+    return this.pluck('value');
+  },
+
+  merge: function(hash) {
+    return $H(hash).inject(this, function(mergedHash, pair) {
+      mergedHash[pair.key] = pair.value;
+      return mergedHash;
+    });
+  },
+
+  remove: function() {
+    var result;
+    for(var i = 0, length = arguments.length; i < length; i++) {
+      var value = this[arguments[i]];
+      if (value !== undefined){
+        if (result === undefined) result = value;
+        else {
+          if (result.constructor != Array) result = [result];
+          result.push(value)
+        }
+      }
+      delete this[arguments[i]];
+    }
+    return result;
+  },
+
+  toQueryString: function() {
+    return Hash.toQueryString(this);
+  },
+
+  inspect: function() {
+    return '#<Hash:{' + this.map(function(pair) {
+      return pair.map(Object.inspect).join(': ');
+    }).join(', ') + '}>';
+  }
+});
+
+function $H(object) {
+  if (object && object.constructor == Hash) return object;
+  return new Hash(object);
+};
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+  initialize: function(start, end, exclusive) {
+    this.start = start;
+    this.end = end;
+    this.exclusive = exclusive;
+  },
+
+  _each: function(iterator) {
+    var value = this.start;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  },
+
+  include: function(value) {
+    if (value < this.start)
+      return false;
+    if (this.exclusive)
+      return value < this.end;
+    return value <= this.end;
+  }
+});
+
+var $R = function(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+  getTransport: function() {
+    return Try.these(
+      function() {return new XMLHttpRequest()},
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+    ) || false;
+  },
+
+  activeRequestCount: 0
+}
+
+Ajax.Responders = {
+  responders: [],
+
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (typeof responder[callback] == 'function') {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) {}
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate: function() {
+    Ajax.activeRequestCount++;
+  },
+  onComplete: function() {
+    Ajax.activeRequestCount--;
+  }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+  setOptions: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   ''
+    }
+    Object.extend(this.options, options || {});
+
+    this.options.method = this.options.method.toLowerCase();
+    if (typeof this.options.parameters == 'string')
+      this.options.parameters = this.options.parameters.toQueryParams();
+  }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+  _complete: false,
+
+  initialize: function(url, options) {
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+    this.request(url);
+  },
+
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = this.options.parameters;
+
+    if (!['get', 'post'].include(this.method)) {
+      // simulate other verbs over post
+      params['_method'] = this.method;
+      this.method = 'post';
+    }
+
+    params = Hash.toQueryString(params);
+    if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
+
+    // when GET, append parameters to URL
+    if (this.method == 'get' && params)
+      this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
+
+    try {
+      Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+      this.transport.open(this.method.toUpperCase(), this.url,
+        this.options.asynchronous);
+
+      if (this.options.asynchronous)
+        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
+
+      this.transport.onreadystatechange = this.onStateChange.bind(this);
+      this.setRequestHeaders();
+
+      var body = this.method == 'post' ? (this.options.postBody || params) : null;
+
+      this.transport.send(body);
+
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
+
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
+
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
+    }
+
+    // user-defined headers
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (typeof extras.push == 'function')
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    return !this.transport.status
+        || (this.transport.status >= 200 && this.transport.status < 300);
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState];
+    var transport = this.transport, json = this.evalJSON();
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + this.transport.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(transport, json);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      if ((this.getHeader('Content-type') || 'text/javascript').strip().
+        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+          this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+      Ajax.Responders.dispatch('on' + state, this, transport, json);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      // avoid memory leak in MSIE: clean up
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name);
+    } catch (e) { return null }
+  },
+
+  evalJSON: function() {
+    try {
+      var json = this.getHeader('X-JSON');
+      return json ? eval('(' + json + ')') : null;
+    } catch (e) { return null }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval(this.transport.responseText);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+  initialize: function(container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    }
+
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+
+    var onComplete = this.options.onComplete || Prototype.emptyFunction;
+    this.options.onComplete = (function(transport, param) {
+      this.updateContent();
+      onComplete(transport, param);
+    }).bind(this);
+
+    this.request(url);
+  },
+
+  updateContent: function() {
+    var receiver = this.container[this.success() ? 'success' : 'failure'];
+    var response = this.transport.responseText;
+
+    if (!this.options.evalScripts) response = response.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (this.options.insertion)
+        new this.options.insertion(receiver, response);
+      else
+        receiver.update(response);
+    }
+
+    if (this.success()) {
+      if (this.onComplete)
+        setTimeout(this.onComplete.bind(this), 10);
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+  initialize: function(container, url, options) {
+    this.setOptions(options);
+    this.onComplete = this.options.onComplete;
+
+    this.frequency = (this.options.frequency || 2);
+    this.decay = (this.options.decay || 1);
+
+    this.updater = {};
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.options.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(request) {
+    if (this.options.decay) {
+      this.decay = (request.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = request.responseText;
+    }
+    this.timer = setTimeout(this.onTimerEvent.bind(this),
+      this.decay * this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+function $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (typeof element == 'string')
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(query.snapshotItem(i));
+    return results;
+  };
+}
+
+document.getElementsByClassName = function(className, parentElement) {
+  if (Prototype.BrowserFeatures.XPath) {
+    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
+    return document._getElementsByXPath(q, parentElement);
+  } else {
+    var children = ($(parentElement) || document.body).getElementsByTagName('*');
+    var elements = [], child;
+    for (var i = 0, length = children.length; i < length; i++) {
+      child = children[i];
+      if (Element.hasClassName(child, className))
+        elements.push(Element.extend(child));
+    }
+    return elements;
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element)
+  var Element = new Object();
+
+Element.extend = function(element) {
+  if (!element || _nativeExtensions || element.nodeType == 3) return element;
+
+  if (!element._extended && element.tagName && element != window) {
+    var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
+
+    if (element.tagName == 'FORM')
+      Object.extend(methods, Form.Methods);
+    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
+      Object.extend(methods, Form.Element.Methods);
+
+    Object.extend(methods, Element.Methods.Simulated);
+
+    for (var property in methods) {
+      var value = methods[property];
+      if (typeof value == 'function' && !(property in element))
+        element[property] = cache.findOrStore(value);
+    }
+  }
+
+  element._extended = true;
+  return element;
+};
+
+Element.extend.cache = {
+  findOrStore: function(value) {
+    return this[value] = this[value] || function() {
+      return value.apply(null, [this].concat($A(arguments)));
+    }
+  }
+};
+
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    $(element).style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    $(element).style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: function(element, html) {
+    html = typeof html == 'undefined' ? '' : html.toString();
+    $(element).innerHTML = html.stripScripts();
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  replace: function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    if (element.outerHTML) {
+      element.outerHTML = html.stripScripts();
+    } else {
+      var range = element.ownerDocument.createRange();
+      range.selectNodeContents(element);
+      element.parentNode.replaceChild(
+        range.createContextualFragment(html.stripScripts()), element);
+    }
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(), attribute = pair.last();
+      var value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
+
+  recursivelyCollect: function(element, property) {
+    element = $(element);
+    var elements = [];
+    while (element = element[property])
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return $(element).recursivelyCollect('parentNode');
+  },
+
+  descendants: function(element) {
+    return $A($(element).getElementsByTagName('*'));
+  },
+
+  immediateDescendants: function(element) {
+    if (!(element = $(element).firstChild)) return [];
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    if (element) return [element].concat($(element).nextSiblings());
+    return [];
+  },
+
+  previousSiblings: function(element) {
+    return $(element).recursivelyCollect('previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return $(element).recursivelyCollect('nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return element.previousSiblings().reverse().concat(element.nextSiblings());
+  },
+
+  match: function(element, selector) {
+    if (typeof selector == 'string')
+      selector = new Selector(selector);
+    return selector.match($(element));
+  },
+
+  up: function(element, expression, index) {
+    return Selector.findElement($(element).ancestors(), expression, index);
+  },
+
+  down: function(element, expression, index) {
+    return Selector.findElement($(element).descendants(), expression, index);
+  },
+
+  previous: function(element, expression, index) {
+    return Selector.findElement($(element).previousSiblings(), expression, index);
+  },
+
+  next: function(element, expression, index) {
+    return Selector.findElement($(element).nextSiblings(), expression, index);
+  },
+
+  getElementsBySelector: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element, args);
+  },
+
+  getElementsByClassName: function(element, className) {
+    return document.getElementsByClassName(className, element);
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (document.all && !window.opera) {
+      var t = Element._attributeTranslations;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name])  name = t.names[name];
+      var attribute = element.attributes[name];
+      if(attribute) return attribute.nodeValue;
+    }
+    return element.getAttribute(name);
+  },
+
+  getHeight: function(element) {
+    return $(element).getDimensions().height;
+  },
+
+  getWidth: function(element) {
+    return $(element).getDimensions().width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    if (elementClassName.length == 0) return false;
+    if (elementClassName == className ||
+        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+      return true;
+    return false;
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).add(className);
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).remove(className);
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
+    return element;
+  },
+
+  observe: function() {
+    Event.observe.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  stopObserving: function() {
+    Event.stopObserving.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.match(/^\s*$/);
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+    while (element = element.parentNode)
+      if (element == ancestor) return true;
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = Position.cumulativeOffset(element);
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    if (['float','cssFloat'].include(style))
+      style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
+    style = style.camelize();
+    var value = element.style[style];
+    if (!value) {
+      if (document.defaultView && document.defaultView.getComputedStyle) {
+        var css = document.defaultView.getComputedStyle(element, null);
+        value = css ? css[style] : null;
+      } else if (element.currentStyle) {
+        value = element.currentStyle[style];
+      }
+    }
+
+    if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
+      value = element['offset'+style.capitalize()] + 'px';
+
+    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+    if(style == 'opacity') {
+      if(value) return parseFloat(value);
+      if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+        if(value[1]) return parseFloat(value[1]) / 100;
+      return 1.0;
+    }
+    return value == 'auto' ? null : value;
+  },
+
+  setStyle: function(element, style) {
+    element = $(element);
+    for (var name in style) {
+      var value = style[name];
+      if(name == 'opacity') {
+        if (value == 1) {
+          value = (/Gecko/.test(navigator.userAgent) &&
+            !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
+          if(/MSIE/.test(navigator.userAgent) && !window.opera)
+            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+        } else if(value == '') {
+          if(/MSIE/.test(navigator.userAgent) && !window.opera)
+            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+        } else {
+          if(value < 0.00001) value = 0;
+          if(/MSIE/.test(navigator.userAgent) && !window.opera)
+            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
+              'alpha(opacity='+value*100+')';
+        }
+      } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
+      element.style[name.camelize()] = value;
+    }
+    return element;
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    var display = $(element).getStyle('display');
+    if (display != 'none' && display != null) // Safari bug
+      return {width: element.offsetWidth, height: element.offsetHeight};
+
+    // All *Width and *Height properties give 0 on elements with display none,
+    // so enable the element temporarily
+    var els = element.style;
+    var originalVisibility = els.visibility;
+    var originalPosition = els.position;
+    var originalDisplay = els.display;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = 'block';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = originalDisplay;
+    els.position = originalPosition;
+    els.visibility = originalVisibility;
+    return {width: originalWidth, height: originalHeight};
+  },
+
+  makePositioned: function(element) {
+    element = $(element);
+    var pos = Element.getStyle(element, 'position');
+    if (pos == 'static' || !pos) {
+      element._madePositioned = true;
+      element.style.position = 'relative';
+      // Opera returns the offset relative to the positioning context, when an
+      // element is position relative but top and left have not been defined
+      if (window.opera) {
+        element.style.top = 0;
+        element.style.left = 0;
+      }
+    }
+    return element;
+  },
+
+  undoPositioned: function(element) {
+    element = $(element);
+    if (element._madePositioned) {
+      element._madePositioned = undefined;
+      element.style.position =
+        element.style.top =
+        element.style.left =
+        element.style.bottom =
+        element.style.right = '';
+    }
+    return element;
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return element;
+    element._overflow = element.style.overflow || 'auto';
+    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+      element.style.overflow = 'hidden';
+    return element;
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (!element._overflow) return element;
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+    element._overflow = null;
+    return element;
+  }
+};
+
+Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
+
+Element._attributeTranslations = {};
+
+Element._attributeTranslations.names = {
+  colspan:   "colSpan",
+  rowspan:   "rowSpan",
+  valign:    "vAlign",
+  datetime:  "dateTime",
+  accesskey: "accessKey",
+  tabindex:  "tabIndex",
+  enctype:   "encType",
+  maxlength: "maxLength",
+  readonly:  "readOnly",
+  longdesc:  "longDesc"
+};
+
+Element._attributeTranslations.values = {
+  _getAttr: function(element, attribute) {
+    return element.getAttribute(attribute, 2);
+  },
+
+  _flag: function(element, attribute) {
+    return $(element).hasAttribute(attribute) ? attribute : null;
+  },
+
+  style: function(element) {
+    return element.style.cssText.toLowerCase();
+  },
+
+  title: function(element) {
+    var node = element.getAttributeNode('title');
+    return node.specified ? node.nodeValue : null;
+  }
+};
+
+Object.extend(Element._attributeTranslations.values, {
+  href: Element._attributeTranslations.values._getAttr,
+  src:  Element._attributeTranslations.values._getAttr,
+  disabled: Element._attributeTranslations.values._flag,
+  checked:  Element._attributeTranslations.values._flag,
+  readonly: Element._attributeTranslations.values._flag,
+  multiple: Element._attributeTranslations.values._flag
+});
+
+Element.Methods.Simulated = {
+  hasAttribute: function(element, attribute) {
+    var t = Element._attributeTranslations;
+    attribute = t.names[attribute] || attribute;
+    return $(element).getAttributeNode(attribute).specified;
+  }
+};
+
+// IE is missing .innerHTML support for TABLE-related elements
+if (document.all && !window.opera){
+  Element.Methods.update = function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    var tagName = element.tagName.toUpperCase();
+    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
+      var div = document.createElement('div');
+      switch (tagName) {
+        case 'THEAD':
+        case 'TBODY':
+          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
+          depth = 2;
+          break;
+        case 'TR':
+          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
+          depth = 3;
+          break;
+        case 'TD':
+          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
+          depth = 4;
+      }
+      $A(element.childNodes).each(function(node){
+        element.removeChild(node)
+      });
+      depth.times(function(){ div = div.firstChild });
+
+      $A(div.childNodes).each(
+        function(node){ element.appendChild(node) });
+    } else {
+      element.innerHTML = html.stripScripts();
+    }
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  }
+};
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
+    var className = 'HTML' + tag + 'Element';
+    if(window[className]) return;
+    var klass = window[className] = {};
+    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
+  });
+
+Element.addMethods = function(methods) {
+  Object.extend(Element.Methods, methods || {});
+
+  function copy(methods, destination, onlyIfAbsent) {
+    onlyIfAbsent = onlyIfAbsent || false;
+    var cache = Element.extend.cache;
+    for (var property in methods) {
+      var value = methods[property];
+      if (!onlyIfAbsent || !(property in destination))
+        destination[property] = cache.findOrStore(value);
+    }
+  }
+
+  if (typeof HTMLElement != 'undefined') {
+    copy(Element.Methods, HTMLElement.prototype);
+    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+    copy(Form.Methods, HTMLFormElement.prototype);
+    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
+      copy(Form.Element.Methods, klass.prototype);
+    });
+    _nativeExtensions = true;
+  }
+}
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+  this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+  initialize: function(element, content) {
+    this.element = $(element);
+    this.content = content.stripScripts();
+
+    if (this.adjacency && this.element.insertAdjacentHTML) {
+      try {
+        this.element.insertAdjacentHTML(this.adjacency, this.content);
+      } catch (e) {
+        var tagName = this.element.tagName.toUpperCase();
+        if (['TBODY', 'TR'].include(tagName)) {
+          this.insertContent(this.contentFromAnonymousTable());
+        } else {
+          throw e;
+        }
+      }
+    } else {
+      this.range = this.element.ownerDocument.createRange();
+      if (this.initializeRange) this.initializeRange();
+      this.insertContent([this.range.createContextualFragment(this.content)]);
+    }
+
+    setTimeout(function() {content.evalScripts()}, 10);
+  },
+
+  contentFromAnonymousTable: function() {
+    var div = document.createElement('div');
+    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+    return $A(div.childNodes[0].childNodes[0].childNodes);
+  }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+  initializeRange: function() {
+    this.range.setStartBefore(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.parentNode.insertBefore(fragment, this.element);
+    }).bind(this));
+  }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(true);
+  },
+
+  insertContent: function(fragments) {
+    fragments.reverse(false).each((function(fragment) {
+      this.element.insertBefore(fragment, this.element.firstChild);
+    }).bind(this));
+  }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.appendChild(fragment);
+    }).bind(this));
+  }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+  initializeRange: function() {
+    this.range.setStartAfter(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.parentNode.insertBefore(fragment,
+        this.element.nextSibling);
+    }).bind(this));
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+  },
+
+  _each: function(iterator) {
+    this.element.className.split(/\s+/).select(function(name) {
+      return name.length > 0;
+    })._each(iterator);
+  },
+
+  set: function(className) {
+    this.element.className = className;
+  },
+
+  add: function(classNameToAdd) {
+    if (this.include(classNameToAdd)) return;
+    this.set($A(this).concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set($A(this).without(classNameToRemove).join(' '));
+  },
+
+  toString: function() {
+    return $A(this).join(' ');
+  }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Selector = Class.create();
+Selector.prototype = {
+  initialize: function(expression) {
+    this.params = {classNames: []};
+    this.expression = expression.toString().strip();
+    this.parseExpression();
+    this.compileMatcher();
+  },
+
+  parseExpression: function() {
+    function abort(message) { throw 'Parse error in selector: ' + message; }
+
+    if (this.expression == '')  abort('empty expression');
+
+    var params = this.params, expr = this.expression, match, modifier, clause, rest;
+    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+      params.attributes = params.attributes || [];
+      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+      expr = match[1];
+    }
+
+    if (expr == '*') return this.params.wildcard = true;
+
+    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
+      modifier = match[1], clause = match[2], rest = match[3];
+      switch (modifier) {
+        case '#':       params.id = clause; break;
+        case '.':       params.classNames.push(clause); break;
+        case '':
+        case undefined: params.tagName = clause.toUpperCase(); break;
+        default:        abort(expr.inspect());
+      }
+      expr = rest;
+    }
+
+    if (expr.length > 0) abort(expr.inspect());
+  },
+
+  buildMatchExpression: function() {
+    var params = this.params, conditions = [], clause;
+
+    if (params.wildcard)
+      conditions.push('true');
+    if (clause = params.id)
+      conditions.push('element.readAttribute("id") == ' + clause.inspect());
+    if (clause = params.tagName)
+      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+    if ((clause = params.classNames).length > 0)
+      for (var i = 0, length = clause.length; i < length; i++)
+        conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
+    if (clause = params.attributes) {
+      clause.each(function(attribute) {
+        var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
+        var splitValueBy = function(delimiter) {
+          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+        }
+
+        switch (attribute.operator) {
+          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
+          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
+          case '|=':      conditions.push(
+                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
+                          ); break;
+          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
+          case '':
+          case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
+          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
+        }
+      });
+    }
+
+    return conditions.join(' && ');
+  },
+
+  compileMatcher: function() {
+    this.match = new Function('element', 'if (!element.tagName) return false; \
+      element = $(element); \
+      return ' + this.buildMatchExpression());
+  },
+
+  findElements: function(scope) {
+    var element;
+
+    if (element = $(this.params.id))
+      if (this.match(element))
+        if (!scope || Element.childOf(element, scope))
+          return [element];
+
+    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+    var results = [];
+    for (var i = 0, length = scope.length; i < length; i++)
+      if (this.match(element = scope[i]))
+        results.push(Element.extend(element));
+
+    return results;
+  },
+
+  toString: function() {
+    return this.expression;
+  }
+}
+
+Object.extend(Selector, {
+  matchElements: function(elements, expression) {
+    var selector = new Selector(expression);
+    return elements.select(selector.match.bind(selector)).map(Element.extend);
+  },
+
+  findElement: function(elements, expression, index) {
+    if (typeof expression == 'number') index = expression, expression = false;
+    return Selector.matchElements(elements, expression || '*')[index || 0];
+  },
+
+  findChildElements: function(element, expressions) {
+    return expressions.map(function(expression) {
+      return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
+        var selector = new Selector(expr);
+        return results.inject([], function(elements, result) {
+          return elements.concat(selector.findElements(result || element));
+        });
+      });
+    }).flatten();
+  }
+});
+
+function $$() {
+  return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+  reset: function(form) {
+    $(form).reset();
+    return form;
+  },
+
+  serializeElements: function(elements, getHash) {
+    var data = elements.inject({}, function(result, element) {
+      if (!element.disabled && element.name) {
+        var key = element.name, value = $(element).getValue();
+        if (value != undefined) {
+          if (result[key]) {
+            if (result[key].constructor != Array) result[key] = [result[key]];
+            result[key].push(value);
+          }
+          else result[key] = value;
+        }
+      }
+      return result;
+    });
+
+    return getHash ? data : Hash.toQueryString(data);
+  }
+};
+
+Form.Methods = {
+  serialize: function(form, getHash) {
+    return Form.serializeElements(Form.getElements(form), getHash);
+  },
+
+  getElements: function(form) {
+    return $A($(form).getElementsByTagName('*')).inject([],
+      function(elements, child) {
+        if (Form.Element.Serializers[child.tagName.toLowerCase()])
+          elements.push(Element.extend(child));
+        return elements;
+      }
+    );
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) || (name && input.name != name))
+        continue;
+      matchingInputs.push(Element.extend(input));
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    form = $(form);
+    form.getElements().each(function(element) {
+      element.blur();
+      element.disabled = 'true';
+    });
+    return form;
+  },
+
+  enable: function(form) {
+    form = $(form);
+    form.getElements().each(function(element) {
+      element.disabled = '';
+    });
+    return form;
+  },
+
+  findFirstElement: function(form) {
+    return $(form).getElements().find(function(element) {
+      return element.type != 'hidden' && !element.disabled &&
+        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+    });
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    form.findFirstElement().activate();
+    return form;
+  }
+}
+
+Object.extend(Form, Form.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+  focus: function(element) {
+    $(element).focus();
+    return element;
+  },
+
+  select: function(element) {
+    $(element).select();
+    return element;
+  }
+}
+
+Form.Element.Methods = {
+  serialize: function(element) {
+    element = $(element);
+    if (!element.disabled && element.name) {
+      var value = element.getValue();
+      if (value != undefined) {
+        var pair = {};
+        pair[element.name] = value;
+        return Hash.toQueryString(pair);
+      }
+    }
+    return '';
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    return Form.Element.Serializers[method](element);
+  },
+
+  clear: function(element) {
+    $(element).value = '';
+    return element;
+  },
+
+  present: function(element) {
+    return $(element).value != '';
+  },
+
+  activate: function(element) {
+    element = $(element);
+    element.focus();
+    if (element.select && ( element.tagName.toLowerCase() != 'input' ||
+      !['button', 'reset', 'submit'].include(element.type) ) )
+      element.select();
+    return element;
+  },
+
+  disable: function(element) {
+    element = $(element);
+    element.disabled = true;
+    return element;
+  },
+
+  enable: function(element) {
+    element = $(element);
+    element.blur();
+    element.disabled = false;
+    return element;
+  }
+}
+
+Object.extend(Form.Element, Form.Element.Methods);
+var Field = Form.Element;
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+  input: function(element) {
+    switch (element.type.toLowerCase()) {
+      case 'checkbox':
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element);
+      default:
+        return Form.Element.Serializers.textarea(element);
+    }
+  },
+
+  inputSelector: function(element) {
+    return element.checked ? element.value : null;
+  },
+
+  textarea: function(element) {
+    return element.value;
+  },
+
+  select: function(element) {
+    return this[element.type == 'select-one' ?
+      'selectOne' : 'selectMany'](element);
+  },
+
+  selectOne: function(element) {
+    var index = element.selectedIndex;
+    return index >= 0 ? this.optionValue(element.options[index]) : null;
+  },
+
+  selectMany: function(element) {
+    var values, length = element.length;
+    if (!length) return null;
+
+    for (var i = 0, values = []; i < length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) values.push(this.optionValue(opt));
+    }
+    return values;
+  },
+
+  optionValue: function(opt) {
+    // extend element because hasAttribute may not be native
+    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+  initialize: function(element, frequency, callback) {
+    this.frequency = frequency;
+    this.element   = $(element);
+    this.callback  = callback;
+
+    this.lastValue = this.getValue();
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    var value = this.getValue();
+    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
+      ? this.lastValue != value : String(this.lastValue) != String(value));
+    if (changed) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+  initialize: function(element, callback) {
+    this.element  = $(element);
+    this.callback = callback;
+
+    this.lastValue = this.getValue();
+    if (this.element.tagName.toLowerCase() == 'form')
+      this.registerFormCallbacks();
+    else
+      this.registerCallback(this.element);
+  },
+
+  onElementEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    Form.getElements(this.element).each(this.registerCallback.bind(this));
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        default:
+          Event.observe(element, 'change', this.onElementEvent.bind(this));
+          break;
+      }
+    }
+  }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+if (!window.Event) {
+  var Event = new Object();
+}
+
+Object.extend(Event, {
+  KEY_BACKSPACE: 8,
+  KEY_TAB:       9,
+  KEY_RETURN:   13,
+  KEY_ESC:      27,
+  KEY_LEFT:     37,
+  KEY_UP:       38,
+  KEY_RIGHT:    39,
+  KEY_DOWN:     40,
+  KEY_DELETE:   46,
+  KEY_HOME:     36,
+  KEY_END:      35,
+  KEY_PAGEUP:   33,
+  KEY_PAGEDOWN: 34,
+
+  element: function(event) {
+    return event.target || event.srcElement;
+  },
+
+  isLeftClick: function(event) {
+    return (((event.which) && (event.which == 1)) ||
+            ((event.button) && (event.button == 1)));
+  },
+
+  pointerX: function(event) {
+    return event.pageX || (event.clientX +
+      (document.documentElement.scrollLeft || document.body.scrollLeft));
+  },
+
+  pointerY: function(event) {
+    return event.pageY || (event.clientY +
+      (document.documentElement.scrollTop || document.body.scrollTop));
+  },
+
+  stop: function(event) {
+    if (event.preventDefault) {
+      event.preventDefault();
+      event.stopPropagation();
+    } else {
+      event.returnValue = false;
+      event.cancelBubble = true;
+    }
+  },
+
+  // find the first node with the given tagName, starting from the
+  // node the event was triggered on; traverses the DOM upwards
+  findElement: function(event, tagName) {
+    var element = Event.element(event);
+    while (element.parentNode && (!element.tagName ||
+        (element.tagName.toUpperCase() != tagName.toUpperCase())))
+      element = element.parentNode;
+    return element;
+  },
+
+  observers: false,
+
+  _observeAndCache: function(element, name, observer, useCapture) {
+    if (!this.observers) this.observers = [];
+    if (element.addEventListener) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.addEventListener(name, observer, useCapture);
+    } else if (element.attachEvent) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.attachEvent('on' + name, observer);
+    }
+  },
+
+  unloadCache: function() {
+    if (!Event.observers) return;
+    for (var i = 0, length = Event.observers.length; i < length; i++) {
+      Event.stopObserving.apply(this, Event.observers[i]);
+      Event.observers[i][0] = null;
+    }
+    Event.observers = false;
+  },
+
+  observe: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+        || element.attachEvent))
+      name = 'keydown';
+
+    Event._observeAndCache(element, name, observer, useCapture);
+  },
+
+  stopObserving: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+        || element.detachEvent))
+      name = 'keydown';
+
+    if (element.removeEventListener) {
+      element.removeEventListener(name, observer, useCapture);
+    } else if (element.detachEvent) {
+      try {
+        element.detachEvent('on' + name, observer);
+      } catch (e) {}
+    }
+  }
+});
+
+/* prevent memory leaks in IE */
+if (navigator.appVersion.match(/\bMSIE\b/))
+  Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+  // set to true if needed, warning: firefox performance problems
+  // NOT neeeded for page scrolling, only if draggable contained in
+  // scrollable elements
+  includeScrollOffsets: false,
+
+  // must be called before calling withinIncludingScrolloffset, every time the
+  // page is scrolled
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  realOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  cumulativeOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  positionedOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+      if (element) {
+        if(element.tagName=='BODY') break;
+        var p = Element.getStyle(element, 'position');
+        if (p == 'relative' || p == 'absolute') break;
+      }
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  offsetParent: function(element) {
+    if (element.offsetParent) return element.offsetParent;
+    if (element == document.body) return element;
+
+    while ((element = element.parentNode) && element != document.body)
+      if (Element.getStyle(element, 'position') != 'static')
+        return element;
+
+    return document.body;
+  },
+
+  // caches x/y coordinate pair to use with overlap
+  within: function(element, x, y) {
+    if (this.includeScrollOffsets)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = this.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = this.realOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = this.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            this.xcomp >= this.offset[0] &&
+            this.xcomp <  this.offset[0] + element.offsetWidth);
+  },
+
+  // within must be called directly before
+  overlap: function(mode, element) {
+    if (!mode) return 0;
+    if (mode == 'vertical')
+      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+  page: function(forElement) {
+    var valueT = 0, valueL = 0;
+
+    var element = forElement;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+
+      // Safari fix
+      if (element.offsetParent==document.body)
+        if (Element.getStyle(element,'position')=='absolute') break;
+
+    } while (element = element.offsetParent);
+
+    element = forElement;
+    do {
+      if (!window.opera || element.tagName=='BODY') {
+        valueT -= element.scrollTop  || 0;
+        valueL -= element.scrollLeft || 0;
+      }
+    } while (element = element.parentNode);
+
+    return [valueL, valueT];
+  },
+
+  clone: function(source, target) {
+    var options = Object.extend({
+      setLeft:    true,
+      setTop:     true,
+      setWidth:   true,
+      setHeight:  true,
+      offsetTop:  0,
+      offsetLeft: 0
+    }, arguments[2] || {})
+
+    // find page position of source
+    source = $(source);
+    var p = Position.page(source);
+
+    // find coordinate system to use
+    target = $(target);
+    var delta = [0, 0];
+    var parent = null;
+    // delta [0,0] will do fine with position: fixed elements,
+    // position:absolute needs offsetParent deltas
+    if (Element.getStyle(target,'position') == 'absolute') {
+      parent = Position.offsetParent(target);
+      delta = Position.page(parent);
+    }
+
+    // correct by body offsets (fixes Safari)
+    if (parent == document.body) {
+      delta[0] -= document.body.offsetLeft;
+      delta[1] -= document.body.offsetTop;
+    }
+
+    // set position
+    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
+    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
+    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
+    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+  },
+
+  absolutize: function(element) {
+    element = $(element);
+    if (element.style.position == 'absolute') return;
+    Position.prepare();
+
+    var offsets = Position.positionedOffset(element);
+    var top     = offsets[1];
+    var left    = offsets[0];
+    var width   = element.clientWidth;
+    var height  = element.clientHeight;
+
+    element._originalLeft   = left - parseFloat(element.style.left  || 0);
+    element._originalTop    = top  - parseFloat(element.style.top || 0);
+    element._originalWidth  = element.style.width;
+    element._originalHeight = element.style.height;
+
+    element.style.position = 'absolute';
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.width  = width + 'px';
+    element.style.height = height + 'px';
+  },
+
+  relativize: function(element) {
+    element = $(element);
+    if (element.style.position == 'relative') return;
+    Position.prepare();
+
+    element.style.position = 'relative';
+    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
+    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.height = element._originalHeight;
+    element.style.width  = element._originalWidth;
+  }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned.  For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+  Position.cumulativeOffset = function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      if (element.offsetParent == document.body)
+        if (Element.getStyle(element, 'position') == 'absolute') break;
+
+      element = element.offsetParent;
+    } while (element);
+
+    return [valueL, valueT];
+  }
+}
+
+Element.addMethods();
+
+
+// ------------------------------------------------------------------------
+// ------------------------------------------------------------------------
+
+// The rest of this file is the actual ray tracer written by Adam
+// Burmister. It's a concatenation of the following files:
+//
+//   flog/color.js
+//   flog/light.js
+//   flog/vector.js
+//   flog/ray.js
+//   flog/scene.js
+//   flog/material/basematerial.js
+//   flog/material/solid.js
+//   flog/material/chessboard.js
+//   flog/shape/baseshape.js
+//   flog/shape/sphere.js
+//   flog/shape/plane.js
+//   flog/intersectioninfo.js
+//   flog/camera.js
+//   flog/background.js
+//   flog/engine.js
+
+
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Color = Class.create();
+
+Flog.RayTracer.Color.prototype = {
+    red : 0.0,
+    green : 0.0,
+    blue : 0.0,
+
+    initialize : function(r, g, b) {
+        if(!r) r = 0.0;
+        if(!g) g = 0.0;
+        if(!b) b = 0.0;
+
+        this.red = r;
+        this.green = g;
+        this.blue = b;
+    },
+
+    add : function(c1, c2){
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red + c2.red;
+        result.green = c1.green + c2.green;
+        result.blue = c1.blue + c2.blue;
+
+        return result;
+    },
+
+    addScalar: function(c1, s){
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red + s;
+        result.green = c1.green + s;
+        result.blue = c1.blue + s;
+
+        result.limit();
+
+        return result;
+    },
+
+    subtract: function(c1, c2){
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red - c2.red;
+        result.green = c1.green - c2.green;
+        result.blue = c1.blue - c2.blue;
+
+        return result;
+    },
+
+    multiply : function(c1, c2) {
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red * c2.red;
+        result.green = c1.green * c2.green;
+        result.blue = c1.blue * c2.blue;
+
+        return result;
+    },
+
+    multiplyScalar : function(c1, f) {
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red * f;
+        result.green = c1.green * f;
+        result.blue = c1.blue * f;
+
+        return result;
+    },
+
+    divideFactor : function(c1, f) {
+        var result = new Flog.RayTracer.Color(0,0,0);
+
+        result.red = c1.red / f;
+        result.green = c1.green / f;
+        result.blue = c1.blue / f;
+
+        return result;
+    },
+
+    limit: function(){
+        this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0;
+        this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0;
+        this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0;
+    },
+
+    distance : function(color) {
+        var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue);
+        return d;
+    },
+
+    blend: function(c1, c2, w){
+        var result = new Flog.RayTracer.Color(0,0,0);
+        result = Flog.RayTracer.Color.prototype.add(
+                    Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w),
+                    Flog.RayTracer.Color.prototype.multiplyScalar(c2, w)
+                  );
+        return result;
+    },
+
+    brightness : function() {
+        var r = Math.floor(this.red*255);
+        var g = Math.floor(this.green*255);
+        var b = Math.floor(this.blue*255);
+        return (r * 77 + g * 150 + b * 29) >> 8;
+    },
+
+    toString : function () {
+        var r = Math.floor(this.red*255);
+        var g = Math.floor(this.green*255);
+        var b = Math.floor(this.blue*255);
+
+        return "rgb("+ r +","+ g +","+ b +")";
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Light = Class.create();
+
+Flog.RayTracer.Light.prototype = {
+    position: null,
+    color: null,
+    intensity: 10.0,
+
+    initialize : function(pos, color, intensity) {
+        this.position = pos;
+        this.color = color;
+        this.intensity = (intensity ? intensity : 10.0);
+    },
+
+    getIntensity: function(distance){
+        if(distance >= intensity) return 0;
+
+        return Math.pow((intensity - distance) / strength, 0.2);
+    },
+
+    toString : function () {
+        return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Vector = Class.create();
+
+Flog.RayTracer.Vector.prototype = {
+    x : 0.0,
+    y : 0.0,
+    z : 0.0,
+
+    initialize : function(x, y, z) {
+        this.x = (x ? x : 0);
+        this.y = (y ? y : 0);
+        this.z = (z ? z : 0);
+    },
+
+    copy: function(vector){
+        this.x = vector.x;
+        this.y = vector.y;
+        this.z = vector.z;
+    },
+
+    normalize : function() {
+        var m = this.magnitude();
+        return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m);
+    },
+
+    magnitude : function() {
+        return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
+    },
+
+    cross : function(w) {
+        return new Flog.RayTracer.Vector(
+                                            -this.z * w.y + this.y * w.z,
+                                           this.z * w.x - this.x * w.z,
+                                          -this.y * w.x + this.x * w.y);
+    },
+
+    dot : function(w) {
+        return this.x * w.x + this.y * w.y + this.z * w.z;
+    },
+
+    add : function(v, w) {
+        return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z);
+    },
+
+    subtract : function(v, w) {
+        if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']';
+        return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z);
+    },
+
+    multiplyVector : function(v, w) {
+        return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z);
+    },
+
+    multiplyScalar : function(v, w) {
+        return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w);
+    },
+
+    toString : function () {
+        return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Ray = Class.create();
+
+Flog.RayTracer.Ray.prototype = {
+    position : null,
+    direction : null,
+    initialize : function(pos, dir) {
+        this.position = pos;
+        this.direction = dir;
+    },
+
+    toString : function () {
+        return 'Ray [' + this.position + ',' + this.direction + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Scene = Class.create();
+
+Flog.RayTracer.Scene.prototype = {
+    camera : null,
+    shapes : [],
+    lights : [],
+    background : null,
+
+    initialize : function() {
+        this.camera = new Flog.RayTracer.Camera(
+            new Flog.RayTracer.Vector(0,0,-5),
+            new Flog.RayTracer.Vector(0,0,1),
+            new Flog.RayTracer.Vector(0,1,0)
+        );
+        this.shapes = new Array();
+        this.lights = new Array();
+        this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2);
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {};
+
+Flog.RayTracer.Material.BaseMaterial = Class.create();
+
+Flog.RayTracer.Material.BaseMaterial.prototype = {
+
+    gloss: 2.0,             // [0...infinity] 0 = matt
+    transparency: 0.0,      // 0=opaque
+    reflection: 0.0,        // [0...infinity] 0 = no reflection
+    refraction: 0.50,
+    hasTexture: false,
+
+    initialize : function() {
+
+    },
+
+    getColor: function(u, v){
+
+    },
+
+    wrapUp: function(t){
+        t = t % 2.0;
+        if(t < -1) t += 2.0;
+        if(t >= 1) t -= 2.0;
+        return t;
+    },
+
+    toString : function () {
+        return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Material.Solid = Class.create();
+
+Flog.RayTracer.Material.Solid.prototype = Object.extend(
+    new Flog.RayTracer.Material.BaseMaterial(), {
+        initialize : function(color, reflection, refraction, transparency, gloss) {
+            this.color = color;
+            this.reflection = reflection;
+            this.transparency = transparency;
+            this.gloss = gloss;
+            this.hasTexture = false;
+        },
+
+        getColor: function(u, v){
+            return this.color;
+        },
+
+        toString : function () {
+            return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
+        }
+    }
+);
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Material.Chessboard = Class.create();
+
+Flog.RayTracer.Material.Chessboard.prototype = Object.extend(
+    new Flog.RayTracer.Material.BaseMaterial(), {
+        colorEven: null,
+        colorOdd: null,
+        density: 0.5,
+
+        initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) {
+            this.colorEven = colorEven;
+            this.colorOdd = colorOdd;
+            this.reflection = reflection;
+            this.transparency = transparency;
+            this.gloss = gloss;
+            this.density = density;
+            this.hasTexture = true;
+        },
+
+        getColor: function(u, v){
+            var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density);
+
+            if(t < 0.0)
+                return this.colorEven;
+            else
+                return this.colorOdd;
+        },
+
+        toString : function () {
+            return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
+        }
+    }
+);
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
+
+Flog.RayTracer.Shape.BaseShape = Class.create();
+
+Flog.RayTracer.Shape.BaseShape.prototype = {
+    position: null,
+    material: null,
+
+    initialize : function() {
+        this.position = new Vector(0,0,0);
+        this.material = new Flog.RayTracer.Material.SolidMaterial(
+            new Flog.RayTracer.Color(1,0,1),
+            0,
+            0,
+            0
+        );
+    },
+
+    toString : function () {
+        return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
+
+Flog.RayTracer.Shape.Sphere = Class.create();
+
+Flog.RayTracer.Shape.Sphere.prototype = {
+    initialize : function(pos, radius, material) {
+        this.radius = radius;
+        this.position = pos;
+        this.material = material;
+    },
+
+    intersect: function(ray){
+        var info = new Flog.RayTracer.IntersectionInfo();
+        info.shape = this;
+
+        var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position);
+
+        var B = dst.dot(ray.direction);
+        var C = dst.dot(dst) - (this.radius * this.radius);
+        var D = (B * B) - C;
+
+        if(D > 0){ // intersection!
+            info.isHit = true;
+            info.distance = (-B) - Math.sqrt(D);
+            info.position = Flog.RayTracer.Vector.prototype.add(
+                                                ray.position,
+                                                Flog.RayTracer.Vector.prototype.multiplyScalar(
+                                                    ray.direction,
+                                                    info.distance
+                                                )
+                                            );
+            info.normal = Flog.RayTracer.Vector.prototype.subtract(
+                                            info.position,
+                                            this.position
+                                        ).normalize();
+
+            info.color = this.material.getColor(0,0);
+        } else {
+            info.isHit = false;
+        }
+        return info;
+    },
+
+    toString : function () {
+        return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
+
+Flog.RayTracer.Shape.Plane = Class.create();
+
+Flog.RayTracer.Shape.Plane.prototype = {
+    d: 0.0,
+
+    initialize : function(pos, d, material) {
+        this.position = pos;
+        this.d = d;
+        this.material = material;
+    },
+
+    intersect: function(ray){
+        var info = new Flog.RayTracer.IntersectionInfo();
+
+        var Vd = this.position.dot(ray.direction);
+        if(Vd == 0) return info; // no intersection
+
+        var t = -(this.position.dot(ray.position) + this.d) / Vd;
+        if(t <= 0) return info;
+
+        info.shape = this;
+        info.isHit = true;
+        info.position = Flog.RayTracer.Vector.prototype.add(
+                                            ray.position,
+                                            Flog.RayTracer.Vector.prototype.multiplyScalar(
+                                                ray.direction,
+                                                t
+                                            )
+                                        );
+        info.normal = this.position;
+        info.distance = t;
+
+        if(this.material.hasTexture){
+            var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x);
+            var vV = vU.cross(this.position);
+            var u = info.position.dot(vU);
+            var v = info.position.dot(vV);
+            info.color = this.material.getColor(u,v);
+        } else {
+            info.color = this.material.getColor(0,0);
+        }
+
+        return info;
+    },
+
+    toString : function () {
+        return 'Plane [' + this.position + ', d=' + this.d + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.IntersectionInfo = Class.create();
+
+Flog.RayTracer.IntersectionInfo.prototype = {
+    isHit: false,
+    hitCount: 0,
+    shape: null,
+    position: null,
+    normal: null,
+    color: null,
+    distance: null,
+
+    initialize : function() {
+        this.color = new Flog.RayTracer.Color(0,0,0);
+    },
+
+    toString : function () {
+        return 'Intersection [' + this.position + ']';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Camera = Class.create();
+
+Flog.RayTracer.Camera.prototype = {
+    position: null,
+    lookAt: null,
+    equator: null,
+    up: null,
+    screen: null,
+
+    initialize : function(pos, lookAt, up) {
+        this.position = pos;
+        this.lookAt = lookAt;
+        this.up = up;
+        this.equator = lookAt.normalize().cross(this.up);
+        this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt);
+    },
+
+    getRay: function(vx, vy){
+        var pos = Flog.RayTracer.Vector.prototype.subtract(
+            this.screen,
+            Flog.RayTracer.Vector.prototype.subtract(
+                Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx),
+                Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy)
+            )
+        );
+        pos.y = pos.y * -1;
+        var dir = Flog.RayTracer.Vector.prototype.subtract(
+            pos,
+            this.position
+        );
+
+        var ray = new Flog.RayTracer.Ray(pos, dir.normalize());
+
+        return ray;
+    },
+
+    toString : function () {
+        return 'Ray []';
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Background = Class.create();
+
+Flog.RayTracer.Background.prototype = {
+    color : null,
+    ambience : 0.0,
+
+    initialize : function(color, ambience) {
+        this.color = color;
+        this.ambience = ambience;
+    }
+}
+/* Fake a Flog.* namespace */
+if(typeof(Flog) == 'undefined') var Flog = {};
+if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
+
+Flog.RayTracer.Engine = Class.create();
+
+Flog.RayTracer.Engine.prototype = {
+    canvas: null, /* 2d context we can render to */
+
+    initialize: function(options){
+        this.options = Object.extend({
+                canvasHeight: 100,
+                canvasWidth: 100,
+                pixelWidth: 2,
+                pixelHeight: 2,
+                renderDiffuse: false,
+                renderShadows: false,
+                renderHighlights: false,
+                renderReflections: false,
+                rayDepth: 2
+            }, options || {});
+
+        this.options.canvasHeight /= this.options.pixelHeight;
+        this.options.canvasWidth /= this.options.pixelWidth;
+
+        /* TODO: dynamically include other scripts */
+    },
+
+    setPixel: function(x, y, color){
+        var pxW, pxH;
+        pxW = this.options.pixelWidth;
+        pxH = this.options.pixelHeight;
+
+        if (this.canvas) {
+          this.canvas.fillStyle = color.toString();
+          this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH);
+        } else {
+          if (x ===  y) {
+            checkNumber += color.brightness();
+          }
+          // print(x * pxW, y * pxH, pxW, pxH);
+        }
+    },
+
+    renderScene: function(scene, canvas){
+        checkNumber = 0;
+        /* Get canvas */
+        if (canvas) {
+          this.canvas = canvas.getContext("2d");
+        } else {
+          this.canvas = null;
+        }
+
+        var canvasHeight = this.options.canvasHeight;
+        var canvasWidth = this.options.canvasWidth;
+
+        for(var y=0; y < canvasHeight; y++){
+            for(var x=0; x < canvasWidth; x++){
+                var yp = y * 1.0 / canvasHeight * 2 - 1;
+                       var xp = x * 1.0 / canvasWidth * 2 - 1;
+
+                       var ray = scene.camera.getRay(xp, yp);
+
+                       var color = this.getPixelColor(ray, scene);
+
+               this.setPixel(x, y, color);
+            }
+        }
+        if (checkNumber !== 2321) {
+          throw new Error("Scene rendered incorrectly");
+        }
+    },
+
+    getPixelColor: function(ray, scene){
+        var info = this.testIntersection(ray, scene, null);
+        if(info.isHit){
+            var color = this.rayTrace(info, ray, scene, 0);
+            return color;
+        }
+        return scene.background.color;
+    },
+
+    testIntersection: function(ray, scene, exclude){
+        var hits = 0;
+        var best = new Flog.RayTracer.IntersectionInfo();
+        best.distance = 2000;
+
+        for(var i=0; i<scene.shapes.length; i++){
+            var shape = scene.shapes[i];
+
+            if(shape != exclude){
+                var info = shape.intersect(ray);
+                if(info.isHit && info.distance >= 0 && info.distance < best.distance){
+                    best = info;
+                    hits++;
+                }
+            }
+        }
+        best.hitCount = hits;
+        return best;
+    },
+
+    getReflectionRay: function(P,N,V){
+        var c1 = -N.dot(V);
+        var R1 = Flog.RayTracer.Vector.prototype.add(
+            Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1),
+            V
+        );
+        return new Flog.RayTracer.Ray(P, R1);
+    },
+
+    rayTrace: function(info, ray, scene, depth){
+        // Calc ambient
+        var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience);
+        var oldColor = color;
+        var shininess = Math.pow(10, info.shape.material.gloss + 1);
+
+        for(var i=0; i<scene.lights.length; i++){
+            var light = scene.lights[i];
+
+            // Calc diffuse lighting
+            var v = Flog.RayTracer.Vector.prototype.subtract(
+                                light.position,
+                                info.position
+                            ).normalize();
+
+            if(this.options.renderDiffuse){
+                var L = v.dot(info.normal);
+                if(L > 0.0){
+                    color = Flog.RayTracer.Color.prototype.add(
+                                        color,
+                                        Flog.RayTracer.Color.prototype.multiply(
+                                            info.color,
+                                            Flog.RayTracer.Color.prototype.multiplyScalar(
+                                                light.color,
+                                                L
+                                            )
+                                        )
+                                    );
+                }
+            }
+
+            // The greater the depth the more accurate the colours, but
+            // this is exponentially (!) expensive
+            if(depth <= this.options.rayDepth){
+          // calculate reflection ray
+          if(this.options.renderReflections && info.shape.material.reflection > 0)
+          {
+              var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction);
+              var refl = this.testIntersection(reflectionRay, scene, info.shape);
+
+              if (refl.isHit && refl.distance > 0){
+                  refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);
+              } else {
+                  refl.color = scene.background.color;
+                        }
+
+                  color = Flog.RayTracer.Color.prototype.blend(
+                    color,
+                    refl.color,
+                    info.shape.material.reflection
+                  );
+          }
+
+                // Refraction
+                /* TODO */
+            }
+
+            /* Render shadows and highlights */
+
+            var shadowInfo = new Flog.RayTracer.IntersectionInfo();
+
+            if(this.options.renderShadows){
+                var shadowRay = new Flog.RayTracer.Ray(info.position, v);
+
+                shadowInfo = this.testIntersection(shadowRay, scene, info.shape);
+                if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){
+                    var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5);
+                    var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5));
+                    color = Flog.RayTracer.Color.prototype.addScalar(vA,dB);
+                }
+            }
+
+      // Phong specular highlights
+      if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){
+        var Lv = Flog.RayTracer.Vector.prototype.subtract(
+                            info.shape.position,
+                            light.position
+                        ).normalize();
+
+        var E = Flog.RayTracer.Vector.prototype.subtract(
+                            scene.camera.position,
+                            info.shape.position
+                        ).normalize();
+
+        var H = Flog.RayTracer.Vector.prototype.subtract(
+                            E,
+                            Lv
+                        ).normalize();
+
+        var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess);
+        color = Flog.RayTracer.Color.prototype.add(
+                            Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight),
+                            color
+                        );
+      }
+        }
+        color.limit();
+        return color;
+    }
+};
+
+
+function renderScene(){
+    var scene = new Flog.RayTracer.Scene();
+
+    scene.camera = new Flog.RayTracer.Camera(
+                        new Flog.RayTracer.Vector(0, 0, -15),
+                        new Flog.RayTracer.Vector(-0.2, 0, 5),
+                        new Flog.RayTracer.Vector(0, 1, 0)
+                    );
+
+    scene.background = new Flog.RayTracer.Background(
+                                new Flog.RayTracer.Color(0.5, 0.5, 0.5),
+                                0.4
+                            );
+
+    var sphere = new Flog.RayTracer.Shape.Sphere(
+        new Flog.RayTracer.Vector(-1.5, 1.5, 2),
+        1.5,
+        new Flog.RayTracer.Material.Solid(
+            new Flog.RayTracer.Color(0,0.5,0.5),
+            0.3,
+            0.0,
+            0.0,
+            2.0
+        )
+    );
+
+    var sphere1 = new Flog.RayTracer.Shape.Sphere(
+        new Flog.RayTracer.Vector(1, 0.25, 1),
+        0.5,
+        new Flog.RayTracer.Material.Solid(
+            new Flog.RayTracer.Color(0.9,0.9,0.9),
+            0.1,
+            0.0,
+            0.0,
+            1.5
+        )
+    );
+
+    var plane = new Flog.RayTracer.Shape.Plane(
+                                new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(),
+                                1.2,
+                                new Flog.RayTracer.Material.Chessboard(
+                                    new Flog.RayTracer.Color(1,1,1),
+                                    new Flog.RayTracer.Color(0,0,0),
+                                    0.2,
+                                    0.0,
+                                    1.0,
+                                    0.7
+                                )
+                            );
+
+    scene.shapes.push(plane);
+    scene.shapes.push(sphere);
+    scene.shapes.push(sphere1);
+
+    var light = new Flog.RayTracer.Light(
+        new Flog.RayTracer.Vector(5, 10, -1),
+        new Flog.RayTracer.Color(0.8, 0.8, 0.8)
+    );
+
+    var light1 = new Flog.RayTracer.Light(
+        new Flog.RayTracer.Vector(-3, 5, -15),
+        new Flog.RayTracer.Color(0.8, 0.8, 0.8),
+        100
+    );
+
+    scene.lights.push(light);
+    scene.lights.push(light1);
+
+    var imageWidth = 100; // $F('imageWidth');
+    var imageHeight = 100; // $F('imageHeight');
+    var pixelSize = "5,5".split(','); //  $F('pixelSize').split(',');
+    var renderDiffuse = true; // $F('renderDiffuse');
+    var renderShadows = true; // $F('renderShadows');
+    var renderHighlights = true; // $F('renderHighlights');
+    var renderReflections = true; // $F('renderReflections');
+    var rayDepth = 2;//$F('rayDepth');
+
+    var raytracer = new Flog.RayTracer.Engine(
+        {
+            canvasWidth: imageWidth,
+            canvasHeight: imageHeight,
+            pixelWidth: pixelSize[0],
+            pixelHeight: pixelSize[1],
+            "renderDiffuse": renderDiffuse,
+            "renderHighlights": renderHighlights,
+            "renderShadows": renderShadows,
+            "renderReflections": renderReflections,
+            "rayDepth": rayDepth
+        }
+    );
+
+    raytracer.renderScene(scene, null, 0);
+}
+
diff --git a/regexp2000/benchmarks/richards.js b/regexp2000/benchmarks/richards.js
new file mode 100644 (file)
index 0000000..bb88623
--- /dev/null
@@ -0,0 +1,539 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// This is a JavaScript implementation of the Richards
+// benchmark from:
+//
+//    http://www.cl.cam.ac.uk/~mr10/Bench.html
+// 
+// The benchmark was originally implemented in BCPL by
+// Martin Richards.
+
+
+var Richards = new BenchmarkSuite('Richards', 34886, [
+  new Benchmark("Richards", runRichards)
+]);
+
+
+/**
+ * The Richards benchmark simulates the task dispatcher of an
+ * operating system.
+ **/
+function runRichards() {
+  var scheduler = new Scheduler();
+  scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
+
+  var queue = new Packet(null, ID_WORKER, KIND_WORK);
+  queue = new Packet(queue,  ID_WORKER, KIND_WORK);
+  scheduler.addWorkerTask(ID_WORKER, 1000, queue);
+
+  queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
+  scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
+
+  queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
+  queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
+  scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
+
+  scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
+
+  scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
+
+  scheduler.schedule();
+
+  if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
+      scheduler.holdCount != EXPECTED_HOLD_COUNT) {
+    var msg =
+        "Error during execution: queueCount = " + scheduler.queueCount +
+        ", holdCount = " + scheduler.holdCount + ".";
+    throw new Error(msg);
+  }
+}
+
+var COUNT = 1000;
+
+/**
+ * These two constants specify how many times a packet is queued and
+ * how many times a task is put on hold in a correct run of richards.
+ * They don't have any meaning a such but are characteristic of a
+ * correct run so if the actual queue or hold count is different from
+ * the expected there must be a bug in the implementation.
+ **/
+var EXPECTED_QUEUE_COUNT = 2322;
+var EXPECTED_HOLD_COUNT = 928;
+
+
+/**
+ * A scheduler can be used to schedule a set of tasks based on their relative
+ * priorities.  Scheduling is done by maintaining a list of task control blocks
+ * which holds tasks and the data queue they are processing.
+ * @constructor
+ */
+function Scheduler() {
+  this.queueCount = 0;
+  this.holdCount = 0;
+  this.blocks = new Array(NUMBER_OF_IDS);
+  this.list = null;
+  this.currentTcb = null;
+  this.currentId = null;
+}
+
+var ID_IDLE       = 0;
+var ID_WORKER     = 1;
+var ID_HANDLER_A  = 2;
+var ID_HANDLER_B  = 3;
+var ID_DEVICE_A   = 4;
+var ID_DEVICE_B   = 5;
+var NUMBER_OF_IDS = 6;
+
+var KIND_DEVICE   = 0;
+var KIND_WORK     = 1;
+
+/**
+ * Add an idle task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {int} count the number of times to schedule the task
+ */
+Scheduler.prototype.addIdleTask = function (id, priority, queue, count) {
+  this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));
+};
+
+/**
+ * Add a work task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addWorkerTask = function (id, priority, queue) {
+  this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));
+};
+
+/**
+ * Add a handler task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addHandlerTask = function (id, priority, queue) {
+  this.addTask(id, priority, queue, new HandlerTask(this));
+};
+
+/**
+ * Add a handler task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addDeviceTask = function (id, priority, queue) {
+  this.addTask(id, priority, queue, new DeviceTask(this))
+};
+
+/**
+ * Add the specified task and mark it as running.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {Task} task the task to add
+ */
+Scheduler.prototype.addRunningTask = function (id, priority, queue, task) {
+  this.addTask(id, priority, queue, task);
+  this.currentTcb.setRunning();
+};
+
+/**
+ * Add the specified task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {Task} task the task to add
+ */
+Scheduler.prototype.addTask = function (id, priority, queue, task) {
+  this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task);
+  this.list = this.currentTcb;
+  this.blocks[id] = this.currentTcb;
+};
+
+/**
+ * Execute the tasks managed by this scheduler.
+ */
+Scheduler.prototype.schedule = function () {
+  this.currentTcb = this.list;
+  while (this.currentTcb != null) {
+    if (this.currentTcb.isHeldOrSuspended()) {
+      this.currentTcb = this.currentTcb.link;
+    } else {
+      this.currentId = this.currentTcb.id;
+      this.currentTcb = this.currentTcb.run();
+    }
+  }
+};
+
+/**
+ * Release a task that is currently blocked and return the next block to run.
+ * @param {int} id the id of the task to suspend
+ */
+Scheduler.prototype.release = function (id) {
+  var tcb = this.blocks[id];
+  if (tcb == null) return tcb;
+  tcb.markAsNotHeld();
+  if (tcb.priority > this.currentTcb.priority) {
+    return tcb;
+  } else {
+    return this.currentTcb;
+  }
+};
+
+/**
+ * Block the currently executing task and return the next task control block
+ * to run.  The blocked task will not be made runnable until it is explicitly
+ * released, even if new work is added to it.
+ */
+Scheduler.prototype.holdCurrent = function () {
+  this.holdCount++;
+  this.currentTcb.markAsHeld();
+  return this.currentTcb.link;
+};
+
+/**
+ * Suspend the currently executing task and return the next task control block
+ * to run.  If new work is added to the suspended task it will be made runnable.
+ */
+Scheduler.prototype.suspendCurrent = function () {
+  this.currentTcb.markAsSuspended();
+  return this.currentTcb;
+};
+
+/**
+ * Add the specified packet to the end of the worklist used by the task
+ * associated with the packet and make the task runnable if it is currently
+ * suspended.
+ * @param {Packet} packet the packet to add
+ */
+Scheduler.prototype.queue = function (packet) {
+  var t = this.blocks[packet.id];
+  if (t == null) return t;
+  this.queueCount++;
+  packet.link = null;
+  packet.id = this.currentId;
+  return t.checkPriorityAdd(this.currentTcb, packet);
+};
+
+/**
+ * A task control block manages a task and the queue of work packages associated
+ * with it.
+ * @param {TaskControlBlock} link the preceding block in the linked block list
+ * @param {int} id the id of this block
+ * @param {int} priority the priority of this block
+ * @param {Packet} queue the queue of packages to be processed by the task
+ * @param {Task} task the task
+ * @constructor
+ */
+function TaskControlBlock(link, id, priority, queue, task) {
+  this.link = link;
+  this.id = id;
+  this.priority = priority;
+  this.queue = queue;
+  this.task = task;
+  if (queue == null) {
+    this.state = STATE_SUSPENDED;
+  } else {
+    this.state = STATE_SUSPENDED_RUNNABLE;
+  }
+}
+
+/**
+ * The task is running and is currently scheduled.
+ */
+var STATE_RUNNING = 0;
+
+/**
+ * The task has packets left to process.
+ */
+var STATE_RUNNABLE = 1;
+
+/**
+ * The task is not currently running.  The task is not blocked as such and may
+* be started by the scheduler.
+ */
+var STATE_SUSPENDED = 2;
+
+/**
+ * The task is blocked and cannot be run until it is explicitly released.
+ */
+var STATE_HELD = 4;
+
+var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
+var STATE_NOT_HELD = ~STATE_HELD;
+
+TaskControlBlock.prototype.setRunning = function () {
+  this.state = STATE_RUNNING;
+};
+
+TaskControlBlock.prototype.markAsNotHeld = function () {
+  this.state = this.state & STATE_NOT_HELD;
+};
+
+TaskControlBlock.prototype.markAsHeld = function () {
+  this.state = this.state | STATE_HELD;
+};
+
+TaskControlBlock.prototype.isHeldOrSuspended = function () {
+  return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED);
+};
+
+TaskControlBlock.prototype.markAsSuspended = function () {
+  this.state = this.state | STATE_SUSPENDED;
+};
+
+TaskControlBlock.prototype.markAsRunnable = function () {
+  this.state = this.state | STATE_RUNNABLE;
+};
+
+/**
+ * Runs this task, if it is ready to be run, and returns the next task to run.
+ */
+TaskControlBlock.prototype.run = function () {
+  var packet;
+  if (this.state == STATE_SUSPENDED_RUNNABLE) {
+    packet = this.queue;
+    this.queue = packet.link;
+    if (this.queue == null) {
+      this.state = STATE_RUNNING;
+    } else {
+      this.state = STATE_RUNNABLE;
+    }
+  } else {
+    packet = null;
+  }
+  return this.task.run(packet);
+};
+
+/**
+ * Adds a packet to the worklist of this block's task, marks this as runnable if
+ * necessary, and returns the next runnable object to run (the one
+ * with the highest priority).
+ */
+TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {
+  if (this.queue == null) {
+    this.queue = packet;
+    this.markAsRunnable();
+    if (this.priority > task.priority) return this;
+  } else {
+    this.queue = packet.addTo(this.queue);
+  }
+  return task;
+};
+
+TaskControlBlock.prototype.toString = function () {
+  return "tcb { " + this.task + "@" + this.state + " }";
+};
+
+/**
+ * An idle task doesn't do any work itself but cycles control between the two
+ * device tasks.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @param {int} v1 a seed value that controls how the device tasks are scheduled
+ * @param {int} count the number of times this task should be scheduled
+ * @constructor
+ */
+function IdleTask(scheduler, v1, count) {
+  this.scheduler = scheduler;
+  this.v1 = v1;
+  this.count = count;
+}
+
+IdleTask.prototype.run = function (packet) {
+  this.count--;
+  if (this.count == 0) return this.scheduler.holdCurrent();
+  if ((this.v1 & 1) == 0) {
+    this.v1 = this.v1 >> 1;
+    return this.scheduler.release(ID_DEVICE_A);
+  } else {
+    this.v1 = (this.v1 >> 1) ^ 0xD008;
+    return this.scheduler.release(ID_DEVICE_B);
+  }
+};
+
+IdleTask.prototype.toString = function () {
+  return "IdleTask"
+};
+
+/**
+ * A task that suspends itself after each time it has been run to simulate
+ * waiting for data from an external device.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @constructor
+ */
+function DeviceTask(scheduler) {
+  this.scheduler = scheduler;
+  this.v1 = null;
+}
+
+DeviceTask.prototype.run = function (packet) {
+  if (packet == null) {
+    if (this.v1 == null) return this.scheduler.suspendCurrent();
+    var v = this.v1;
+    this.v1 = null;
+    return this.scheduler.queue(v);
+  } else {
+    this.v1 = packet;
+    return this.scheduler.holdCurrent();
+  }
+};
+
+DeviceTask.prototype.toString = function () {
+  return "DeviceTask";
+};
+
+/**
+ * A task that manipulates work packets.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @param {int} v1 a seed used to specify how work packets are manipulated
+ * @param {int} v2 another seed used to specify how work packets are manipulated
+ * @constructor
+ */
+function WorkerTask(scheduler, v1, v2) {
+  this.scheduler = scheduler;
+  this.v1 = v1;
+  this.v2 = v2;
+}
+
+WorkerTask.prototype.run = function (packet) {
+  if (packet == null) {
+    return this.scheduler.suspendCurrent();
+  } else {
+    if (this.v1 == ID_HANDLER_A) {
+      this.v1 = ID_HANDLER_B;
+    } else {
+      this.v1 = ID_HANDLER_A;
+    }
+    packet.id = this.v1;
+    packet.a1 = 0;
+    for (var i = 0; i < DATA_SIZE; i++) {
+      this.v2++;
+      if (this.v2 > 26) this.v2 = 1;
+      packet.a2[i] = this.v2;
+    }
+    return this.scheduler.queue(packet);
+  }
+};
+
+WorkerTask.prototype.toString = function () {
+  return "WorkerTask";
+};
+
+/**
+ * A task that manipulates work packets and then suspends itself.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @constructor
+ */
+function HandlerTask(scheduler) {
+  this.scheduler = scheduler;
+  this.v1 = null;
+  this.v2 = null;
+}
+
+HandlerTask.prototype.run = function (packet) {
+  if (packet != null) {
+    if (packet.kind == KIND_WORK) {
+      this.v1 = packet.addTo(this.v1);
+    } else {
+      this.v2 = packet.addTo(this.v2);
+    }
+  }
+  if (this.v1 != null) {
+    var count = this.v1.a1;
+    var v;
+    if (count < DATA_SIZE) {
+      if (this.v2 != null) {
+        v = this.v2;
+        this.v2 = this.v2.link;
+        v.a1 = this.v1.a2[count];
+        this.v1.a1 = count + 1;
+        return this.scheduler.queue(v);
+      }
+    } else {
+      v = this.v1;
+      this.v1 = this.v1.link;
+      return this.scheduler.queue(v);
+    }
+  }
+  return this.scheduler.suspendCurrent();
+};
+
+HandlerTask.prototype.toString = function () {
+  return "HandlerTask";
+};
+
+/* --- *
+ * P a c k e t
+ * --- */
+
+var DATA_SIZE = 4;
+
+/**
+ * A simple package of data that is manipulated by the tasks.  The exact layout
+ * of the payload data carried by a packet is not importaint, and neither is the
+ * nature of the work performed on packets by the tasks.
+ *
+ * Besides carrying data, packets form linked lists and are hence used both as
+ * data and worklists.
+ * @param {Packet} link the tail of the linked list of packets
+ * @param {int} id an ID for this packet
+ * @param {int} kind the type of this packet
+ * @constructor
+ */
+function Packet(link, id, kind) {
+  this.link = link;
+  this.id = id;
+  this.kind = kind;
+  this.a1 = 0;
+  this.a2 = new Array(DATA_SIZE);
+}
+
+/**
+ * Add this packet to the end of a worklist, and return the worklist.
+ * @param {Packet} queue the worklist to add this packet to
+ */
+Packet.prototype.addTo = function (queue) {
+  this.link = null;
+  if (queue == null) return this;
+  var peek, next = queue;
+  while ((peek = next.link) != null)
+    next = peek;
+  next.link = this;
+  return queue;
+};
+
+Packet.prototype.toString = function () {
+  return "Packet";
+};
diff --git a/regexp2000/benchmarks/run.html b/regexp2000/benchmarks/run.html
new file mode 100644 (file)
index 0000000..41e4f78
--- /dev/null
@@ -0,0 +1,171 @@
+<html>
+<head>
+<title>V8 Benchmark Suite</title>
+<script type="text/javascript" src="base.js"></script>
+<script type="text/javascript" src="richards.js"></script>
+<script type="text/javascript" src="deltablue.js"></script>
+<script type="text/javascript" src="crypto.js"></script>
+<script type="text/javascript" src="raytrace.js"></script>
+<script type="text/javascript" src="earley-boyer.js"></script>
+<style>
+body {
+  font-family: sans-serif;
+}
+
+hr{
+  border:1px solid;
+  border-color:#36C;
+  margin:1em 0
+}
+
+h1,h2,h3,h4{margin:0; margin-bottom:0}
+h1{font-size: 200%; height: 2em}
+h2{font-size: 140%; height: 2em}
+h3{font-size: 100%; height: 2em}
+
+li{
+  margin:.3em 0 1em 0;
+}
+
+body{
+  font-family: Helvetica,Arial,sans-serif;
+  font-size: small;
+  color: #000;
+  background-color: #fff;
+}
+
+div.title {
+  background-color: rgb(229, 236, 249);
+  border-top: 1px solid rgb(51, 102, 204);
+  text-align: center;
+  padding-top: 0.2em;
+  padding-bottom: 0.2em;
+  margin-bottom: 20px;
+}
+
+td.contents {
+  text-align: start;
+}
+
+div.run {
+  margin: 20px;
+  width: 300px;
+  height: 300px;
+  float: right;
+  background-color: rgb(229, 236, 249);
+  background-image: url(v8-logo.png);
+  background-position: center center;
+  background-repeat: no-repeat;
+  border: 1px solid rgb(51, 102, 204);
+}
+</style>
+
+<script type="text/javascript">
+var completed = 0;
+var benchmarks = BenchmarkSuite.CountBenchmarks();
+var success = true;
+
+function ShowProgress(name) {
+  var status = document.getElementById("status");
+  var percentage = ((++completed) / benchmarks) * 100;
+  status.innerHTML = "Running: " + Math.round(percentage) + "% completed.";
+}
+
+
+function AddResult(name, result) {
+  var text = name + ': ' + result;
+  var results = document.getElementById("results");
+  results.innerHTML += (text + "<br/>");  
+}
+
+
+function AddError(name, error) {
+  AddResult(name, '<b>error</b>');
+  success = false;
+}
+
+
+function AddScore(score) {
+  var status = document.getElementById("status");
+  if (success) {
+    status.innerHTML = "Score: " + score;
+  }
+}
+
+
+function Run() {
+  BenchmarkSuite.RunSuites({ NotifyStep: ShowProgress,
+                             NotifyError: AddError,
+                             NotifyResult: AddResult,
+                             NotifyScore: AddScore }); 
+}
+
+function Load() {
+  var version = BenchmarkSuite.version;
+  document.getElementById("version").innerHTML = version;
+  window.setTimeout(Run, 200);
+}
+</script>
+</head>
+<body onLoad="Load()">
+<div>
+  <div class="title"><h1>V8 Benchmark Suite - version <span id="version">?</span></h1></div>
+  <table>
+    <tr>
+      <td class="contents">
+This page contains a suite of pure JavaScript benchmarks that we have
+used to tune V8. The final score is computed as the geometric mean of
+the individual results to make it independent of the running times of
+the individual benchmarks and of a reference system (score
+100). Scores are not comparable across benchmark suite versions and
+higher scores means better performance: <em>Bigger is better!</em>
+
+<ul>
+<li><b>Richards</b><br/>OS kernel simulation benchmark, originally written in BCPL by Martin Richards (<i>539 lines</i>).</li>
+<li><b>DeltaBlue</b><br/>One-way constraint solver, originally written in Smalltalk by John Maloney and Mario Wolczko (<i>880 lines</i>).</li>
+<li><b>Crypto</b><br/>Encryption and decryption benchmark based on code by Tom Wu (<i>1689 lines</i>).</li>
+<li><b>RayTrace</b><br/>Ray tracer benchmark based on code by <a href="http://flog.co.nz/">Adam Burmister</a> (<i>3418 lines</i>).</li>
+<li><b>EarleyBoyer</b><br/>Classic Scheme benchmarks, translated to JavaScript by Florian Loitsch's Scheme2Js compiler (<i>4682 lines</i>).</li>
+</ul>
+
+<div class="title"><h2>Revisions of the benchmark suite</h2></div>
+
+<p><i>Please note that benchmark results are not comparable unless both
+results are run with the same revision of the benchmark suite.  We will be
+making revisions from time to time in order to fix bugs or expand the scope
+of the benchmark suite.</i></p>
+
+<div class="title"><h3>Version 1</h3></div>
+
+<p>Initial release.</p>
+
+<div class="title"><h3>Version 2</h3></div>
+
+<p>For version 2 the crypto benchmark was fixed.  Previously, the
+decryption stage was given plaintext as input, which resulted in an
+error.  Now, the decryption stage is given the output of the
+encryption stage as input.  The result is checked against the original
+plaintext.  For this to give the correct results the crypto objects
+are reset for each iteration of the benchmark.  In addition, the size
+of the plain text has been increased a little and the use of
+Math.random() and new Date() to build an RNG pool has been
+removed. </p>
+
+<p>Other benchmarks were fixed to do elementary verification of the
+results of their calculations.  This is to avoid accidentally
+obtaining scores that are the result of an incorrect JavaScript engine
+optimization.</p>
+
+
+</td><td style="text-align: center">
+<div class="run">
+  <div id="status" style="text-align: center; margin-top: 75px; font-size: 120%; font-weight: bold;">Starting...</div>
+  <div style="text-align: left; margin: 30px 0 0 90px;" id="results">
+  <div>
+</div>
+</td></tr></table>
+
+</div>
+
+</body>
+</html>
diff --git a/regexp2000/benchmarks/run.js b/regexp2000/benchmarks/run.js
new file mode 100644 (file)
index 0000000..da2373b
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+load('base.js');
+load('richards.js');
+load('deltablue.js');
+load('crypto.js');
+load('raytrace.js');
+load('earley-boyer.js');
+
+var success = true;
+
+function PrintResult(name, result) {
+  print(name + ': ' + result);
+}
+
+
+function PrintError(name, error) {
+  PrintResult(name, error);
+  success = false;
+}
+
+
+function PrintScore(score) {
+  if (success) {
+    print('----');
+    print('Score (version ' + BenchmarkSuite.version + '): ' + score);
+  }
+}
+
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+                           NotifyError: PrintError,
+                           NotifyScore: PrintScore });
diff --git a/regexp2000/benchmarks/v8-logo.png b/regexp2000/benchmarks/v8-logo.png
new file mode 100644 (file)
index 0000000..9186765
Binary files /dev/null and b/regexp2000/benchmarks/v8-logo.png differ
diff --git a/regexp2000/include/v8-debug.h b/regexp2000/include/v8-debug.h
new file mode 100644 (file)
index 0000000..f537d7d
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_DEBUG_H_
+#define V8_DEBUG_H_
+
+#include "v8.h"
+
+#ifdef _WIN32
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;  // NOLINT
+typedef long long int64_t;  // NOLINT
+
+// Setup for Windows DLL export/import. See v8.h in this directory for
+// information on how to build/use V8 as a DLL.
+#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED)
+#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\
+  build configuration to ensure that at most one of these is set
+#endif
+
+#ifdef BUILDING_V8_SHARED
+#define EXPORT __declspec(dllexport)
+#elif USING_V8_SHARED
+#define EXPORT __declspec(dllimport)
+#else
+#define EXPORT
+#endif
+
+#else  // _WIN32
+
+// Setup for Linux shared library export. See v8.h in this directory for
+// information on how to build/use V8 as shared library.
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define EXPORT __attribute__ ((visibility("default")))
+#else  // defined(__GNUC__) && (__GNUC__ >= 4)
+#define EXPORT
+#endif  // defined(__GNUC__) && (__GNUC__ >= 4)
+
+#endif  // _WIN32
+
+
+/**
+ * Debugger support for the V8 JavaScript engine.
+ */
+namespace v8 {
+
+// Debug events which can occur in the V8 JavaScript engine.
+enum DebugEvent {
+  Break = 1,
+  Exception = 2,
+  NewFunction = 3,
+  BeforeCompile = 4,
+  AfterCompile  = 5
+};
+
+
+/**
+ * Debug event callback function.
+ *
+ * \param event the debug event from which occoured (from the DebugEvent
+ *              enumeration)
+ * \param exec_state execution state (JavaScript object)
+ * \param event_data event specific data (JavaScript object)
+ * \param data value passed by the user to AddDebugEventListener
+ */
+typedef void (*DebugEventCallback)(DebugEvent event,
+                                   Handle<Object> exec_state,
+                                   Handle<Object> event_data,
+                                   Handle<Value> data);
+
+
+/**
+ * Debug message callback function.
+ *
+ * \param message the debug message
+ * \param length length of the message
+ * A DebugMessageHandler does not take posession of the message string,
+ * and must not rely on the data persisting after the handler returns.
+ */
+typedef void (*DebugMessageHandler)(const uint16_t* message, int length,
+                                    void* data);
+
+
+class EXPORT Debug {
+ public:
+  // Add a C debug event listener.
+  static bool AddDebugEventListener(DebugEventCallback that,
+                                    Handle<Value> data = Handle<Value>());
+
+  // Add a JavaScript debug event listener.
+  static bool AddDebugEventListener(v8::Handle<v8::Function> that,
+                                    Handle<Value> data = Handle<Value>());
+
+  // Remove a C debug event listener.
+  static void RemoveDebugEventListener(DebugEventCallback that);
+
+  // Remove a JavaScript debug event listener.
+  static void RemoveDebugEventListener(v8::Handle<v8::Function> that);
+
+  // Generate a stack dump.
+  static void StackDump();
+
+  // Break execution of JavaScript.
+  static void DebugBreak();
+
+  // Message based interface. The message protocol is JSON.
+  static void SetMessageHandler(DebugMessageHandler handler, void* data = NULL);
+  static void SendCommand(const uint16_t* command, int length);
+};
+
+
+}  // namespace v8
+
+
+#undef EXPORT
+
+
+#endif  // V8_DEBUG_H_
diff --git a/regexp2000/include/v8.h b/regexp2000/include/v8.h
new file mode 100644 (file)
index 0000000..70b1f52
--- /dev/null
@@ -0,0 +1,2433 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/** \mainpage V8 API Reference Guide
+ *
+ * V8 is Google's open source JavaScript engine.
+ *
+ * This set of documents provides reference material generated from the
+ * V8 header file, include/v8.h.
+ *
+ * For other documentation see http://code.google.com/apis/v8/
+ */
+
+#ifndef V8_H_
+#define V8_H_
+
+#include <stdio.h>
+
+#ifdef _WIN32
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;  // NOLINT
+typedef long long int64_t;  // NOLINT
+
+// Setup for Windows DLL export/import. When building the V8 DLL the
+// BUILDING_V8_SHARED needs to be defined. When building a program which uses
+// the V8 DLL USING_V8_SHARED needs to be defined. When either building the V8
+// static library or building a program which uses the V8 static library neither
+// BUILDING_V8_SHARED nor USING_V8_SHARED should be defined.
+// The reason for having both EXPORT and EXPORT_INLINE is that classes which
+// have their code inside this header file needs to have __declspec(dllexport)
+// when building the DLL but cannot have __declspec(dllimport) when building
+// a program which uses the DLL.
+#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED)
+#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\
+  build configuration to ensure that at most one of these is set
+#endif
+
+#ifdef BUILDING_V8_SHARED
+#define EXPORT __declspec(dllexport)
+#define EXPORT_INLINE __declspec(dllexport)
+#elif USING_V8_SHARED
+#define EXPORT __declspec(dllimport)
+#define EXPORT_INLINE
+#else
+#define EXPORT
+#define EXPORT_INLINE
+#endif  // BUILDING_V8_SHARED
+
+#else  // _WIN32
+
+#include <stdint.h>
+
+// Setup for Linux shared library export. There is no need to destinguish
+// neither between building or using the V8 shared library nor between using
+// the shared or static V8 library as there is on Windows. Therefore there is
+// no checking of BUILDING_V8_SHARED and USING_V8_SHARED.
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define EXPORT __attribute__ ((visibility("default")))
+#define EXPORT_INLINE __attribute__ ((visibility("default")))
+#else  // defined(__GNUC__) && (__GNUC__ >= 4)
+#define EXPORT
+#define EXPORT_INLINE
+#endif  // defined(__GNUC__) && (__GNUC__ >= 4)
+
+#endif  // _WIN32
+
+/**
+ * The v8 JavaScript engine.
+ */
+namespace v8 {
+
+class Context;
+class String;
+class Value;
+class Utils;
+class Number;
+class Object;
+class Array;
+class Int32;
+class Uint32;
+class External;
+class Primitive;
+class Boolean;
+class Integer;
+class Function;
+class Date;
+class ImplementationUtilities;
+class Signature;
+template <class T> class Handle;
+template <class T> class Local;
+template <class T> class Persistent;
+class FunctionTemplate;
+class ObjectTemplate;
+class Data;
+
+
+// --- W e a k  H a n d l e s
+
+
+/**
+ * A weak reference callback function.
+ *
+ * \param object the weak global object to be reclaimed by the garbage collector
+ * \param parameter the value passed in when making the weak global object
+ */
+typedef void (*WeakReferenceCallback)(Persistent<Value> object,
+                                      void* parameter);
+
+
+// --- H a n d l e s ---
+
+#define TYPE_CHECK(T, S)                              \
+  while (false) {                                     \
+    *(static_cast<T**>(0)) = static_cast<S*>(0);      \
+  }
+
+/**
+ * An object reference managed by the v8 garbage collector.
+ *
+ * All objects returned from v8 have to be tracked by the garbage
+ * collector so that it knows that the objects are still alive.  Also,
+ * because the garbage collector may move objects, it is unsafe to
+ * point directly to an object.  Instead, all objects are stored in
+ * handles which are known by the garbage collector and updated
+ * whenever an object moves.  Handles should always be passed by value
+ * (except in cases like out-parameters) and they should never be
+ * allocated on the heap.
+ *
+ * There are two types of handles: local and persistent handles.
+ * Local handles are light-weight and transient and typically used in
+ * local operations.  They are managed by HandleScopes.  Persistent
+ * handles can be used when storing objects across several independent
+ * operations and have to be explicitly deallocated when they're no
+ * longer used.
+ *
+ * It is safe to extract the object stored in the handle by
+ * dereferencing the handle (for instance, to extract the Object* from
+ * an Handle<Object>); the value will still be governed by a handle
+ * behind the scenes and the same rules apply to these values as to
+ * their handles.
+ */
+template <class T> class EXPORT_INLINE Handle {
+ public:
+
+  /**
+   * Creates an empty handle.
+   */
+  Handle();
+
+  /**
+   * Creates a new handle for the specified value.
+   */
+  explicit Handle(T* val) : val_(val) { }
+
+  /**
+   * Creates a handle for the contents of the specified handle.  This
+   * constructor allows you to pass handles as arguments by value and
+   * to assign between handles.  However, if you try to assign between
+   * incompatible handles, for instance from a Handle<String> to a
+   * Handle<Number> it will cause a compiletime error.  Assigning
+   * between compatible handles, for instance assigning a
+   * Handle<String> to a variable declared as Handle<Value>, is legal
+   * because String is a subclass of Value.
+   */
+  template <class S> inline Handle(Handle<S> that)
+      : val_(reinterpret_cast<T*>(*that)) {
+    /**
+     * This check fails when trying to convert between incompatible
+     * handles. For example, converting from a Handle<String> to a
+     * Handle<Number>.
+     */
+    TYPE_CHECK(T, S);
+  }
+
+  /**
+   * Returns true if the handle is empty.
+   */
+  bool IsEmpty() { return val_ == 0; }
+
+  T* operator->();
+
+  T* operator*();
+
+  /**
+   * Sets the handle to be empty. IsEmpty() will then return true.
+   */
+  void Clear() { this->val_ = 0; }
+
+  /**
+   * Checks whether two handles are the same.
+   * Returns true if both are empty, or if the objects
+   * to which they refer are identical.
+   * The handles' references are not checked.
+   */
+  template <class S> bool operator==(Handle<S> that) {
+    void** a = reinterpret_cast<void**>(**this);
+    void** b = reinterpret_cast<void**>(*that);
+    if (a == 0) return b == 0;
+    if (b == 0) return false;
+    return *a == *b;
+  }
+
+  /**
+   * Checks whether two handles are different.
+   * Returns true if only one of the handles is empty, or if
+   * the objects to which they refer are different.
+   * The handles' references are not checked.
+   */
+  template <class S> bool operator!=(Handle<S> that) {
+    return !operator==(that);
+  }
+
+  template <class S> static inline Handle<T> Cast(Handle<S> that) {
+    if (that.IsEmpty()) return Handle<T>();
+    return Handle<T>(T::Cast(*that));
+  }
+
+ private:
+  T* val_;
+};
+
+
+/**
+ * A light-weight stack-allocated object handle.  All operations
+ * that return objects from within v8 return them in local handles.  They
+ * are created within HandleScopes, and all local handles allocated within a
+ * handle scope are destroyed when the handle scope is destroyed.  Hence it
+ * is not necessary to explicitly deallocate local handles.
+ */
+template <class T> class EXPORT_INLINE Local : public Handle<T> {
+ public:
+  Local();
+  template <class S> inline Local(Local<S> that)
+      : Handle<T>(reinterpret_cast<T*>(*that)) {
+    /**
+     * This check fails when trying to convert between incompatible
+     * handles. For example, converting from a Handle<String> to a
+     * Handle<Number>.
+     */
+    TYPE_CHECK(T, S);
+  }
+  template <class S> inline Local(S* that) : Handle<T>(that) { }
+  template <class S> static inline Local<T> Cast(Local<S> that) {
+    if (that.IsEmpty()) return Local<T>();
+    return Local<T>(T::Cast(*that));
+  }
+
+  /** Create a local handle for the content of another handle.
+   *  The referee is kept alive by the local handle even when
+   *  the original handle is destroyed/disposed.
+   */
+  static Local<T> New(Handle<T> that);
+};
+
+
+/**
+ * An object reference that is independent of any handle scope.  Where
+ * a Local handle only lives as long as the HandleScope in which it was
+ * allocated, a Persistent handle remains valid until it is explicitly
+ * disposed.
+ *
+ * A persistent handle contains a reference to a storage cell within
+ * the v8 engine which holds an object value and which is updated by
+ * the garbage collector whenever the object is moved.  A new storage
+ * cell can be created using Persistent::New and existing handles can
+ * be disposed using Persistent::Dispose.  Since persistent handles
+ * are passed by value you may have many persistent handle objects
+ * that point to the same storage cell.  For instance, if you pass a
+ * persistent handle as an argument to a function you will not get two
+ * different storage cells but rather two references to the same
+ * storage cell.
+ */
+template <class T> class EXPORT_INLINE Persistent : public Handle<T> {
+ public:
+
+  /**
+   * Creates an empty persistent handle that doesn't point to any
+   * storage cell.
+   */
+  Persistent();
+
+  /**
+   * Creates a persistent handle for the same storage cell as the
+   * specified handle.  This constructor allows you to pass persistent
+   * handles as arguments by value and to assign between persistent
+   * handles.  However, attempting to assign between incompatible
+   * persistent handles, for instance from a Persistent<String> to a
+   * Persistent<Number> will cause a compiletime error.  Assigning
+   * between compatible persistent handles, for instance assigning a
+   * Persistent<String> to a variable declared as Persistent<Value>,
+   * is allowed as String is a subclass of Value.
+   */
+  template <class S> inline Persistent(Persistent<S> that)
+      : Handle<T>(reinterpret_cast<T*>(*that)) {
+    /**
+     * This check fails when trying to convert between incompatible
+     * handles. For example, converting from a Handle<String> to a
+     * Handle<Number>.
+     */
+    TYPE_CHECK(T, S);
+  }
+
+  template <class S> inline Persistent(S* that) : Handle<T>(that) { }
+
+  /**
+   * "Casts" a plain handle which is known to be a persistent handle
+   * to a persistent handle.
+   */
+  template <class S> explicit inline Persistent(Handle<S> that)
+      : Handle<T>(*that) { }
+
+  template <class S> static inline Persistent<T> Cast(Persistent<S> that) {
+    if (that.IsEmpty()) return Persistent<T>();
+    return Persistent<T>(T::Cast(*that));
+  }
+
+  /**
+   * Creates a new persistent handle for an existing local or
+   * persistent handle.
+   */
+  static Persistent<T> New(Handle<T> that);
+
+  /**
+   * Releases the storage cell referenced by this persistent handle.
+   * Does not remove the reference to the cell from any handles.
+   * This handle's reference, and any any other references to the storage
+   * cell remain and IsEmpty will still return false.
+   */
+  void Dispose();
+
+  /**
+   * Make the reference to this object weak.  When only weak handles
+   * refer to the object, the garbage collector will perform a
+   * callback to the given V8::WeakReferenceCallback function, passing
+   * it the object reference and the given parameters.
+   */
+  void MakeWeak(void* parameters, WeakReferenceCallback callback);
+
+  /** Clears the weak reference to this object.*/
+  void ClearWeak();
+
+  /**
+   *Checks if the handle holds the only reference to an object.
+   */
+  bool IsNearDeath();
+
+  /**
+   * Returns true if the handle's reference is weak.
+   */
+  bool IsWeak();
+
+ private:
+  friend class ImplementationUtilities;
+  friend class ObjectTemplate;
+};
+
+
+ /**
+ * A stack-allocated class that governs a number of local handles.
+ * After a handle scope has been created, all local handles will be
+ * allocated within that handle scope until either the handle scope is
+ * deleted or another handle scope is created.  If there is already a
+ * handle scope and a new one is created, all allocations will take
+ * place in the new handle scope until it is deleted.  After that,
+ * new handles will again be allocated in the original handle scope.
+ *
+ * After the handle scope of a local handle has been deleted the
+ * garbage collector will no longer track the object stored in the
+ * handle and may deallocate it.  The behavior of accessing a handle
+ * for which the handle scope has been deleted is undefined.
+ */
+class EXPORT HandleScope {
+ public:
+  HandleScope() : previous_(current_), is_closed_(false) {
+    current_.extensions = 0;
+  }
+
+  ~HandleScope() {
+    // TODO(1245391): In a perfect world, there would be a way of not
+    // having to check for explicitly closed scopes maybe through
+    // subclassing HandleScope?
+    if (!is_closed_) RestorePreviousState();
+  }
+
+  /**
+   * TODO(1245391): Consider introducing a subclass for this.
+   * Closes the handle scope and returns the value as a handle in the
+   * previous scope, which is the new current scope after the call.
+   */
+  template <class T> Local<T> Close(Handle<T> value);
+
+  /**
+   * Counts the number of allocated handles.
+   */
+  static int NumberOfHandles();
+
+  /**
+   * Creates a new handle with the given value.
+   */
+  static void** CreateHandle(void* value);
+
+ private:
+  // Make it impossible to create heap-allocated or illegal handle
+  // scopes by disallowing certain operations.
+  HandleScope(const HandleScope&);
+  void operator=(const HandleScope&);
+  void* operator new(size_t size);
+  void operator delete(void*, size_t);
+
+  class EXPORT Data {
+   public:
+    int extensions;
+    void** next;
+    void** limit;
+    inline void Initialize() {
+      extensions = -1;
+      next = limit = NULL;
+    }
+  };
+
+  static Data current_;
+  const Data previous_;
+
+  /**
+   * Re-establishes the previous scope state. Should be called only
+   * once, and only for the current scope.
+   */
+  void RestorePreviousState() {
+    if (current_.extensions > 0) DeleteExtensions();
+    current_ = previous_;
+#ifdef DEBUG
+    ZapRange(current_.next, current_.limit);
+#endif
+  }
+
+  // TODO(1245391): Consider creating a subclass for this.
+  bool is_closed_;
+  void** RawClose(void** value);
+
+  /** Deallocates any extensions used by the current scope.*/
+  static void DeleteExtensions();
+
+  // Zaps the handles in the half-open interval [start, end).
+  static void ZapRange(void** start, void** end);
+
+  friend class ImplementationUtilities;
+};
+
+
+// --- S p e c i a l   o b j e c t s ---
+
+
+/**
+ * The superclass of values and API object templates.
+ */
+class EXPORT Data {
+ private:
+  Data();
+};
+
+
+/**
+ * Pre-compilation data that can be associated with a script.  This
+ * data can be calculated for a script in advance of actually
+ * compiling it, and can be stored between compilations.  When script
+ * data is given to the compile method compilation will be faster.
+ */
+class EXPORT ScriptData {  // NOLINT
+ public:
+  virtual ~ScriptData() { }
+  static ScriptData* PreCompile(const char* input, int length);
+  static ScriptData* New(unsigned* data, int length);
+
+  virtual int Length() = 0;
+  virtual unsigned* Data() = 0;
+};
+
+
+/**
+ * The origin, within a file, of a script.
+ */
+class EXPORT ScriptOrigin {
+ public:
+  ScriptOrigin(Handle<Value> resource_name,
+               Handle<Integer> resource_line_offset = Handle<Integer>(),
+               Handle<Integer> resource_column_offset = Handle<Integer>())
+      : resource_name_(resource_name),
+        resource_line_offset_(resource_line_offset),
+        resource_column_offset_(resource_column_offset) { }
+  inline Handle<Value> ResourceName() const;
+  inline Handle<Integer> ResourceLineOffset() const;
+  inline Handle<Integer> ResourceColumnOffset() const;
+ private:
+  Handle<Value> resource_name_;
+  Handle<Integer> resource_line_offset_;
+  Handle<Integer> resource_column_offset_;
+};
+
+
+/**
+ * A compiled JavaScript script.
+ */
+class EXPORT Script {
+ public:
+
+  /**
+   * Compiles the specified script. The ScriptOrigin* and ScriptData*
+   * parameters are owned by the caller of Script::Compile. No
+   * references to these objects are kept after compilation finishes.
+   */
+  static Local<Script> Compile(Handle<String> source,
+                               ScriptOrigin* origin = NULL,
+                               ScriptData* pre_data = NULL);
+
+  /**
+   * Compiles the specified script using the specified file name
+   * object (typically a string) as the script's origin.
+   */
+  static Local<Script> Compile(Handle<String> source,
+                               Handle<Value> file_name);
+
+  /**
+   * Runs the script returning the resulting value.
+   */
+  Local<Value> Run();
+};
+
+
+/**
+ * An error message.
+ */
+class EXPORT Message {
+ public:
+  Local<String> Get();
+  Local<String> GetSourceLine();
+
+  Handle<Value> GetScriptResourceName();
+
+  /**
+   * Returns the number, 1-based, of the line where the error occurred.
+   */
+  int GetLineNumber();
+
+  /**
+   * Returns the index within the script of the first character where
+   * the error occurred.
+   */
+  int GetStartPosition();
+
+  /**
+   * Returns the index within the script of the last character where
+   * the error occurred.
+   */
+  int GetEndPosition();
+
+  /**
+   * Returns the index within the line of the first character where
+   * the error occurred.
+   */
+  int GetStartColumn();
+
+  /**
+   * Returns the index within the line of the last character where
+   * the error occurred.
+   */
+  int GetEndColumn();
+
+  // TODO(1245381): Print to a string instead of on a FILE.
+  static void PrintCurrentStackTrace(FILE* out);
+};
+
+
+// --- V a l u e ---
+
+
+/**
+ * The superclass of all JavaScript values and objects.
+ */
+class EXPORT Value : public Data {
+ public:
+
+  /**
+   * Returns true if this value is the undefined value.  See ECMA-262
+   * 4.3.10.
+   */
+  bool IsUndefined();
+
+  /**
+   * Returns true if this value is the null value.  See ECMA-262
+   * 4.3.11.
+   */
+  bool IsNull();
+
+   /**
+   * Returns true if this value is true.
+   */
+  bool IsTrue();
+
+  /**
+   * Returns true if this value is false.
+   */
+  bool IsFalse();
+
+  /**
+   * Returns true if this value is an instance of the String type.
+   * See ECMA-262 8.4.
+   */
+  bool IsString();
+
+  /**
+   * Returns true if this value is a function.
+   */
+  bool IsFunction();
+
+  /**
+   * Returns true if this value is an array.
+   */
+  bool IsArray();
+
+  /**
+   * Returns true if this value is an object.
+   */
+  bool IsObject();
+
+  /**
+   * Returns true if this value is boolean.
+   */
+  bool IsBoolean();
+
+  /**
+   * Returns true if this value is a number.
+   */
+  bool IsNumber();
+
+  /**
+   * Returns true if this value is external.
+   */
+  bool IsExternal();
+
+  /**
+   * Returns true if this value is a 32-bit signed integer.
+   */
+  bool IsInt32();
+
+  /**
+   * Returns true if this value is a Date.
+   */
+  bool IsDate();
+
+  Local<Boolean> ToBoolean();
+  Local<Number> ToNumber();
+  Local<String> ToString();
+  Local<String> ToDetailString();
+  Local<Object> ToObject();
+  Local<Integer> ToInteger();
+  Local<Uint32> ToUint32();
+  Local<Int32> ToInt32();
+
+  /**
+   * Attempts to convert a string to an array index.
+   * Returns an empty handle if the conversion fails.
+   */
+  Local<Uint32> ToArrayIndex();
+
+  bool BooleanValue();
+  double NumberValue();
+  int64_t IntegerValue();
+  uint32_t Uint32Value();
+  int32_t Int32Value();
+
+  /** JS == */
+  bool Equals(Handle<Value> that);
+  bool StrictEquals(Handle<Value> that);
+};
+
+
+/**
+ * The superclass of primitive values.  See ECMA-262 4.3.2.
+ */
+class EXPORT Primitive : public Value { };
+
+
+/**
+ * A primitive boolean value (ECMA-262, 4.3.14).  Either the true
+ * or false value.
+ */
+class EXPORT Boolean : public Primitive {
+ public:
+  bool Value();
+  static inline Handle<Boolean> New(bool value);
+};
+
+
+/**
+ * A JavaScript string value (ECMA-262, 4.3.17).
+ */
+class EXPORT String : public Primitive {
+ public:
+
+  /**
+   * Returns the number of characters in this string.
+   */
+  int Length();
+
+  /**
+   * Returns the number of bytes in the UTF-8 encoded
+   * representation of this string.
+   */
+  int Utf8Length();
+
+  /**
+   * Write the contents of the string to an external buffer.
+   * If no arguments are given, expects the buffer to be large
+   * enough to hold the entire string and NULL terminator. Copies
+   * the contents of the string and the NULL terminator into the
+   * buffer.
+   *
+   * Copies up to length characters into the output buffer.
+   * Only null-terminates if there is enough space in the buffer.
+   *
+   * \param buffer The buffer into which the string will be copied.
+   * \param start The starting position within the string at which
+   * copying begins.
+   * \param length The number of bytes to copy from the string.
+   * \return The number of characters copied to the buffer
+   * excluding the NULL terminator.
+   */
+  int Write(uint16_t* buffer, int start = 0, int length = -1);  // UTF-16
+  int WriteAscii(char* buffer, int start = 0, int length = -1);  // ASCII
+  int WriteUtf8(char* buffer, int length = -1); // UTF-8
+
+  /**
+   * Returns true if the string is external
+   */
+  bool IsExternal();
+
+  /**
+   * Returns true if the string is both external and ascii
+   */
+  bool IsExternalAscii();
+  /**
+   * An ExternalStringResource is a wrapper around a two-byte string
+   * buffer that resides outside V8's heap. Implement an
+   * ExternalStringResource to manage the life cycle of the underlying
+   * buffer.  Note that the string data must be immutable.
+   */
+  class EXPORT ExternalStringResource {  // NOLINT
+   public:
+    /**
+     * Override the destructor to manage the life cycle of the underlying
+     * buffer.
+     */
+    virtual ~ExternalStringResource() {}
+    /** The string data from the underlying buffer.*/
+    virtual const uint16_t* data() const = 0;
+    /** The length of the string. That is, the number of two-byte characters.*/
+    virtual size_t length() const = 0;
+   protected:
+    ExternalStringResource() {}
+   private:
+    // Disallow copying and assigning.
+    ExternalStringResource(const ExternalStringResource&);
+    void operator=(const ExternalStringResource&);
+  };
+
+  /**
+   * An ExternalAsciiStringResource is a wrapper around an ascii
+   * string buffer that resides outside V8's heap. Implement an
+   * ExternalAsciiStringResource to manage the life cycle of the
+   * underlying buffer.  Note that the string data must be immutable
+   * and that the data must be strict 7-bit ASCII, not Latin1 or
+   * UTF-8, which would require special treatment internally in the
+   * engine and, in the case of UTF-8, do not allow efficient indexing.
+   * Use String::New or convert to 16 bit data for non-ASCII.
+   */
+
+  class EXPORT ExternalAsciiStringResource {  // NOLINT
+   public:
+    /**
+     * Override the destructor to manage the life cycle of the underlying
+     * buffer.
+     */
+    virtual ~ExternalAsciiStringResource() {}
+    /** The string data from the underlying buffer.*/
+    virtual const char* data() const = 0;
+    /** The number of ascii characters in the string.*/
+    virtual size_t length() const = 0;
+   protected:
+    ExternalAsciiStringResource() {}
+   private:
+    // Disallow copying and assigning.
+    ExternalAsciiStringResource(const ExternalAsciiStringResource&);
+    void operator=(const ExternalAsciiStringResource&);
+  };
+
+  /**
+   * Get the ExternalStringResource for an external string.  Only
+   * valid if IsExternal() returns true.
+   */
+  ExternalStringResource* GetExternalStringResource();
+
+  /**
+   * Get the ExternalAsciiStringResource for an external ascii string.
+   * Only valid if IsExternalAscii() returns true.
+   */
+  ExternalAsciiStringResource* GetExternalAsciiStringResource();
+
+  static String* Cast(v8::Value* obj);
+
+  /**
+   * Allocates a new string from either utf-8 encoded or ascii data.
+   * The second parameter 'length' gives the buffer length.
+   * If the data is utf-8 encoded, the caller must
+   * be careful to supply the length parameter.
+   * If it is not given, the function calls
+   * 'strlen' to determine the buffer length, it might be
+   * wrong if 'data' contains a null character.
+   */
+  static Local<String> New(const char* data, int length = -1);
+
+  /** Allocates a new string from utf16 data.*/
+  static Local<String> New(const uint16_t* data, int length = -1);
+
+  /** Creates a symbol. Returns one if it exists already.*/
+  static Local<String> NewSymbol(const char* data, int length = -1);
+
+  /**
+   * Creates a new external string using the data defined in the given
+   * resource. The resource is deleted when the external string is no
+   * longer live on V8's heap. The caller of this function should not
+   * delete or modify the resource. Neither should the underlying buffer be
+   * deallocated or modified except through the destructor of the
+   * external string resource.
+   */
+  static Local<String> NewExternal(ExternalStringResource* resource);
+
+  /**
+   * Creates a new external string using the ascii data defined in the given
+   * resource. The resource is deleted when the external string is no
+   * longer live on V8's heap. The caller of this function should not
+   * delete or modify the resource. Neither should the underlying buffer be
+   * deallocated or modified except through the destructor of the
+   * external string resource.
+   */
+  static Local<String> NewExternal(ExternalAsciiStringResource* resource);
+
+  /** Creates an undetectable string from the supplied ascii or utf-8 data.*/
+  static Local<String> NewUndetectable(const char* data, int length = -1);
+
+  /** Creates an undetectable string from the supplied utf-16 data.*/
+  static Local<String> NewUndetectable(const uint16_t* data, int length = -1);
+
+  /**
+   * Converts an object to a utf8-encoded character array.  Useful if
+   * you want to print the object.
+   */
+  class EXPORT Utf8Value {
+   public:
+    explicit Utf8Value(Handle<v8::Value> obj);
+    ~Utf8Value();
+    char* operator*() { return str_; }
+    int length() { return length_; }
+   private:
+    char* str_;
+    int length_;
+
+    // Disallow copying and assigning.
+    Utf8Value(const Utf8Value&);
+    void operator=(const Utf8Value&);
+  };
+
+  /**
+   * Converts an object to an ascii string.
+   * Useful if you want to print the object.
+   */
+  class EXPORT AsciiValue {
+   public:
+    explicit AsciiValue(Handle<v8::Value> obj);
+    ~AsciiValue();
+    char* operator*() { return str_; }
+    int length() { return length_; }
+   private:
+    char* str_;
+    int length_;
+
+    // Disallow copying and assigning.
+    AsciiValue(const AsciiValue&);
+    void operator=(const AsciiValue&);
+  };
+
+  /**
+   * Converts an object to a two-byte string.
+   */
+  class EXPORT Value {
+   public:
+    explicit Value(Handle<v8::Value> obj);
+    ~Value();
+    uint16_t* operator*() { return str_; }
+    int length() { return length_; }
+   private:
+    uint16_t* str_;
+    int length_;
+
+    // Disallow copying and assigning.
+    Value(const Value&);
+    void operator=(const Value&);
+  };
+};
+
+
+/**
+ * A JavaScript number value (ECMA-262, 4.3.20)
+ */
+class EXPORT Number : public Primitive {
+ public:
+  double Value();
+  static Local<Number> New(double value);
+  static Number* Cast(v8::Value* obj);
+ private:
+  Number();
+};
+
+
+/**
+ * A JavaScript value representing a signed integer.
+ */
+class EXPORT Integer : public Number {
+ public:
+  static Local<Integer> New(int32_t value);
+  int64_t Value();
+  static Integer* Cast(v8::Value* obj);
+ private:
+  Integer();
+};
+
+
+/**
+ * A JavaScript value representing a 32-bit signed integer.
+ */
+class EXPORT Int32 : public Integer {
+ public:
+  int32_t Value();
+ private:
+  Int32();
+};
+
+
+/**
+ * A JavaScript value representing a 32-bit unsigned integer.
+ */
+class EXPORT Uint32 : public Integer {
+ public:
+  uint32_t Value();
+ private:
+  Uint32();
+};
+
+
+/**
+ * An instance of the built-in Date constructor (ECMA-262, 15.9).
+ */
+class EXPORT Date : public Value {
+ public:
+  static Local<Value> New(double time);
+
+  /**
+   * A specialization of Value::NumberValue that is more efficient
+   * because we know the structure of this object.
+   */
+  double NumberValue();
+
+  static Date* Cast(v8::Value* obj);
+};
+
+
+enum PropertyAttribute {
+  None       = 0,
+  ReadOnly   = 1 << 0,
+  DontEnum   = 1 << 1,
+  DontDelete = 1 << 2
+};
+
+/**
+ * A JavaScript object (ECMA-262, 4.3.3)
+ */
+class EXPORT Object : public Value {
+ public:
+  bool Set(Handle<Value> key,
+           Handle<Value> value,
+           PropertyAttribute attribs = None);
+  Local<Value> Get(Handle<Value> key);
+
+  // TODO(1245389): Replace the type-specific versions of these
+  // functions with generic ones that accept a Handle<Value> key.
+  bool Has(Handle<String> key);
+  bool Delete(Handle<String> key);
+  bool Has(uint32_t index);
+  bool Delete(uint32_t index);
+
+  /**
+   * Returns an array containing the names of the enumerable properties
+   * of this object, including properties from prototype objects.  The
+   * array returned by this method contains the same values as would
+   * be enumerated by a for-in statement over this object.
+   */
+  Local<Array> GetPropertyNames();
+
+  /**
+   * Get the prototype object.  This does not skip objects marked to
+   * be skipped by __proto__ and it does not consult the security
+   * handler.
+   */
+  Local<Value> GetPrototype();
+
+  /**
+   * Call builtin Object.prototype.toString on this object.
+   * This is different from Value::ToString() that may call
+   * user-defined toString function. This one does not.
+   */
+  Local<String> ObjectProtoToString();
+
+  /** Gets the number of internal fields for this Object. */
+  int InternalFieldCount();
+  /** Gets the value in an internal field. */
+  Local<Value> GetInternalField(int index);
+  /** Sets the value in an internal field. */
+  void SetInternalField(int index, Handle<Value> value);
+
+  // Testers for local properties.
+  bool HasRealNamedProperty(Handle<String> key);
+  bool HasRealIndexedProperty(uint32_t index);
+  bool HasRealNamedCallbackProperty(Handle<String> key);
+
+  /**
+   * If result.IsEmpty() no real property was located in the prototype chain.
+   * This means interceptors in the prototype chain are not called.
+   */
+  Handle<Value> GetRealNamedPropertyInPrototypeChain(Handle<String> key);
+
+  /** Tests for a named lookup interceptor.*/
+  bool HasNamedLookupInterceptor();
+
+  /** Tests for an index lookup interceptor.*/
+  bool HasIndexedLookupInterceptor();
+
+  /**
+   * Turns on access check on the object if the object is an instance of
+   * a template that has access check callbacks. If an object has no
+   * access check info, the object cannot be accessed by anyone.
+   */
+  void TurnOnAccessCheck();
+
+  static Local<Object> New();
+  static Object* Cast(Value* obj);
+ private:
+  Object();
+};
+
+
+/**
+ * An instance of the built-in array constructor (ECMA-262, 15.4.2).
+ */
+class EXPORT Array : public Object {
+ public:
+  uint32_t Length();
+
+  static Local<Array> New(int length = 0);
+  static Array* Cast(Value* obj);
+ private:
+  Array();
+};
+
+
+/**
+ * A JavaScript function object (ECMA-262, 15.3).
+ */
+class EXPORT Function : public Object {
+ public:
+  Local<Object> NewInstance();
+  Local<Object> NewInstance(int argc, Handle<Value> argv[]);
+  Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]);
+  void SetName(Handle<String> name);
+  Handle<Value> GetName();
+  static Function* Cast(Value* obj);
+ private:
+  Function();
+};
+
+
+/**
+ * A JavaScript value that wraps a c++ void*.  This type of value is
+ * mainly used to associate c++ data structures with JavaScript
+ * objects.
+ */
+class EXPORT External : public Value {
+ public:
+  static Local<External> New(void* value);
+  static External* Cast(Value* obj);
+  void* Value();
+ private:
+  External();
+};
+
+
+// --- T e m p l a t e s ---
+
+
+/**
+ * The superclass of object and function templates.
+ */
+class EXPORT Template : public Data {
+ public:
+  /** Adds a property to each instance created by this template.*/
+  void Set(Handle<String> name, Handle<Data> value,
+           PropertyAttribute attributes = None);
+  inline void Set(const char* name, Handle<Data> value);
+ private:
+  Template();
+
+  friend class ObjectTemplate;
+  friend class FunctionTemplate;
+};
+
+
+/**
+ * The argument information given to function call callbacks.  This
+ * class provides access to information about the context of the call,
+ * including the receiver, the number and values of arguments, and
+ * the holder of the function.
+ */
+class EXPORT Arguments {
+ public:
+  inline int Length() const;
+  inline Local<Value> operator[](int i) const;
+  inline Local<Function> Callee() const;
+  inline Local<Object> This() const;
+  inline Local<Object> Holder() const;
+  inline bool IsConstructCall() const;
+  inline Local<Value> Data() const;
+ private:
+  Arguments();
+  friend class ImplementationUtilities;
+  inline Arguments(Local<Value> data,
+                   Local<Object> holder,
+                   Local<Function> callee,
+                   bool is_construct_call,
+                   void** values, int length);
+  Local<Value> data_;
+  Local<Object> holder_;
+  Local<Function> callee_;
+  bool is_construct_call_;
+  void** values_;
+  int length_;
+};
+
+
+/**
+ * The information passed to an accessor callback about the context
+ * of the property access.
+ */
+class EXPORT AccessorInfo {
+ public:
+  inline AccessorInfo(Local<Object> self,
+                      Local<Value> data,
+                      Local<Object> holder)
+      : self_(self), data_(data), holder_(holder) { }
+  inline Local<Value> Data() const;
+  inline Local<Object> This() const;
+  inline Local<Object> Holder() const;
+ private:
+  Local<Object> self_;
+  Local<Value> data_;
+  Local<Object> holder_;
+};
+
+
+typedef Handle<Value> (*InvocationCallback)(const Arguments& args);
+
+typedef int (*LookupCallback)(Local<Object> self, Local<String> name);
+
+/**
+ * Accessor[Getter|Setter] are used as callback functions when
+ * setting|getting a particular property. See objectTemplate::SetAccessor.
+ */
+typedef Handle<Value> (*AccessorGetter)(Local<String> property,
+                                        const AccessorInfo& info);
+
+
+typedef void (*AccessorSetter)(Local<String> property,
+                               Local<Value> value,
+                               const AccessorInfo& info);
+
+
+/**
+ * NamedProperty[Getter|Setter] are used as interceptors on object.
+ * See ObjectTemplate::SetNamedPropertyHandler.
+ */
+typedef Handle<Value> (*NamedPropertyGetter)(Local<String> property,
+                                             const AccessorInfo& info);
+
+
+/**
+ * Returns the value if the setter intercepts the request.
+ * Otherwise, returns an empty handle.
+ */
+typedef Handle<Value> (*NamedPropertySetter)(Local<String> property,
+                                             Local<Value> value,
+                                             const AccessorInfo& info);
+
+
+/**
+ * Returns a non-empty handle if the interceptor intercepts the request.
+ * The result is true if the property exists and false otherwise.
+ */
+typedef Handle<Boolean> (*NamedPropertyQuery)(Local<String> property,
+                                              const AccessorInfo& info);
+
+
+/**
+ * Returns a non-empty handle if the deleter intercepts the request.
+ * The return value is true if the property could be deleted and false
+ * otherwise.
+ */
+typedef Handle<Boolean> (*NamedPropertyDeleter)(Local<String> property,
+                                                const AccessorInfo& info);
+
+/**
+ * Returns an array containing the names of the properties the named
+ * property getter intercepts.
+ */
+typedef Handle<Array> (*NamedPropertyEnumerator)(const AccessorInfo& info);
+
+
+/**
+ * Returns the value of the property if the getter intercepts the
+ * request.  Otherwise, returns an empty handle.
+ */
+typedef Handle<Value> (*IndexedPropertyGetter)(uint32_t index,
+                                               const AccessorInfo& info);
+
+
+/**
+ * Returns the value if the setter intercepts the request.
+ * Otherwise, returns an empty handle.
+ */
+typedef Handle<Value> (*IndexedPropertySetter)(uint32_t index,
+                                               Local<Value> value,
+                                               const AccessorInfo& info);
+
+
+/**
+ * Returns a non-empty handle if the interceptor intercepts the request.
+ * The result is true if the property exists and false otherwise.
+ */
+typedef Handle<Boolean> (*IndexedPropertyQuery)(uint32_t index,
+                                                const AccessorInfo& info);
+
+/**
+ * Returns a non-empty handle if the deleter intercepts the request.
+ * The return value is true if the property could be deleted and false
+ * otherwise.
+ */
+typedef Handle<Boolean> (*IndexedPropertyDeleter)(uint32_t index,
+                                                  const AccessorInfo& info);
+
+/**
+ * Returns an array containing the indices of the properties the
+ * indexed property getter intercepts.
+ */
+typedef Handle<Array> (*IndexedPropertyEnumerator)(const AccessorInfo& info);
+
+
+/**
+ * Access control specifications.
+ *
+ * Some accessors should be accessible across contexts.  These
+ * accessors have an explicit access control parameter which specifies
+ * the kind of cross-context access that should be allowed.
+ */
+enum AccessControl {
+  DEFAULT         = 0,
+  ALL_CAN_READ    = 1,
+  ALL_CAN_WRITE   = 2
+};
+
+
+/**
+ * Access type specification.
+ */
+enum AccessType {
+  ACCESS_GET,
+  ACCESS_SET,
+  ACCESS_HAS,
+  ACCESS_DELETE,
+  ACCESS_KEYS
+};
+
+
+/**
+ * Returns true if cross-context access should be allowed to the named
+ * property with the given key on the global object.
+ */
+typedef bool (*NamedSecurityCallback)(Local<Object> global,
+                                      Local<Value> key,
+                                      AccessType type,
+                                      Local<Value> data);
+
+
+/**
+ * Returns true if cross-context access should be allowed to the indexed
+ * property with the given index on the global object.
+ */
+typedef bool (*IndexedSecurityCallback)(Local<Object> global,
+                                        uint32_t index,
+                                        AccessType type,
+                                        Local<Value> data);
+
+
+/**
+ * A FunctionTemplate is used to create functions at runtime. There
+ * can only be one function created from a FunctionTemplate in a
+ * context.
+ *
+ * A FunctionTemplate can have properties, these properties are added to the
+ * function object when it is created.
+ *
+ * A FunctionTemplate has a corresponding instance template which is
+ * used to create object instances when the function is used as a
+ * constructor. Properties added to the instance template are added to
+ * each object instance.
+ *
+ * A FunctionTemplate can have a prototype template. The prototype template
+ * is used to create the prototype object of the function.
+ *
+ * The following example shows how to use a FunctionTemplate:
+ *
+ * \code
+ *    v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+ *    t->Set("func_property", v8::Number::New(1));
+ *
+ *    v8::Local<v8::Template> proto_t = t->PrototypeTemplate();
+ *    proto_t->Set("proto_method", v8::FunctionTemplate::New(InvokeCallback));
+ *    proto_t->Set("proto_const", v8::Number::New(2));
+ *
+ *    v8::Local<v8::ObjectTemplate> instance_t = t->InstanceTemplate();
+ *    instance_t->SetAccessor("instance_accessor", InstanceAccessorCallback);
+ *    instance_t->SetNamedPropertyHandler(PropertyHandlerCallback, ...);
+ *    instance_t->Set("instance_property", Number::New(3));
+ *
+ *    v8::Local<v8::Function> function = t->GetFunction();
+ *    v8::Local<v8::Object> instance = function->NewInstance();
+ * \endcode
+ *
+ * Let's use "function" as the JS variable name of the function object
+ * and "instance" for the instance object created above.  The function
+ * and the instance will have the following properties:
+ *
+ * \code
+ *   func_property in function == true;
+ *   function.func_property == 1;
+ *
+ *   function.prototype.proto_method() invokes 'InvokeCallback'
+ *   function.prototype.proto_const == 2;
+ *
+ *   instance instanceof function == true;
+ *   instance.instance_accessor calls 'InstanceAccessorCallback'
+ *   instance.instance_property == 3;
+ * \endcode
+ *
+ * A FunctionTemplate can inherit from another one by calling the
+ * FunctionTemplate::Inherit method.  The following graph illustrates
+ * the semantics of inheritance:
+ *
+ * \code
+ *   FunctionTemplate Parent  -> Parent() . prototype -> { }
+ *     ^                                                  ^
+ *     | Inherit(Parent)                                  | .__proto__
+ *     |                                                  |
+ *   FunctionTemplate Child   -> Child()  . prototype -> { }
+ * \endcode
+ *
+ * A FunctionTemplate 'Child' inherits from 'Parent', the prototype
+ * object of the Child() function has __proto__ pointing to the
+ * Parent() function's prototype object. An instance of the Child
+ * function has all properties on Parent's instance templates.
+ *
+ * Let Parent be the FunctionTemplate initialized in the previous
+ * section and create a Child FunctionTemplate by:
+ *
+ * \code
+ *   Local<FunctionTemplate> parent = t;
+ *   Local<FunctionTemplate> child = FunctionTemplate::New();
+ *   child->Inherit(parent);
+ *
+ *   Local<Function> child_function = child->GetFunction();
+ *   Local<Object> child_instance = child_function->NewInstance();
+ * \endcode
+ *
+ * The Child function and Child instance will have the following
+ * properties:
+ *
+ * \code
+ *   child_func.prototype.__proto__ == function.prototype;
+ *   child_instance.instance_accessor calls 'InstanceAccessorCallback'
+ *   child_instance.instance_property == 3;
+ * \endcode
+ */
+class EXPORT FunctionTemplate : public Template {
+ public:
+  /** Creates a function template.*/
+  static Local<FunctionTemplate> New(
+      InvocationCallback callback = 0,
+      Handle<Value> data = Handle<Value>(),
+      Handle<Signature> signature = Handle<Signature>());
+  /** Returns the unique function instance in the current execution context.*/
+  Local<Function> GetFunction();
+
+  /**
+   * Set the call-handler callback for a FunctionTemplate.  This
+   * callback is called whenever the function created from this
+   * FunctionTemplate is called.
+   */
+  void SetCallHandler(InvocationCallback callback,
+                      Handle<Value> data = Handle<Value>());
+
+  /** Get the InstanceTemplate. */
+  Local<ObjectTemplate> InstanceTemplate();
+
+  /** Causes the function template to inherit from a parent function template.*/
+  void Inherit(Handle<FunctionTemplate> parent);
+
+  /**
+   * A PrototypeTemplate is the template used to create the prototype object
+   * of the function created by this template.
+   */
+  Local<ObjectTemplate> PrototypeTemplate();
+
+
+  /**
+   * Set the class name of the FunctionTemplate.  This is used for
+   * printing objects created with the function created from the
+   * FunctionTemplate as its constructor.
+   */
+  void SetClassName(Handle<String> name);
+
+  /**
+   * Determines whether the __proto__ accessor ignores instances of
+   * the function template.  If instances of the function template are
+   * ignored, __proto__ skips all instances and instead returns the
+   * next object in the prototype chain.
+   *
+   * Call with a value of true to make the __proto__ accessor ignore
+   * instances of the function template.  Call with a value of false
+   * to make the __proto__ accessor not ignore instances of the
+   * function template.  By default, instances of a function template
+   * are not ignored.
+   */
+  void SetHiddenPrototype(bool value);
+
+  /**
+   * Returns true if the given object is an instance of this function
+   * template.
+   */
+  bool HasInstance(Handle<Value> object);
+
+ private:
+  FunctionTemplate();
+  void AddInstancePropertyAccessor(Handle<String> name,
+                                   AccessorGetter getter,
+                                   AccessorSetter setter,
+                                   Handle<Value> data,
+                                   AccessControl settings,
+                                   PropertyAttribute attributes);
+  void SetNamedInstancePropertyHandler(NamedPropertyGetter getter,
+                                       NamedPropertySetter setter,
+                                       NamedPropertyQuery query,
+                                       NamedPropertyDeleter remover,
+                                       NamedPropertyEnumerator enumerator,
+                                       Handle<Value> data);
+  void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
+                                         IndexedPropertySetter setter,
+                                         IndexedPropertyQuery query,
+                                         IndexedPropertyDeleter remover,
+                                         IndexedPropertyEnumerator enumerator,
+                                         Handle<Value> data);
+  void SetInstanceCallAsFunctionHandler(InvocationCallback callback,
+                                        Handle<Value> data);
+
+  friend class Context;
+  friend class ObjectTemplate;
+};
+
+
+/**
+ * An ObjectTemplate is used to create objects at runtime.
+ *
+ * Properties added to an ObjectTemplate are added to each object
+ * created from the ObjectTemplate.
+ */
+class EXPORT ObjectTemplate : public Template {
+ public:
+  /** Creates an ObjectTemplate. */
+  static Local<ObjectTemplate> New();
+
+  /** Creates a new instance of this template.*/
+  Local<Object> NewInstance();
+
+  /**
+   * Sets an accessor on the object template.
+   *
+   * Whenever the property with the given name is accessed on objects
+   * created from this ObjectTemplate the getter and setter callbacks
+   * are called instead of getting and setting the property directly
+   * on the JavaScript object.
+   *
+   * \param name The name of the property for which an accessor is added.
+   * \param getter The callback to invoke when getting the property.
+   * \param setter The callback to invoke when setting the property.
+   * \param data A piece of data that will be passed to the getter and setter
+   *   callbacks whenever they are invoked.
+   * \param settings Access control settings for the accessor. This is a bit
+   *   field consisting of one of more of
+   *   DEFAULT = 0, ALL_CAN_READ = 1, or ALL_CAN_WRITE = 2.
+   *   The default is to not allow cross-context access.
+   *   ALL_CAN_READ means that all cross-context reads are allowed.
+   *   ALL_CAN_WRITE means that all cross-context writes are allowed.
+   *   The combination ALL_CAN_READ | ALL_CAN_WRITE can be used to allow all
+   *   cross-context access.
+   * \param attribute The attributes of the property for which an accessor
+   *   is added.
+   */
+  void SetAccessor(Handle<String> name,
+                   AccessorGetter getter,
+                   AccessorSetter setter = 0,
+                   Handle<Value> data = Handle<Value>(),
+                   AccessControl settings = DEFAULT,
+                   PropertyAttribute attribute = None);
+
+  /**
+   * Sets a named property handler on the object template.
+   *
+   * Whenever a named property is accessed on objects created from
+   * this object template, the provided callback is invoked instead of
+   * accessing the property directly on the JavaScript object.
+   *
+   * \param getter The callback to invoke when getting a property.
+   * \param setter The callback to invoke when setting a property.
+   * \param query The callback to invoke to check is an object has a property.
+   * \param deleter The callback to invoke when deleting a property.
+   * \param enumerator The callback to invoke to enumerate all the named
+   *   properties of an object.
+   * \param data A piece of data that will be passed to the callbacks
+   *   whenever they are invoked.
+   */
+  void SetNamedPropertyHandler(NamedPropertyGetter getter,
+                               NamedPropertySetter setter = 0,
+                               NamedPropertyQuery query = 0,
+                               NamedPropertyDeleter deleter = 0,
+                               NamedPropertyEnumerator enumerator = 0,
+                               Handle<Value> data = Handle<Value>());
+
+  /**
+   * Sets an indexed property handler on the object template.
+   *
+   * Whenever an indexed property is accessed on objects created from
+   * this object template, the provided callback is invoked instead of
+   * accessing the property directly on the JavaScript object.
+   *
+   * \param getter The callback to invoke when getting a property.
+   * \param setter The callback to invoke when setting a property.
+   * \param query The callback to invoke to check is an object has a property.
+   * \param deleter The callback to invoke when deleting a property.
+   * \param enumerator The callback to invoke to enumerate all the indexed
+   *   properties of an object.
+   * \param data A piece of data that will be passed to the callbacks
+   *   whenever they are invoked.
+   */
+  void SetIndexedPropertyHandler(IndexedPropertyGetter getter,
+                                 IndexedPropertySetter setter = 0,
+                                 IndexedPropertyQuery query = 0,
+                                 IndexedPropertyDeleter deleter = 0,
+                                 IndexedPropertyEnumerator enumerator = 0,
+                                 Handle<Value> data = Handle<Value>());
+  /**
+   * Sets the callback to be used when calling instances created from
+   * this template as a function.  If no callback is set, instances
+   * behave like normal JavaScript objects that cannot be called as a
+   * function.
+   */
+  void SetCallAsFunctionHandler(InvocationCallback callback,
+                                Handle<Value> data = Handle<Value>());
+
+  /**
+   * Mark object instances of the template as undetectable.
+   *
+   * In many ways, undetectable objects behave as though they are not
+   * there.  They behave like 'undefined' in conditionals and when
+   * printed.  However, properties can be accessed and called as on
+   * normal objects.
+   */
+  void MarkAsUndetectable();
+
+  /**
+   * Sets access check callbacks on the object template.
+   *
+   * When accessing properties on instances of this object template,
+   * the access check callback will be called to determine whether or
+   * not to allow cross-context access to the properties.
+   * The last parameter specifies whether access checks are turned
+   * on by default on instances. If access checks are off by default,
+   * they can be turned on on individual instances by calling
+   * Object::TurnOnAccessCheck().
+   */
+  void SetAccessCheckCallbacks(NamedSecurityCallback named_handler,
+                               IndexedSecurityCallback indexed_handler,
+                               Handle<Value> data = Handle<Value>(),
+                               bool turned_on_by_default = true);
+
+  /**
+   * Gets the number of internal fields for objects generated from
+   * this template.
+   */
+  int InternalFieldCount();
+
+  /**
+   * Sets the number of internal fields for objects generated from
+   * this template.
+   */
+  void SetInternalFieldCount(int value);
+
+ private:
+  ObjectTemplate();
+  static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
+  friend class FunctionTemplate;
+};
+
+
+/**
+ * A Signature specifies which receivers and arguments a function can
+ * legally be called with.
+ */
+class EXPORT Signature : public Data {
+ public:
+  static Local<Signature> New(Handle<FunctionTemplate> receiver =
+                                  Handle<FunctionTemplate>(),
+                              int argc = 0,
+                              Handle<FunctionTemplate> argv[] = 0);
+ private:
+  Signature();
+};
+
+
+/**
+ * A utility for determining the type of objects based on the template
+ * they were constructed from.
+ */
+class EXPORT TypeSwitch : public Data {
+ public:
+  static Local<TypeSwitch> New(Handle<FunctionTemplate> type);
+  static Local<TypeSwitch> New(int argc, Handle<FunctionTemplate> types[]);
+  int match(Handle<Value> value);
+ private:
+  TypeSwitch();
+};
+
+
+// --- E x t e n s i o n s ---
+
+
+/**
+ * Ignore
+ */
+class EXPORT Extension {  // NOLINT
+ public:
+  Extension(const char* name,
+            const char* source = 0,
+            int dep_count = 0,
+            const char** deps = 0);
+  virtual ~Extension() { }
+  virtual v8::Handle<v8::FunctionTemplate>
+      GetNativeFunction(v8::Handle<v8::String> name) {
+    return v8::Handle<v8::FunctionTemplate>();
+  }
+
+  const char* name() { return name_; }
+  const char* source() { return source_; }
+  int dependency_count() { return dep_count_; }
+  const char** dependencies() { return deps_; }
+  void set_auto_enable(bool value) { auto_enable_ = value; }
+  bool auto_enable() { return auto_enable_; }
+
+ private:
+  const char* name_;
+  const char* source_;
+  int dep_count_;
+  const char** deps_;
+  bool auto_enable_;
+
+  // Disallow copying and assigning.
+  Extension(const Extension&);
+  void operator=(const Extension&);
+};
+
+
+void EXPORT RegisterExtension(Extension* extension);
+
+
+/**
+ * Ignore
+ */
+class EXPORT DeclareExtension {
+ public:
+  inline DeclareExtension(Extension* extension) {
+    RegisterExtension(extension);
+  }
+};
+
+
+// --- S t a t i c s ---
+
+
+Handle<Primitive> EXPORT Undefined();
+Handle<Primitive> EXPORT Null();
+Handle<Boolean> EXPORT True();
+Handle<Boolean> EXPORT False();
+
+
+/**
+ * A set of constraints that specifies the limits of the runtime's
+ * memory use.
+ */
+class EXPORT ResourceConstraints {
+ public:
+  ResourceConstraints();
+  int max_young_space_size() const { return max_young_space_size_; }
+  void set_max_young_space_size(int value) { max_young_space_size_ = value; }
+  int max_old_space_size() const { return max_old_space_size_; }
+  void set_max_old_space_size(int value) { max_old_space_size_ = value; }
+  uint32_t* stack_limit() const { return stack_limit_; }
+  void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
+ private:
+  int max_young_space_size_;
+  int max_old_space_size_;
+  uint32_t* stack_limit_;
+};
+
+
+bool SetResourceConstraints(ResourceConstraints* constraints);
+
+
+// --- E x c e p t i o n s ---
+
+
+typedef void (*FatalErrorCallback)(const char* location, const char* message);
+
+
+typedef void (*MessageCallback)(Handle<Message> message, Handle<Value> data);
+
+
+/**
+ * Schedules an exception to be thrown when returning to JavaScript.  When an
+ * exception has been scheduled it is illegal to invoke any JavaScript
+ * operation; the caller must return immediately and only after the exception
+ * has been handled does it become legal to invoke JavaScript operations.
+ */
+Handle<Value> EXPORT ThrowException(Handle<Value> exception);
+
+/**
+ * Create new error objects by calling the corresponding error object
+ * constructor with the message.
+ */
+class EXPORT Exception {
+ public:
+  static Local<Value> RangeError(Handle<String> message);
+  static Local<Value> ReferenceError(Handle<String> message);
+  static Local<Value> SyntaxError(Handle<String> message);
+  static Local<Value> TypeError(Handle<String> message);
+  static Local<Value> Error(Handle<String> message);
+};
+
+
+// --- C o u n t e r s  C a l l b a c k s
+
+typedef int* (*CounterLookupCallback)(const wchar_t* name);
+
+// --- F a i l e d A c c e s s C h e c k C a l l b a c k ---
+typedef void (*FailedAccessCheckCallback)(Local<Object> target,
+                                          AccessType type,
+                                          Local<Value> data);
+
+// --- G a r b a g e C o l l e c t i o n  C a l l b a c k s
+
+/**
+ * Applications can register a callback function which is called
+ * before and after a major garbage collection.  Allocations are not
+ * allowed in the callback function, you therefore cannot manipulate
+ * objects (set or delete properties for example) since it is possible
+ * such operations will result in the allocation of objects.
+ */
+typedef void (*GCCallback)();
+
+
+//  --- C o n t e x t  G e n e r a t o r
+
+/**
+ * Applications must provide a callback function which is called to generate
+ * a context if a context was not deserialized from the snapshot.
+ */
+typedef Persistent<Context> (*ContextGenerator)();
+
+
+/**
+ * Container class for static utility functions.
+ */
+class EXPORT V8 {
+ public:
+  /** Set the callback to invoke in case of fatal errors. */
+  static void SetFatalErrorHandler(FatalErrorCallback that);
+
+  /**
+   * Ignore out-of-memory exceptions.
+   *
+   * V8 running out of memory is treated as a fatal error by default.
+   * This means that the fatal error handler is called and that V8 is
+   * terminated.
+   *
+   * IgnoreOutOfMemoryException can be used to not treat a
+   * out-of-memory situation as a fatal error.  This way, the contexts
+   * that did not cause the out of memory problem might be able to
+   * continue execution.
+   */
+  static void IgnoreOutOfMemoryException();
+
+  /**
+   * Check if V8 is dead and therefore unusable.  This is the case after
+   * fatal errors such as out-of-memory situations.
+   */
+  static bool IsDead();
+
+  /**
+   * Adds a message listener.
+   *
+   * The same message listener can be added more than once and it that
+   * case it will be called more than once for each message.
+   */
+  static bool AddMessageListener(MessageCallback that,
+                                 Handle<Value> data = Handle<Value>());
+
+  /**
+   * Remove all message listeners from the specified callback function.
+   */
+  static void RemoveMessageListeners(MessageCallback that);
+
+  /**
+   * Sets V8 flags from a string.
+   */
+  static void SetFlagsFromString(const char* str, int length);
+
+  /**
+   * Sets V8 flags from the command line.
+   */
+  static void SetFlagsFromCommandLine(int* argc,
+                                      char** argv,
+                                      bool remove_flags);
+
+  /** Get the version string. */
+  static const char* GetVersion();
+
+  /**
+   * Enables the host application to provide a mechanism for recording
+   * statistics counters.
+   */
+  static void SetCounterFunction(CounterLookupCallback);
+
+  /**
+   * Enables the computation of a sliding window of states. The sliding
+   * window information is recorded in statistics counters.
+   */
+  static void EnableSlidingStateWindow();
+
+  /** Callback function for reporting failed access checks.*/
+  static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
+
+  /**
+   * Enables the host application to receive a notification before a
+   * major garbage colletion.  Allocations are not allowed in the
+   * callback function, you therefore cannot manipulate objects (set
+   * or delete properties for example) since it is possible such
+   * operations will result in the allocation of objects.
+   */
+  static void SetGlobalGCPrologueCallback(GCCallback);
+
+  /**
+   * Enables the host application to receive a notification after a
+   * major garbage collection.  Allocations are not allowed in the
+   * callback function, you therefore cannot manipulate objects (set
+   * or delete properties for example) since it is possible such
+   * operations will result in the allocation of objects.
+   */
+  static void SetGlobalGCEpilogueCallback(GCCallback);
+
+  /**
+   * Allows the host application to group objects together. If one
+   * object in the group is alive, all objects in the group are alive.
+   * After each garbage collection, object groups are removed. It is
+   * intended to be used in the before-garbage-collection callback
+   * function for istance to simulate DOM tree connections among JS
+   * wrapper objects.
+   */
+  static void AddObjectToGroup(void* id, Persistent<Object> obj);
+
+  /**
+   * Initializes from snapshot if possible. Otherwise, attempts to
+   * initialize from scratch.
+   */
+  static bool Initialize();
+
+  /**
+   * Adjusts the amount of registered external memory.  Used to give
+   * V8 an indication of the amount of externally allocated memory
+   * that is kept alive by JavaScript objects.  V8 uses this to decide
+   * when to perform global garbage collections.  Registering
+   * externally allocated memory will trigger global garbage
+   * collections more often than otherwise in an attempt to garbage
+   * collect the JavaScript objects keeping the externally allocated
+   * memory alive.
+   *
+   * \param change_in_bytes the change in externally allocated memory
+   *   that is kept alive by JavaScript objects.
+   * \returns the adjusted value.
+   */
+  static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
+
+ private:
+  V8();
+
+  static void** GlobalizeReference(void** handle);
+  static void DisposeGlobal(void** global_handle);
+  static void MakeWeak(void** global_handle, void* data, WeakReferenceCallback);
+  static void ClearWeak(void** global_handle);
+  static bool IsGlobalNearDeath(void** global_handle);
+  static bool IsGlobalWeak(void** global_handle);
+
+  template <class T> friend class Handle;
+  template <class T> friend class Local;
+  template <class T> friend class Persistent;
+  friend class Context;
+};
+
+
+/**
+ * An external exception handler.
+ */
+class EXPORT TryCatch {
+ public:
+
+  /**
+   * Creates a new try/catch block and registers it with v8.
+   */
+  TryCatch();
+
+  /**
+   * Unregisters and deletes this try/catch block.
+   */
+  ~TryCatch();
+
+  /**
+   * Returns true if an exception has been caught by this try/catch block.
+   */
+  bool HasCaught() const;
+
+  /**
+   * Returns the exception caught by this try/catch block.  If no exception has
+   * been caught an empty handle is returned.
+   *
+   * The returned handle is valid until this TryCatch block has been destroyed.
+   */
+  Local<Value> Exception() const;
+
+  /**
+   * Returns the message associated with this exception.  If there is
+   * no message associated an empty handle is returned.
+   *
+   * The returned handle is valid until this TryCatch block has been
+   * destroyed.
+   */
+  Local<v8::Message> Message() const;
+
+  /**
+   * Clears any exceptions that may have been caught by this try/catch block.
+   * After this method has been called, HasCaught() will return false.
+   *
+   * It is not necessary to clear a try/catch block before using it again; if
+   * another exception is thrown the previously caught exception will just be
+   * overwritten.  However, it is often a good idea since it makes it easier
+   * to determine which operation threw a given exception.
+   */
+  void Reset();
+
+  /**
+   * Set verbosity of the external exception handler.
+   *
+   * By default, exceptions that are caught by an external exception
+   * handler are not reported.  Call SetVerbose with true on an
+   * external exception handler to have exceptions caught by the
+   * handler reported as if they were not caught.
+   */
+  void SetVerbose(bool value);
+
+  /**
+   * Set whether or not this TryCatch should capture a Message object
+   * which holds source information about where the exception
+   * occurred.  True by default.
+   */
+  void SetCaptureMessage(bool value);
+
+ public:
+  TryCatch* next_;
+  void* exception_;
+  void* message_;
+  bool is_verbose_;
+  bool capture_message_;
+};
+
+
+// --- C o n t e x t ---
+
+
+/**
+ * Ignore
+ */
+class EXPORT ExtensionConfiguration {
+ public:
+  ExtensionConfiguration(int name_count, const char* names[])
+      : name_count_(name_count), names_(names) { }
+ private:
+  friend class ImplementationUtilities;
+  int name_count_;
+  const char** names_;
+};
+
+
+/**
+ * A sandboxed execution context with its own set of built-in objects
+ * and functions.
+ */
+class EXPORT Context {
+ public:
+  /** Returns the global object of the context. */
+  Local<Object> Global();
+
+  /**
+   * Detaches the global object from its context before
+   * the global object can be reused to create a new context.
+   */
+  void DetachGlobal();
+
+  /** Creates a new context. */
+  static Persistent<Context> New(
+      ExtensionConfiguration* extensions = 0,
+      Handle<ObjectTemplate> global_template = Handle<ObjectTemplate>(),
+      Handle<Value> global_object = Handle<Value>());
+
+  /** Returns the last entered context. */
+  static Local<Context> GetEntered();
+
+  /** Returns the context that is on the top of the stack. */
+  static Local<Context> GetCurrent();
+
+  /**
+   * Sets the security token for the context.  To access an object in
+   * another context, the security tokens must match.
+   */
+  void SetSecurityToken(Handle<Value> token);
+
+  /** Restores the security token to the default value. */
+  void UseDefaultSecurityToken();
+
+  /** Returns the security token of this context.*/
+  Handle<Value> GetSecurityToken();
+
+  /**
+   * Enter this context.  After entering a context, all code compiled
+   * and run is compiled and run in this context.  If another context
+   * is already entered, this old context is saved so it can be
+   * restored when the new context is exited.
+   */
+  void Enter();
+
+  /**
+   * Exit this context.  Exiting the current context restores the
+   * context that was in place when entering the current context.
+   */
+  void Exit();
+
+  /** Returns true if the context has experienced an out of memory situation. */
+  bool HasOutOfMemoryException();
+
+  /** Returns true if V8 has a current context. */
+  static bool InContext();
+
+  /**
+   * Stack-allocated class which sets the execution context for all
+   * operations executed within a local scope.
+   */
+  class EXPORT Scope {
+   public:
+    inline Scope(Handle<Context> context) : context_(context) {
+      context_->Enter();
+    }
+    inline ~Scope() { context_->Exit(); }
+   private:
+    Handle<Context> context_;
+  };
+
+ private:
+  friend class Value;
+  friend class Script;
+  friend class Object;
+  friend class Function;
+};
+
+
+/**
+ * Multiple threads in V8 are allowed, but only one thread at a time
+ * is allowed to use V8.  The definition of 'using V8' includes
+ * accessing handles or holding onto object pointers obtained from V8
+ * handles.  It is up to the user of V8 to ensure (perhaps with
+ * locking) that this constraint is not violated.
+ *
+ * If you wish to start using V8 in a thread you can do this by constructing
+ * a v8::Locker object.  After the code using V8 has completed for the
+ * current thread you can call the destructor.  This can be combined
+ * with C++ scope-based construction as follows:
+ *
+ * \code
+ * ...
+ * {
+ *   v8::Locker locker;
+ *   ...
+ *   // Code using V8 goes here.
+ *   ...
+ * } // Destructor called here
+ * \endcode
+ *
+ * If you wish to stop using V8 in a thread A you can do this by either
+ * by destroying the v8::Locker object as above or by constructing a
+ * v8::Unlocker object:
+ *
+ * \code
+ * {
+ *   v8::Unlocker unlocker;
+ *   ...
+ *   // Code not using V8 goes here while V8 can run in another thread.
+ *   ...
+ * } // Destructor called here.
+ * \endcode
+ *
+ * The Unlocker object is intended for use in a long-running callback
+ * from V8, where you want to release the V8 lock for other threads to
+ * use.
+ *
+ * The v8::Locker is a recursive lock.  That is, you can lock more than
+ * once in a given thread.  This can be useful if you have code that can
+ * be called either from code that holds the lock or from code that does
+ * not.  The Unlocker is not recursive so you can not have several
+ * Unlockers on the stack at once, and you can not use an Unlocker in a
+ * thread that is not inside a Locker's scope.
+ *
+ * An unlocker will unlock several lockers if it has to and reinstate
+ * the correct depth of locking on its destruction. eg.:
+ *
+ * \code
+ * // V8 not locked.
+ * {
+ *   v8::Locker locker;
+ *   // V8 locked.
+ *   {
+ *     v8::Locker another_locker;
+ *     // V8 still locked (2 levels).
+ *     {
+ *       v8::Unlocker unlocker;
+ *       // V8 not locked.
+ *     }
+ *     // V8 locked again (2 levels).
+ *   }
+ *   // V8 still locked (1 level).
+ * }
+ * // V8 Now no longer locked.
+ * \endcode
+ */
+class EXPORT Unlocker {
+ public:
+  Unlocker();
+  ~Unlocker();
+};
+
+
+class EXPORT Locker {
+ public:
+  Locker();
+  ~Locker();
+
+  /**
+   * Start preemption.
+   *
+   * When preemption is started, a timer is fired every n milli seconds
+   * that will switch between multiple threads that are in contention
+   * for the V8 lock.
+   */
+  static void StartPreemption(int every_n_ms);
+
+  /**
+   * Stop preemption.
+   */
+  static void StopPreemption();
+
+  /**
+   * Returns whether or not the locker is locked by the current thread.
+   */
+  static bool IsLocked();
+
+ private:
+  bool has_lock_;
+  bool top_level_;
+
+  // Disallow copying and assigning.
+  Locker(const Locker&);
+  void operator=(const Locker&);
+};
+
+
+
+// --- I m p l e m e n t a t i o n ---
+
+template <class T>
+Handle<T>::Handle() : val_(0) { }
+
+
+template <class T>
+Local<T>::Local() : Handle<T>() { }
+
+
+template <class T>
+Local<T> Local<T>::New(Handle<T> that) {
+  if (that.IsEmpty()) return Local<T>();
+  void** p = reinterpret_cast<void**>(*that);
+  return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(*p)));
+}
+
+
+template <class T>
+Persistent<T> Persistent<T>::New(Handle<T> that) {
+  if (that.IsEmpty()) return Persistent<T>();
+  void** p = reinterpret_cast<void**>(*that);
+  return Persistent<T>(reinterpret_cast<T*>(V8::GlobalizeReference(p)));
+}
+
+
+template <class T>
+bool Persistent<T>::IsNearDeath() {
+  if (this->IsEmpty()) return false;
+  return V8::IsGlobalNearDeath(reinterpret_cast<void**>(**this));
+}
+
+
+template <class T>
+bool Persistent<T>::IsWeak() {
+  if (this->IsEmpty()) return false;
+  return V8::IsGlobalWeak(reinterpret_cast<void**>(**this));
+}
+
+
+template <class T>
+void Persistent<T>::Dispose() {
+  if (this->IsEmpty()) return;
+  V8::DisposeGlobal(reinterpret_cast<void**>(**this));
+}
+
+
+template <class T>
+Persistent<T>::Persistent() : Handle<T>() { }
+
+template <class T>
+void Persistent<T>::MakeWeak(void* parameters, WeakReferenceCallback callback) {
+  V8::MakeWeak(reinterpret_cast<void**>(**this), parameters, callback);
+}
+
+template <class T>
+void Persistent<T>::ClearWeak() {
+  V8::ClearWeak(reinterpret_cast<void**>(**this));
+}
+
+template <class T>
+T* Handle<T>::operator->() {
+  return val_;
+}
+
+
+template <class T>
+T* Handle<T>::operator*() {
+  return val_;
+}
+
+
+Local<Value> Arguments::operator[](int i) const {
+  if (i < 0 || length_ <= i) return Local<Value>(*Undefined());
+  return Local<Value>(reinterpret_cast<Value*>(values_ - i));
+}
+
+
+Local<Function> Arguments::Callee() const {
+  return callee_;
+}
+
+
+Local<Object> Arguments::This() const {
+  return Local<Object>(reinterpret_cast<Object*>(values_ + 1));
+}
+
+
+Local<Object> Arguments::Holder() const {
+  return holder_;
+}
+
+
+Local<Value> Arguments::Data() const {
+  return data_;
+}
+
+
+bool Arguments::IsConstructCall() const {
+  return is_construct_call_;
+}
+
+
+int Arguments::Length() const {
+  return length_;
+}
+
+
+Local<Value> AccessorInfo::Data() const {
+  return data_;
+}
+
+
+Local<Object> AccessorInfo::This() const {
+  return self_;
+}
+
+
+Local<Object> AccessorInfo::Holder() const {
+  return holder_;
+}
+
+
+template <class T>
+Local<T> HandleScope::Close(Handle<T> value) {
+  void** after = RawClose(reinterpret_cast<void**>(*value));
+  return Local<T>(reinterpret_cast<T*>(after));
+}
+
+Handle<Value> ScriptOrigin::ResourceName() const {
+  return resource_name_;
+}
+
+
+Handle<Integer> ScriptOrigin::ResourceLineOffset() const {
+  return resource_line_offset_;
+}
+
+
+Handle<Integer> ScriptOrigin::ResourceColumnOffset() const {
+  return resource_column_offset_;
+}
+
+
+Handle<Boolean> Boolean::New(bool value) {
+  return value ? True() : False();
+}
+
+
+void Template::Set(const char* name, v8::Handle<Data> value) {
+  Set(v8::String::New(name), value);
+}
+
+
+/**
+ * \example shell.cc
+ * A simple shell that takes a list of expressions on the
+ * command-line and executes them.
+ */
+
+
+/**
+ * \example process.cc
+ */
+
+
+}  // namespace v8
+
+
+#undef EXPORT
+#undef EXPORT_INLINE
+#undef TYPE_CHECK
+
+
+#endif  // V8_H_
diff --git a/regexp2000/samples/SConscript b/regexp2000/samples/SConscript
new file mode 100644 (file)
index 0000000..31990b6
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from os.path import join
+Import('sample context')
+
+def ConfigureObjectFiles():
+  env = Environment()
+  env.Replace(**context.flags['sample'])
+  context.ApplyEnvOverrides(env)
+  return env.Object(sample + '.cc')
+
+sample_object = ConfigureObjectFiles()
+Return('sample_object')
diff --git a/regexp2000/samples/count-hosts.js b/regexp2000/samples/count-hosts.js
new file mode 100644 (file)
index 0000000..bea6553
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function Initialize() { }
+
+function Process(request) {
+  if (options.verbose) {
+    log("Processing " + request.host + request.path +
+        " from " + request.referrer + "@" + request.userAgent);
+  }
+  if (!output[request.host]) {
+    output[request.host] = 1;
+  } else {
+    output[request.host]++
+  }
+}
+
+Initialize();
diff --git a/regexp2000/samples/process.cc b/regexp2000/samples/process.cc
new file mode 100644 (file)
index 0000000..6567f08
--- /dev/null
@@ -0,0 +1,624 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <v8.h>
+
+// To avoid warnings from <map> on windows we disable exceptions.
+#define _HAS_EXCEPTIONS 0
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace v8;
+
+// These interfaces represent an existing request processing interface.
+// The idea is to imagine a real application that uses these interfaces
+// and then add scripting capabilities that allow you to interact with
+// the objects through JavaScript.
+
+/**
+ * A simplified http request.
+ */
+class HttpRequest {
+ public:
+  virtual ~HttpRequest() { }
+  virtual const string& Path() = 0;
+  virtual const string& Referrer() = 0;
+  virtual const string& Host() = 0;
+  virtual const string& UserAgent() = 0;
+};
+
+/**
+ * The abstract superclass of http request processors.
+ */
+class HttpRequestProcessor {
+ public:
+  virtual ~HttpRequestProcessor() { }
+
+  // Initialize this processor.  The map contains options that control
+  // how requests should be processed.
+  virtual bool Initialize(map<string, string>* options,
+                          map<string, string>* output) = 0;
+
+  // Process a single request.
+  virtual bool Process(HttpRequest* req) = 0;
+
+  static void Log(const char* event);
+};
+
+/**
+ * An http request processor that is scriptable using JavaScript.
+ */
+class JsHttpRequestProcessor : public HttpRequestProcessor {
+ public:
+
+  // Creates a new processor that processes requests by invoking the
+  // Process function of the JavaScript script given as an argument.
+  explicit JsHttpRequestProcessor(Handle<String> script) : script_(script) { }
+  virtual ~JsHttpRequestProcessor();
+
+  virtual bool Initialize(map<string, string>* opts,
+                          map<string, string>* output);
+  virtual bool Process(HttpRequest* req);
+
+ private:
+
+  // Execute the script associated with this processor and extract the
+  // Process function.  Returns true if this succeeded, otherwise false.
+  bool ExecuteScript(Handle<String> script);
+
+  // Wrap the options and output map in a JavaScript objects and
+  // install it in the global namespace as 'options' and 'output'.
+  bool InstallMaps(map<string, string>* opts, map<string, string>* output);
+
+  // Constructs the template that describes the JavaScript wrapper
+  // type for requests.
+  static Handle<ObjectTemplate> MakeRequestTemplate();
+  static Handle<ObjectTemplate> MakeMapTemplate();
+
+  // Callbacks that access the individual fields of request objects.
+  static Handle<Value> GetPath(Local<String> name, const AccessorInfo& info);
+  static Handle<Value> GetReferrer(Local<String> name,
+                                   const AccessorInfo& info);
+  static Handle<Value> GetHost(Local<String> name, const AccessorInfo& info);
+  static Handle<Value> GetUserAgent(Local<String> name,
+                                    const AccessorInfo& info);
+
+  // Callbacks that access maps
+  static Handle<Value> MapGet(Local<String> name, const AccessorInfo& info);
+  static Handle<Value> MapSet(Local<String> name,
+                              Local<Value> value,
+                              const AccessorInfo& info);
+
+  // Utility methods for wrapping C++ objects as JavaScript objects,
+  // and going back again.
+  static Handle<Object> WrapMap(map<string, string>* obj);
+  static map<string, string>* UnwrapMap(Handle<Object> obj);
+  static Handle<Object> WrapRequest(HttpRequest* obj);
+  static HttpRequest* UnwrapRequest(Handle<Object> obj);
+
+  Handle<String> script_;
+  Persistent<Context> context_;
+  Persistent<Function> process_;
+  static Persistent<ObjectTemplate> request_template_;
+  static Persistent<ObjectTemplate> map_template_;
+};
+
+// -------------------------
+// --- P r o c e s s o r ---
+// -------------------------
+
+
+static Handle<Value> LogCallback(const Arguments& args) {
+  if (args.Length() < 1) return v8::Undefined();
+  HandleScope scope;
+  Handle<Value> arg = args[0];
+  String::Utf8Value value(arg);
+  HttpRequestProcessor::Log(*value);
+  return v8::Undefined();
+}
+
+
+// Execute the script and fetch the Process method.
+bool JsHttpRequestProcessor::Initialize(map<string, string>* opts,
+                                        map<string, string>* output) {
+  // Create a handle scope to hold the temporary references.
+  HandleScope handle_scope;
+
+  // Create a template for the global object where we set the
+  // built-in global functions.
+  Handle<ObjectTemplate> global = ObjectTemplate::New();
+  global->Set(String::New("log"), FunctionTemplate::New(LogCallback));
+
+  // Each processor gets its own context so different processors
+  // don't affect each other (ignore the first three lines).
+  Handle<Context> context = Context::New(NULL, global);
+
+  // Store the context in the processor object in a persistent handle,
+  // since we want the reference to remain after we return from this
+  // method.
+  context_ = Persistent<Context>::New(context);
+
+  // Enter the new context so all the following operations take place
+  // within it.
+  Context::Scope context_scope(context);
+
+  // Make the options mapping available within the context
+  if (!InstallMaps(opts, output))
+    return false;
+
+  // Compile and run the script
+  if (!ExecuteScript(script_))
+    return false;
+
+  // The script compiled and ran correctly.  Now we fetch out the
+  // Process function from the global object.
+  Handle<String> process_name = String::New("Process");
+  Handle<Value> process_val = context->Global()->Get(process_name);
+
+  // If there is no Process function, or if it is not a function,
+  // bail out
+  if (!process_val->IsFunction()) return false;
+
+  // It is a function; cast it to a Function
+  Handle<Function> process_fun = Handle<Function>::Cast(process_val);
+
+  // Store the function in a Persistent handle, since we also want
+  // that to remain after this call returns
+  process_ = Persistent<Function>::New(process_fun);
+
+  // All done; all went well
+  return true;
+}
+
+
+bool JsHttpRequestProcessor::ExecuteScript(Handle<String> script) {
+  HandleScope handle_scope;
+
+  // We're just about to compile the script; set up an error handler to
+  // catch any exceptions the script might throw.
+  TryCatch try_catch;
+
+  // Compile the script and check for errors.
+  Handle<Script> compiled_script = Script::Compile(script);
+  if (compiled_script.IsEmpty()) {
+    String::Utf8Value error(try_catch.Exception());
+    Log(*error);
+    // The script failed to compile; bail out.
+    return false;
+  }
+
+  // Run the script!
+  Handle<Value> result = compiled_script->Run();
+  if (result.IsEmpty()) {
+    // The TryCatch above is still in effect and will have caught the error.
+    String::Utf8Value error(try_catch.Exception());
+    Log(*error);
+    // Running the script failed; bail out.
+    return false;
+  }
+  return true;
+}
+
+
+bool JsHttpRequestProcessor::InstallMaps(map<string, string>* opts,
+                                         map<string, string>* output) {
+  HandleScope handle_scope;
+
+  // Wrap the map object in a JavaScript wrapper
+  Handle<Object> opts_obj = WrapMap(opts);
+
+  // Set the options object as a property on the global object.
+  context_->Global()->Set(String::New("options"), opts_obj);
+
+  Handle<Object> output_obj = WrapMap(output);
+  context_->Global()->Set(String::New("output"), output_obj);
+
+  return true;
+}
+
+
+bool JsHttpRequestProcessor::Process(HttpRequest* request) {
+  // Create a handle scope to keep the temporary object references.
+  HandleScope handle_scope;
+
+  // Enter this processor's context so all the remaining operations
+  // take place there
+  Context::Scope context_scope(context_);
+
+  // Wrap the C++ request object in a JavaScript wrapper
+  Handle<Object> request_obj = WrapRequest(request);
+
+  // Set up an exception handler before calling the Process function
+  TryCatch try_catch;
+
+  // Invoke the process function, giving the global object as 'this'
+  // and one argument, the request.
+  const int argc = 1;
+  Handle<Value> argv[argc] = { request_obj };
+  Handle<Value> result = process_->Call(context_->Global(), argc, argv);
+  if (result.IsEmpty()) {
+    String::Utf8Value error(try_catch.Exception());
+    Log(*error);
+    return false;
+  } else {
+    return true;
+  }
+}
+
+
+JsHttpRequestProcessor::~JsHttpRequestProcessor() {
+  // Dispose the persistent handles.  When noone else has any
+  // references to the objects stored in the handles they will be
+  // automatically reclaimed.
+  context_.Dispose();
+  process_.Dispose();
+}
+
+
+Persistent<ObjectTemplate> JsHttpRequestProcessor::request_template_;
+Persistent<ObjectTemplate> JsHttpRequestProcessor::map_template_;
+
+
+// -----------------------------------
+// --- A c c e s s i n g   M a p s ---
+// -----------------------------------
+
+// Utility function that wraps a C++ http request object in a
+// JavaScript object.
+Handle<Object> JsHttpRequestProcessor::WrapMap(map<string, string>* obj) {
+  // Handle scope for temporary handles.
+  HandleScope handle_scope;
+
+  // Fetch the template for creating JavaScript map wrappers.
+  // It only has to be created once, which we do on demand.
+  if (request_template_.IsEmpty()) {
+    Handle<ObjectTemplate> raw_template = MakeMapTemplate();
+    map_template_ = Persistent<ObjectTemplate>::New(raw_template);
+  }
+  Handle<ObjectTemplate> templ = map_template_;
+
+  // Create an empty map wrapper.
+  Handle<Object> result = templ->NewInstance();
+
+  // Wrap the raw C++ pointer in an External so it can be referenced
+  // from within JavaScript.
+  Handle<External> map_ptr = External::New(obj);
+
+  // Store the map pointer in the JavaScript wrapper.
+  result->SetInternalField(0, map_ptr);
+
+  // Return the result through the current handle scope.  Since each
+  // of these handles will go away when the handle scope is deleted
+  // we need to call Close to let one, the result, escape into the
+  // outer handle scope.
+  return handle_scope.Close(result);
+}
+
+
+// Utility function that extracts the C++ map pointer from a wrapper
+// object.
+map<string, string>* JsHttpRequestProcessor::UnwrapMap(Handle<Object> obj) {
+  Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
+  void* ptr = field->Value();
+  return static_cast<map<string, string>*>(ptr);
+}
+
+
+// Convert a JavaScript string to a std::string.  To not bother too
+// much with string encodings we just use ascii.
+string ObjectToString(Local<Value> value) {
+  String::Utf8Value utf8_value(value);
+  return string(*utf8_value);
+}
+
+
+Handle<Value> JsHttpRequestProcessor::MapGet(Local<String> name,
+                                             const AccessorInfo& info) {
+  // Fetch the map wrapped by this object.
+  map<string, string>* obj = UnwrapMap(info.Holder());
+
+  // Convert the JavaScript string to a std::string.
+  string key = ObjectToString(name);
+
+  // Look up the value if it exists using the standard STL ideom.
+  map<string, string>::iterator iter = obj->find(key);
+
+  // If the key is not present return an empty handle as signal
+  if (iter == obj->end()) return Handle<Value>();
+
+  // Otherwise fetch the value and wrap it in a JavaScript string
+  const string& value = (*iter).second;
+  return String::New(value.c_str(), value.length());
+}
+
+
+Handle<Value> JsHttpRequestProcessor::MapSet(Local<String> name,
+                                             Local<Value> value_obj,
+                                             const AccessorInfo& info) {
+  // Fetch the map wrapped by this object.
+  map<string, string>* obj = UnwrapMap(info.Holder());
+
+  // Convert the key and value to std::strings.
+  string key = ObjectToString(name);
+  string value = ObjectToString(value_obj);
+
+  // Update the map.
+  (*obj)[key] = value;
+
+  // Return the value; any non-empty handle will work.
+  return value_obj;
+}
+
+
+Handle<ObjectTemplate> JsHttpRequestProcessor::MakeMapTemplate() {
+  HandleScope handle_scope;
+
+  Handle<ObjectTemplate> result = ObjectTemplate::New();
+  result->SetInternalFieldCount(1);
+  result->SetNamedPropertyHandler(MapGet, MapSet);
+
+  // Again, return the result through the current handle scope.
+  return handle_scope.Close(result);
+}
+
+
+// -------------------------------------------
+// --- A c c e s s i n g   R e q u e s t s ---
+// -------------------------------------------
+
+/**
+ * Utility function that wraps a C++ http request object in a
+ * JavaScript object.
+ */
+Handle<Object> JsHttpRequestProcessor::WrapRequest(HttpRequest* request) {
+  // Handle scope for temporary handles.
+  HandleScope handle_scope;
+
+  // Fetch the template for creating JavaScript http request wrappers.
+  // It only has to be created once, which we do on demand.
+  if (request_template_.IsEmpty()) {
+    Handle<ObjectTemplate> raw_template = MakeRequestTemplate();
+    request_template_ = Persistent<ObjectTemplate>::New(raw_template);
+  }
+  Handle<ObjectTemplate> templ = request_template_;
+
+  // Create an empty http request wrapper.
+  Handle<Object> result = templ->NewInstance();
+
+  // Wrap the raw C++ pointer in an External so it can be referenced
+  // from within JavaScript.
+  Handle<External> request_ptr = External::New(request);
+
+  // Store the request pointer in the JavaScript wrapper.
+  result->SetInternalField(0, request_ptr);
+
+  // Return the result through the current handle scope.  Since each
+  // of these handles will go away when the handle scope is deleted
+  // we need to call Close to let one, the result, escape into the
+  // outer handle scope.
+  return handle_scope.Close(result);
+}
+
+
+/**
+ * Utility function that extracts the C++ http request object from a
+ * wrapper object.
+ */
+HttpRequest* JsHttpRequestProcessor::UnwrapRequest(Handle<Object> obj) {
+  Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
+  void* ptr = field->Value();
+  return static_cast<HttpRequest*>(ptr);
+}
+
+
+Handle<Value> JsHttpRequestProcessor::GetPath(Local<String> name,
+                                              const AccessorInfo& info) {
+  // Extract the C++ request object from the JavaScript wrapper.
+  HttpRequest* request = UnwrapRequest(info.Holder());
+
+  // Fetch the path.
+  const string& path = request->Path();
+
+  // Wrap the result in a JavaScript string and return it.
+  return String::New(path.c_str(), path.length());
+}
+
+
+Handle<Value> JsHttpRequestProcessor::GetReferrer(Local<String> name,
+                                                  const AccessorInfo& info) {
+  HttpRequest* request = UnwrapRequest(info.Holder());
+  const string& path = request->Referrer();
+  return String::New(path.c_str(), path.length());
+}
+
+
+Handle<Value> JsHttpRequestProcessor::GetHost(Local<String> name,
+                                              const AccessorInfo& info) {
+  HttpRequest* request = UnwrapRequest(info.Holder());
+  const string& path = request->Host();
+  return String::New(path.c_str(), path.length());
+}
+
+
+Handle<Value> JsHttpRequestProcessor::GetUserAgent(Local<String> name,
+                                                   const AccessorInfo& info) {
+  HttpRequest* request = UnwrapRequest(info.Holder());
+  const string& path = request->UserAgent();
+  return String::New(path.c_str(), path.length());
+}
+
+
+Handle<ObjectTemplate> JsHttpRequestProcessor::MakeRequestTemplate() {
+  HandleScope handle_scope;
+
+  Handle<ObjectTemplate> result = ObjectTemplate::New();
+  result->SetInternalFieldCount(1);
+
+  // Add accessors for each of the fields of the request.
+  result->SetAccessor(String::NewSymbol("path"), GetPath);
+  result->SetAccessor(String::NewSymbol("referrer"), GetReferrer);
+  result->SetAccessor(String::NewSymbol("host"), GetHost);
+  result->SetAccessor(String::NewSymbol("userAgent"), GetUserAgent);
+
+  // Again, return the result through the current handle scope.
+  return handle_scope.Close(result);
+}
+
+
+// --- Test ---
+
+
+void HttpRequestProcessor::Log(const char* event) {
+  printf("Logged: %s\n", event);
+}
+
+
+/**
+ * A simplified http request.
+ */
+class StringHttpRequest : public HttpRequest {
+ public:
+  StringHttpRequest(const string& path,
+                    const string& referrer,
+                    const string& host,
+                    const string& user_agent);
+  virtual const string& Path() { return path_; }
+  virtual const string& Referrer() { return referrer_; }
+  virtual const string& Host() { return host_; }
+  virtual const string& UserAgent() { return user_agent_; }
+ private:
+  string path_;
+  string referrer_;
+  string host_;
+  string user_agent_;
+};
+
+
+StringHttpRequest::StringHttpRequest(const string& path,
+                                     const string& referrer,
+                                     const string& host,
+                                     const string& user_agent)
+    : path_(path),
+      referrer_(referrer),
+      host_(host),
+      user_agent_(user_agent) { }
+
+
+void ParseOptions(int argc,
+                  char* argv[],
+                  map<string, string>& options,
+                  string* file) {
+  for (int i = 1; i < argc; i++) {
+    string arg = argv[i];
+    int index = arg.find('=', 0);
+    if (index == string::npos) {
+      *file = arg;
+    } else {
+      string key = arg.substr(0, index);
+      string value = arg.substr(index+1);
+      options[key] = value;
+    }
+  }
+}
+
+
+// Reads a file into a v8 string.
+Handle<String> ReadFile(const string& name) {
+  FILE* file = fopen(name.c_str(), "rb");
+  if (file == NULL) return Handle<String>();
+
+  fseek(file, 0, SEEK_END);
+  int size = ftell(file);
+  rewind(file);
+
+  char* chars = new char[size + 1];
+  chars[size] = '\0';
+  for (int i = 0; i < size;) {
+    int read = fread(&chars[i], 1, size - i, file);
+    i += read;
+  }
+  fclose(file);
+  Handle<String> result = String::New(chars, size);
+  delete[] chars;
+  return result;
+}
+
+
+const int kSampleSize = 6;
+StringHttpRequest kSampleRequests[kSampleSize] = {
+  StringHttpRequest("/process.cc", "localhost", "google.com", "firefox"),
+  StringHttpRequest("/", "localhost", "google.net", "firefox"),
+  StringHttpRequest("/", "localhost", "google.org", "safari"),
+  StringHttpRequest("/", "localhost", "yahoo.com", "ie"),
+  StringHttpRequest("/", "localhost", "yahoo.com", "safari"),
+  StringHttpRequest("/", "localhost", "yahoo.com", "firefox")
+};
+
+
+bool ProcessEntries(HttpRequestProcessor* processor, int count,
+                    StringHttpRequest* reqs) {
+  for (int i = 0; i < count; i++) {
+    if (!processor->Process(&reqs[i]))
+      return false;
+  }
+  return true;
+}
+
+
+void PrintMap(map<string, string>* m) {
+  for (map<string, string>::iterator i = m->begin(); i != m->end(); i++) {
+    pair<string, string> entry = *i;
+    printf("%s: %s\n", entry.first.c_str(), entry.second.c_str());
+  }
+}
+
+
+int main(int argc, char* argv[]) {
+  map<string, string> options;
+  string file;
+  ParseOptions(argc, argv, options, &file);
+  if (file.empty()) {
+    fprintf(stderr, "No script was specified.\n");
+    return 1;
+  }
+  HandleScope scope;
+  Handle<String> source = ReadFile(file);
+  if (source.IsEmpty()) {
+    fprintf(stderr, "Error reading '%s'.\n", file.c_str());
+    return 1;
+  }
+  JsHttpRequestProcessor processor(source);
+  map<string, string> output;
+  if (!processor.Initialize(&options, &output)) {
+    fprintf(stderr, "Error initializing processor.\n");
+    return 1;
+  }
+  if (!ProcessEntries(&processor, kSampleSize, kSampleRequests))
+    return 1;
+  PrintMap(&output);
+}
diff --git a/regexp2000/samples/shell.cc b/regexp2000/samples/shell.cc
new file mode 100644 (file)
index 0000000..0209410
--- /dev/null
@@ -0,0 +1,258 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <v8.h>
+#include <cstring>
+#include <cstdio>
+#include <cstdlib>
+
+
+void RunShell(v8::Handle<v8::Context> context);
+bool ExecuteString(v8::Handle<v8::String> source,
+                   v8::Handle<v8::Value> name,
+                   bool print_result,
+                   bool report_exceptions);
+v8::Handle<v8::Value> Print(const v8::Arguments& args);
+v8::Handle<v8::Value> Load(const v8::Arguments& args);
+v8::Handle<v8::Value> Quit(const v8::Arguments& args);
+v8::Handle<v8::Value> Version(const v8::Arguments& args);
+v8::Handle<v8::String> ReadFile(const char* name);
+void ReportException(v8::TryCatch* handler);
+
+
+int main(int argc, char* argv[]) {
+  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
+  v8::HandleScope handle_scope;
+  // Create a template for the global object.
+  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+  // Bind the global 'print' function to the C++ Print callback.
+  global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
+  // Bind the global 'load' function to the C++ Load callback.
+  global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
+  // Bind the 'quit' function
+  global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
+  // Bind the 'version' function
+  global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
+  // Create a new execution environment containing the built-in
+  // functions
+  v8::Handle<v8::Context> context = v8::Context::New(NULL, global);
+  // Enter the newly created execution environment.
+  v8::Context::Scope context_scope(context);
+  bool run_shell = (argc == 1);
+  for (int i = 1; i < argc; i++) {
+    const char* str = argv[i];
+    if (strcmp(str, "--shell") == 0) {
+      run_shell = true;
+    } else if (strcmp(str, "-f") == 0) {
+      // Ignore any -f flags for compatibility with the other stand-
+      // alone JavaScript engines.
+      continue;
+    } else if (strncmp(str, "--", 2) == 0) {
+      printf("Warning: unknown flag %s.\n", str);
+    } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
+      // Execute argument given to -e option directly
+      v8::HandleScope handle_scope;
+      v8::Handle<v8::String> file_name = v8::String::New("unnamed");
+      v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
+      if (!ExecuteString(source, file_name, false, true))
+        return 1;
+      i++;
+    } else {
+      // Use all other arguments as names of files to load and run.
+      v8::HandleScope handle_scope;
+      v8::Handle<v8::String> file_name = v8::String::New(str);
+      v8::Handle<v8::String> source = ReadFile(str);
+      if (source.IsEmpty()) {
+        printf("Error reading '%s'\n", str);
+        return 1;
+      }
+      if (!ExecuteString(source, file_name, false, true))
+        return 1;
+    }
+  }
+  if (run_shell) RunShell(context);
+  return 0;
+}
+
+
+// The callback that is invoked by v8 whenever the JavaScript 'print'
+// function is called.  Prints its arguments on stdout separated by
+// spaces and ending with a newline.
+v8::Handle<v8::Value> Print(const v8::Arguments& args) {
+  bool first = true;
+  for (int i = 0; i < args.Length(); i++) {
+    v8::HandleScope handle_scope;
+    if (first) {
+      first = false;
+    } else {
+      printf(" ");
+    }
+    v8::String::Utf8Value str(args[i]);
+    printf("%s", *str);
+  }
+  printf("\n");
+  return v8::Undefined();
+}
+
+
+// The callback that is invoked by v8 whenever the JavaScript 'load'
+// function is called.  Loads, compiles and executes its argument
+// JavaScript file.
+v8::Handle<v8::Value> Load(const v8::Arguments& args) {
+  for (int i = 0; i < args.Length(); i++) {
+    v8::HandleScope handle_scope;
+    v8::String::Utf8Value file(args[i]);
+    v8::Handle<v8::String> source = ReadFile(*file);
+    if (source.IsEmpty()) {
+      return v8::ThrowException(v8::String::New("Error loading file"));
+    }
+    if (!ExecuteString(source, v8::String::New(*file), false, false)) {
+      return v8::ThrowException(v8::String::New("Error executing  file"));
+    }
+  }
+  return v8::Undefined();
+}
+
+
+// The callback that is invoked by v8 whenever the JavaScript 'quit'
+// function is called.  Quits.
+v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
+  // If not arguments are given args[0] will yield undefined which
+  // converts to the integer value 0.
+  int exit_code = args[0]->Int32Value();
+  exit(exit_code);
+  return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> Version(const v8::Arguments& args) {
+  return v8::String::New(v8::V8::GetVersion());
+}
+
+
+// Reads a file into a v8 string.
+v8::Handle<v8::String> ReadFile(const char* name) {
+  FILE* file = fopen(name, "rb");
+  if (file == NULL) return v8::Handle<v8::String>();
+
+  fseek(file, 0, SEEK_END);
+  int size = ftell(file);
+  rewind(file);
+
+  char* chars = new char[size + 1];
+  chars[size] = '\0';
+  for (int i = 0; i < size;) {
+    int read = fread(&chars[i], 1, size - i, file);
+    i += read;
+  }
+  fclose(file);
+  v8::Handle<v8::String> result = v8::String::New(chars, size);
+  delete[] chars;
+  return result;
+}
+
+
+// The read-eval-execute loop of the shell.
+void RunShell(v8::Handle<v8::Context> context) {
+  printf("V8 version %s\n", v8::V8::GetVersion());
+  static const int kBufferSize = 256;
+  while (true) {
+    char buffer[kBufferSize];
+    printf("> ");
+    char* str = fgets(buffer, kBufferSize, stdin);
+    if (str == NULL) break;
+    v8::HandleScope handle_scope;
+    ExecuteString(v8::String::New(str),
+                  v8::String::New("(shell)"),
+                  true,
+                  true);
+  }
+  printf("\n");
+}
+
+
+// Executes a string within the current v8 context.
+bool ExecuteString(v8::Handle<v8::String> source,
+                   v8::Handle<v8::Value> name,
+                   bool print_result,
+                   bool report_exceptions) {
+  v8::HandleScope handle_scope;
+  v8::TryCatch try_catch;
+  v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
+  if (script.IsEmpty()) {
+    // Print errors that happened during compilation.
+    if (report_exceptions)
+      ReportException(&try_catch);
+    return false;
+  } else {
+    v8::Handle<v8::Value> result = script->Run();
+    if (result.IsEmpty()) {
+      // Print errors that happened during execution.
+      if (report_exceptions)
+        ReportException(&try_catch);
+      return false;
+    } else {
+      if (print_result && !result->IsUndefined()) {
+        // If all went well and the result wasn't undefined then print
+        // the returned value.
+        v8::String::Utf8Value str(result);
+        printf("%s\n", *str);
+      }
+      return true;
+    }
+  }
+}
+
+
+void ReportException(v8::TryCatch* try_catch) {
+  v8::HandleScope handle_scope;
+  v8::String::Utf8Value exception(try_catch->Exception());
+  v8::Handle<v8::Message> message = try_catch->Message();
+  if (message.IsEmpty()) {
+    // V8 didn't provide any extra information about this error; just
+    // print the exception.
+    printf("%s\n", *exception);
+  } else {
+    // Print (filename):(line number): (message).
+    v8::String::Utf8Value filename(message->GetScriptResourceName());
+    int linenum = message->GetLineNumber();
+    printf("%s:%i: %s\n", *filename, linenum, *exception);
+    // Print line of source code.
+    v8::String::Utf8Value sourceline(message->GetSourceLine());
+    printf("%s\n", *sourceline);
+    // Print wavy underline (GetUnderline is deprecated).
+    int start = message->GetStartColumn();
+    for (int i = 0; i < start; i++) {
+      printf(" ");
+    }
+    int end = message->GetEndColumn();
+    for (int i = start; i < end; i++) {
+      printf("^");
+    }
+    printf("\n");
+  }
+}
diff --git a/regexp2000/src/SConscript b/regexp2000/src/SConscript
new file mode 100644 (file)
index 0000000..c1a6433
--- /dev/null
@@ -0,0 +1,160 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+from os.path import join, dirname, abspath
+root_dir = dirname(File('SConstruct').rfile().abspath)
+sys.path.append(join(root_dir, 'tools'))
+import js2c
+Import('context')
+
+
+SOURCES = {
+  'all': [
+    'accessors.cc', 'allocation.cc', 'api.cc', 'assembler.cc', 'ast.cc',
+    'bootstrapper.cc', 'builtins.cc', 'checks.cc', 'code-stubs.cc',
+    'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
+    'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
+    'disassembler.cc', 'execution.cc', 'factory.cc', 'flags.cc', 'frames.cc',
+    'global-handles.cc', 'handles.cc', 'hashmap.cc', 'heap.cc', 'ic.cc',
+    'jsregexp.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 'objects.cc',
+    'parser.cc', 'property.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
+    'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
+    'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
+    'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc',
+    'v8.cc', 'v8threads.cc', 'variables.cc', 'zone.cc'
+  ],
+  'arch:arm':  ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc',
+      'cpu-arm.cc', 'disasm-arm.cc', 'frames-arm.cc', 'ic-arm.cc',
+      'macro-assembler-arm.cc', 'stub-cache-arm.cc'],
+  'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc',
+      'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc',
+      'macro-assembler-ia32.cc', 'stub-cache-ia32.cc'],
+  'simulator:arm': ['simulator-arm.cc'],
+  'os:linux':  ['platform-linux.cc'],
+  'os:macos':  ['platform-macos.cc'],
+  'os:nullos': ['platform-nullos.cc'],
+  'os:win32':  ['platform-win32.cc'],
+  'mode:release': [],
+  'mode:debug': ['objects-debug.cc', 'prettyprinter.cc']
+}
+
+
+D8_FILES = {
+  'all': [
+    'd8.cc'
+  ],
+  'console:readline': [
+    'd8-readline.cc'
+  ]
+}
+
+
+LIBRARY_FILES = '''
+runtime.js
+v8natives.js
+array.js
+string.js
+uri.js
+math.js
+messages.js
+apinatives.js
+debug-delay.js
+mirror-delay.js
+date-delay.js
+regexp-delay.js
+'''.split()
+
+
+JSCRE_FILES = '''
+pcre_compile.cpp
+pcre_exec.cpp
+pcre_tables.cpp
+pcre_ucp_searchfuncs.cpp
+pcre_xclass.cpp
+'''.split()
+
+
+def Abort(message):
+  print message
+  sys.exit(1)
+
+
+def ConfigureObjectFiles():
+  env = Environment()
+  env.Replace(**context.flags['v8'])
+  context.ApplyEnvOverrides(env)
+  env['BUILDERS']['JS2C'] = Builder(action=js2c.JS2C)
+  env['BUILDERS']['Snapshot'] = Builder(action='$SOURCE $TARGET --logfile "$LOGFILE"')
+
+  # Build the standard platform-independent source files.
+  source_files = context.GetRelevantSources(SOURCES)
+
+  d8_files = context.GetRelevantSources(D8_FILES)
+  d8_js = env.JS2C('d8-js.cc', 'd8.js', TYPE='D8')
+  d8_js_obj = context.ConfigureObject(env, d8_js, CPPPATH=['.'])
+  d8_objs = [context.ConfigureObject(env, [d8_files]), d8_js_obj]
+
+  # Combine the JavaScript library files into a single C++ file and
+  # compile it.
+  library_files = [s for s in LIBRARY_FILES]
+  library_files.append('macros.py')
+  libraries_src, libraries_empty_src = env.JS2C(['libraries.cc', 'libraries-empty.cc'], library_files, TYPE='CORE')
+  libraries_obj = context.ConfigureObject(env, libraries_src, CPPPATH=['.'])
+
+  # Build JSCRE.
+  jscre_env = env.Copy()
+  jscre_env.Replace(**context.flags['jscre'])
+  jscre_files = [join('third_party', 'jscre', s) for s in JSCRE_FILES]
+  jscre_obj = context.ConfigureObject(jscre_env, jscre_files)
+
+  # Build dtoa.
+  dtoa_env = env.Copy()
+  dtoa_env.Replace(**context.flags['dtoa'])
+  dtoa_files = ['dtoa-config.c']
+  dtoa_obj = context.ConfigureObject(dtoa_env, dtoa_files)
+
+  source_objs = context.ConfigureObject(env, source_files)
+  non_snapshot_files = [jscre_obj, dtoa_obj, source_objs]
+
+  # Create snapshot if necessary.
+  empty_snapshot_obj = context.ConfigureObject(env, 'snapshot-empty.cc')
+  if context.use_snapshot:
+    mksnapshot_src = 'mksnapshot.cc'
+    mksnapshot = env.Program('mksnapshot', [mksnapshot_src, libraries_obj, non_snapshot_files, empty_snapshot_obj], PDB='mksnapshot.exe.pdb')
+    snapshot_cc = env.Snapshot('snapshot.cc', mksnapshot, LOGFILE=File('snapshot.log').abspath)
+    snapshot_obj = context.ConfigureObject(env, snapshot_cc, CPPPATH=['.'])
+    libraries_obj = context.ConfigureObject(env, libraries_empty_src, CPPPATH=['.'])
+  else:
+    snapshot_obj = empty_snapshot_obj
+
+  library_objs = [non_snapshot_files, libraries_obj, snapshot_obj]
+  return (library_objs, d8_objs)
+
+
+(library_objs, d8_objs) = ConfigureObjectFiles()
+Return('library_objs d8_objs')
diff --git a/regexp2000/src/accessors.cc b/regexp2000/src/accessors.cc
new file mode 100644 (file)
index 0000000..47d58a4
--- /dev/null
@@ -0,0 +1,510 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "accessors.h"
+#include "execution.h"
+#include "factory.h"
+#include "scopeinfo.h"
+#include "top.h"
+#include "zone-inl.h"
+
+namespace v8 { namespace internal {
+
+
+template <class C>
+static C* FindInPrototypeChain(Object* obj, bool* found_it) {
+  ASSERT(!*found_it);
+  while (!Is<C>(obj)) {
+    if (obj == Heap::null_value()) return NULL;
+    obj = obj->GetPrototype();
+  }
+  *found_it = true;
+  return C::cast(obj);
+}
+
+
+// Entry point that never should be called.
+Object* Accessors::IllegalSetter(JSObject*, Object*, void*) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+Object* Accessors::IllegalGetAccessor(Object* object, void*) {
+  UNREACHABLE();
+  return object;
+}
+
+
+Object* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
+  // According to ECMA-262, section 8.6.2.2, page 28, setting
+  // read-only properties must be silently ignored.
+  return value;
+}
+
+
+//
+// Accessors::ArrayLength
+//
+
+
+Object* Accessors::ArrayGetLength(Object* object, void*) {
+  // Traverse the prototype chain until we reach an array.
+  bool found_it = false;
+  JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
+  if (!found_it) return Smi::FromInt(0);
+  return holder->length();
+}
+
+
+// The helper function will 'flatten' Number objects.
+Object* Accessors::FlattenNumber(Object* value) {
+  if (value->IsNumber() || !value->IsJSValue()) return value;
+  JSValue* wrapper = JSValue::cast(value);
+  ASSERT(
+      Top::context()->global_context()->number_function()->has_initial_map());
+  Map* number_map =
+      Top::context()->global_context()->number_function()->initial_map();
+  if (wrapper->map() == number_map) return wrapper->value();
+  return value;
+}
+
+
+Object* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
+  value = FlattenNumber(value);
+
+  // Need to call methods that may trigger GC.
+  HandleScope scope;
+
+  // Protect raw pointers.
+  Handle<JSObject> object_handle(object);
+  Handle<Object> value_handle(value);
+
+  bool has_exception;
+  Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
+  if (has_exception) return Failure::Exception();
+  Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
+  if (has_exception) return Failure::Exception();
+
+  // Restore raw pointers,
+  object = *object_handle;
+  value = *value_handle;
+
+  if (uint32_v->Number() == number_v->Number()) {
+    if (object->IsJSArray()) {
+      return JSArray::cast(object)->SetElementsLength(*uint32_v);
+    } else {
+      // This means one of the object's prototypes is a JSArray and
+      // the object does not have a 'length' property.
+      // Calling SetProperty causes an infinite loop.
+      return object->IgnoreAttributesAndSetLocalProperty(Heap::length_symbol(),
+                                                         value, NONE);
+    }
+  }
+  return Top::Throw(*Factory::NewRangeError("invalid_array_length",
+                                            HandleVector<Object>(NULL, 0)));
+}
+
+
+const AccessorDescriptor Accessors::ArrayLength = {
+  ArrayGetLength,
+  ArraySetLength,
+  0
+};
+
+
+//
+// Accessors::StringLength
+//
+
+
+Object* Accessors::StringGetLength(Object* object, void*) {
+  Object* value = object;
+  if (object->IsJSValue()) value = JSValue::cast(object)->value();
+  if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
+  // If object is not a string we return 0 to be compatible with WebKit.
+  // Note: Firefox returns the length of ToString(object).
+  return Smi::FromInt(0);
+}
+
+
+const AccessorDescriptor Accessors::StringLength = {
+  StringGetLength,
+  IllegalSetter,
+  0
+};
+
+
+//
+// Accessors::ScriptSource
+//
+
+
+Object* Accessors::ScriptGetSource(Object* object, void*) {
+  Object* script = JSValue::cast(object)->value();
+  return Script::cast(script)->source();
+}
+
+
+const AccessorDescriptor Accessors::ScriptSource = {
+  ScriptGetSource,
+  IllegalSetter,
+  0
+};
+
+
+//
+// Accessors::ScriptName
+//
+
+
+Object* Accessors::ScriptGetName(Object* object, void*) {
+  Object* script = JSValue::cast(object)->value();
+  return Script::cast(script)->name();
+}
+
+
+const AccessorDescriptor Accessors::ScriptName = {
+  ScriptGetName,
+  IllegalSetter,
+  0
+};
+
+
+//
+// Accessors::ScriptLineOffset
+//
+
+
+Object* Accessors::ScriptGetLineOffset(Object* object, void*) {
+  Object* script = JSValue::cast(object)->value();
+  return Script::cast(script)->line_offset();
+}
+
+
+const AccessorDescriptor Accessors::ScriptLineOffset = {
+  ScriptGetLineOffset,
+  IllegalSetter,
+  0
+};
+
+
+//
+// Accessors::ScriptColumnOffset
+//
+
+
+Object* Accessors::ScriptGetColumnOffset(Object* object, void*) {
+  Object* script = JSValue::cast(object)->value();
+  return Script::cast(script)->column_offset();
+}
+
+
+const AccessorDescriptor Accessors::ScriptColumnOffset = {
+  ScriptGetColumnOffset,
+  IllegalSetter,
+  0
+};
+
+
+//
+// Accessors::ScriptType
+//
+
+
+Object* Accessors::ScriptGetType(Object* object, void*) {
+  Object* script = JSValue::cast(object)->value();
+  return Script::cast(script)->type();
+}
+
+
+const AccessorDescriptor Accessors::ScriptType = {
+  ScriptGetType,
+  IllegalSetter,
+  0
+};
+
+
+//
+// Accessors::FunctionPrototype
+//
+
+
+Object* Accessors::FunctionGetPrototype(Object* object, void*) {
+  bool found_it = false;
+  JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
+  if (!found_it) return Heap::undefined_value();
+  if (!function->has_prototype()) {
+    Object* prototype = Heap::AllocateFunctionPrototype(function);
+    if (prototype->IsFailure()) return prototype;
+    Object* result = function->SetPrototype(prototype);
+    if (result->IsFailure()) return result;
+  }
+  return function->prototype();
+}
+
+
+Object* Accessors::FunctionSetPrototype(JSObject* object,
+                                        Object* value,
+                                        void*) {
+  bool found_it = false;
+  JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
+  if (!found_it) return Heap::undefined_value();
+  if (function->has_initial_map()) {
+    // If the function has allocated the initial map
+    // replace it with a copy containing the new prototype.
+    Object* new_map = function->initial_map()->CopyDropTransitions();
+    if (new_map->IsFailure()) return new_map;
+    function->set_initial_map(Map::cast(new_map));
+  }
+  Object* prototype = function->SetPrototype(value);
+  if (prototype->IsFailure()) return prototype;
+  ASSERT(function->prototype() == value);
+  return function;
+}
+
+
+const AccessorDescriptor Accessors::FunctionPrototype = {
+  FunctionGetPrototype,
+  FunctionSetPrototype,
+  0
+};
+
+
+//
+// Accessors::FunctionLength
+//
+
+
+Object* Accessors::FunctionGetLength(Object* object, void*) {
+  bool found_it = false;
+  JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
+  if (!found_it) return Smi::FromInt(0);
+  // Check if already compiled.
+  if (!function->is_compiled()) {
+    // If the function isn't compiled yet, the length is not computed
+    // correctly yet. Compile it now and return the right length.
+    HandleScope scope;
+    Handle<JSFunction> function_handle(function);
+    if (!CompileLazy(function_handle, KEEP_EXCEPTION)) {
+      return Failure::Exception();
+    }
+    return Smi::FromInt(function_handle->shared()->length());
+  } else {
+    return Smi::FromInt(function->shared()->length());
+  }
+}
+
+
+const AccessorDescriptor Accessors::FunctionLength = {
+  FunctionGetLength,
+  ReadOnlySetAccessor,
+  0
+};
+
+
+//
+// Accessors::FunctionName
+//
+
+
+Object* Accessors::FunctionGetName(Object* object, void*) {
+  bool found_it = false;
+  JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
+  if (!found_it) return Heap::undefined_value();
+  return holder->shared()->name();
+}
+
+
+const AccessorDescriptor Accessors::FunctionName = {
+  FunctionGetName,
+  ReadOnlySetAccessor,
+  0
+};
+
+
+//
+// Accessors::FunctionArguments
+//
+
+
+Object* Accessors::FunctionGetArguments(Object* object, void*) {
+  HandleScope scope;
+  bool found_it = false;
+  JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
+  if (!found_it) return Heap::undefined_value();
+  Handle<JSFunction> function(holder);
+
+  // Find the top invocation of the function by traversing frames.
+  for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
+    // Skip all frames that aren't invocations of the given function.
+    JavaScriptFrame* frame = it.frame();
+    if (frame->function() != *function) continue;
+
+    // If there is an arguments variable in the stack, we return that.
+    int index = ScopeInfo<>::StackSlotIndex(frame->FindCode(),
+                                          Heap::arguments_symbol());
+    if (index >= 0) return frame->GetExpression(index);
+
+    // If there isn't an arguments variable in the stack, we need to
+    // find the frame that holds the actual arguments passed to the
+    // function on the stack.
+    it.AdvanceToArgumentsFrame();
+    frame = it.frame();
+
+    // Get the number of arguments and construct an arguments object
+    // mirror for the right frame.
+    const int length = frame->GetProvidedParametersCount();
+    Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
+    Handle<FixedArray> array = Factory::NewFixedArray(length);
+
+    // Copy the parameters to the arguments object.
+    ASSERT(array->length() == length);
+    for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
+    arguments->set_elements(*array);
+
+    // Return the freshly allocated arguments object.
+    return *arguments;
+  }
+
+  // No frame corresponding to the given function found. Return null.
+  return Heap::null_value();
+}
+
+
+const AccessorDescriptor Accessors::FunctionArguments = {
+  FunctionGetArguments,
+  ReadOnlySetAccessor,
+  0
+};
+
+
+//
+// Accessors::FunctionCaller
+//
+
+
+Object* Accessors::FunctionGetCaller(Object* object, void*) {
+  HandleScope scope;
+  bool found_it = false;
+  JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
+  if (!found_it) return Heap::undefined_value();
+  Handle<JSFunction> function(holder);
+
+  // Find the top invocation of the function by traversing frames.
+  for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
+    // Skip all frames that aren't invocations of the given function.
+    if (it.frame()->function() != *function) continue;
+    // Once we have found the frame, we need to go to the caller
+    // frame. This may require skipping through a number of top-level
+    // frames, e.g. frames for scripts not functions.
+    while (true) {
+      it.Advance();
+      if (it.done()) return Heap::null_value();
+      JSFunction* caller = JSFunction::cast(it.frame()->function());
+      if (!caller->shared()->is_toplevel()) return caller;
+    }
+  }
+
+  // No frame corresponding to the given function found. Return null.
+  return Heap::null_value();
+}
+
+
+const AccessorDescriptor Accessors::FunctionCaller = {
+  FunctionGetCaller,
+  ReadOnlySetAccessor,
+  0
+};
+
+
+//
+// Accessors::ObjectPrototype
+//
+
+
+Object* Accessors::ObjectGetPrototype(Object* receiver, void*) {
+  Object* current = receiver->GetPrototype();
+  while (current->IsJSObject() &&
+         JSObject::cast(current)->map()->is_hidden_prototype()) {
+    current = current->GetPrototype();
+  }
+  return current;
+}
+
+
+Object* Accessors::ObjectSetPrototype(JSObject* receiver,
+                                      Object* value,
+                                      void*) {
+  // Before we can set the prototype we need to be sure
+  // prototype cycles are prevented.
+  // It is sufficient to validate that the receiver is not in the new prototype
+  // chain.
+
+  // Silently ignore the change if value is not a JSObject or null.
+  // SpiderMonkey behaves this way.
+  if (!value->IsJSObject() && !value->IsNull()) return value;
+
+  for (Object* pt = value; pt != Heap::null_value(); pt = pt->GetPrototype()) {
+    if (JSObject::cast(pt) == receiver) {
+      // Cycle detected.
+      HandleScope scope;
+      return Top::Throw(*Factory::NewError("cyclic_proto",
+                                           HandleVector<Object>(NULL, 0)));
+    }
+  }
+
+  // Find the first object in the chain whose prototype object is not
+  // hidden and set the new prototype on that object.
+  JSObject* current = receiver;
+  Object* current_proto = receiver->GetPrototype();
+  while (current_proto->IsJSObject() &&
+         JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
+    current = JSObject::cast(current_proto);
+    current_proto = current_proto->GetPrototype();
+  }
+
+  // Set the new prototype of the object.
+  Object* new_map = current->map()->CopyDropTransitions();
+  if (new_map->IsFailure()) return new_map;
+  Map::cast(new_map)->set_prototype(value);
+  current->set_map(Map::cast(new_map));
+
+  // To be consistent with other Set functions, return the value.
+  return value;
+}
+
+
+const AccessorDescriptor Accessors::ObjectPrototype = {
+  ObjectGetPrototype,
+  ObjectSetPrototype,
+  0
+};
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/accessors.h b/regexp2000/src/accessors.h
new file mode 100644 (file)
index 0000000..6fb3195
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ACCESSORS_H_
+#define V8_ACCESSORS_H_
+
+namespace v8 { namespace internal {
+
+// The list of accessor descriptors. This is a second-order macro
+// taking a macro to be applied to all accessor descriptor names.
+#define ACCESSOR_DESCRIPTOR_LIST(V) \
+  V(FunctionPrototype)   \
+  V(FunctionLength)      \
+  V(FunctionName)        \
+  V(FunctionArguments)   \
+  V(FunctionCaller)      \
+  V(ArrayLength)         \
+  V(StringLength)        \
+  V(ScriptSource)        \
+  V(ScriptName)          \
+  V(ScriptLineOffset)    \
+  V(ScriptColumnOffset)  \
+  V(ScriptType)          \
+  V(ObjectPrototype)
+
+// Accessors contains all predefined proxy accessors.
+
+class Accessors : public AllStatic {
+ public:
+  // Accessor descriptors.
+#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
+  static const AccessorDescriptor name;
+  ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
+#undef ACCESSOR_DESCRIPTOR_DECLARATION
+
+  enum DescriptorId {
+#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
+    k##name,
+  ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
+#undef ACCESSOR_DESCRIPTOR_DECLARATION
+    descriptorCount
+  };
+
+  // Accessor functions called directly from the runtime system.
+  static Object* FunctionGetPrototype(Object* object, void*);
+  static Object* FunctionSetPrototype(JSObject* object, Object* value, void*);
+ private:
+  // Accessor functions only used through the descriptor.
+  static Object* FunctionGetLength(Object* object, void*);
+  static Object* FunctionGetName(Object* object, void*);
+  static Object* FunctionGetArguments(Object* object, void*);
+  static Object* FunctionGetCaller(Object* object, void*);
+  static Object* ArraySetLength(JSObject* object, Object* value, void*);
+  static Object* ArrayGetLength(Object* object, void*);
+  static Object* StringGetLength(Object* object, void*);
+  static Object* ScriptGetName(Object* object, void*);
+  static Object* ScriptGetSource(Object* object, void*);
+  static Object* ScriptGetLineOffset(Object* object, void*);
+  static Object* ScriptGetColumnOffset(Object* object, void*);
+  static Object* ScriptGetType(Object* object, void*);
+  static Object* ObjectGetPrototype(Object* receiver, void*);
+  static Object* ObjectSetPrototype(JSObject* receiver, Object* value, void*);
+
+  // Helper functions.
+  static Object* FlattenNumber(Object* value);
+  static Object* IllegalSetter(JSObject*, Object*, void*);
+  static Object* IllegalGetAccessor(Object* object, void*);
+  static Object* ReadOnlySetAccessor(JSObject*, Object* value, void*);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ACCESSORS_H_
diff --git a/regexp2000/src/allocation.cc b/regexp2000/src/allocation.cc
new file mode 100644 (file)
index 0000000..d7d21aa
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+namespace v8 { namespace internal {
+
+
+void* Malloced::New(size_t size) {
+  ASSERT(NativeAllocationChecker::allocation_allowed());
+  void* result = malloc(size);
+  if (result == NULL) V8::FatalProcessOutOfMemory("Malloced operator new");
+  return result;
+}
+
+
+void Malloced::Delete(void* p) {
+  free(p);
+}
+
+
+void Malloced::FatalProcessOutOfMemory() {
+  V8::FatalProcessOutOfMemory("Out of memory");
+}
+
+
+#ifdef DEBUG
+
+static void* invalid = static_cast<void*>(NULL);
+
+void* Embedded::operator new(size_t size) {
+  UNREACHABLE();
+  return invalid;
+}
+
+
+void Embedded::operator delete(void* p) {
+  UNREACHABLE();
+}
+
+
+void* AllStatic::operator new(size_t size) {
+  UNREACHABLE();
+  return invalid;
+}
+
+
+void AllStatic::operator delete(void* p) {
+  UNREACHABLE();
+}
+
+#endif
+
+
+char* StrDup(const char* str) {
+  int length = strlen(str);
+  char* result = NewArray<char>(length + 1);
+  memcpy(result, str, length * kCharSize);
+  result[length] = '\0';
+  return result;
+}
+
+
+int NativeAllocationChecker::allocation_disallowed_ = 0;
+
+
+PreallocatedStorage PreallocatedStorage::in_use_list_(0);
+PreallocatedStorage PreallocatedStorage::free_list_(0);
+bool PreallocatedStorage::preallocated_ = false;
+
+
+void PreallocatedStorage::Init(size_t size) {
+  ASSERT(free_list_.next_ == &free_list_);
+  ASSERT(free_list_.previous_ == &free_list_);
+  PreallocatedStorage* free_chunk =
+      reinterpret_cast<PreallocatedStorage*>(new char[size]);
+  free_list_.next_ = free_list_.previous_ = free_chunk;
+  free_chunk->next_ = free_chunk->previous_ = &free_list_;
+  free_chunk->size_ = size - sizeof(PreallocatedStorage);
+  preallocated_ = true;
+}
+
+
+void* PreallocatedStorage::New(size_t size) {
+  if (!preallocated_) {
+    return FreeStoreAllocationPolicy::New(size);
+  }
+  ASSERT(free_list_.next_ != &free_list_);
+  ASSERT(free_list_.previous_ != &free_list_);
+  size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
+  // Search for exact fit.
+  for (PreallocatedStorage* storage = free_list_.next_;
+       storage != &free_list_;
+       storage = storage->next_) {
+    if (storage->size_ == size) {
+      storage->Unlink();
+      storage->LinkTo(&in_use_list_);
+      return reinterpret_cast<void*>(storage + 1);
+    }
+  }
+  // Search for first fit.
+  for (PreallocatedStorage* storage = free_list_.next_;
+       storage != &free_list_;
+       storage = storage->next_) {
+    if (storage->size_ >= size + sizeof(PreallocatedStorage)) {
+      storage->Unlink();
+      storage->LinkTo(&in_use_list_);
+      PreallocatedStorage* left_over =
+          reinterpret_cast<PreallocatedStorage*>(
+              reinterpret_cast<char*>(storage + 1) + size);
+      left_over->size_ = storage->size_ - size - sizeof(PreallocatedStorage);
+      ASSERT(size + left_over->size_ + sizeof(PreallocatedStorage) ==
+             storage->size_);
+      storage->size_ = size;
+      left_over->LinkTo(&free_list_);
+      return reinterpret_cast<void*>(storage + 1);
+    }
+  }
+  // Allocation failure.
+  ASSERT(false);
+  return NULL;
+}
+
+
+// We don't attempt to coalesce.
+void PreallocatedStorage::Delete(void* p) {
+  if (p == NULL) {
+    return;
+  }
+  if (!preallocated_) {
+    FreeStoreAllocationPolicy::Delete(p);
+    return;
+  }
+  PreallocatedStorage* storage = reinterpret_cast<PreallocatedStorage*>(p) - 1;
+  ASSERT(storage->next_->previous_ == storage);
+  ASSERT(storage->previous_->next_ == storage);
+  storage->Unlink();
+  storage->LinkTo(&free_list_);
+}
+
+
+void PreallocatedStorage::LinkTo(PreallocatedStorage* other) {
+  next_ = other->next_;
+  other->next_->previous_ = this;
+  previous_ = other;
+  other->next_ = this;
+}
+
+
+void PreallocatedStorage::Unlink() {
+  next_->previous_ = previous_;
+  previous_->next_ = next_;
+}
+
+
+PreallocatedStorage::PreallocatedStorage(size_t size)
+  : size_(size) {
+  previous_ = next_ = this;
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/allocation.h b/regexp2000/src/allocation.h
new file mode 100644 (file)
index 0000000..35e68bd
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ALLOCATION_H_
+#define V8_ALLOCATION_H_
+
+namespace v8 { namespace internal {
+
+
+// A class that controls whether allocation is allowed.  This is for
+// the C++ heap only!
+class NativeAllocationChecker {
+ public:
+  typedef enum { ALLOW, DISALLOW } NativeAllocationAllowed;
+  explicit inline NativeAllocationChecker(NativeAllocationAllowed allowed)
+      : allowed_(allowed) {
+#ifdef DEBUG
+    if (allowed == DISALLOW) {
+      allocation_disallowed_++;
+    }
+#endif
+  }
+  ~NativeAllocationChecker() {
+#ifdef DEBUG
+    if (allowed_ == DISALLOW) {
+      allocation_disallowed_--;
+    }
+#endif
+    ASSERT(allocation_disallowed_ >= 0);
+  }
+  static inline bool allocation_allowed() {
+    return allocation_disallowed_ == 0;
+  }
+ private:
+  // This static counter ensures that NativeAllocationCheckers can be nested.
+  static int allocation_disallowed_;
+  // This flag applies to this particular instance.
+  NativeAllocationAllowed allowed_;
+};
+
+
+// Superclass for classes managed with new & delete.
+class Malloced {
+ public:
+  void* operator new(size_t size) { return New(size); }
+  void  operator delete(void* p) { Delete(p); }
+
+  static void FatalProcessOutOfMemory();
+  static void* New(size_t size);
+  static void Delete(void* p);
+};
+
+
+// A macro is used for defining the base class used for embedded instances.
+// The reason is some compilers allocate a minimum of one word for the
+// superclass. The macro prevents the use of new & delete in debug mode.
+// In release mode we are not willing to pay this overhead.
+
+#ifdef DEBUG
+// Superclass for classes with instances allocated inside stack
+// activations or inside other objects.
+class Embedded {
+ public:
+  void* operator new(size_t size);
+  void  operator delete(void* p);
+};
+#define BASE_EMBEDDED : public Embedded
+#else
+#define BASE_EMBEDDED
+#endif
+
+
+// Superclass for classes only using statics.
+class AllStatic {
+#ifdef DEBUG
+ public:
+  void* operator new(size_t size);
+  void operator delete(void* p);
+#endif
+};
+
+
+template <typename T>
+static T* NewArray(int size) {
+  ASSERT(NativeAllocationChecker::allocation_allowed());
+  T* result = new T[size];
+  if (result == NULL) Malloced::FatalProcessOutOfMemory();
+  return result;
+}
+
+
+template <typename T>
+static void DeleteArray(T* array) {
+  delete[] array;
+}
+
+
+// The normal strdup function uses malloc.  This version of StrDup
+// uses new and calls the FatalProcessOutOfMemory handler if
+// allocation fails.
+char* StrDup(const char* str);
+
+
+// Allocation policy for allocating in the C free store using malloc
+// and free. Used as the default policy for lists.
+class FreeStoreAllocationPolicy {
+ public:
+  INLINE(static void* New(size_t size)) { return Malloced::New(size); }
+  INLINE(static void Delete(void* p)) { Malloced::Delete(p); }
+};
+
+
+// Allocation policy for allocating in preallocated space.
+// Used as an allocation policy for ScopeInfo when generating
+// stack traces.
+class PreallocatedStorage : public AllStatic {
+ public:
+  explicit PreallocatedStorage(size_t size);
+  size_t size() { return size_; }
+  static void* New(size_t size);
+  static void Delete(void* p);
+
+  // Preallocate a set number of bytes.
+  static void Init(size_t size);
+
+ private:
+  size_t size_;
+  PreallocatedStorage* previous_;
+  PreallocatedStorage* next_;
+  static bool preallocated_;
+
+  static PreallocatedStorage in_use_list_;
+  static PreallocatedStorage free_list_;
+
+  void LinkTo(PreallocatedStorage* other);
+  void Unlink();
+  DISALLOW_IMPLICIT_CONSTRUCTORS(PreallocatedStorage);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ALLOCATION_H_
diff --git a/regexp2000/src/api.cc b/regexp2000/src/api.cc
new file mode 100644 (file)
index 0000000..2fb5680
--- /dev/null
@@ -0,0 +1,2966 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "bootstrapper.h"
+#include "compiler.h"
+#include "debug.h"
+#include "execution.h"
+#include "global-handles.h"
+#include "platform.h"
+#include "serialize.h"
+#include "snapshot.h"
+
+
+namespace i = v8::internal;
+#define LOG_API(expr) LOG(ApiEntryCall(expr))
+
+
+namespace v8 {
+
+
+#define ON_BAILOUT(location, code)              \
+  if (IsDeadCheck(location)) {                  \
+    code;                                       \
+    UNREACHABLE();                              \
+  }
+
+
+#define EXCEPTION_PREAMBLE()                                      \
+  thread_local.IncrementCallDepth();                              \
+  ASSERT(!i::Top::external_caught_exception());                   \
+  bool has_pending_exception = false
+
+
+#define EXCEPTION_BAILOUT_CHECK(value)                                         \
+  do {                                                                         \
+    thread_local.DecrementCallDepth();                                         \
+    if (has_pending_exception) {                                               \
+      if (thread_local.CallDepthIsZero() && i::Top::is_out_of_memory()) {      \
+        if (!thread_local.IgnoreOutOfMemory())                                 \
+          i::V8::FatalProcessOutOfMemory(NULL);                                \
+      }                                                                        \
+      bool call_depth_is_zero = thread_local.CallDepthIsZero();                \
+      i::Top::optional_reschedule_exception(call_depth_is_zero);               \
+      return value;                                                            \
+    }                                                                          \
+  } while (false)
+
+
+// --- D a t a   t h a t   i s   s p e c i f i c   t o   a   t h r e a d ---
+
+
+static i::HandleScopeImplementer thread_local;
+
+
+// --- E x c e p t i o n   B e h a v i o r ---
+
+
+static bool has_shut_down = false;
+static FatalErrorCallback exception_behavior = NULL;
+
+
+static void DefaultFatalErrorHandler(const char* location,
+                                     const char* message) {
+  API_Fatal(location, message);
+}
+
+
+
+static FatalErrorCallback& GetFatalErrorHandler() {
+  if (exception_behavior == NULL) {
+    exception_behavior = DefaultFatalErrorHandler;
+  }
+  return exception_behavior;
+}
+
+
+
+// When V8 cannot allocated memory FatalProcessOutOfMemory is called.
+// The default fatal error handler is called and execution is stopped.
+void i::V8::FatalProcessOutOfMemory(const char* location) {
+  has_shut_down = true;
+  FatalErrorCallback callback = GetFatalErrorHandler();
+  callback(location, "Allocation failed - process out of memory");
+  // If the callback returns, we stop execution.
+  UNREACHABLE();
+}
+
+
+void V8::SetFatalErrorHandler(FatalErrorCallback that) {
+  exception_behavior = that;
+}
+
+
+bool Utils::ReportApiFailure(const char* location, const char* message) {
+  FatalErrorCallback callback = GetFatalErrorHandler();
+  callback(location, message);
+  has_shut_down = true;
+  return false;
+}
+
+
+bool V8::IsDead() {
+  return has_shut_down;
+}
+
+
+static inline bool ApiCheck(bool condition,
+                            const char* location,
+                            const char* message) {
+  return condition ? true : Utils::ReportApiFailure(location, message);
+}
+
+
+static bool ReportV8Dead(const char* location) {
+  FatalErrorCallback callback = GetFatalErrorHandler();
+  callback(location, "V8 is no longer useable");
+  return true;
+}
+
+
+static bool ReportEmptyHandle(const char* location) {
+  FatalErrorCallback callback = GetFatalErrorHandler();
+  callback(location, "Reading from empty handle");
+  return true;
+}
+
+
+/**
+ * IsDeadCheck checks that the vm is useable.  If, for instance, the vm has been
+ * out of memory at some point this check will fail.  It should be called on
+ * entry to all methods that touch anything in the heap, except destructors
+ * which you sometimes can't avoid calling after the vm has crashed.  Functions
+ * that call EnsureInitialized or ON_BAILOUT don't have to also call
+ * IsDeadCheck.  ON_BAILOUT has the advantage over EnsureInitialized that you
+ * can arrange to return if the VM is dead.  This is needed to ensure that no VM
+ * heap allocations are attempted on a dead VM.  EnsureInitialized has the
+ * advantage over ON_BAILOUT that it actually initializes the VM if this has not
+ * yet been done.
+ */
+static inline bool IsDeadCheck(const char* location) {
+  return has_shut_down ? ReportV8Dead(location) : false;
+}
+
+
+static inline bool EmptyCheck(const char* location, v8::Handle<v8::Data> obj) {
+  return obj.IsEmpty() ? ReportEmptyHandle(location) : false;
+}
+
+
+static inline bool EmptyCheck(const char* location, v8::Data* obj) {
+  return (obj == 0) ? ReportEmptyHandle(location) : false;
+}
+
+// --- S t a t i c s ---
+
+
+static i::StringInputBuffer write_input_buffer;
+
+
+static void EnsureInitialized(const char* location) {
+  if (IsDeadCheck(location)) return;
+  ApiCheck(v8::V8::Initialize(), location, "Error initializing V8");
+}
+
+
+v8::Handle<v8::Primitive> ImplementationUtilities::Undefined() {
+  if (IsDeadCheck("v8::Undefined()")) return v8::Handle<v8::Primitive>();
+  EnsureInitialized("v8::Undefined()");
+  return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::undefined_value()));
+}
+
+
+v8::Handle<v8::Primitive> ImplementationUtilities::Null() {
+  if (IsDeadCheck("v8::Null()")) return v8::Handle<v8::Primitive>();
+  EnsureInitialized("v8::Null()");
+  return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::null_value()));
+}
+
+
+v8::Handle<v8::Boolean> ImplementationUtilities::True() {
+  if (IsDeadCheck("v8::True()")) return v8::Handle<v8::Boolean>();
+  EnsureInitialized("v8::True()");
+  return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::true_value()));
+}
+
+
+v8::Handle<v8::Boolean> ImplementationUtilities::False() {
+  if (IsDeadCheck("v8::False()")) return v8::Handle<v8::Boolean>();
+  EnsureInitialized("v8::False()");
+  return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::false_value()));
+}
+
+
+void V8::SetFlagsFromString(const char* str, int length) {
+  i::FlagList::SetFlagsFromString(str, length);
+}
+
+
+void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
+  i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
+}
+
+
+v8::Handle<Value> ThrowException(v8::Handle<v8::Value> value) {
+  if (IsDeadCheck("v8::ThrowException()")) return v8::Handle<Value>();
+  i::Top::ScheduleThrow(*Utils::OpenHandle(*value));
+  return v8::Undefined();
+}
+
+
+RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
+
+
+RegisteredExtension::RegisteredExtension(Extension* extension)
+    : extension_(extension), state_(UNVISITED) { }
+
+
+void RegisteredExtension::Register(RegisteredExtension* that) {
+  that->next_ = RegisteredExtension::first_extension_;
+  RegisteredExtension::first_extension_ = that;
+}
+
+
+void RegisterExtension(Extension* that) {
+  RegisteredExtension* extension = new RegisteredExtension(that);
+  RegisteredExtension::Register(extension);
+}
+
+
+Extension::Extension(const char* name,
+                     const char* source,
+                     int dep_count,
+                     const char** deps)
+    : name_(name),
+      source_(source),
+      dep_count_(dep_count),
+      deps_(deps),
+      auto_enable_(false) { }
+
+
+v8::Handle<Primitive> Undefined() {
+  LOG_API("Undefined");
+  return ImplementationUtilities::Undefined();
+}
+
+
+v8::Handle<Primitive> Null() {
+  LOG_API("Null");
+  return ImplementationUtilities::Null();
+}
+
+
+v8::Handle<Boolean> True() {
+  LOG_API("True");
+  return ImplementationUtilities::True();
+}
+
+
+v8::Handle<Boolean> False() {
+  LOG_API("False");
+  return ImplementationUtilities::False();
+}
+
+
+ResourceConstraints::ResourceConstraints()
+  : max_young_space_size_(0),
+    max_old_space_size_(0),
+    stack_limit_(NULL) { }
+
+
+bool SetResourceConstraints(ResourceConstraints* constraints) {
+  bool result = i::Heap::ConfigureHeap(constraints->max_young_space_size(),
+                                       constraints->max_old_space_size());
+  if (!result) return false;
+  if (constraints->stack_limit() != NULL) {
+    uintptr_t limit = reinterpret_cast<uintptr_t>(constraints->stack_limit());
+    i::StackGuard::SetStackLimit(limit);
+  }
+  return true;
+}
+
+
+void** V8::GlobalizeReference(void** obj) {
+  LOG_API("Persistent::New");
+  if (IsDeadCheck("V8::Persistent::New")) return NULL;
+  i::Handle<i::Object> result =
+      i::GlobalHandles::Create(*reinterpret_cast<i::Object**>(obj));
+  return reinterpret_cast<void**>(result.location());
+}
+
+
+void V8::MakeWeak(void** object, void* parameters,
+                  WeakReferenceCallback callback) {
+  LOG_API("MakeWeak");
+  i::GlobalHandles::MakeWeak(reinterpret_cast<i::Object**>(object), parameters,
+      callback);
+}
+
+
+void V8::ClearWeak(void** obj) {
+  LOG_API("ClearWeak");
+  i::GlobalHandles::ClearWeakness(reinterpret_cast<i::Object**>(obj));
+}
+
+
+bool V8::IsGlobalNearDeath(void** obj) {
+  LOG_API("IsGlobalNearDeath");
+  if (has_shut_down) return false;
+  return i::GlobalHandles::IsNearDeath(reinterpret_cast<i::Object**>(obj));
+}
+
+
+bool V8::IsGlobalWeak(void** obj) {
+  LOG_API("IsGlobalWeak");
+  if (has_shut_down) return false;
+  return i::GlobalHandles::IsWeak(reinterpret_cast<i::Object**>(obj));
+}
+
+
+void V8::DisposeGlobal(void** obj) {
+  LOG_API("DisposeGlobal");
+  if (has_shut_down) return;
+  i::GlobalHandles::Destroy(reinterpret_cast<i::Object**>(obj));
+}
+
+// --- H a n d l e s ---
+
+
+HandleScope::Data HandleScope::current_ = { -1, NULL, NULL };
+
+
+int HandleScope::NumberOfHandles() {
+  int n = thread_local.Blocks()->length();
+  if (n == 0) return 0;
+  return ((n - 1) * i::kHandleBlockSize) +
+       (current_.next - thread_local.Blocks()->last());
+}
+
+
+void** v8::HandleScope::CreateHandle(void* value) {
+  void** result = current_.next;
+  if (result == current_.limit) {
+    // Make sure there's at least one scope on the stack and that the
+    // top of the scope stack isn't a barrier.
+    if (!ApiCheck(current_.extensions >= 0,
+                  "v8::HandleScope::CreateHandle()",
+                  "Cannot create a handle without a HandleScope")) {
+      return NULL;
+    }
+    // If there's more room in the last block, we use that. This is used
+    // for fast creation of scopes after scope barriers.
+    if (!thread_local.Blocks()->is_empty()) {
+      void** limit = &thread_local.Blocks()->last()[i::kHandleBlockSize];
+      if (current_.limit != limit) {
+        current_.limit = limit;
+      }
+    }
+
+    // If we still haven't found a slot for the handle, we extend the
+    // current handle scope by allocating a new handle block.
+    if (result == current_.limit) {
+      // If there's a spare block, use it for growing the current scope.
+      result = thread_local.GetSpareOrNewBlock();
+      // Add the extension to the global list of blocks, but count the
+      // extension as part of the current scope.
+      thread_local.Blocks()->Add(result);
+      current_.extensions++;
+      current_.limit = &result[i::kHandleBlockSize];
+    }
+  }
+
+  // Update the current next field, set the value in the created
+  // handle, and return the result.
+  ASSERT(result < current_.limit);
+  current_.next = result + 1;
+  *result = value;
+  return result;
+}
+
+
+void Context::Enter() {
+  if (IsDeadCheck("v8::Context::Enter()")) return;
+  i::Handle<i::Context> env = Utils::OpenHandle(this);
+  thread_local.EnterContext(env);
+
+  thread_local.SaveContext(i::GlobalHandles::Create(i::Top::context()));
+  i::Top::set_context(*env);
+}
+
+
+void Context::Exit() {
+  if (has_shut_down) return;
+  if (!ApiCheck(thread_local.LeaveLastContext(),
+                "v8::Context::Exit()",
+                "Cannot exit non-entered context")) {
+    return;
+  }
+
+  // Content of 'last_context' could be NULL.
+  i::Handle<i::Object> last_context = thread_local.RestoreContext();
+  i::Top::set_context(static_cast<i::Context*>(*last_context));
+  i::GlobalHandles::Destroy(last_context.location());
+}
+
+
+void v8::HandleScope::DeleteExtensions() {
+  ASSERT(current_.extensions != 0);
+  thread_local.DeleteExtensions(current_.extensions);
+}
+
+
+void HandleScope::ZapRange(void** start, void** end) {
+  if (start == NULL) return;
+  for (void** p = start; p < end; p++) {
+    *p = reinterpret_cast<void*>(v8::internal::kHandleZapValue);
+  }
+}
+
+
+void** v8::HandleScope::RawClose(void** value) {
+  if (!ApiCheck(!is_closed_,
+                "v8::HandleScope::Close()",
+                "Local scope has already been closed")) {
+    return 0;
+  }
+  LOG_API("CloseHandleScope");
+
+  // Read the result before popping the handle block.
+  i::Object* result = reinterpret_cast<i::Object*>(*value);
+  is_closed_ = true;
+  RestorePreviousState();
+
+  // Allocate a new handle on the previous handle block.
+  i::Handle<i::Object> handle(result);
+  return reinterpret_cast<void**>(handle.location());
+}
+
+
+// --- N e a n d e r ---
+
+
+// A constructor cannot easily return an error value, therefore it is necessary
+// to check for a dead VM with ON_BAILOUT before constructing any Neander
+// objects.  To remind you about this there is no HandleScope in the
+// NeanderObject constructor.  When you add one to the site calling the
+// constructor you should check that you ensured the VM was not dead first.
+NeanderObject::NeanderObject(int size) {
+  EnsureInitialized("v8::Nowhere");
+  value_ = i::Factory::NewNeanderObject();
+  i::Handle<i::FixedArray> elements = i::Factory::NewFixedArray(size);
+  value_->set_elements(*elements);
+}
+
+
+int NeanderObject::size() {
+  return i::FixedArray::cast(value_->elements())->length();
+}
+
+
+NeanderArray::NeanderArray() : obj_(2) {
+  obj_.set(0, i::Smi::FromInt(0));
+}
+
+
+int NeanderArray::length() {
+  return i::Smi::cast(obj_.get(0))->value();
+}
+
+
+i::Object* NeanderArray::get(int offset) {
+  ASSERT(0 <= offset);
+  ASSERT(offset < length());
+  return obj_.get(offset + 1);
+}
+
+
+// This method cannot easily return an error value, therefore it is necessary
+// to check for a dead VM with ON_BAILOUT before calling it.  To remind you
+// about this there is no HandleScope in this method.  When you add one to the
+// site calling this method you should check that you ensured the VM was not
+// dead first.
+void NeanderArray::add(i::Handle<i::Object> value) {
+  int length = this->length();
+  int size = obj_.size();
+  if (length == size - 1) {
+    i::Handle<i::FixedArray> new_elms = i::Factory::NewFixedArray(2 * size);
+    for (int i = 0; i < length; i++)
+      new_elms->set(i + 1, get(i));
+    obj_.value()->set_elements(*new_elms);
+  }
+  obj_.set(length + 1, *value);
+  obj_.set(0, i::Smi::FromInt(length + 1));
+}
+
+
+void NeanderArray::set(int index, i::Object* value) {
+  if (index < 0 || index >= this->length()) return;
+  obj_.set(index + 1, value);
+}
+
+
+// --- T e m p l a t e ---
+
+
+static void InitializeTemplate(i::Handle<i::TemplateInfo> that, int type) {
+  that->set_tag(i::Smi::FromInt(type));
+}
+
+
+void Template::Set(v8::Handle<String> name, v8::Handle<Data> value,
+                   v8::PropertyAttribute attribute) {
+  if (IsDeadCheck("v8::Template::SetProperty()")) return;
+  HandleScope scope;
+  i::Handle<i::Object> list(Utils::OpenHandle(this)->property_list());
+  if (list->IsUndefined()) {
+    list = NeanderArray().value();
+    Utils::OpenHandle(this)->set_property_list(*list);
+  }
+  NeanderArray array(list);
+  array.add(Utils::OpenHandle(*name));
+  array.add(Utils::OpenHandle(*value));
+  array.add(Utils::OpenHandle(*v8::Integer::New(attribute)));
+}
+
+
+// --- F u n c t i o n   T e m p l a t e ---
+static void InitializeFunctionTemplate(
+      i::Handle<i::FunctionTemplateInfo> info) {
+  info->set_tag(i::Smi::FromInt(Consts::FUNCTION_TEMPLATE));
+  info->set_flag(0);
+}
+
+
+Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() {
+  if (IsDeadCheck("v8::FunctionTemplate::PrototypeTemplate()")) {
+    return Local<ObjectTemplate>();
+  }
+  i::Handle<i::Object> result(Utils::OpenHandle(this)->prototype_template());
+  if (result->IsUndefined()) {
+    result = Utils::OpenHandle(*ObjectTemplate::New());
+    Utils::OpenHandle(this)->set_prototype_template(*result);
+  }
+  return Local<ObjectTemplate>(ToApi<ObjectTemplate>(result));
+}
+
+
+void FunctionTemplate::Inherit(v8::Handle<FunctionTemplate> value) {
+  if (IsDeadCheck("v8::FunctionTemplate::Inherit()")) return;
+  Utils::OpenHandle(this)->set_parent_template(*Utils::OpenHandle(*value));
+}
+
+
+// To distinguish the function templates, so that we can find them in the
+// function cache of the global context.
+static int next_serial_number = 0;
+
+
+Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
+    v8::Handle<Value> data, v8::Handle<Signature> signature) {
+  EnsureInitialized("v8::FunctionTemplate::New()");
+  LOG_API("FunctionTemplate::New");
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
+  i::Handle<i::FunctionTemplateInfo> obj =
+      i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
+  InitializeFunctionTemplate(obj);
+  obj->set_serial_number(i::Smi::FromInt(next_serial_number++));
+  if (callback != 0) {
+    if (data.IsEmpty()) data = v8::Undefined();
+    Utils::ToLocal(obj)->SetCallHandler(callback, data);
+  }
+  obj->set_undetectable(false);
+  obj->set_needs_access_check(false);
+
+  if (!signature.IsEmpty())
+    obj->set_signature(*Utils::OpenHandle(*signature));
+  return Utils::ToLocal(obj);
+}
+
+
+Local<Signature> Signature::New(Handle<FunctionTemplate> receiver,
+      int argc, Handle<FunctionTemplate> argv[]) {
+  EnsureInitialized("v8::Signature::New()");
+  LOG_API("Signature::New");
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::SIGNATURE_INFO_TYPE);
+  i::Handle<i::SignatureInfo> obj =
+      i::Handle<i::SignatureInfo>::cast(struct_obj);
+  if (!receiver.IsEmpty()) obj->set_receiver(*Utils::OpenHandle(*receiver));
+  if (argc > 0) {
+    i::Handle<i::FixedArray> args = i::Factory::NewFixedArray(argc);
+    for (int i = 0; i < argc; i++) {
+      if (!argv[i].IsEmpty())
+        args->set(i, *Utils::OpenHandle(*argv[i]));
+    }
+    obj->set_args(*args);
+  }
+  return Utils::ToLocal(obj);
+}
+
+
+Local<TypeSwitch> TypeSwitch::New(Handle<FunctionTemplate> type) {
+  Handle<FunctionTemplate> types[1] = { type };
+  return TypeSwitch::New(1, types);
+}
+
+
+Local<TypeSwitch> TypeSwitch::New(int argc, Handle<FunctionTemplate> types[]) {
+  EnsureInitialized("v8::TypeSwitch::New()");
+  LOG_API("TypeSwitch::New");
+  i::Handle<i::FixedArray> vector = i::Factory::NewFixedArray(argc);
+  for (int i = 0; i < argc; i++)
+    vector->set(i, *Utils::OpenHandle(*types[i]));
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::TYPE_SWITCH_INFO_TYPE);
+  i::Handle<i::TypeSwitchInfo> obj =
+      i::Handle<i::TypeSwitchInfo>::cast(struct_obj);
+  obj->set_types(*vector);
+  return Utils::ToLocal(obj);
+}
+
+
+int TypeSwitch::match(v8::Handle<Value> value) {
+  LOG_API("TypeSwitch::match");
+  i::Handle<i::Object> obj = Utils::OpenHandle(*value);
+  i::Handle<i::TypeSwitchInfo> info = Utils::OpenHandle(this);
+  i::FixedArray* types = i::FixedArray::cast(info->types());
+  for (int i = 0; i < types->length(); i++) {
+    if (obj->IsInstanceOf(i::FunctionTemplateInfo::cast(types->get(i))))
+      return i + 1;
+  }
+  return 0;
+}
+
+
+void FunctionTemplate::SetCallHandler(InvocationCallback callback,
+                                      v8::Handle<Value> data) {
+  if (IsDeadCheck("v8::FunctionTemplate::SetCallHandler()")) return;
+  HandleScope scope;
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE);
+  i::Handle<i::CallHandlerInfo> obj =
+      i::Handle<i::CallHandlerInfo>::cast(struct_obj);
+  obj->set_callback(*FromCData(callback));
+  if (data.IsEmpty()) data = v8::Undefined();
+  obj->set_data(*Utils::OpenHandle(*data));
+  Utils::OpenHandle(this)->set_call_code(*obj);
+}
+
+
+void FunctionTemplate::AddInstancePropertyAccessor(
+      v8::Handle<String> name,
+      AccessorGetter getter,
+      AccessorSetter setter,
+      v8::Handle<Value> data,
+      v8::AccessControl settings,
+      v8::PropertyAttribute attributes) {
+  if (IsDeadCheck("v8::FunctionTemplate::AddInstancePropertyAccessor()")) {
+    return;
+  }
+  HandleScope scope;
+  i::Handle<i::AccessorInfo> obj = i::Factory::NewAccessorInfo();
+  ASSERT(getter != NULL);
+  obj->set_getter(*FromCData(getter));
+  obj->set_setter(*FromCData(setter));
+  if (data.IsEmpty()) data = v8::Undefined();
+  obj->set_data(*Utils::OpenHandle(*data));
+  obj->set_name(*Utils::OpenHandle(*name));
+  if (settings & ALL_CAN_READ) obj->set_all_can_read(true);
+  if (settings & ALL_CAN_WRITE) obj->set_all_can_write(true);
+  obj->set_property_attributes(static_cast<PropertyAttributes>(attributes));
+
+  i::Handle<i::Object> list(Utils::OpenHandle(this)->property_accessors());
+  if (list->IsUndefined()) {
+    list = NeanderArray().value();
+    Utils::OpenHandle(this)->set_property_accessors(*list);
+  }
+  NeanderArray array(list);
+  array.add(obj);
+}
+
+
+Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
+  if (IsDeadCheck("v8::FunctionTemplate::InstanceTemplate()")
+      || EmptyCheck("v8::FunctionTemplate::InstanceTemplate()", this))
+    return Local<ObjectTemplate>();
+  if (Utils::OpenHandle(this)->instance_template()->IsUndefined()) {
+    Local<ObjectTemplate> templ =
+        ObjectTemplate::New(v8::Handle<FunctionTemplate>(this));
+    Utils::OpenHandle(this)->set_instance_template(*Utils::OpenHandle(*templ));
+  }
+  i::Handle<i::ObjectTemplateInfo> result(i::ObjectTemplateInfo::cast(
+        Utils::OpenHandle(this)->instance_template()));
+  return Utils::ToLocal(result);
+}
+
+
+void FunctionTemplate::SetClassName(Handle<String> name) {
+  if (IsDeadCheck("v8::FunctionTemplate::SetClassName()")) return;
+  Utils::OpenHandle(this)->set_class_name(*Utils::OpenHandle(*name));
+}
+
+
+void FunctionTemplate::SetHiddenPrototype(bool value) {
+  if (IsDeadCheck("v8::FunctionTemplate::SetHiddenPrototype()")) return;
+  Utils::OpenHandle(this)->set_hidden_prototype(value);
+}
+
+
+void FunctionTemplate::SetNamedInstancePropertyHandler(
+      NamedPropertyGetter getter,
+      NamedPropertySetter setter,
+      NamedPropertyQuery query,
+      NamedPropertyDeleter remover,
+      NamedPropertyEnumerator enumerator,
+      Handle<Value> data) {
+  if (IsDeadCheck("v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) {
+    return;
+  }
+  HandleScope scope;
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE);
+  i::Handle<i::InterceptorInfo> obj =
+      i::Handle<i::InterceptorInfo>::cast(struct_obj);
+  if (getter != 0) obj->set_getter(*FromCData(getter));
+  if (setter != 0) obj->set_setter(*FromCData(setter));
+  if (query != 0) obj->set_query(*FromCData(query));
+  if (remover != 0) obj->set_deleter(*FromCData(remover));
+  if (enumerator != 0) obj->set_enumerator(*FromCData(enumerator));
+  if (data.IsEmpty()) data = v8::Undefined();
+  obj->set_data(*Utils::OpenHandle(*data));
+  Utils::OpenHandle(this)->set_named_property_handler(*obj);
+}
+
+
+void FunctionTemplate::SetIndexedInstancePropertyHandler(
+      IndexedPropertyGetter getter,
+      IndexedPropertySetter setter,
+      IndexedPropertyQuery query,
+      IndexedPropertyDeleter remover,
+      IndexedPropertyEnumerator enumerator,
+      Handle<Value> data) {
+  if (IsDeadCheck(
+        "v8::FunctionTemplate::SetIndexedInstancePropertyHandler()")) {
+    return;
+  }
+  HandleScope scope;
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE);
+  i::Handle<i::InterceptorInfo> obj =
+      i::Handle<i::InterceptorInfo>::cast(struct_obj);
+  if (getter != 0) obj->set_getter(*FromCData(getter));
+  if (setter != 0) obj->set_setter(*FromCData(setter));
+  if (query != 0) obj->set_query(*FromCData(query));
+  if (remover != 0) obj->set_deleter(*FromCData(remover));
+  if (enumerator != 0) obj->set_enumerator(*FromCData(enumerator));
+  if (data.IsEmpty()) data = v8::Undefined();
+  obj->set_data(*Utils::OpenHandle(*data));
+  Utils::OpenHandle(this)->set_indexed_property_handler(*obj);
+}
+
+
+void FunctionTemplate::SetInstanceCallAsFunctionHandler(
+      InvocationCallback callback,
+      Handle<Value> data) {
+  if (IsDeadCheck("v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) {
+    return;
+  }
+  HandleScope scope;
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE);
+  i::Handle<i::CallHandlerInfo> obj =
+      i::Handle<i::CallHandlerInfo>::cast(struct_obj);
+  obj->set_callback(*FromCData(callback));
+  if (data.IsEmpty()) data = v8::Undefined();
+  obj->set_data(*Utils::OpenHandle(*data));
+  Utils::OpenHandle(this)->set_instance_call_handler(*obj);
+}
+
+
+// --- O b j e c t T e m p l a t e ---
+
+
+Local<ObjectTemplate> ObjectTemplate::New() {
+  return New(Local<FunctionTemplate>());
+}
+
+
+Local<ObjectTemplate> ObjectTemplate::New(
+      v8::Handle<FunctionTemplate> constructor) {
+  if (IsDeadCheck("v8::ObjectTemplate::New()")) return Local<ObjectTemplate>();
+  EnsureInitialized("v8::ObjectTemplate::New()");
+  LOG_API("ObjectTemplate::New");
+  i::Handle<i::Struct> struct_obj =
+      i::Factory::NewStruct(i::OBJECT_TEMPLATE_INFO_TYPE);
+  i::Handle<i::ObjectTemplateInfo> obj =
+      i::Handle<i::ObjectTemplateInfo>::cast(struct_obj);
+  InitializeTemplate(obj, Consts::OBJECT_TEMPLATE);
+  if (!constructor.IsEmpty())
+    obj->set_constructor(*Utils::OpenHandle(*constructor));
+  obj->set_internal_field_count(i::Smi::FromInt(0));
+  return Utils::ToLocal(obj);
+}
+
+
+// Ensure that the object template has a constructor.  If no
+// constructor is available we create one.
+static void EnsureConstructor(ObjectTemplate* object_template) {
+  if (Utils::OpenHandle(object_template)->constructor()->IsUndefined()) {
+    Local<FunctionTemplate> templ = FunctionTemplate::New();
+    i::Handle<i::FunctionTemplateInfo> constructor = Utils::OpenHandle(*templ);
+    constructor->set_instance_template(*Utils::OpenHandle(object_template));
+    Utils::OpenHandle(object_template)->set_constructor(*constructor);
+  }
+}
+
+
+void ObjectTemplate::SetAccessor(v8::Handle<String> name,
+                                 AccessorGetter getter,
+                                 AccessorSetter setter,
+                                 v8::Handle<Value> data,
+                                 AccessControl settings,
+                                 PropertyAttribute attribute) {
+  if (IsDeadCheck("v8::ObjectTemplate::SetAccessor()")) return;
+  HandleScope scope;
+  EnsureConstructor(this);
+  i::FunctionTemplateInfo* constructor =
+      i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
+  i::Handle<i::FunctionTemplateInfo> cons(constructor);
+  Utils::ToLocal(cons)->AddInstancePropertyAccessor(name,
+                                                    getter,
+                                                    setter,
+                                                    data,
+                                                    settings,
+                                                    attribute);
+}
+
+
+void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
+                                             NamedPropertySetter setter,
+                                             NamedPropertyQuery query,
+                                             NamedPropertyDeleter remover,
+                                             NamedPropertyEnumerator enumerator,
+                                             Handle<Value> data) {
+  if (IsDeadCheck("v8::ObjectTemplate::SetNamedPropertyHandler()")) return;
+  HandleScope scope;
+  EnsureConstructor(this);
+  i::FunctionTemplateInfo* constructor =
+      i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
+  i::Handle<i::FunctionTemplateInfo> cons(constructor);
+  Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter,
+                                                        setter,
+                                                        query,
+                                                        remover,
+                                                        enumerator,
+                                                        data);
+}
+
+
+void ObjectTemplate::MarkAsUndetectable() {
+  if (IsDeadCheck("v8::ObjectTemplate::MarkAsUndetectable()")) return;
+  HandleScope scope;
+  EnsureConstructor(this);
+  i::FunctionTemplateInfo* constructor =
+      i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
+  i::Handle<i::FunctionTemplateInfo> cons(constructor);
+  cons->set_undetectable(true);
+}
+
+
+void ObjectTemplate::SetAccessCheckCallbacks(
+      NamedSecurityCallback named_callback,
+      IndexedSecurityCallback indexed_callback,
+      Handle<Value> data,
+      bool turned_on_by_default) {
+  if (IsDeadCheck("v8::ObjectTemplate::SetAccessCheckCallbacks()")) return;
+  HandleScope scope;
+  EnsureConstructor(this);
+
+  i::Handle<i::Struct> struct_info =
+      i::Factory::NewStruct(i::ACCESS_CHECK_INFO_TYPE);
+  i::Handle<i::AccessCheckInfo> info =
+      i::Handle<i::AccessCheckInfo>::cast(struct_info);
+  info->set_named_callback(*FromCData(named_callback));
+  info->set_indexed_callback(*FromCData(indexed_callback));
+  if (data.IsEmpty()) data = v8::Undefined();
+  info->set_data(*Utils::OpenHandle(*data));
+
+  i::FunctionTemplateInfo* constructor =
+      i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
+  i::Handle<i::FunctionTemplateInfo> cons(constructor);
+  cons->set_access_check_info(*info);
+  cons->set_needs_access_check(turned_on_by_default);
+}
+
+
+void ObjectTemplate::SetIndexedPropertyHandler(
+      IndexedPropertyGetter getter,
+      IndexedPropertySetter setter,
+      IndexedPropertyQuery query,
+      IndexedPropertyDeleter remover,
+      IndexedPropertyEnumerator enumerator,
+      Handle<Value> data) {
+  if (IsDeadCheck("v8::ObjectTemplate::SetIndexedPropertyHandler()")) return;
+  HandleScope scope;
+  EnsureConstructor(this);
+  i::FunctionTemplateInfo* constructor =
+      i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
+  i::Handle<i::FunctionTemplateInfo> cons(constructor);
+  Utils::ToLocal(cons)->SetIndexedInstancePropertyHandler(getter,
+                                                          setter,
+                                                          query,
+                                                          remover,
+                                                          enumerator,
+                                                          data);
+}
+
+
+void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback,
+                                              Handle<Value> data) {
+  if (IsDeadCheck("v8::ObjectTemplate::SetCallAsFunctionHandler()")) return;
+  HandleScope scope;
+  EnsureConstructor(this);
+  i::FunctionTemplateInfo* constructor =
+      i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
+  i::Handle<i::FunctionTemplateInfo> cons(constructor);
+  Utils::ToLocal(cons)->SetInstanceCallAsFunctionHandler(callback, data);
+}
+
+
+int ObjectTemplate::InternalFieldCount() {
+  if (IsDeadCheck("v8::ObjectTemplate::InternalFieldCount()")) {
+    return 0;
+  }
+  return i::Smi::cast(Utils::OpenHandle(this)->internal_field_count())->value();
+}
+
+
+void ObjectTemplate::SetInternalFieldCount(int value) {
+  if (IsDeadCheck("v8::ObjectTemplate::SetInternalFieldCount()")) return;
+  if (!ApiCheck(i::Smi::IsValid(value),
+                "v8::ObjectTemplate::SetInternalFieldCount()",
+                "Invalid internal field count")) {
+    return;
+  }
+  if (value > 0) {
+    // The internal field count is set by the constructor function's
+    // construct code, so we ensure that there is a constructor
+    // function to do the setting.
+    EnsureConstructor(this);
+  }
+  Utils::OpenHandle(this)->set_internal_field_count(i::Smi::FromInt(value));
+}
+
+
+// --- S c r i p t D a t a ---
+
+
+ScriptData* ScriptData::PreCompile(const char* input, int length) {
+  unibrow::Utf8InputBuffer<> buf(input, length);
+  return i::PreParse(&buf, NULL);
+}
+
+
+ScriptData* ScriptData::New(unsigned* data, int length) {
+  return new i::ScriptDataImpl(i::Vector<unsigned>(data, length));
+}
+
+
+// --- S c r i p t ---
+
+
+Local<Script> Script::Compile(v8::Handle<String> source,
+                              v8::ScriptOrigin* origin,
+                              v8::ScriptData* script_data) {
+  ON_BAILOUT("v8::Script::Compile()", return Local<Script>());
+  LOG_API("Script::Compile");
+  i::Handle<i::String> str = Utils::OpenHandle(*source);
+  i::Handle<i::Object> name_obj;
+  int line_offset = 0;
+  int column_offset = 0;
+  if (origin != NULL) {
+    if (!origin->ResourceName().IsEmpty()) {
+      name_obj = Utils::OpenHandle(*origin->ResourceName());
+    }
+    if (!origin->ResourceLineOffset().IsEmpty()) {
+      line_offset = static_cast<int>(origin->ResourceLineOffset()->Value());
+    }
+    if (!origin->ResourceColumnOffset().IsEmpty()) {
+      column_offset = static_cast<int>(origin->ResourceColumnOffset()->Value());
+    }
+  }
+  EXCEPTION_PREAMBLE();
+  i::ScriptDataImpl* pre_data = static_cast<i::ScriptDataImpl*>(script_data);
+  // We assert that the pre-data is sane, even though we can actually
+  // handle it if it turns out not to be in release mode.
+  ASSERT(pre_data == NULL || pre_data->SanityCheck());
+  // If the pre-data isn't sane we simply ignore it
+  if (pre_data != NULL && !pre_data->SanityCheck())
+    pre_data = NULL;
+  i::Handle<i::JSFunction> boilerplate = i::Compiler::Compile(str,
+                                                              name_obj,
+                                                              line_offset,
+                                                              column_offset,
+                                                              NULL,
+                                                              pre_data);
+  has_pending_exception = boilerplate.is_null();
+  EXCEPTION_BAILOUT_CHECK(Local<Script>());
+  i::Handle<i::JSFunction> result =
+      i::Factory::NewFunctionFromBoilerplate(boilerplate,
+                                             i::Top::global_context());
+  return Local<Script>(ToApi<Script>(result));
+}
+
+
+Local<Script> Script::Compile(v8::Handle<String> source,
+                              v8::Handle<Value> file_name) {
+  ScriptOrigin origin(file_name);
+  return Compile(source, &origin);
+}
+
+
+Local<Value> Script::Run() {
+  ON_BAILOUT("v8::Script::Run()", return Local<Value>());
+  LOG_API("Script::Run");
+  i::Object* raw_result = NULL;
+  {
+    HandleScope scope;
+    i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
+    EXCEPTION_PREAMBLE();
+    i::Handle<i::Object> receiver(i::Top::context()->global_proxy());
+    i::Handle<i::Object> result =
+        i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<Value>());
+    raw_result = *result;
+  }
+  i::Handle<i::Object> result(raw_result);
+  return Utils::ToLocal(result);
+}
+
+
+// --- E x c e p t i o n s ---
+
+
+v8::TryCatch::TryCatch()
+    : next_(i::Top::try_catch_handler()),
+      exception_(i::Heap::the_hole_value()),
+      message_(i::Smi::FromInt(0)),
+      is_verbose_(false),
+      capture_message_(true) {
+  i::Top::RegisterTryCatchHandler(this);
+}
+
+
+v8::TryCatch::~TryCatch() {
+  i::Top::UnregisterTryCatchHandler(this);
+}
+
+
+bool v8::TryCatch::HasCaught() const {
+  return !reinterpret_cast<i::Object*>(exception_)->IsTheHole();
+}
+
+
+v8::Local<Value> v8::TryCatch::Exception() const {
+  if (HasCaught()) {
+    // Check for out of memory exception.
+    i::Object* exception = reinterpret_cast<i::Object*>(exception_);
+    return v8::Utils::ToLocal(i::Handle<i::Object>(exception));
+  } else {
+    return v8::Local<Value>();
+  }
+}
+
+
+v8::Local<v8::Message> v8::TryCatch::Message() const {
+  if (HasCaught() && message_ != i::Smi::FromInt(0)) {
+    i::Object* message = reinterpret_cast<i::Object*>(message_);
+    return v8::Utils::MessageToLocal(i::Handle<i::Object>(message));
+  } else {
+    return v8::Local<v8::Message>();
+  }
+}
+
+
+void v8::TryCatch::Reset() {
+  exception_ = i::Heap::the_hole_value();
+  message_ = i::Smi::FromInt(0);
+}
+
+
+void v8::TryCatch::SetVerbose(bool value) {
+  is_verbose_ = value;
+}
+
+
+void v8::TryCatch::SetCaptureMessage(bool value) {
+  capture_message_ = value;
+}
+
+
+// --- M e s s a g e ---
+
+
+Local<String> Message::Get() {
+  ON_BAILOUT("v8::Message::Get()", return Local<String>());
+  HandleScope scope;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::String> raw_result = i::MessageHandler::GetMessage(obj);
+  Local<String> result = Utils::ToLocal(raw_result);
+  return scope.Close(result);
+}
+
+
+v8::Handle<Value> Message::GetScriptResourceName() {
+  if (IsDeadCheck("v8::Message::GetScriptResourceName()")) {
+    return Local<String>();
+  }
+  HandleScope scope;
+  i::Handle<i::JSObject> obj =
+      i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
+  // Return this.script.name.
+  i::Handle<i::JSValue> script =
+      i::Handle<i::JSValue>::cast(GetProperty(obj, "script"));
+  i::Handle<i::Object> resource_name(i::Script::cast(script->value())->name());
+  return scope.Close(Utils::ToLocal(resource_name));
+}
+
+
+static i::Handle<i::Object> CallV8HeapFunction(const char* name,
+                                               i::Handle<i::Object> recv,
+                                               int argc,
+                                               i::Object** argv[],
+                                               bool* has_pending_exception) {
+  i::Handle<i::String> fmt_str = i::Factory::LookupAsciiSymbol(name);
+  i::Object* object_fun = i::Top::builtins()->GetProperty(*fmt_str);
+  i::Handle<i::JSFunction> fun =
+      i::Handle<i::JSFunction>(i::JSFunction::cast(object_fun));
+  i::Handle<i::Object> value =
+      i::Execution::Call(fun, recv, argc, argv, has_pending_exception);
+  return value;
+}
+
+
+static i::Handle<i::Object> CallV8HeapFunction(const char* name,
+                                               i::Handle<i::Object> data,
+                                               bool* has_pending_exception) {
+  i::Object** argv[1] = { data.location() };
+  return CallV8HeapFunction(name,
+                            i::Top::builtins(),
+                            1,
+                            argv,
+                            has_pending_exception);
+}
+
+
+int Message::GetLineNumber() {
+  ON_BAILOUT("v8::Message::GetLineNumber()", return -1);
+  HandleScope scope;
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber",
+                                                   Utils::OpenHandle(this),
+                                                   &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(0);
+  return static_cast<int>(result->Number());
+}
+
+
+int Message::GetStartPosition() {
+  if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0;
+  HandleScope scope;
+
+  i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
+  return static_cast<int>(GetProperty(data_obj, "startPos")->Number());
+}
+
+
+int Message::GetEndPosition() {
+  if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0;
+  HandleScope scope;
+  i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
+  return static_cast<int>(GetProperty(data_obj, "endPos")->Number());
+}
+
+
+int Message::GetStartColumn() {
+  if (IsDeadCheck("v8::Message::GetStartColumn()")) return 0;
+  HandleScope scope;
+  i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
+      "GetPositionInLine",
+      data_obj,
+      &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(0);
+  return static_cast<int>(start_col_obj->Number());
+}
+
+
+int Message::GetEndColumn() {
+  if (IsDeadCheck("v8::Message::GetEndColumn()")) return 0;
+  HandleScope scope;
+  i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
+      "GetPositionInLine",
+      data_obj,
+      &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(0);
+  int start = static_cast<int>(GetProperty(data_obj, "startPos")->Number());
+  int end = static_cast<int>(GetProperty(data_obj, "endPos")->Number());
+  return static_cast<int>(start_col_obj->Number()) + (end - start);
+}
+
+
+Local<String> Message::GetSourceLine() {
+  ON_BAILOUT("v8::Message::GetSourceLine()", return Local<String>());
+  HandleScope scope;
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> result = CallV8HeapFunction("GetSourceLine",
+                                                   Utils::OpenHandle(this),
+                                                   &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(Local<v8::String>());
+  if (result->IsString()) {
+    return scope.Close(Utils::ToLocal(i::Handle<i::String>::cast(result)));
+  } else {
+    return Local<String>();
+  }
+}
+
+
+void Message::PrintCurrentStackTrace(FILE* out) {
+  if (IsDeadCheck("v8::Message::PrintCurrentStackTrace()")) return;
+  i::Top::PrintCurrentStackTrace(out);
+}
+
+
+// --- D a t a ---
+
+bool Value::IsUndefined() {
+  if (IsDeadCheck("v8::Value::IsUndefined()")) return false;
+  return Utils::OpenHandle(this)->IsUndefined();
+}
+
+
+bool Value::IsNull() {
+  if (IsDeadCheck("v8::Value::IsNull()")) return false;
+  return Utils::OpenHandle(this)->IsNull();
+}
+
+
+bool Value::IsTrue() {
+  if (IsDeadCheck("v8::Value::IsTrue()")) return false;
+  return Utils::OpenHandle(this)->IsTrue();
+}
+
+
+bool Value::IsFalse() {
+  if (IsDeadCheck("v8::Value::IsFalse()")) return false;
+  return Utils::OpenHandle(this)->IsFalse();
+}
+
+
+bool Value::IsFunction() {
+  if (IsDeadCheck("v8::Value::IsFunction()")) return false;
+  return Utils::OpenHandle(this)->IsJSFunction();
+}
+
+
+bool Value::IsString() {
+  if (IsDeadCheck("v8::Value::IsString()")) return false;
+  return Utils::OpenHandle(this)->IsString();
+}
+
+
+bool Value::IsArray() {
+  if (IsDeadCheck("v8::Value::IsArray()")) return false;
+  return Utils::OpenHandle(this)->IsJSArray();
+}
+
+
+bool Value::IsObject() {
+  if (IsDeadCheck("v8::Value::IsObject()")) return false;
+  return Utils::OpenHandle(this)->IsJSObject();
+}
+
+
+bool Value::IsNumber() {
+  if (IsDeadCheck("v8::Value::IsNumber()")) return false;
+  return Utils::OpenHandle(this)->IsNumber();
+}
+
+
+bool Value::IsBoolean() {
+  if (IsDeadCheck("v8::Value::IsBoolean()")) return false;
+  return Utils::OpenHandle(this)->IsBoolean();
+}
+
+
+bool Value::IsExternal() {
+  if (IsDeadCheck("v8::Value::IsExternal()")) return false;
+  return Utils::OpenHandle(this)->IsProxy();
+}
+
+
+bool Value::IsInt32() {
+  if (IsDeadCheck("v8::Value::IsInt32()")) return false;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return true;
+  if (obj->IsNumber()) {
+    double value = obj->Number();
+    return i::FastI2D(i::FastD2I(value)) == value;
+  }
+  return false;
+}
+
+
+bool Value::IsDate() {
+  if (IsDeadCheck("v8::Value::IsDate()")) return false;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return obj->HasSpecificClassOf(i::Heap::Date_symbol());
+}
+
+
+Local<String> Value::ToString() {
+  if (IsDeadCheck("v8::Value::ToString()")) return Local<String>();
+  LOG_API("ToString");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> str;
+  if (obj->IsString()) {
+    str = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    str = i::Execution::ToString(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<String>());
+  }
+  return Local<String>(ToApi<String>(str));
+}
+
+
+Local<String> Value::ToDetailString() {
+  if (IsDeadCheck("v8::Value::ToDetailString()")) return Local<String>();
+  LOG_API("ToDetailString");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> str;
+  if (obj->IsString()) {
+    str = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    str = i::Execution::ToDetailString(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<String>());
+  }
+  return Local<String>(ToApi<String>(str));
+}
+
+
+Local<v8::Object> Value::ToObject() {
+  if (IsDeadCheck("v8::Value::ToObject()")) return Local<v8::Object>();
+  LOG_API("ToObject");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> val;
+  if (obj->IsJSObject()) {
+    val = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    val = i::Execution::ToObject(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
+  }
+  return Local<v8::Object>(ToApi<Object>(val));
+}
+
+
+Local<Boolean> Value::ToBoolean() {
+  if (IsDeadCheck("v8::Value::ToBoolean()")) return Local<Boolean>();
+  LOG_API("ToBoolean");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> val =
+      obj->IsBoolean() ? obj : i::Execution::ToBoolean(obj);
+  return Local<Boolean>(ToApi<Boolean>(val));
+}
+
+
+Local<Number> Value::ToNumber() {
+  if (IsDeadCheck("v8::Value::ToNumber()")) return Local<Number>();
+  LOG_API("ToNumber");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> num;
+  if (obj->IsNumber()) {
+    num = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    num = i::Execution::ToNumber(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<Number>());
+  }
+  return Local<Number>(ToApi<Number>(num));
+}
+
+
+Local<Integer> Value::ToInteger() {
+  if (IsDeadCheck("v8::Value::ToInteger()")) return Local<Integer>();
+  LOG_API("ToInteger");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> num;
+  if (obj->IsSmi()) {
+    num = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    num = i::Execution::ToInteger(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<Integer>());
+  }
+  return Local<Integer>(ToApi<Integer>(num));
+}
+
+
+External* External::Cast(v8::Value* that) {
+  if (IsDeadCheck("v8::External::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsProxy(),
+           "v8::External::Cast()",
+           "Could not convert to external");
+  return static_cast<External*>(that);
+}
+
+
+v8::Object* v8::Object::Cast(Value* that) {
+  if (IsDeadCheck("v8::Object::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsJSObject(),
+           "v8::Object::Cast()",
+           "Could not convert to object");
+  return static_cast<v8::Object*>(that);
+}
+
+
+v8::Function* v8::Function::Cast(Value* that) {
+  if (IsDeadCheck("v8::Function::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsJSFunction(),
+           "v8::Function::Cast()",
+           "Could not convert to function");
+  return static_cast<v8::Function*>(that);
+}
+
+
+v8::String* v8::String::Cast(v8::Value* that) {
+  if (IsDeadCheck("v8::String::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsString(),
+           "v8::String::Cast()",
+           "Could not convert to string");
+  return static_cast<v8::String*>(that);
+}
+
+
+v8::Number* v8::Number::Cast(v8::Value* that) {
+  if (IsDeadCheck("v8::Number::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsNumber(),
+           "v8::Number::Cast()",
+           "Could not convert to number");
+  return static_cast<v8::Number*>(that);
+}
+
+
+v8::Integer* v8::Integer::Cast(v8::Value* that) {
+  if (IsDeadCheck("v8::Integer::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsNumber(),
+           "v8::Integer::Cast()",
+           "Could not convert to number");
+  return static_cast<v8::Integer*>(that);
+}
+
+
+v8::Array* v8::Array::Cast(Value* that) {
+  if (IsDeadCheck("v8::Array::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsJSArray(),
+           "v8::Array::Cast()",
+           "Could not convert to array");
+  return static_cast<v8::Array*>(that);
+}
+
+
+v8::Date* v8::Date::Cast(v8::Value* that) {
+  if (IsDeadCheck("v8::Date::Cast()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->HasSpecificClassOf(i::Heap::Date_symbol()),
+           "v8::Date::Cast()",
+           "Could not convert to date");
+  return static_cast<v8::Date*>(that);
+}
+
+
+bool Value::BooleanValue() {
+  if (IsDeadCheck("v8::Value::BooleanValue()")) return false;
+  LOG_API("BooleanValue");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> value =
+      obj->IsBoolean() ? obj : i::Execution::ToBoolean(obj);
+  return value->IsTrue();
+}
+
+
+double Value::NumberValue() {
+  if (IsDeadCheck("v8::Value::NumberValue()")) return i::OS::nan_value();
+  LOG_API("NumberValue");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> num;
+  if (obj->IsNumber()) {
+    num = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    num = i::Execution::ToNumber(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(i::OS::nan_value());
+  }
+  return num->Number();
+}
+
+
+int64_t Value::IntegerValue() {
+  if (IsDeadCheck("v8::Value::IntegerValue()")) return 0;
+  LOG_API("IntegerValue");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> num;
+  if (obj->IsNumber()) {
+    num = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    num = i::Execution::ToInteger(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(0);
+  }
+  if (num->IsSmi()) {
+    return i::Smi::cast(*num)->value();
+  } else {
+    return static_cast<int64_t>(num->Number());
+  }
+}
+
+
+Local<Int32> Value::ToInt32() {
+  if (IsDeadCheck("v8::Value::ToInt32()")) return Local<Int32>();
+  LOG_API("ToInt32");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> num;
+  if (obj->IsSmi()) {
+    num = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    num = i::Execution::ToInt32(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<Int32>());
+  }
+  return Local<Int32>(ToApi<Int32>(num));
+}
+
+
+Local<Uint32> Value::ToUint32() {
+  if (IsDeadCheck("v8::Value::ToUint32()")) return Local<Uint32>();
+  LOG_API("ToUInt32");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> num;
+  if (obj->IsSmi()) {
+    num = obj;
+  } else {
+    EXCEPTION_PREAMBLE();
+    num = i::Execution::ToUint32(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<Uint32>());
+  }
+  return Local<Uint32>(ToApi<Uint32>(num));
+}
+
+
+Local<Uint32> Value::ToArrayIndex() {
+  if (IsDeadCheck("v8::Value::ToArrayIndex()")) return Local<Uint32>();
+  LOG_API("ToArrayIndex");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    if (i::Smi::cast(*obj)->value() >= 0) return Utils::Uint32ToLocal(obj);
+    return Local<Uint32>();
+  }
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> string_obj =
+      i::Execution::ToString(obj, &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(Local<Uint32>());
+  i::Handle<i::String> str = i::Handle<i::String>::cast(string_obj);
+  uint32_t index;
+  if (str->AsArrayIndex(&index)) {
+    i::Handle<i::Object> value;
+    if (index <= static_cast<uint32_t>(i::Smi::kMaxValue)) {
+      value = i::Handle<i::Object>(i::Smi::FromInt(index));
+    } else {
+      value = i::Factory::NewNumber(index);
+    }
+    return Utils::Uint32ToLocal(value);
+  }
+  return Local<Uint32>();
+}
+
+
+int32_t Value::Int32Value() {
+  if (IsDeadCheck("v8::Value::Int32Value()")) return 0;
+  LOG_API("Int32Value");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    return i::Smi::cast(*obj)->value();
+  } else {
+    LOG_API("Int32Value (slow)");
+    EXCEPTION_PREAMBLE();
+    i::Handle<i::Object> num =
+        i::Execution::ToInt32(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(0);
+    if (num->IsSmi()) {
+      return i::Smi::cast(*num)->value();
+    } else {
+      return static_cast<int32_t>(num->Number());
+    }
+  }
+}
+
+
+bool Value::Equals(Handle<Value> that) {
+  if (IsDeadCheck("v8::Value::Equals()")
+      || EmptyCheck("v8::Value::Equals()", this)
+      || EmptyCheck("v8::Value::Equals()", that))
+    return false;
+  LOG_API("Equals");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> other = Utils::OpenHandle(*that);
+  i::Object** args[1] = { other.location() };
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> result =
+      CallV8HeapFunction("EQUALS", obj, 1, args, &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(false);
+  return *result == i::Smi::FromInt(i::EQUAL);
+}
+
+
+bool Value::StrictEquals(Handle<Value> that) {
+  if (IsDeadCheck("v8::Value::StrictEquals()")
+      || EmptyCheck("v8::Value::StrictEquals()", this)
+      || EmptyCheck("v8::Value::StrictEquals()", that))
+    return false;
+  LOG_API("StrictEquals");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::Object> other = Utils::OpenHandle(*that);
+  // Must check HeapNumber first, since NaN !== NaN.
+  if (obj->IsHeapNumber()) {
+    if (!other->IsNumber()) return false;
+    double x = obj->Number();
+    double y = other->Number();
+    // Must check explicitly for NaN:s on Windows, but -0 works fine.
+    return x == y && !isnan(x) && !isnan(y);
+  } else if (*obj == *other) {  // Also covers Booleans.
+    return true;
+  } else if (obj->IsSmi()) {
+    return other->IsNumber() && obj->Number() == other->Number();
+  } else if (obj->IsString()) {
+    return other->IsString() &&
+      i::String::cast(*obj)->Equals(i::String::cast(*other));
+  } else if (obj->IsUndefined() || obj->IsUndetectableObject()) {
+    return other->IsUndefined() || other->IsUndetectableObject();
+  } else {
+    return false;
+  }
+}
+
+
+uint32_t Value::Uint32Value() {
+  if (IsDeadCheck("v8::Value::Uint32Value()")) return 0;
+  LOG_API("Uint32Value");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    return i::Smi::cast(*obj)->value();
+  } else {
+    EXCEPTION_PREAMBLE();
+    i::Handle<i::Object> num =
+        i::Execution::ToUint32(obj, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(0);
+    if (num->IsSmi()) {
+      return i::Smi::cast(*num)->value();
+    } else {
+      return static_cast<uint32_t>(num->Number());
+    }
+  }
+}
+
+
+bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value,
+                     v8::PropertyAttribute attribs) {
+  ON_BAILOUT("v8::Object::Set()", return false);
+  i::Handle<i::Object> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+  i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> obj = i::SetProperty(
+      self,
+      key_obj,
+      value_obj,
+      static_cast<PropertyAttributes>(attribs));
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(false);
+  return true;
+}
+
+
+Local<Value> v8::Object::Get(v8::Handle<Value> key) {
+  ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
+  i::Handle<i::Object> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> result = i::GetProperty(self, key_obj);
+  has_pending_exception = result.is_null();
+  EXCEPTION_BAILOUT_CHECK(Local<Value>());
+  return Utils::ToLocal(result);
+}
+
+
+Local<Value> v8::Object::GetPrototype() {
+  ON_BAILOUT("v8::Object::GetPrototype()", return Local<v8::Value>());
+  i::Handle<i::Object> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> result = i::GetPrototype(self);
+  return Utils::ToLocal(result);
+}
+
+
+Local<Array> v8::Object::GetPropertyNames() {
+  ON_BAILOUT("v8::Object::GetPropertyNames()", return Local<v8::Array>());
+  v8::HandleScope scope;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::FixedArray> value = i::GetKeysInFixedArrayFor(self);
+  // Because we use caching to speed up enumeration it is important
+  // to never change the result of the basic enumeration function so
+  // we clone the result.
+  i::Handle<i::FixedArray> elms = i::Factory::CopyFixedArray(value);
+  i::Handle<i::JSArray> result = i::Factory::NewJSArrayWithElements(elms);
+  return scope.Close(Utils::ToLocal(result));
+}
+
+
+Local<String> v8::Object::ObjectProtoToString() {
+  ON_BAILOUT("v8::Object::ObjectProtoToString()", return Local<v8::String>());
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+
+  i::Handle<i::Object> name(self->class_name());
+
+  // Native implementation of Object.prototype.toString (v8natives.js):
+  //   var c = %ClassOf(this);
+  //   if (c === 'Arguments') c  = 'Object';
+  //   return "[object " + c + "]";
+
+  if (!name->IsString()) {
+    return v8::String::New("[object ]");
+
+  } else {
+    i::Handle<i::String> class_name = i::Handle<i::String>::cast(name);
+    if (class_name->IsEqualTo(i::CStrVector("Arguments"))) {
+      return v8::String::New("[object Object]");
+
+    } else {
+      const char* prefix = "[object ";
+      Local<String> str = Utils::ToLocal(class_name);
+      const char* postfix = "]";
+
+      size_t prefix_len = strlen(prefix);
+      size_t str_len = str->Length();
+      size_t postfix_len = strlen(postfix);
+
+      size_t buf_len = prefix_len + str_len + postfix_len;
+      char* buf = i::NewArray<char>(buf_len);
+
+      // Write prefix.
+      char* ptr = buf;
+      memcpy(ptr, prefix, prefix_len * v8::internal::kCharSize);
+      ptr += prefix_len;
+
+      // Write real content.
+      str->WriteAscii(ptr, 0, str_len);
+      ptr += str_len;
+
+      // Write postfix.
+      memcpy(ptr, postfix, postfix_len * v8::internal::kCharSize);
+
+      // Copy the buffer into a heap-allocated string and return it.
+      Local<String> result = v8::String::New(buf, buf_len);
+      i::DeleteArray(buf);
+      return result;
+    }
+  }
+}
+
+
+bool v8::Object::Delete(v8::Handle<String> key) {
+  ON_BAILOUT("v8::Object::Delete()", return false);
+  HandleScope scope;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+  return i::DeleteProperty(self, key_obj)->IsTrue();
+}
+
+
+bool v8::Object::Has(v8::Handle<String> key) {
+  ON_BAILOUT("v8::Object::Has()", return false);
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+  return self->HasProperty(*key_obj);
+}
+
+
+bool v8::Object::Delete(uint32_t index) {
+  ON_BAILOUT("v8::Object::DeleteProperty()", return false);
+  HandleScope scope;
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  return i::DeleteElement(self, index)->IsTrue();
+}
+
+
+bool v8::Object::Has(uint32_t index) {
+  ON_BAILOUT("v8::Object::HasProperty()", return false);
+  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+  return self->HasElement(index);
+}
+
+
+bool v8::Object::HasRealNamedProperty(Handle<String> key) {
+  ON_BAILOUT("v8::Object::HasRealNamedProperty()", return false);
+  return Utils::OpenHandle(this)->HasRealNamedProperty(
+      *Utils::OpenHandle(*key));
+}
+
+
+bool v8::Object::HasRealIndexedProperty(uint32_t index) {
+  ON_BAILOUT("v8::Object::HasRealIndexedProperty()", return false);
+  return Utils::OpenHandle(this)->HasRealElementProperty(index);
+}
+
+
+bool v8::Object::HasRealNamedCallbackProperty(Handle<String> key) {
+  ON_BAILOUT("v8::Object::HasRealNamedCallbackProperty()", return false);
+  return Utils::OpenHandle(this)->HasRealNamedCallbackProperty(
+      *Utils::OpenHandle(*key));
+}
+
+
+bool v8::Object::HasNamedLookupInterceptor() {
+  ON_BAILOUT("v8::Object::HasNamedLookupInterceptor()", return false);
+  return Utils::OpenHandle(this)->HasNamedInterceptor();
+}
+
+
+bool v8::Object::HasIndexedLookupInterceptor() {
+  ON_BAILOUT("v8::Object::HasIndexedLookupInterceptor()", return false);
+  return Utils::OpenHandle(this)->HasIndexedInterceptor();
+}
+
+
+Handle<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
+      Handle<String> key) {
+  ON_BAILOUT("v8::Object::GetRealNamedPropertyInPrototypeChain()",
+             return Local<Value>());
+  i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
+  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+  i::LookupResult lookup;
+  self_obj->LookupRealNamedPropertyInPrototypes(*key_obj, &lookup);
+  if (lookup.IsValid()) {
+    PropertyAttributes attributes;
+    i::Handle<i::Object> result(self_obj->GetProperty(*self_obj,
+                                                      &lookup,
+                                                      *key_obj,
+                                                      &attributes));
+    return Utils::ToLocal(result);
+  }
+  return Local<Value>();  // No real property was found in prototype chain.
+}
+
+
+// Turns on access checks by copying the map and setting the check flag.
+// Because the object gets a new map, existing inline cache caching
+// the old map of this object will fail.
+void v8::Object::TurnOnAccessCheck() {
+  ON_BAILOUT("v8::Object::TurnOnAccessCheck()", return);
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+
+  i::Handle<i::Map> new_map =
+    i::Factory::CopyMapDropTransitions(i::Handle<i::Map>(obj->map()));
+  new_map->set_is_access_check_needed();
+  obj->set_map(*new_map);
+}
+
+
+Local<v8::Object> Function::NewInstance() {
+  return NewInstance(0, NULL);
+}
+
+
+Local<v8::Object> Function::NewInstance(int argc,
+                                        v8::Handle<v8::Value> argv[]) {
+  ON_BAILOUT("v8::Function::NewInstance()", return Local<v8::Object>());
+  LOG_API("Function::NewInstance");
+  HandleScope scope;
+  i::Handle<i::JSFunction> function = Utils::OpenHandle(this);
+  STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
+  i::Object*** args = reinterpret_cast<i::Object***>(argv);
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> returned =
+      i::Execution::New(function, argc, args, &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
+  return scope.Close(Utils::ToLocal(i::Handle<i::JSObject>::cast(returned)));
+}
+
+
+Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
+                                v8::Handle<v8::Value> argv[]) {
+  ON_BAILOUT("v8::Function::Call()", return Local<v8::Value>());
+  LOG_API("Function::Call");
+  i::Object* raw_result = NULL;
+  {
+    HandleScope scope;
+    i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
+    i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
+    STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
+    i::Object*** args = reinterpret_cast<i::Object***>(argv);
+    EXCEPTION_PREAMBLE();
+    i::Handle<i::Object> returned =
+        i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
+    EXCEPTION_BAILOUT_CHECK(Local<Object>());
+    raw_result = *returned;
+  }
+  i::Handle<i::Object> result(raw_result);
+  return Utils::ToLocal(result);
+}
+
+
+void Function::SetName(v8::Handle<v8::String> name) {
+  i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
+  func->shared()->set_name(*Utils::OpenHandle(*name));
+}
+
+
+Handle<Value> Function::GetName() {
+  i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
+  return Utils::ToLocal(i::Handle<i::Object>(func->shared()->name()));
+}
+
+
+int String::Length() {
+  if (IsDeadCheck("v8::String::Length()")) return 0;
+  return Utils::OpenHandle(this)->length();
+}
+
+
+int String::Utf8Length() {
+  if (IsDeadCheck("v8::String::Utf8Length()")) return 0;
+  return Utils::OpenHandle(this)->Utf8Length();
+}
+
+
+int String::WriteUtf8(char* buffer, int capacity) {
+  if (IsDeadCheck("v8::String::WriteUtf8()")) return 0;
+  LOG_API("String::WriteUtf8");
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  write_input_buffer.Reset(0, *str);
+  int len = str->length();
+  // Encode the first K - 3 bytes directly into the buffer since we
+  // know there's room for them.  If no capacity is given we copy all
+  // of them here.
+  int fast_end = capacity - (unibrow::Utf8::kMaxEncodedSize - 1);
+  int i;
+  int pos = 0;
+  for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) {
+    i::uc32 c = write_input_buffer.GetNext();
+    int written = unibrow::Utf8::Encode(buffer + pos, c);
+    pos += written;
+  }
+  if (i < len) {
+    // For the last characters we need to check the length for each one
+    // because they may be longer than the remaining space in the
+    // buffer.
+    char intermediate[unibrow::Utf8::kMaxEncodedSize];
+    for (; i < len && pos < capacity; i++) {
+      i::uc32 c = write_input_buffer.GetNext();
+      int written = unibrow::Utf8::Encode(intermediate, c);
+      if (pos + written <= capacity) {
+        for (int j = 0; j < written; j++)
+          buffer[pos + j] = intermediate[j];
+        pos += written;
+      } else {
+        // We've reached the end of the buffer
+        break;
+      }
+    }
+  }
+  if (i == len && (capacity == -1 || pos < capacity))
+    buffer[pos++] = '\0';
+  return pos;
+}
+
+
+int String::WriteAscii(char* buffer, int start, int length) {
+  if (IsDeadCheck("v8::String::WriteAscii()")) return 0;
+  LOG_API("String::WriteAscii");
+  ASSERT(start >= 0 && length >= -1);
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  // Flatten the string for efficiency.  This applies whether we are
+  // using StringInputBuffer or Get(i) to access the characters.
+  str->TryFlatten();
+  int end = length;
+  if ( (length == -1) || (length > str->length() - start) )
+    end = str->length() - start;
+  if (end < 0) return 0;
+  write_input_buffer.Reset(start, *str);
+  int i;
+  for (i = 0; i < end; i++) {
+    char c = static_cast<char>(write_input_buffer.GetNext());
+    if (c == '\0') c = ' ';
+    buffer[i] = c;
+  }
+  if (length == -1 || i < length)
+    buffer[i] = '\0';
+  return i;
+}
+
+
+int String::Write(uint16_t* buffer, int start, int length) {
+  if (IsDeadCheck("v8::String::Write()")) return 0;
+  LOG_API("String::Write");
+  ASSERT(start >= 0 && length >= -1);
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  // Flatten the string for efficiency.  This applies whether we are
+  // using StringInputBuffer or Get(i) to access the characters.
+  str->TryFlatten();
+  int end = length;
+  if ( (length == -1) || (length > str->length() - start) )
+    end = str->length() - start;
+  if (end < 0) return 0;
+  write_input_buffer.Reset(start, *str);
+  int i;
+  for (i = 0; i < end; i++)
+    buffer[i] = write_input_buffer.GetNext();
+  if (length == -1 || i < length)
+    buffer[i] = '\0';
+  return i;
+}
+
+
+bool v8::String::IsExternal() {
+  EnsureInitialized("v8::String::IsExternal()");
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  return str->IsExternalTwoByteString();
+}
+
+
+bool v8::String::IsExternalAscii() {
+  EnsureInitialized("v8::String::IsExternalAscii()");
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  return str->IsExternalAsciiString();
+}
+
+
+v8::String::ExternalStringResource* v8::String::GetExternalStringResource() {
+  EnsureInitialized("v8::String::GetExternalStringResource()");
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  ASSERT(str->IsExternalTwoByteString());
+  void* resource = i::Handle<i::ExternalTwoByteString>::cast(str)->resource();
+  return reinterpret_cast<ExternalStringResource*>(resource);
+}
+
+
+v8::String::ExternalAsciiStringResource*
+      v8::String::GetExternalAsciiStringResource() {
+  EnsureInitialized("v8::String::GetExternalAsciiStringResource()");
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  ASSERT(str->IsExternalAsciiString());
+  void* resource = i::Handle<i::ExternalAsciiString>::cast(str)->resource();
+  return reinterpret_cast<ExternalAsciiStringResource*>(resource);
+}
+
+
+double Number::Value() {
+  if (IsDeadCheck("v8::Number::Value()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return obj->Number();
+}
+
+
+bool Boolean::Value() {
+  if (IsDeadCheck("v8::Boolean::Value()")) return false;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return obj->IsTrue();
+}
+
+
+int64_t Integer::Value() {
+  if (IsDeadCheck("v8::Integer::Value()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    return i::Smi::cast(*obj)->value();
+  } else {
+    return static_cast<int64_t>(obj->Number());
+  }
+}
+
+
+int32_t Int32::Value() {
+  if (IsDeadCheck("v8::Int32::Value()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    return i::Smi::cast(*obj)->value();
+  } else {
+    return static_cast<int32_t>(obj->Number());
+  }
+}
+
+
+void* External::Value() {
+  if (IsDeadCheck("v8::External::Value()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return reinterpret_cast<void*>(i::Proxy::cast(*obj)->proxy());
+}
+
+
+int v8::Object::InternalFieldCount() {
+  if (IsDeadCheck("v8::Object::InternalFieldCount()")) return 0;
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  return obj->GetInternalFieldCount();
+}
+
+
+Local<Value> v8::Object::GetInternalField(int index) {
+  if (IsDeadCheck("v8::Object::GetInternalField()")) return Local<Value>();
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  if (!ApiCheck(index < obj->GetInternalFieldCount(),
+                "v8::Object::GetInternalField()",
+                "Reading internal field out of bounds")) {
+    return Local<Value>();
+  }
+  i::Handle<i::Object> value(obj->GetInternalField(index));
+  return Utils::ToLocal(value);
+}
+
+
+void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
+  if (IsDeadCheck("v8::Object::SetInternalField()")) return;
+  i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+  if (!ApiCheck(index < obj->GetInternalFieldCount(),
+                "v8::Object::SetInternalField()",
+                "Writing internal field out of bounds")) {
+    return;
+  }
+  i::Handle<i::Object> val = Utils::OpenHandle(*value);
+  obj->SetInternalField(index, *val);
+}
+
+
+// --- E n v i r o n m e n t ---
+
+bool v8::V8::Initialize() {
+  if (i::V8::HasBeenSetup()) return true;
+  HandleScope scope;
+  if (i::Snapshot::Initialize()) {
+    i::Serializer::disable();
+    return true;
+  } else {
+    return i::V8::Initialize(NULL);
+  }
+}
+
+
+const char* v8::V8::GetVersion() {
+  return "0.4.1 (candidate)";
+}
+
+
+static i::Handle<i::FunctionTemplateInfo>
+    EnsureConstructor(i::Handle<i::ObjectTemplateInfo> templ) {
+  if (templ->constructor()->IsUndefined()) {
+    Local<FunctionTemplate> constructor = FunctionTemplate::New();
+    Utils::OpenHandle(*constructor)->set_instance_template(*templ);
+    templ->set_constructor(*Utils::OpenHandle(*constructor));
+  }
+  return i::Handle<i::FunctionTemplateInfo>(
+    i::FunctionTemplateInfo::cast(templ->constructor()));
+}
+
+
+Persistent<Context> v8::Context::New(
+    v8::ExtensionConfiguration* extensions,
+    v8::Handle<ObjectTemplate> global_template,
+    v8::Handle<Value> global_object) {
+  EnsureInitialized("v8::Context::New()");
+  LOG_API("Context::New");
+  ON_BAILOUT("v8::Context::New()", return Persistent<Context>());
+
+  // Make sure that the global_template has a constructor.
+  if (!global_template.IsEmpty()) {
+    i::Handle<i::FunctionTemplateInfo> constructor =
+        EnsureConstructor(Utils::OpenHandle(*global_template));
+
+    // Create a fresh template for global proxy object.
+    Local<ObjectTemplate> proxy_template = ObjectTemplate::New();
+
+    i::Handle<i::FunctionTemplateInfo> proxy_constructor =
+      EnsureConstructor(Utils::OpenHandle(*proxy_template));
+
+    // Set the global template to be the prototype template
+    // of global proxy template.
+    proxy_constructor->set_prototype_template(
+        *Utils::OpenHandle(*global_template));
+
+    // Migrate security handlers from global_template to proxy_template.
+    if (!constructor->access_check_info()->IsUndefined()) {
+       proxy_constructor->set_access_check_info(
+           constructor->access_check_info());
+       proxy_constructor->set_needs_access_check(true);
+
+       // Remove access check info from global_template.
+       constructor->set_needs_access_check(false);
+       constructor->set_access_check_info(i::Heap::undefined_value());
+    }
+
+    global_template = proxy_template;
+  }
+
+  i::Handle<i::Context> env = i::Bootstrapper::CreateEnvironment(
+      Utils::OpenHandle(*global_object),
+      global_template, extensions);
+  if (!ApiCheck(!env.is_null(),
+                "v8::Context::New()",
+                "Could not initialize environment"))
+    return Persistent<Context>();
+  return Persistent<Context>(Utils::ToLocal(env));
+}
+
+
+void v8::Context::SetSecurityToken(Handle<Value> token) {
+  if (IsDeadCheck("v8::Context::SetSecurityToken()")) return;
+  i::Handle<i::Context> env = Utils::OpenHandle(this);
+  i::Handle<i::Object> token_handle = Utils::OpenHandle(*token);
+  env->set_security_token(*token_handle);
+}
+
+
+void v8::Context::UseDefaultSecurityToken() {
+  if (IsDeadCheck("v8::Context::UseDefaultSecurityToken()")) return;
+  i::Handle<i::Context> env = Utils::OpenHandle(this);
+  env->set_security_token(env->global());
+}
+
+
+Handle<Value> v8::Context::GetSecurityToken() {
+  if (IsDeadCheck("v8::Context::GetSecurityToken()")) return Handle<Value>();
+  i::Handle<i::Context> env = Utils::OpenHandle(this);
+  i::Object* security_token = env->security_token();
+  i::Handle<i::Object> token_handle(security_token);
+  return Utils::ToLocal(token_handle);
+}
+
+
+bool Context::HasOutOfMemoryException() {
+  i::Handle<i::Context> env = Utils::OpenHandle(this);
+  return env->has_out_of_memory();
+}
+
+
+bool Context::InContext() {
+  return i::Top::context() != NULL;
+}
+
+
+v8::Local<v8::Context> Context::GetEntered() {
+  if (IsDeadCheck("v8::Context::GetEntered()")) return Local<Context>();
+  i::Handle<i::Object> last = thread_local.LastEnteredContext();
+  if (last.is_null()) return Local<Context>();
+  i::Handle<i::Context> context = i::Handle<i::Context>::cast(last);
+  return Utils::ToLocal(context);
+}
+
+
+v8::Local<v8::Context> Context::GetCurrent() {
+  if (IsDeadCheck("v8::Context::GetCurrent()")) return Local<Context>();
+  i::Handle<i::Context> context(i::Top::global_context());
+  return Utils::ToLocal(context);
+}
+
+
+v8::Local<v8::Object> Context::Global() {
+  if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>();
+  i::Object** ctx = reinterpret_cast<i::Object**>(this);
+  i::Handle<i::Context> context =
+      i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
+  i::Handle<i::Object> global(context->global_proxy());
+  return Utils::ToLocal(i::Handle<i::JSObject>::cast(global));
+}
+
+
+void Context::DetachGlobal() {
+  if (IsDeadCheck("v8::Context::DetachGlobal()")) return;
+  i::Object** ctx = reinterpret_cast<i::Object**>(this);
+  i::Handle<i::Context> context =
+      i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
+  i::Bootstrapper::DetachGlobal(context);
+}
+
+
+Local<v8::Object> ObjectTemplate::NewInstance() {
+  ON_BAILOUT("v8::ObjectTemplate::NewInstance()", return Local<v8::Object>());
+  LOG_API("ObjectTemplate::NewInstance");
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> obj =
+      i::Execution::InstantiateObject(Utils::OpenHandle(this),
+                                      &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
+  return Utils::ToLocal(i::Handle<i::JSObject>::cast(obj));
+}
+
+
+Local<v8::Function> FunctionTemplate::GetFunction() {
+  ON_BAILOUT("v8::FunctionTemplate::GetFunction()",
+             return Local<v8::Function>());
+  LOG_API("FunctionTemplate::GetFunction");
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> obj =
+      i::Execution::InstantiateFunction(Utils::OpenHandle(this),
+                                        &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(Local<v8::Function>());
+  return Utils::ToLocal(i::Handle<i::JSFunction>::cast(obj));
+}
+
+
+bool FunctionTemplate::HasInstance(v8::Handle<v8::Value> value) {
+  ON_BAILOUT("v8::FunctionTemplate::HasInstanceOf()", return false);
+  i::Object* obj = *Utils::OpenHandle(*value);
+  return obj->IsInstanceOf(*Utils::OpenHandle(this));
+}
+
+
+Local<External> v8::External::New(void* data) {
+  STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
+  LOG_API("External::New");
+  EnsureInitialized("v8::External::New()");
+  i::Handle<i::Proxy> obj = i::Factory::NewProxy(static_cast<i::Address>(data));
+  return Utils::ToLocal(obj);
+}
+
+
+Local<String> v8::String::New(const char* data, int length) {
+  EnsureInitialized("v8::String::New()");
+  LOG_API("String::New(char)");
+  if (length == -1) length = strlen(data);
+  i::Handle<i::String> result =
+      i::Factory::NewStringFromUtf8(i::Vector<const char>(data, length));
+  return Utils::ToLocal(result);
+}
+
+
+Local<String> v8::String::NewUndetectable(const char* data, int length) {
+  EnsureInitialized("v8::String::NewUndetectable()");
+  LOG_API("String::NewUndetectable(char)");
+  if (length == -1) length = strlen(data);
+  i::Handle<i::String> result =
+      i::Factory::NewStringFromUtf8(i::Vector<const char>(data, length));
+  result->MarkAsUndetectable();
+  return Utils::ToLocal(result);
+}
+
+
+static int TwoByteStringLength(const uint16_t* data) {
+  int length = 0;
+  while (data[length] != '\0') length++;
+  return length;
+}
+
+
+Local<String> v8::String::New(const uint16_t* data, int length) {
+  EnsureInitialized("v8::String::New()");
+  LOG_API("String::New(uint16_)");
+  if (length == -1) length = TwoByteStringLength(data);
+  i::Handle<i::String> result =
+      i::Factory::NewStringFromTwoByte(i::Vector<const uint16_t>(data, length));
+  return Utils::ToLocal(result);
+}
+
+
+Local<String> v8::String::NewUndetectable(const uint16_t* data, int length) {
+  EnsureInitialized("v8::String::NewUndetectable()");
+  LOG_API("String::NewUndetectable(uint16_)");
+  if (length == -1) length = TwoByteStringLength(data);
+  i::Handle<i::String> result =
+      i::Factory::NewStringFromTwoByte(i::Vector<const uint16_t>(data, length));
+  result->MarkAsUndetectable();
+  return Utils::ToLocal(result);
+}
+
+
+i::Handle<i::String> NewExternalStringHandle(
+      v8::String::ExternalStringResource* resource) {
+  i::Handle<i::String> result =
+      i::Factory::NewExternalStringFromTwoByte(resource);
+  return result;
+}
+
+
+i::Handle<i::String> NewExternalAsciiStringHandle(
+      v8::String::ExternalAsciiStringResource* resource) {
+  i::Handle<i::String> result =
+      i::Factory::NewExternalStringFromAscii(resource);
+  return result;
+}
+
+
+static void DisposeExternalString(v8::Persistent<v8::Value> obj,
+                                  void* parameter) {
+  v8::String::ExternalStringResource* resource =
+    reinterpret_cast<v8::String::ExternalStringResource*>(parameter);
+  const size_t total_size = resource->length() * sizeof(*resource->data());
+  i::Counters::total_external_string_memory.Decrement(total_size);
+  delete resource;
+  obj.Dispose();
+}
+
+
+static void DisposeExternalAsciiString(v8::Persistent<v8::Value> obj,
+                                       void* parameter) {
+  v8::String::ExternalAsciiStringResource* resource =
+    reinterpret_cast<v8::String::ExternalAsciiStringResource*>(parameter);
+  const size_t total_size = resource->length() * sizeof(*resource->data());
+  i::Counters::total_external_string_memory.Decrement(total_size);
+  delete resource;
+  obj.Dispose();
+}
+
+
+Local<String> v8::String::NewExternal(
+      v8::String::ExternalStringResource* resource) {
+  EnsureInitialized("v8::String::NewExternal()");
+  LOG_API("String::NewExternal");
+  const size_t total_size = resource->length() * sizeof(*resource->data());
+  i::Counters::total_external_string_memory.Increment(total_size);
+  i::Handle<i::String> result = NewExternalStringHandle(resource);
+  i::Handle<i::Object> handle = i::GlobalHandles::Create(*result);
+  i::GlobalHandles::MakeWeak(handle.location(),
+                             resource,
+                             &DisposeExternalString);
+  return Utils::ToLocal(result);
+}
+
+
+Local<String> v8::String::NewExternal(
+      v8::String::ExternalAsciiStringResource* resource) {
+  EnsureInitialized("v8::String::NewExternal()");
+  LOG_API("String::NewExternal");
+  const size_t total_size = resource->length() * sizeof(*resource->data());
+  i::Counters::total_external_string_memory.Increment(total_size);
+  i::Handle<i::String> result = NewExternalAsciiStringHandle(resource);
+  i::Handle<i::Object> handle = i::GlobalHandles::Create(*result);
+  i::GlobalHandles::MakeWeak(handle.location(),
+                             resource,
+                             &DisposeExternalAsciiString);
+  return Utils::ToLocal(result);
+}
+
+
+Local<v8::Object> v8::Object::New() {
+  EnsureInitialized("v8::Object::New()");
+  LOG_API("Object::New");
+  i::Handle<i::JSObject> obj =
+      i::Factory::NewJSObject(i::Top::object_function());
+  return Utils::ToLocal(obj);
+}
+
+
+Local<v8::Value> v8::Date::New(double time) {
+  EnsureInitialized("v8::Date::New()");
+  LOG_API("Date::New");
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::Object> obj =
+      i::Execution::NewDate(time, &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(Local<v8::Value>());
+  return Utils::ToLocal(obj);
+}
+
+
+double v8::Date::NumberValue() {
+  if (IsDeadCheck("v8::Date::NumberValue()")) return 0;
+  LOG_API("Date::NumberValue");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
+  return jsvalue->value()->Number();
+}
+
+
+Local<v8::Array> v8::Array::New(int length) {
+  EnsureInitialized("v8::Array::New()");
+  LOG_API("Array::New");
+  i::Handle<i::JSArray> obj = i::Factory::NewJSArray(length);
+  return Utils::ToLocal(obj);
+}
+
+
+uint32_t v8::Array::Length() {
+  if (IsDeadCheck("v8::Array::Length()")) return 0;
+  i::Handle<i::JSArray> obj = Utils::OpenHandle(this);
+  i::Object* length = obj->length();
+  if (length->IsSmi()) {
+    return i::Smi::cast(length)->value();
+  } else {
+    return static_cast<uint32_t>(length->Number());
+  }
+}
+
+
+Local<String> v8::String::NewSymbol(const char* data, int length) {
+  EnsureInitialized("v8::String::NewSymbol()");
+  LOG_API("String::NewSymbol(char)");
+  if (length == -1) length = strlen(data);
+  i::Handle<i::String> result =
+      i::Factory::LookupSymbol(i::Vector<const char>(data, length));
+  return Utils::ToLocal(result);
+}
+
+
+Local<Number> v8::Number::New(double value) {
+  EnsureInitialized("v8::Number::New()");
+  i::Handle<i::Object> result = i::Factory::NewNumber(value);
+  return Utils::NumberToLocal(result);
+}
+
+
+Local<Integer> v8::Integer::New(int32_t value) {
+  EnsureInitialized("v8::Integer::New()");
+  if (i::Smi::IsValid(value)) {
+    return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value)));
+  }
+  i::Handle<i::Object> result = i::Factory::NewNumber(value);
+  return Utils::IntegerToLocal(result);
+}
+
+
+void V8::IgnoreOutOfMemoryException() {
+  thread_local.SetIgnoreOutOfMemory(true);
+}
+
+
+bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
+  EnsureInitialized("v8::V8::AddMessageListener()");
+  ON_BAILOUT("v8::V8::AddMessageListener()", return false);
+  HandleScope scope;
+  NeanderArray listeners(i::Factory::message_listeners());
+  NeanderObject obj(2);
+  obj.set(0, *i::Factory::NewProxy(FUNCTION_ADDR(that)));
+  obj.set(1, data.IsEmpty() ?
+             i::Heap::undefined_value() :
+             *Utils::OpenHandle(*data));
+  listeners.add(obj.value());
+  return true;
+}
+
+
+void V8::RemoveMessageListeners(MessageCallback that) {
+  EnsureInitialized("v8::V8::RemoveMessageListener()");
+  ON_BAILOUT("v8::V8::RemoveMessageListeners()", return);
+  HandleScope scope;
+  NeanderArray listeners(i::Factory::message_listeners());
+  for (int i = 0; i < listeners.length(); i++) {
+    if (listeners.get(i)->IsUndefined()) continue;  // skip deleted ones
+
+    NeanderObject listener(i::JSObject::cast(listeners.get(i)));
+    i::Handle<i::Proxy> callback_obj(i::Proxy::cast(listener.get(0)));
+    if (callback_obj->proxy() == FUNCTION_ADDR(that)) {
+      listeners.set(i, i::Heap::undefined_value());
+    }
+  }
+}
+
+
+void V8::SetCounterFunction(CounterLookupCallback callback) {
+  if (IsDeadCheck("v8::V8::SetCounterFunction()")) return;
+  i::StatsTable::SetCounterFunction(callback);
+}
+
+
+void V8::EnableSlidingStateWindow() {
+  if (IsDeadCheck("v8::V8::EnableSlidingStateWindow()")) return;
+  i::Logger::EnableSlidingStateWindow();
+}
+
+
+void V8::SetFailedAccessCheckCallbackFunction(
+      FailedAccessCheckCallback callback) {
+  if (IsDeadCheck("v8::V8::SetFailedAccessCheckCallbackFunction()")) return;
+  i::Top::SetFailedAccessCheckCallback(callback);
+}
+
+
+void V8::AddObjectToGroup(void* group_id, Persistent<Object> obj) {
+  if (IsDeadCheck("v8::V8::AddObjectToGroup()")) return;
+  i::GlobalHandles::AddToGroup(group_id, reinterpret_cast<i::Object**>(*obj));
+}
+
+
+int V8::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
+  if (IsDeadCheck("v8::V8::AdjustAmountOfExternalAllocatedMemory()")) return 0;
+  return i::Heap::AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
+}
+
+
+void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
+  if (IsDeadCheck("v8::V8::SetGlobalGCPrologueCallback()")) return;
+  i::Heap::SetGlobalGCPrologueCallback(callback);
+}
+
+
+void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
+  if (IsDeadCheck("v8::V8::SetGlobalGCEpilogueCallback()")) return;
+  i::Heap::SetGlobalGCEpilogueCallback(callback);
+}
+
+
+String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
+  EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
+  if (obj.IsEmpty()) {
+    str_ = NULL;
+    length_ = 0;
+    return;
+  }
+  HandleScope scope;
+  TryCatch try_catch;
+  Handle<String> str = obj->ToString();
+  if (str.IsEmpty()) {
+    str_ = NULL;
+    length_ = 0;
+  } else {
+    length_ = str->Utf8Length();
+    str_ = i::NewArray<char>(length_ + 1);
+    str->WriteUtf8(str_);
+  }
+}
+
+
+String::Utf8Value::~Utf8Value() {
+  i::DeleteArray(str_);
+}
+
+
+String::AsciiValue::AsciiValue(v8::Handle<v8::Value> obj) {
+  EnsureInitialized("v8::String::AsciiValue::AsciiValue()");
+  if (obj.IsEmpty()) {
+    str_ = NULL;
+    length_ = 0;
+    return;
+  }
+  HandleScope scope;
+  TryCatch try_catch;
+  Handle<String> str = obj->ToString();
+  if (str.IsEmpty()) {
+    str_ = NULL;
+    length_ = 0;
+  } else {
+    length_ = str->Length();
+    str_ = i::NewArray<char>(length_ + 1);
+    str->WriteAscii(str_);
+  }
+}
+
+
+String::AsciiValue::~AsciiValue() {
+  i::DeleteArray(str_);
+}
+
+
+String::Value::Value(v8::Handle<v8::Value> obj) {
+  EnsureInitialized("v8::String::Value::Value()");
+  if (obj.IsEmpty()) {
+    str_ = NULL;
+    length_ = 0;
+    return;
+  }
+  HandleScope scope;
+  TryCatch try_catch;
+  Handle<String> str = obj->ToString();
+  if (str.IsEmpty()) {
+    str_ = NULL;
+    length_ = 0;
+  } else {
+    length_ = str->Length();
+    str_ = i::NewArray<uint16_t>(length_ + 1);
+    str->Write(str_);
+  }
+}
+
+
+String::Value::~Value() {
+  i::DeleteArray(str_);
+}
+
+Local<Value> Exception::RangeError(v8::Handle<v8::String> raw_message) {
+  LOG_API("RangeError");
+  ON_BAILOUT("v8::Exception::RangeError()", return Local<Value>());
+  i::Object* error;
+  {
+    HandleScope scope;
+    i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
+    i::Handle<i::Object> result = i::Factory::NewRangeError(message);
+    error = *result;
+  }
+  i::Handle<i::Object> result(error);
+  return Utils::ToLocal(result);
+}
+
+Local<Value> Exception::ReferenceError(v8::Handle<v8::String> raw_message) {
+  LOG_API("ReferenceError");
+  ON_BAILOUT("v8::Exception::ReferenceError()", return Local<Value>());
+  i::Object* error;
+  {
+    HandleScope scope;
+    i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
+    i::Handle<i::Object> result = i::Factory::NewReferenceError(message);
+    error = *result;
+  }
+  i::Handle<i::Object> result(error);
+  return Utils::ToLocal(result);
+}
+
+Local<Value> Exception::SyntaxError(v8::Handle<v8::String> raw_message) {
+  LOG_API("SyntaxError");
+  ON_BAILOUT("v8::Exception::SyntaxError()", return Local<Value>());
+  i::Object* error;
+  {
+    HandleScope scope;
+    i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
+    i::Handle<i::Object> result = i::Factory::NewSyntaxError(message);
+    error = *result;
+  }
+  i::Handle<i::Object> result(error);
+  return Utils::ToLocal(result);
+}
+
+Local<Value> Exception::TypeError(v8::Handle<v8::String> raw_message) {
+  LOG_API("TypeError");
+  ON_BAILOUT("v8::Exception::TypeError()", return Local<Value>());
+  i::Object* error;
+  {
+    HandleScope scope;
+    i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
+    i::Handle<i::Object> result = i::Factory::NewTypeError(message);
+    error = *result;
+  }
+  i::Handle<i::Object> result(error);
+  return Utils::ToLocal(result);
+}
+
+Local<Value> Exception::Error(v8::Handle<v8::String> raw_message) {
+  LOG_API("Error");
+  ON_BAILOUT("v8::Exception::Error()", return Local<Value>());
+  i::Object* error;
+  {
+    HandleScope scope;
+    i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
+    i::Handle<i::Object> result = i::Factory::NewError(message);
+    error = *result;
+  }
+  i::Handle<i::Object> result(error);
+  return Utils::ToLocal(result);
+}
+
+
+// --- D e b u g   S u p p o r t ---
+
+
+bool Debug::AddDebugEventListener(DebugEventCallback that, Handle<Value> data) {
+  EnsureInitialized("v8::V8::AddDebugEventListener()");
+  ON_BAILOUT("v8::V8::AddDebugEventListener()", return false);
+  HandleScope scope;
+  NeanderArray listeners(i::Factory::debug_event_listeners());
+  NeanderObject obj(2);
+  obj.set(0, *i::Factory::NewProxy(FUNCTION_ADDR(that)));
+  obj.set(1, data.IsEmpty() ?
+             i::Heap::undefined_value() :
+             *Utils::OpenHandle(*data));
+  listeners.add(obj.value());
+  i::Debugger::UpdateActiveDebugger();
+  return true;
+}
+
+
+bool Debug::AddDebugEventListener(v8::Handle<v8::Function> that,
+                                  Handle<Value> data) {
+  ON_BAILOUT("v8::V8::AddDebugEventListener()", return false);
+  HandleScope scope;
+  NeanderArray listeners(i::Factory::debug_event_listeners());
+  NeanderObject obj(2);
+  obj.set(0, *Utils::OpenHandle(*that));
+  obj.set(1, data.IsEmpty() ?
+             i::Heap::undefined_value() :
+             *Utils::OpenHandle(*data));
+  listeners.add(obj.value());
+  i::Debugger::UpdateActiveDebugger();
+  return true;
+}
+
+
+void Debug::RemoveDebugEventListener(DebugEventCallback that) {
+  EnsureInitialized("v8::V8::RemoveDebugEventListener()");
+  ON_BAILOUT("v8::V8::RemoveDebugEventListener()", return);
+  HandleScope scope;
+  NeanderArray listeners(i::Factory::debug_event_listeners());
+  for (int i = 0; i < listeners.length(); i++) {
+    if (listeners.get(i)->IsUndefined()) continue;  // skip deleted ones
+
+    NeanderObject listener(i::JSObject::cast(listeners.get(i)));
+    // When removing a C debug event listener only consider proxy objects.
+    if (listener.get(0)->IsProxy()) {
+      i::Handle<i::Proxy> callback_obj(i::Proxy::cast(listener.get(0)));
+      if (callback_obj->proxy() == FUNCTION_ADDR(that)) {
+        listeners.set(i, i::Heap::undefined_value());
+      }
+    }
+  }
+  i::Debugger::UpdateActiveDebugger();
+}
+
+
+void Debug::RemoveDebugEventListener(v8::Handle<v8::Function> that) {
+  ON_BAILOUT("v8::V8::RemoveDebugEventListener()", return);
+  HandleScope scope;
+  NeanderArray listeners(i::Factory::debug_event_listeners());
+  for (int i = 0; i < listeners.length(); i++) {
+    if (listeners.get(i)->IsUndefined()) continue;  // skip deleted ones
+
+    NeanderObject listener(i::JSObject::cast(listeners.get(i)));
+    // When removing a JavaScript debug event listener only consider JavaScript
+    // function objects.
+    if (listener.get(0)->IsJSFunction()) {
+      i::JSFunction* callback = i::JSFunction::cast(listener.get(0));
+      i::Handle<i::JSFunction> callback_fun(callback);
+      if (callback_fun.is_identical_to(Utils::OpenHandle(*that))) {
+        listeners.set(i, i::Heap::undefined_value());
+      }
+    }
+  }
+  i::Debugger::UpdateActiveDebugger();
+}
+
+
+void Debug::DebugBreak() {
+  i::StackGuard::DebugBreak();
+}
+
+
+void Debug::SetMessageHandler(v8::DebugMessageHandler handler, void* data) {
+  i::Debugger::SetMessageHandler(handler, data);
+}
+
+
+void Debug::SendCommand(const uint16_t* command, int length) {
+  i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length));
+}
+
+
+namespace internal {
+
+
+HandleScopeImplementer* HandleScopeImplementer::instance() {
+  return &thread_local;
+}
+
+
+char* HandleScopeImplementer::ArchiveThread(char* storage) {
+  return thread_local.ArchiveThreadHelper(storage);
+}
+
+
+char* HandleScopeImplementer::ArchiveThreadHelper(char* storage) {
+  ImplementationUtilities::HandleScopeData* current =
+      ImplementationUtilities::CurrentHandleScope();
+  handle_scope_data_ = *current;
+  memcpy(storage, this, sizeof(*this));
+
+  Initialize();
+  current->Initialize();
+
+  return storage + ArchiveSpacePerThread();
+}
+
+
+int HandleScopeImplementer::ArchiveSpacePerThread() {
+  return sizeof(thread_local);
+}
+
+
+char* HandleScopeImplementer::RestoreThread(char* storage) {
+  return thread_local.RestoreThreadHelper(storage);
+}
+
+
+char* HandleScopeImplementer::RestoreThreadHelper(char* storage) {
+  memcpy(this, storage, sizeof(*this));
+  *ImplementationUtilities::CurrentHandleScope() = handle_scope_data_;
+  return storage + ArchiveSpacePerThread();
+}
+
+
+void HandleScopeImplementer::Iterate(
+    ObjectVisitor* v,
+    List<void**>* blocks,
+    ImplementationUtilities::HandleScopeData* handle_data) {
+  // Iterate over all handles in the blocks except for the last.
+  for (int i = blocks->length() - 2; i >= 0; --i) {
+    Object** block =
+        reinterpret_cast<Object**>(blocks->at(i));
+    v->VisitPointers(block, &block[kHandleBlockSize]);
+  }
+
+  // Iterate over live handles in the last block (if any).
+  if (!blocks->is_empty()) {
+    v->VisitPointers(reinterpret_cast<Object**>(blocks->last()),
+       reinterpret_cast<Object**>(handle_data->next));
+  }
+}
+
+
+void HandleScopeImplementer::Iterate(ObjectVisitor* v) {
+  ImplementationUtilities::HandleScopeData* current =
+      ImplementationUtilities::CurrentHandleScope();
+  Iterate(v, thread_local.Blocks(), current);
+}
+
+
+char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) {
+  HandleScopeImplementer* thread_local =
+      reinterpret_cast<HandleScopeImplementer*>(storage);
+  List<void**>* blocks_of_archived_thread = thread_local->Blocks();
+  ImplementationUtilities::HandleScopeData* handle_data_of_archived_thread =
+      &thread_local->handle_scope_data_;
+  Iterate(v, blocks_of_archived_thread, handle_data_of_archived_thread);
+
+  return storage + ArchiveSpacePerThread();
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/api.h b/regexp2000/src/api.h
new file mode 100644 (file)
index 0000000..4843926
--- /dev/null
@@ -0,0 +1,490 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_API_H_
+#define V8_API_H_
+
+#include "factory.h"
+
+namespace v8 {
+
+// Constants used in the implementation of the API.  The most natural thing
+// would usually be to place these with the classes that use them, but
+// we want to keep them out of v8.h because it is an externally
+// visible file.
+class Consts {
+ public:
+  enum TemplateType {
+    FUNCTION_TEMPLATE = 0,
+    OBJECT_TEMPLATE = 1
+  };
+};
+
+
+// Utilities for working with neander-objects, primitive
+// env-independent JSObjects used by the api.
+class NeanderObject {
+ public:
+  explicit NeanderObject(int size);
+  inline NeanderObject(v8::internal::Handle<v8::internal::Object> obj);
+  inline NeanderObject(v8::internal::Object* obj);
+  inline v8::internal::Object* get(int index);
+  inline void set(int index, v8::internal::Object* value);
+  inline v8::internal::Handle<v8::internal::JSObject> value() { return value_; }
+  int size();
+ private:
+  v8::internal::Handle<v8::internal::JSObject> value_;
+};
+
+
+// Utilities for working with neander-arrays, a simple extensible
+// array abstraction built on neander-objects.
+class NeanderArray {
+ public:
+  NeanderArray();
+  inline NeanderArray(v8::internal::Handle<v8::internal::Object> obj);
+  inline v8::internal::Handle<v8::internal::JSObject> value() {
+    return obj_.value();
+  }
+
+  void add(v8::internal::Handle<v8::internal::Object> value);
+
+  int length();
+
+  v8::internal::Object* get(int index);
+  // Change the value at an index to undefined value. If the index is
+  // out of bounds, the request is ignored. Returns the old value.
+  void set(int index, v8::internal::Object* value);
+ private:
+  NeanderObject obj_;
+};
+
+
+NeanderObject::NeanderObject(v8::internal::Handle<v8::internal::Object> obj)
+    : value_(v8::internal::Handle<v8::internal::JSObject>::cast(obj)) { }
+
+
+NeanderObject::NeanderObject(v8::internal::Object* obj)
+    : value_(v8::internal::Handle<v8::internal::JSObject>(
+        v8::internal::JSObject::cast(obj))) { }
+
+
+NeanderArray::NeanderArray(v8::internal::Handle<v8::internal::Object> obj)
+    : obj_(obj) { }
+
+
+v8::internal::Object* NeanderObject::get(int offset) {
+  ASSERT(value()->HasFastElements());
+  return v8::internal::FixedArray::cast(value()->elements())->get(offset);
+}
+
+
+void NeanderObject::set(int offset, v8::internal::Object* value) {
+  ASSERT(value_->HasFastElements());
+  v8::internal::FixedArray::cast(value_->elements())->set(offset, value);
+}
+
+
+template <typename T> static inline T ToCData(v8::internal::Object* obj) {
+  STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
+  return reinterpret_cast<T>(
+      reinterpret_cast<intptr_t>(v8::internal::Proxy::cast(obj)->proxy()));
+}
+
+
+template <typename T>
+static inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) {
+  STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
+  return v8::internal::Factory::NewProxy(
+      reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(obj)));
+}
+
+
+v8::Arguments::Arguments(v8::Local<v8::Value> data,
+                         v8::Local<v8::Object> holder,
+                         v8::Local<v8::Function> callee,
+                         bool is_construct_call,
+                         void** values, int length)
+    : data_(data), holder_(holder), callee_(callee),
+      is_construct_call_(is_construct_call),
+      values_(values), length_(length) { }
+
+
+enum ExtensionTraversalState {
+  UNVISITED, VISITED, INSTALLED
+};
+
+
+class RegisteredExtension {
+ public:
+  explicit RegisteredExtension(Extension* extension);
+  static void Register(RegisteredExtension* that);
+  Extension* extension() { return extension_; }
+  RegisteredExtension* next() { return next_; }
+  RegisteredExtension* next_auto() { return next_auto_; }
+  ExtensionTraversalState state() { return state_; }
+  void set_state(ExtensionTraversalState value) { state_ = value; }
+  static RegisteredExtension* first_extension() { return first_extension_; }
+ private:
+  Extension* extension_;
+  RegisteredExtension* next_;
+  RegisteredExtension* next_auto_;
+  ExtensionTraversalState state_;
+  static RegisteredExtension* first_extension_;
+  static RegisteredExtension* first_auto_extension_;
+};
+
+
+class ImplementationUtilities {
+ public:
+  static v8::Handle<v8::Primitive> Undefined();
+  static v8::Handle<v8::Primitive> Null();
+  static v8::Handle<v8::Boolean> True();
+  static v8::Handle<v8::Boolean> False();
+
+  static int GetNameCount(ExtensionConfiguration* that) {
+    return that->name_count_;
+  }
+
+  static const char** GetNames(ExtensionConfiguration* that) {
+    return that->names_;
+  }
+
+  static v8::Arguments NewArguments(Local<Value> data,
+                                    Local<Object> holder,
+                                    Local<Function> callee,
+                                    bool is_construct_call,
+                                    void** argv, int argc) {
+    return v8::Arguments(data, holder, callee, is_construct_call, argv, argc);
+  }
+
+  // Introduce an alias for the handle scope data to allow non-friends
+  // to access the HandleScope data.
+  typedef v8::HandleScope::Data HandleScopeData;
+
+  static HandleScopeData* CurrentHandleScope() {
+    return &v8::HandleScope::current_;
+  }
+
+#ifdef DEBUG
+  static void ZapHandleRange(void** begin, void** end) {
+    v8::HandleScope::ZapRange(begin, end);
+  }
+#endif
+};
+
+
+class Utils {
+ public:
+  static bool ReportApiFailure(const char* location, const char* message);
+
+  static Local<FunctionTemplate> ToFunctionTemplate(NeanderObject obj);
+  static Local<ObjectTemplate> ToObjectTemplate(NeanderObject obj);
+
+  static inline Local<Context> ToLocal(
+      v8::internal::Handle<v8::internal::Context> obj);
+  static inline Local<Value> ToLocal(
+      v8::internal::Handle<v8::internal::Object> obj);
+  static inline Local<Function> ToLocal(
+      v8::internal::Handle<v8::internal::JSFunction> obj);
+  static inline Local<String> ToLocal(
+      v8::internal::Handle<v8::internal::String> obj);
+  static inline Local<Object> ToLocal(
+      v8::internal::Handle<v8::internal::JSObject> obj);
+  static inline Local<Array> ToLocal(
+      v8::internal::Handle<v8::internal::JSArray> obj);
+  static inline Local<External> ToLocal(
+      v8::internal::Handle<v8::internal::Proxy> obj);
+  static inline Local<Message> MessageToLocal(
+      v8::internal::Handle<v8::internal::Object> obj);
+  static inline Local<Number> NumberToLocal(
+      v8::internal::Handle<v8::internal::Object> obj);
+  static inline Local<Integer> IntegerToLocal(
+      v8::internal::Handle<v8::internal::Object> obj);
+  static inline Local<Uint32> Uint32ToLocal(
+      v8::internal::Handle<v8::internal::Object> obj);
+  static inline Local<FunctionTemplate> ToLocal(
+      v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj);
+  static inline Local<ObjectTemplate> ToLocal(
+      v8::internal::Handle<v8::internal::ObjectTemplateInfo> obj);
+  static inline Local<Signature> ToLocal(
+      v8::internal::Handle<v8::internal::SignatureInfo> obj);
+  static inline Local<TypeSwitch> ToLocal(
+      v8::internal::Handle<v8::internal::TypeSwitchInfo> obj);
+
+  static inline v8::internal::Handle<v8::internal::TemplateInfo>
+      OpenHandle(Template* that);
+  static inline v8::internal::Handle<v8::internal::FunctionTemplateInfo>
+      OpenHandle(FunctionTemplate* that);
+  static inline v8::internal::Handle<v8::internal::ObjectTemplateInfo>
+      OpenHandle(ObjectTemplate* that);
+  static inline v8::internal::Handle<v8::internal::Object>
+      OpenHandle(Data* data);
+  static inline v8::internal::Handle<v8::internal::JSObject>
+      OpenHandle(v8::Object* data);
+  static inline v8::internal::Handle<v8::internal::JSArray>
+      OpenHandle(v8::Array* data);
+  static inline v8::internal::Handle<v8::internal::String>
+      OpenHandle(String* data);
+  static inline v8::internal::Handle<v8::internal::JSFunction>
+      OpenHandle(Script* data);
+  static inline v8::internal::Handle<v8::internal::JSFunction>
+      OpenHandle(Function* data);
+  static inline v8::internal::Handle<v8::internal::JSObject>
+      OpenHandle(Message* message);
+  static inline v8::internal::Handle<v8::internal::Context>
+      OpenHandle(v8::Context* context);
+  static inline v8::internal::Handle<v8::internal::SignatureInfo>
+      OpenHandle(v8::Signature* sig);
+  static inline v8::internal::Handle<v8::internal::TypeSwitchInfo>
+      OpenHandle(v8::TypeSwitch* that);
+  static inline v8::internal::Handle<v8::internal::Proxy>
+      OpenHandle(v8::External* that);
+};
+
+
+template <class T>
+static inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
+  return reinterpret_cast<T*>(obj.location());
+}
+
+
+template <class T>
+v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom(
+    HandleScope* scope) {
+  return Utils::OpenHandle(*scope->Close(Utils::ToLocal(*this)));
+}
+
+
+// Implementations of ToLocal
+
+#define MAKE_TO_LOCAL(Name, From, To) \
+  Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \
+    return Local<To>(reinterpret_cast<To*>(obj.location())); \
+  }
+
+MAKE_TO_LOCAL(ToLocal, Context, Context)
+MAKE_TO_LOCAL(ToLocal, Object, Value)
+MAKE_TO_LOCAL(ToLocal, JSFunction, Function)
+MAKE_TO_LOCAL(ToLocal, String, String)
+MAKE_TO_LOCAL(ToLocal, JSObject, Object)
+MAKE_TO_LOCAL(ToLocal, JSArray, Array)
+MAKE_TO_LOCAL(ToLocal, Proxy, External)
+MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate)
+MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate)
+MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature)
+MAKE_TO_LOCAL(ToLocal, TypeSwitchInfo, TypeSwitch)
+MAKE_TO_LOCAL(MessageToLocal, Object, Message)
+MAKE_TO_LOCAL(NumberToLocal, Object, Number)
+MAKE_TO_LOCAL(IntegerToLocal, Object, Integer)
+MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32)
+
+#undef MAKE_TO_LOCAL
+
+
+// Implementations of OpenHandle
+
+#define MAKE_OPEN_HANDLE(From, To) \
+  v8::internal::Handle<v8::internal::To> Utils::OpenHandle(v8::From* that) { \
+    return v8::internal::Handle<v8::internal::To>( \
+        reinterpret_cast<v8::internal::To**>(that)); \
+  }
+
+MAKE_OPEN_HANDLE(Template, TemplateInfo)
+MAKE_OPEN_HANDLE(FunctionTemplate, FunctionTemplateInfo)
+MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo)
+MAKE_OPEN_HANDLE(Signature, SignatureInfo)
+MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo)
+MAKE_OPEN_HANDLE(Data, Object)
+MAKE_OPEN_HANDLE(Object, JSObject)
+MAKE_OPEN_HANDLE(Array, JSArray)
+MAKE_OPEN_HANDLE(String, String)
+MAKE_OPEN_HANDLE(Script, JSFunction)
+MAKE_OPEN_HANDLE(Function, JSFunction)
+MAKE_OPEN_HANDLE(Message, JSObject)
+MAKE_OPEN_HANDLE(Context, Context)
+MAKE_OPEN_HANDLE(External, Proxy)
+
+#undef MAKE_OPEN_HANDLE
+
+
+namespace internal {
+
+// This class is here in order to be able to declare it a friend of
+// HandleScope.  Moving these methods to be members of HandleScope would be
+// neat in some ways, but it would expose external implementation details in
+// our public header file, which is undesirable.
+//
+// There is a singleton instance of this class to hold the per-thread data.
+// For multithreaded V8 programs this data is copied in and out of storage
+// so that the currently executing thread always has its own copy of this
+// data.
+class HandleScopeImplementer {
+ public:
+
+  HandleScopeImplementer()
+      : blocks(0),
+        entered_contexts_(0),
+        saved_contexts_(0) {
+    Initialize();
+  }
+
+  void Initialize() {
+    blocks.Initialize(0);
+    entered_contexts_.Initialize(0);
+    saved_contexts_.Initialize(0);
+    spare = NULL;
+    ignore_out_of_memory = false;
+    call_depth = 0;
+  }
+
+  static HandleScopeImplementer* instance();
+
+  // Threading support for handle data.
+  static int ArchiveSpacePerThread();
+  static char* RestoreThread(char* from);
+  static char* ArchiveThread(char* to);
+
+  // Garbage collection support.
+  static void Iterate(v8::internal::ObjectVisitor* v);
+  static char* Iterate(v8::internal::ObjectVisitor* v, char* data);
+
+
+  inline void** GetSpareOrNewBlock();
+  inline void DeleteExtensions(int extensions);
+
+  inline void IncrementCallDepth() {call_depth++;}
+  inline void DecrementCallDepth() {call_depth--;}
+  inline bool CallDepthIsZero() { return call_depth == 0; }
+
+  inline void EnterContext(Handle<Object> context);
+  inline bool LeaveLastContext();
+
+  // Returns the last entered context or an empty handle if no
+  // contexts have been entered.
+  inline Handle<Object> LastEnteredContext();
+
+  inline void SaveContext(Handle<Object> context);
+  inline Handle<Object> RestoreContext();
+  inline bool HasSavedContexts();
+
+  inline List<void**>* Blocks() { return &blocks; }
+
+  inline bool IgnoreOutOfMemory() { return ignore_out_of_memory; }
+  inline void SetIgnoreOutOfMemory(bool value) { ignore_out_of_memory = value; }
+
+ private:
+  List<void**> blocks;
+  Object** spare;
+  int call_depth;
+  // Used as a stack to keep track of entered contexts.
+  List<Handle<Object> > entered_contexts_;
+  // Used as a stack to keep track of saved contexts.
+  List<Handle<Object> > saved_contexts_;
+  bool ignore_out_of_memory;
+  // This is only used for threading support.
+  ImplementationUtilities::HandleScopeData handle_scope_data_;
+
+  static void Iterate(ObjectVisitor* v,
+                      List<void**>* blocks,
+                      ImplementationUtilities::HandleScopeData* handle_data);
+  char* RestoreThreadHelper(char* from);
+  char* ArchiveThreadHelper(char* to);
+
+  DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer);
+};
+
+
+static const int kHandleBlockSize = v8::internal::KB - 2;  // fit in one page
+
+
+void HandleScopeImplementer::SaveContext(Handle<Object> context) {
+  saved_contexts_.Add(context);
+}
+
+
+Handle<Object> HandleScopeImplementer::RestoreContext() {
+  return saved_contexts_.RemoveLast();
+}
+
+
+bool HandleScopeImplementer::HasSavedContexts() {
+  return !saved_contexts_.is_empty();
+}
+
+
+void HandleScopeImplementer::EnterContext(Handle<Object> context) {
+  entered_contexts_.Add(context);
+}
+
+
+bool HandleScopeImplementer::LeaveLastContext() {
+  if (entered_contexts_.is_empty()) return false;
+  entered_contexts_.RemoveLast();
+  return true;
+}
+
+
+Handle<Object> HandleScopeImplementer::LastEnteredContext() {
+  if (entered_contexts_.is_empty()) return Handle<Object>::null();
+  return entered_contexts_.last();
+}
+
+
+// If there's a spare block, use it for growing the current scope.
+void** HandleScopeImplementer::GetSpareOrNewBlock() {
+  void** block = (spare != NULL) ?
+      reinterpret_cast<void**>(spare) :
+      NewArray<void*>(kHandleBlockSize);
+  spare = NULL;
+  return block;
+}
+
+
+void HandleScopeImplementer::DeleteExtensions(int extensions) {
+  if (spare != NULL) {
+    DeleteArray(spare);
+    spare = NULL;
+  }
+  for (int i = extensions; i > 1; --i) {
+    void** block = blocks.RemoveLast();
+#ifdef DEBUG
+    ImplementationUtilities::ZapHandleRange(block, &block[kHandleBlockSize]);
+#endif
+    DeleteArray(block);
+  }
+  spare = reinterpret_cast<Object**>(blocks.RemoveLast());
+#ifdef DEBUG
+  ImplementationUtilities::ZapHandleRange(
+      reinterpret_cast<void**>(spare),
+      reinterpret_cast<void**>(&spare[kHandleBlockSize]));
+#endif
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_API_H_
diff --git a/regexp2000/src/apinatives.js b/regexp2000/src/apinatives.js
new file mode 100644 (file)
index 0000000..8741f59
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file contains infrastructure used by the API.  See
+// v8natives.js for an explanation of these files are processed and
+// loaded.
+
+
+function CreateDate(time) {
+  var date = new ORIGINAL_DATE();
+  date.setTime(time);
+  return date;
+}
+
+
+const kApiFunctionCache = {};
+const functionCache = kApiFunctionCache;
+
+
+function Instantiate(data, name) {
+  if (!%IsTemplate(data)) return data;
+  var tag = %GetTemplateField(data, kApiTagOffset);
+  switch (tag) {
+    case kFunctionTag:
+      return InstantiateFunction(data, name);
+    case kNewObjectTag:
+      var Constructor = %GetTemplateField(data, kApiConstructorOffset);
+      var result = Constructor ? new (Instantiate(Constructor))() : {};
+      ConfigureTemplateInstance(result, data);
+      return result;
+    default:
+      throw 'Unknown API tag <' + tag + '>';
+  }
+}
+
+
+function InstantiateFunction(data, name) {
+  var serialNumber = %GetTemplateField(data, kApiSerialNumberOffset);
+  if (!(serialNumber in kApiFunctionCache)) {
+    kApiFunctionCache[serialNumber] = null;
+    var fun = %CreateApiFunction(data);
+    if (name) %FunctionSetName(fun, name);
+    kApiFunctionCache[serialNumber] = fun;
+    var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset);
+    fun.prototype = prototype ? Instantiate(prototype) : {};
+    %SetProperty(fun.prototype, "constructor", fun, DONT_ENUM);
+    var parent = %GetTemplateField(data, kApiParentTemplateOffset);
+    if (parent) {
+      var parent_fun = Instantiate(parent);
+      fun.prototype.__proto__ = parent_fun.prototype;
+    }
+    ConfigureTemplateInstance(fun, data);
+  }
+  return kApiFunctionCache[serialNumber];
+}
+
+
+function ConfigureTemplateInstance(obj, data) {
+  var properties = %GetTemplateField(data, kApiPropertyListOffset);
+  if (properties) {
+    for (var i = 0; i < properties[0]; i += 3) {
+      var name = properties[i + 1];
+      var prop_data = properties[i + 2];
+      var attributes = properties[i + 3];
+      var value = Instantiate(prop_data, name);
+      %SetProperty(obj, name, value, attributes);
+    }
+  }
+}
diff --git a/regexp2000/src/arguments.h b/regexp2000/src/arguments.h
new file mode 100644 (file)
index 0000000..2ec68ed
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ARGUMENTS_H_
+#define V8_ARGUMENTS_H_
+
+namespace v8 { namespace internal {
+
+// Arguments provides access to runtime call parameters.
+//
+// It uses the fact that the instance fields of Arguments
+// (length_, arguments_) are "overlayed" with the parameters
+// (no. of parameters, and the parameter pointer) passed so
+// that inside the C++ function, the parameters passed can
+// be accessed conveniently:
+//
+//   Object* Runtime_function(Arguments args) {
+//     ... use args[i] here ...
+//   }
+
+class Arguments BASE_EMBEDDED {
+ public:
+  Object*& operator[] (int index) {
+    ASSERT(0 <= index && index < length_);
+    return arguments_[-index];
+  }
+
+  template <class S> Handle<S> at(int index) {
+    Object** value = &((*this)[index]);
+    // This cast checks that the object we're accessing does indeed have the
+    // expected type.
+    S::cast(*value);
+    return Handle<S>(reinterpret_cast<S**>(value));
+  }
+
+  // Get the total number of arguments including the receiver.
+  int length() const { return length_; }
+
+ private:
+  int length_;
+  Object** arguments_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARGUMENTS_H_
diff --git a/regexp2000/src/array.js b/regexp2000/src/array.js
new file mode 100644 (file)
index 0000000..c183159
--- /dev/null
@@ -0,0 +1,959 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file relies on the fact that the following declarations have been made
+// in runtime.js:
+// const $Array = global.Array;
+
+// -------------------------------------------------------------------
+
+// Global list of arrays visited during toString, toLocaleString and
+// join invocations.
+var visited_arrays = new $Array();
+
+
+// Gets a sorted array of array keys.  Useful for operations on sparse
+// arrays.  Dupes have not been removed.
+function GetSortedArrayKeys(array, intervals) {
+  var length = intervals.length;
+  var keys = [];
+  for (var k = 0; k < length; k++) {
+    var key = intervals[k];
+    if (key < 0) {
+      var j = -1 - key;
+      var limit = j + intervals[++k];
+      for (; j < limit; j++) {
+        var e = array[j];
+        if (!IS_UNDEFINED(e) || j in array) {
+          keys.push(j);
+        }
+      }
+    } else {
+      // The case where key is undefined also ends here.
+      if (!IS_UNDEFINED(key)) {
+        var e = array[key];
+        if (!IS_UNDEFINED(e) || key in array) {
+          keys.push(key);
+        }
+      }
+    }
+  }
+  keys.sort(function(a, b) { return a - b; });
+  return keys;
+}
+
+
+// Optimized for sparse arrays if separator is ''.
+function SparseJoin(array, len, convert) {
+  var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
+  var builder = new StringBuilder();
+  var last_key = -1;
+  var keys_length = keys.length;
+  for (var i = 0; i < keys_length; i++) {
+    var key = keys[i];
+    if (key != last_key) {
+      var e = array[key];
+      builder.add(convert(e));
+      last_key = key;
+    }
+  }
+  return builder.generate();
+}
+
+
+function UseSparseVariant(object, length, is_array) {
+   return is_array &&
+       length > 1000 &&
+       (!%_IsSmi(length) ||
+        %EstimateNumberOfElements(object) < (length >> 2));
+}
+
+
+function Join(array, length, separator, convert) {
+  if (length == 0) return '';
+
+  var is_array = IS_ARRAY(array);
+
+  if (is_array) {
+    // If the array is cyclic, return the empty string for already
+    // visited arrays.
+    if (!%PushIfAbsent(visited_arrays, array)) return '';
+  }
+
+  // Attempt to convert the elements.
+  try {
+    if (UseSparseVariant(array, length, is_array) && separator === '') {
+      return SparseJoin(array, length, convert);
+    }
+
+    // Fast case for one-element arrays.
+    if (length == 1) {
+      var e = array[0];
+      if (!IS_UNDEFINED(e) || (0 in array)) {
+        return convert(e);
+      }
+    }
+
+    var builder = new StringBuilder();
+
+    for (var i = 0; i < length; i++) {
+      var e = array[i];
+      if (i != 0) builder.add(separator);
+      if (!IS_UNDEFINED(e) || (i in array)) {
+        builder.add(convert(e));
+      }
+    }
+    return builder.generate();
+  } finally {
+    // Make sure to pop the visited array no matter what happens.
+    if (is_array) visited_arrays.pop();
+  }
+}
+
+
+function ConvertToString(e) {
+  if (e == null) return '';
+  else return ToString(e);
+}
+
+
+function ConvertToLocaleString(e) {
+  if (e == null) return '';
+  else {
+    // e_obj's toLocaleString might be overwritten, check if it is a function.
+    // Call ToString if toLocaleString is not a function.
+    // See issue 877615.
+    var e_obj = ToObject(e);
+    if (IS_FUNCTION(e_obj.toLocaleString))
+      return e_obj.toLocaleString();
+    else
+      return ToString(e);
+  }
+}
+
+
+// This function implements the optimized splice implementation that can use
+// special array operations to handle sparse arrays in a sensible fashion.
+function SmartSlice(array, start_i, del_count, len, deleted_elements) {
+  // Move deleted elements to a new array (the return value from splice).
+  // Intervals array can contain keys and intervals.  See comment in Concat.
+  var intervals = %GetArrayKeys(array, start_i + del_count);
+  var length = intervals.length;
+  for (var k = 0; k < length; k++) {
+    var key = intervals[k];
+    if (key < 0) {
+      var j = -1 - key;
+      var interval_limit = j + intervals[++k];
+      if (j < start_i) {
+        j = start_i;
+      }
+      for (; j < interval_limit; j++) {
+        // ECMA-262 15.4.4.12 line 10.  The spec could also be
+        // interpreted such that %HasLocalProperty would be the
+        // appropriate test.  We follow KJS in consulting the
+        // prototype.
+        var current = array[j];
+        if (!IS_UNDEFINED(current) || j in array) {
+          deleted_elements[j - start_i] = current;
+        }
+      }
+    } else {
+      if (!IS_UNDEFINED(key)) {
+        if (key >= start_i) {
+          // ECMA-262 15.4.4.12 line 10.  The spec could also be
+          // interpreted such that %HasLocalProperty would be the
+          // appropriate test.  We follow KJS in consulting the
+          // prototype.
+          var current = array[key];
+          if (!IS_UNDEFINED(current) || key in array) {
+            deleted_elements[key - start_i] = current;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+// This function implements the optimized splice implementation that can use
+// special array operations to handle sparse arrays in a sensible fashion.
+function SmartMove(array, start_i, del_count, len, num_additional_args) {
+  // Move data to new array.
+  var new_array = new $Array(len - del_count + num_additional_args);
+  var intervals = %GetArrayKeys(array, len);
+  var length = intervals.length;
+  for (var k = 0; k < length; k++) {
+    var key = intervals[k];
+    if (key < 0) {
+      var j = -1 - key;
+      var interval_limit = j + intervals[++k];
+      while (j < start_i && j < interval_limit) {
+        // The spec could also be interpreted such that
+        // %HasLocalProperty would be the appropriate test.  We follow
+        // KJS in consulting the prototype.
+        var current = array[j];
+        if (!IS_UNDEFINED(current) || j in array) {
+          new_array[j] = current;
+        }
+        j++;
+      }
+      j = start_i + del_count;
+      while (j < interval_limit) {
+        // ECMA-262 15.4.4.12 lines 24 and 41.  The spec could also be
+        // interpreted such that %HasLocalProperty would be the
+        // appropriate test.  We follow KJS in consulting the
+        // prototype.
+        var current = array[j];
+        if (!IS_UNDEFINED(current) || j in array) {
+          new_array[j - del_count + num_additional_args] = current;
+        }
+        j++;
+      }
+    } else {
+      if (!IS_UNDEFINED(key)) {
+        if (key < start_i) {
+          // The spec could also be interpreted such that
+          // %HasLocalProperty would be the appropriate test.  We follow
+          // KJS in consulting the prototype.
+          var current = array[key];
+          if (!IS_UNDEFINED(current) || key in array) {
+            new_array[key] = current;
+          }
+        } else if (key >= start_i + del_count) {
+          // ECMA-262 15.4.4.12 lines 24 and 41.  The spec could also
+          // be interpreted such that %HasLocalProperty would be the
+          // appropriate test.  We follow KJS in consulting the
+          // prototype.
+          var current = array[key];
+          if (!IS_UNDEFINED(current) || key in array) {
+            new_array[key - del_count + num_additional_args] = current;
+          }
+        }
+      }
+    }
+  }
+  // Move contents of new_array into this array
+  %MoveArrayContents(new_array, array);
+}
+
+
+// This is part of the old simple-minded splice.  We are using it either
+// because the receiver is not an array (so we have no choice) or because we
+// know we are not deleting or moving a lot of elements.
+function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
+  for (var i = 0; i < del_count; i++) {
+    var index = start_i + i;
+    // The spec could also be interpreted such that %HasLocalProperty
+    // would be the appropriate test.  We follow KJS in consulting the
+    // prototype.
+    var current = array[index];
+    if (!IS_UNDEFINED(current) || index in array)
+      deleted_elements[i] = current;
+  }
+}
+
+
+function SimpleMove(array, start_i, del_count, len, num_additional_args) {
+  if (num_additional_args !== del_count) {
+    // Move the existing elements after the elements to be deleted
+    // to the right position in the resulting array.
+    if (num_additional_args > del_count) {
+      for (var i = len - del_count; i > start_i; i--) {
+        var from_index = i + del_count - 1;
+        var to_index = i + num_additional_args - 1;
+        // The spec could also be interpreted such that
+        // %HasLocalProperty would be the appropriate test.  We follow
+        // KJS in consulting the prototype.
+        var current = array[from_index];
+        if (!IS_UNDEFINED(current) || from_index in array) {
+          array[to_index] = current;
+        } else {
+          delete array[to_index];
+        }
+      }
+    } else {
+      for (var i = start_i; i < len - del_count; i++) {
+        var from_index = i + del_count;
+        var to_index = i + num_additional_args;
+        // The spec could also be interpreted such that
+        // %HasLocalProperty would be the appropriate test.  We follow
+        // KJS in consulting the prototype.
+        var current = array[from_index];
+        if (!IS_UNDEFINED(current) || from_index in array) {
+          array[to_index] = current;
+        } else {
+          delete array[to_index];
+        }
+      }
+      for (var i = len; i > len - del_count + num_additional_args; i--) {
+        delete array[i - 1];
+      }
+    }
+  }
+}
+
+
+// -------------------------------------------------------------------
+
+
+function ArrayToString() {
+  if (!IS_ARRAY(this)) {
+    throw new $TypeError('Array.prototype.toString is not generic');
+  }
+  return Join(this, this.length, ',', ConvertToString);
+}
+
+
+function ArrayToLocaleString() {
+  if (!IS_ARRAY(this)) {
+    throw new $TypeError('Array.prototype.toString is not generic');
+  }
+  return Join(this, this.length, ',', ConvertToLocaleString);
+}
+
+
+function ArrayJoin(separator) {
+  if (IS_UNDEFINED(separator)) separator = ',';
+  else separator = ToString(separator);
+  return Join(this, ToUint32(this.length), separator, ConvertToString);
+}
+
+
+// Removes the last element from the array and returns it. See
+// ECMA-262, section 15.4.4.6.
+function ArrayPop() {
+  var n = ToUint32(this.length);
+  if (n == 0) {
+    this.length = n;
+    return;
+  }
+  n--;
+  var value = this[n];
+  this.length = n;
+  delete this[n];
+  return value;
+}
+
+
+// Appends the arguments to the end of the array and returns the new
+// length of the array. See ECMA-262, section 15.4.4.7.
+function ArrayPush() {
+  var n = ToUint32(this.length);
+  var m = %_ArgumentsLength();
+  for (var i = 0; i < m; i++) {
+    this[i+n] = %_Arguments(i);
+  }
+  this.length = n + m;
+  return this.length;
+}
+
+
+function ArrayConcat(arg1) {  // length == 1
+  var arg_number = 0, arg_count = %_ArgumentsLength();
+  var n = 0;
+
+  var A = $Array(1 + arg_count);
+  var E = this;
+
+  while (true) {
+    if (IS_ARRAY(E)) {
+      // This is an array of intervals or an array of keys.  Keys are
+      // represented by non-negative integers.  Intervals are represented by
+      // negative integers, followed by positive counts.  The interval start
+      // is determined by subtracting the entry from -1.  There may also be
+      // undefined entries in the array which should be skipped.
+      var intervals = %GetArrayKeys(E, E.length);
+      var length = intervals.length;
+      for (var k = 0; k < length; k++) {
+        var key = intervals[k];
+        if (key < 0) {
+          var j = -1 - key;
+          var limit = j + intervals[++k];
+          for (; j < limit; j++) {
+            if (j in E) {
+              A[n + j] = E[j];
+            }
+          }
+        } else {
+          // The case where key is undefined also ends here.
+          if (!IS_UNDEFINED(key)) {
+            A[n + key] = E[key];
+          }
+        }
+      }
+      n += E.length;
+    } else {
+      A[n++] = E;
+    }
+    if (arg_number == arg_count) break;
+    E = %_Arguments(arg_number++);
+  }
+
+  A.length = n;  // may contain empty arrays
+  return A;
+}
+
+
+// For implementing reverse() on large, sparse arrays.
+function SparseReverse(array, len) {
+  var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
+  var high_counter = keys.length - 1;
+  var low_counter = 0;
+  while (low_counter <= high_counter) {
+    var i = keys[low_counter];
+    var j = keys[high_counter];
+
+    var j_complement = len - j - 1;
+    var low, high;
+
+    if (j_complement <= i) {
+      high = j;
+      while (keys[--high_counter] == j);
+      low = j_complement;
+    }
+    if (j_complement >= i) {
+      low = i;
+      while (keys[++low_counter] == i);
+      high = len - i - 1;
+    }
+
+    var current_i = array[low];
+    if (!IS_UNDEFINED(current_i) || low in array) {
+      var current_j = array[high];
+      if (!IS_UNDEFINED(current_j) || high in array) {
+        array[low] = current_j;
+        array[high] = current_i;
+      } else {
+        array[high] = current_i;
+        delete array[low];
+      }
+    } else {
+      var current_j = array[high];
+      if (!IS_UNDEFINED(current_j) || high in array) {
+        array[low] = current_j;
+        delete array[high];
+      }
+    }
+  }
+}
+
+
+function ArrayReverse() {
+  var j = ToUint32(this.length) - 1;
+
+  if (UseSparseVariant(this, j, IS_ARRAY(this))) {
+    SparseReverse(this, j+1);
+    return this;
+  }
+
+  for (var i = 0; i < j; i++, j--) {
+    var current_i = this[i];
+    if (!IS_UNDEFINED(current_i) || i in this) {
+      var current_j = this[j];
+      if (!IS_UNDEFINED(current_j) || j in this) {
+        this[i] = current_j;
+        this[j] = current_i;
+      } else {
+        this[j] = current_i;
+        delete this[i];
+      }
+    } else {
+      var current_j = this[j];
+      if (!IS_UNDEFINED(current_j) || j in this) {
+        this[i] = current_j;
+        delete this[j];
+      }
+    }
+  }
+  return this;
+}
+
+
+function ArrayShift() {
+  var len = ToUint32(this.length);
+
+  if (len === 0) {
+    this.length = 0;
+    return;
+  }
+
+  var first = this[0];
+
+  if (IS_ARRAY(this))
+    SmartMove(this, 0, 1, len, 0);
+  else
+    SimpleMove(this, 0, 1, len, 0);
+
+  this.length = len - 1;
+
+  return first;
+}
+
+
+function ArrayUnshift(arg1) {  // length == 1
+  var len = ToUint32(this.length);
+  var num_arguments = %_ArgumentsLength();
+
+  if (IS_ARRAY(this))
+    SmartMove(this, 0, 0, len, num_arguments);
+  else
+    SimpleMove(this, 0, 0, len, num_arguments);
+
+  for (var i = 0; i < num_arguments; i++) {
+    this[i] = %_Arguments(i);
+  }
+
+  this.length = len + num_arguments;
+
+  return len + num_arguments;
+}
+
+
+function ArraySlice(start, end) {
+  var len = ToUint32(this.length);
+  var start_i = TO_INTEGER(start);
+  var end_i = len;
+
+  if (end !== void 0) end_i = TO_INTEGER(end);
+
+  if (start_i < 0) {
+    start_i += len;
+    if (start_i < 0) start_i = 0;
+  } else {
+    if (start_i > len) start_i = len;
+  }
+
+  if (end_i < 0) {
+    end_i += len;
+    if (end_i < 0) end_i = 0;
+  } else {
+    if (end_i > len) end_i = len;
+  }
+
+  var result = [];
+
+  if (end_i < start_i) return result;
+
+  if (IS_ARRAY(this)) {
+    SmartSlice(this, start_i, end_i - start_i, len, result);
+  } else {
+    SimpleSlice(this, start_i, end_i - start_i, len, result);
+  }
+
+  result.length = end_i - start_i;
+
+  return result;
+}
+
+
+function ArraySplice(start, delete_count) {
+  var num_arguments = %_ArgumentsLength();
+
+  // SpiderMonkey and KJS return undefined in the case where no
+  // arguments are given instead of using the implicit undefined
+  // arguments.  This does not follow ECMA-262, but we do the same for
+  // compatibility.
+  if (num_arguments == 0) return;
+
+  var len = ToUint32(this.length);
+  var start_i = TO_INTEGER(start);
+
+  if (start_i < 0) {
+    start_i += len;
+    if (start_i < 0) start_i = 0;
+  } else {
+    if (start_i > len) start_i = len;
+  }
+
+  // SpiderMonkey and KJS treat the case where no delete count is
+  // given differently from when an undefined delete count is given.
+  // This does not follow ECMA-262, but we do the same for
+  // compatibility.
+  var del_count = 0;
+  if (num_arguments > 1) {
+    del_count = TO_INTEGER(delete_count);
+    if (del_count < 0) del_count = 0;
+    if (del_count > len - start_i) del_count = len - start_i;
+  } else {
+    del_count = len - start_i;
+  }
+
+  var deleted_elements = [];
+  deleted_elements.length = del_count;
+
+  // Number of elements to add.
+  var num_additional_args = 0;
+  if (num_arguments > 2) {
+    num_additional_args = num_arguments - 2;
+  }
+
+  var use_simple_splice = true;
+
+  if (IS_ARRAY(this) && num_additional_args !== del_count) {
+    // If we are only deleting/moving a few things near the end of the
+    // array then the simple version is going to be faster, because it
+    // doesn't touch most of the array.
+    var estimated_non_hole_elements = %EstimateNumberOfElements(this);
+    if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) {
+      use_simple_splice = false;
+    }
+  }
+
+  if (use_simple_splice) {
+    SimpleSlice(this, start_i, del_count, len, deleted_elements);
+    SimpleMove(this, start_i, del_count, len, num_additional_args);
+  } else {
+    SmartSlice(this, start_i, del_count, len, deleted_elements);
+    SmartMove(this, start_i, del_count, len, num_additional_args);
+  }
+
+  // Insert the arguments into the resulting array in
+  // place of the deleted elements.
+  var i = start_i;
+  var arguments_index = 2;
+  var arguments_length = %_ArgumentsLength();
+  while (arguments_index < arguments_length) {
+    this[i++] = %_Arguments(arguments_index++);
+  }
+  this.length = len - del_count + num_additional_args;
+
+  // Return the deleted elements.
+  return deleted_elements;
+}
+
+
+function ArraySort(comparefn) {
+  // In-place QuickSort algorithm.
+  // For short (length <= 22) arrays, insertion sort is used for efficiency.
+
+  var custom_compare = IS_FUNCTION(comparefn);
+
+  function Compare(x,y) {
+    if (custom_compare) {
+      return comparefn.call(null, x, y);
+    }
+    if (%_IsSmi(x) && %_IsSmi(y)) {
+      return %SmiLexicographicCompare(x, y);
+    }
+    x = ToString(x);
+    y = ToString(y);
+    if (x == y) return 0;
+    else return x < y ? -1 : 1;
+  };
+
+  function InsertionSort(a, from, to) {
+    for (var i = from + 1; i < to; i++) {
+      var element = a[i];
+      // place element in a[from..i[
+      // binary search
+      var min = from;
+      var max = i;
+      // The search interval is a[min..max[
+      while (min < max) {
+        var mid = min + ((max - min) >> 1);
+        var order = Compare(a[mid], element);
+        if (order == 0) {
+          min = max = mid;
+          break;
+        }
+        if (order < 0) {
+          min = mid + 1;
+        } else {
+          max = mid;
+        }
+      }
+      // place element at position min==max.
+      for (var j = i; j > min; j--) {
+        a[j] = a[j - 1];
+      }
+      a[min] = element;
+    }
+  }
+
+  function QuickSort(a, from, to) {
+    // Insertion sort is faster for short arrays.
+    if (to - from <= 22) { 
+      InsertionSort(a, from, to);
+      return;
+    }
+    var pivot_index = $floor($random() * (to - from)) + from;
+    var pivot = a[pivot_index];
+    // Issue 95: Keep the pivot element out of the comparisons to avoid
+    // infinite recursion if comparefn(pivot, pivot) != 0.
+    a[pivot_index] = a[to - 1];
+    a[to - 1] = pivot;
+    var low_end = from;   // Upper bound of the elements lower than pivot.
+    var high_start = to - 1; // Lower bound of the elements greater than pivot.
+    for (var i = from; i < high_start; ) {
+      var element = a[i];
+      var order = Compare(element, pivot);
+      if (order < 0) {
+        a[i] = a[low_end];
+        a[low_end] = element;
+        low_end++;
+        i++;
+      } else if (order > 0) {
+        high_start--;
+        a[i] = a[high_start];
+        a[high_start] = element;
+      } else { // order == 0
+        i++;
+      }
+    }
+    // Restore the pivot element to its rightful place.
+    a[to - 1] = a[high_start];
+    a[high_start] = pivot;
+    high_start++;
+    QuickSort(a, from, low_end);
+    QuickSort(a, high_start, to);
+  }
+
+  var old_length = ToUint32(this.length);
+
+  %RemoveArrayHoles(this);
+
+  var length = ToUint32(this.length);
+
+  // Move undefined elements to the end of the array.
+  for (var i = 0; i < length; ) {
+    if (IS_UNDEFINED(this[i])) {
+      length--;
+      this[i] = this[length];
+      this[length] = void 0;
+    } else {
+      i++;
+    }
+  }
+
+  QuickSort(this, 0, length);
+
+  // We only changed the length of the this object (in
+  // RemoveArrayHoles) if it was an array.  We are not allowed to set
+  // the length of the this object if it is not an array because this
+  // might introduce a new length property.
+  if (IS_ARRAY(this)) {
+    this.length = old_length;
+  }
+
+  return this;
+}
+
+
+// The following functions cannot be made efficient on sparse arrays while
+// preserving the semantics, since the calls to the receiver function can add
+// or delete elements from the array.
+function ArrayFilter(f, receiver) {
+  if (!IS_FUNCTION(f)) {
+    throw MakeTypeError('called_non_callable', [ f ]);
+  }
+  // Pull out the length so that modifications to the length in the
+  // loop will not affect the looping.
+  var length = this.length;
+  var result = [];
+  for (var i = 0; i < length; i++) {
+    var current = this[i];
+    if (!IS_UNDEFINED(current) || i in this) {
+      if (f.call(receiver, current, i, this)) result.push(current);
+    }
+  }
+  return result;
+}
+
+
+function ArrayForEach(f, receiver) {
+  if (!IS_FUNCTION(f)) {
+    throw MakeTypeError('called_non_callable', [ f ]);
+  }
+  // Pull out the length so that modifications to the length in the
+  // loop will not affect the looping.
+  var length = this.length;
+  for (var i = 0; i < length; i++) {
+    var current = this[i];
+    if (!IS_UNDEFINED(current) || i in this) {
+      f.call(receiver, current, i, this);
+    }
+  }
+}
+
+
+// Executes the function once for each element present in the
+// array until it finds one where callback returns true.
+function ArraySome(f, receiver) {
+  if (!IS_FUNCTION(f)) {
+    throw MakeTypeError('called_non_callable', [ f ]);
+  }
+  // Pull out the length so that modifications to the length in the
+  // loop will not affect the looping.
+  var length = this.length;
+  for (var i = 0; i < length; i++) {
+    var current = this[i];
+    if (!IS_UNDEFINED(current) || i in this) {
+      if (f.call(receiver, current, i, this)) return true;
+    }
+  }
+  return false;
+}
+
+
+function ArrayEvery(f, receiver) {
+  if (!IS_FUNCTION(f)) {
+    throw MakeTypeError('called_non_callable', [ f ]);
+  }
+  // Pull out the length so that modifications to the length in the
+  // loop will not affect the looping.
+  var length = this.length;
+  for (var i = 0; i < length; i++) {
+    var current = this[i];
+    if (!IS_UNDEFINED(current) || i in this) {
+      if (!f.call(receiver, current, i, this)) return false;
+    }
+  }
+
+  return true;
+}
+
+
+function ArrayMap(f, receiver) {
+  if (!IS_FUNCTION(f)) {
+    throw MakeTypeError('called_non_callable', [ f ]);
+  }
+  // Pull out the length so that modifications to the length in the
+  // loop will not affect the looping.
+  var length = this.length;
+  var result = new $Array(length);
+  for (var i = 0; i < length; i++) {
+    var current = this[i];
+    if (!IS_UNDEFINED(current) || i in this) {
+      result[i] = f.call(receiver, current, i, this);
+    }
+  }
+  return result;
+}
+
+
+function ArrayIndexOf(element, index) {
+  var length = this.length;
+  if (index == null) {
+    index = 0;
+  } else {
+    index = TO_INTEGER(index);
+    // If index is negative, index from the end of the array.
+    if (index < 0) index = length + index;
+    // If index is still negative, search the entire array.
+    if (index < 0) index = 0;
+  }
+  // Lookup through the array.
+  for (var i = index; i < length; i++) {
+    var current = this[i];
+    if (!IS_UNDEFINED(current) || i in this) {
+      if (current === element) return i;
+    }
+  }
+  return -1;
+}
+
+
+function ArrayLastIndexOf(element, index) {
+  var length = this.length;
+  if (index == null) {
+    index = length - 1;
+  } else {
+    index = TO_INTEGER(index);
+    // If index is negative, index from end of the array.
+    if (index < 0) index = length + index;
+    // If index is still negative, do not search the array.
+    if (index < 0) index = -1;
+    else if (index >= length) index = length - 1;
+  }
+  // Lookup through the array.
+  for (var i = index; i >= 0; i--) {
+    var current = this[i];
+    if (!IS_UNDEFINED(current) || i in this) {
+      if (current === element) return i;
+    }
+  }
+  return -1;
+}
+
+
+// -------------------------------------------------------------------
+
+
+function UpdateFunctionLengths(lengths) {
+  for (var key in lengths) {
+    %FunctionSetLength(this[key], lengths[key]);
+  }
+}
+
+
+// -------------------------------------------------------------------
+
+function SetupArray() {
+  // Setup non-enumerable constructor property on the Array.prototype
+  // object.
+  %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
+
+  // Setup non-enumerable functions of the Array.prototype object and
+  // set their names.
+  InstallFunctions($Array.prototype, DONT_ENUM, $Array(
+    "toString", ArrayToString,
+    "toLocaleString", ArrayToLocaleString,
+    "join", ArrayJoin,
+    "pop", ArrayPop,
+    "push", ArrayPush,
+    "concat", ArrayConcat,
+    "reverse", ArrayReverse,
+    "shift", ArrayShift,
+    "unshift", ArrayUnshift,
+    "slice", ArraySlice,
+    "splice", ArraySplice,
+    "sort", ArraySort,
+    "filter", ArrayFilter,
+    "forEach", ArrayForEach,
+    "some", ArraySome,
+    "every", ArrayEvery,
+    "map", ArrayMap,
+    "indexOf", ArrayIndexOf,
+    "lastIndexOf", ArrayLastIndexOf
+  ));
+
+  // Manipulate the length of some of the functions to meet
+  // expectations set by ECMA-262 or Mozilla.
+  UpdateFunctionLengths({
+    ArrayFilter: 1,
+    ArrayForEach: 1,
+    ArraySome: 1,
+    ArrayEvery: 1,
+    ArrayMap: 1,
+    ArrayIndexOf: 1,
+    ArrayLastIndexOf: 1,
+    ArrayPush: 1
+  });
+}
+
+
+SetupArray();
diff --git a/regexp2000/src/assembler-arm-inl.h b/regexp2000/src/assembler-arm-inl.h
new file mode 100644 (file)
index 0000000..fbe37d7
--- /dev/null
@@ -0,0 +1,243 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+#ifndef V8_ASSEMBLER_ARM_INL_H_
+#define V8_ASSEMBLER_ARM_INL_H_
+
+#include "assembler-arm.h"
+#include "cpu.h"
+
+
+namespace v8 { namespace internal {
+
+Condition NegateCondition(Condition cc) {
+  ASSERT(cc != al);
+  return static_cast<Condition>(cc ^ ne);
+}
+
+
+void RelocInfo::apply(int delta) {
+  if (RelocInfo::IsInternalReference(rmode_)) {
+    // absolute code pointer inside code object moves with the code object.
+    int32_t* p = reinterpret_cast<int32_t*>(pc_);
+    *p += delta;  // relocate entry
+  }
+  // We do not use pc relative addressing on ARM, so there is
+  // nothing else to do.
+}
+
+
+Address RelocInfo::target_address() {
+  ASSERT(IsCodeTarget(rmode_));
+  return Assembler::target_address_at(pc_);
+}
+
+
+void RelocInfo::set_target_address(Address target) {
+  ASSERT(IsCodeTarget(rmode_));
+  Assembler::set_target_address_at(pc_, target);
+}
+
+
+Object* RelocInfo::target_object() {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return reinterpret_cast<Object*>(Assembler::target_address_at(pc_));
+}
+
+
+Object** RelocInfo::target_object_address() {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return reinterpret_cast<Object**>(Assembler::target_address_address_at(pc_));
+}
+
+
+void RelocInfo::set_target_object(Object* target) {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
+}
+
+
+Address* RelocInfo::target_reference_address() {
+  ASSERT(rmode_ == EXTERNAL_REFERENCE);
+  return reinterpret_cast<Address*>(pc_);
+}
+
+
+Address RelocInfo::call_address() {
+  ASSERT(is_call_instruction());
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+void RelocInfo::set_call_address(Address target) {
+  ASSERT(is_call_instruction());
+  UNIMPLEMENTED();
+}
+
+
+Object* RelocInfo::call_object() {
+  ASSERT(is_call_instruction());
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+Object** RelocInfo::call_object_address() {
+  ASSERT(is_call_instruction());
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+void RelocInfo::set_call_object(Object* target) {
+  ASSERT(is_call_instruction());
+  UNIMPLEMENTED();
+}
+
+
+bool RelocInfo::is_call_instruction() {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)  {
+  rm_ = no_reg;
+  imm32_ = immediate;
+  rmode_ = rmode;
+}
+
+
+Operand::Operand(const char* s) {
+  rm_ = no_reg;
+  imm32_ = reinterpret_cast<int32_t>(s);
+  rmode_ = RelocInfo::EMBEDDED_STRING;
+}
+
+
+Operand::Operand(const ExternalReference& f)  {
+  rm_ = no_reg;
+  imm32_ = reinterpret_cast<int32_t>(f.address());
+  rmode_ = RelocInfo::EXTERNAL_REFERENCE;
+}
+
+
+Operand::Operand(Object** opp) {
+  rm_ = no_reg;
+  imm32_ = reinterpret_cast<int32_t>(opp);
+  rmode_ = RelocInfo::NONE;
+}
+
+
+Operand::Operand(Context** cpp) {
+  rm_ = no_reg;
+  imm32_ = reinterpret_cast<int32_t>(cpp);
+  rmode_ = RelocInfo::NONE;
+}
+
+
+Operand::Operand(Smi* value) {
+  rm_ = no_reg;
+  imm32_ =  reinterpret_cast<intptr_t>(value);
+  rmode_ = RelocInfo::NONE;
+}
+
+
+Operand::Operand(Register rm) {
+  rm_ = rm;
+  rs_ = no_reg;
+  shift_op_ = LSL;
+  shift_imm_ = 0;
+}
+
+
+bool Operand::is_reg() const {
+  return rm_.is_valid() &&
+         rs_.is(no_reg) &&
+         shift_op_ == LSL &&
+         shift_imm_ == 0;
+}
+
+
+void Assembler::CheckBuffer() {
+  if (buffer_space() <= kGap) {
+    GrowBuffer();
+  }
+  if (pc_offset() > next_buffer_check_) {
+    CheckConstPool(false, true);
+  }
+}
+
+
+void Assembler::emit(Instr x) {
+  CheckBuffer();
+  *reinterpret_cast<Instr*>(pc_) = x;
+  pc_ += kInstrSize;
+}
+
+
+Address Assembler::target_address_address_at(Address pc) {
+  Instr instr = Memory::int32_at(pc);
+  // Verify that the instruction at pc is a ldr<cond> <Rd>, [pc +/- offset_12].
+  ASSERT((instr & 0x0f7f0000) == 0x051f0000);
+  int offset = instr & 0xfff;  // offset_12 is unsigned
+  if ((instr & (1 << 23)) == 0) offset = -offset;  // U bit defines offset sign
+  // Verify that the constant pool comes after the instruction referencing it.
+  ASSERT(offset >= -4);
+  return pc + offset + 8;
+}
+
+
+Address Assembler::target_address_at(Address pc) {
+  return Memory::Address_at(target_address_address_at(pc));
+}
+
+
+void Assembler::set_target_address_at(Address pc, Address target) {
+  Memory::Address_at(target_address_address_at(pc)) = target;
+  // Intuitively, we would think it is necessary to flush the instruction cache
+  // after patching a target address in the code as follows:
+  //   CPU::FlushICache(pc, sizeof(target));
+  // However, on ARM, no instruction was actually patched by the assignment
+  // above; the target address is not part of an instruction, it is patched in
+  // the constant pool and is read via a data access; the instruction accessing
+  // this address in the constant pool remains unchanged.
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_ASSEMBLER_ARM_INL_H_
diff --git a/regexp2000/src/assembler-arm.cc b/regexp2000/src/assembler-arm.cc
new file mode 100644 (file)
index 0000000..3307760
--- /dev/null
@@ -0,0 +1,1502 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+#include "v8.h"
+
+#include "assembler-arm-inl.h"
+#include "serialize.h"
+
+namespace v8 { namespace internal {
+
+// -----------------------------------------------------------------------------
+// Implementation of Register and CRegister
+
+Register no_reg = { -1 };
+
+Register r0  = {  0 };
+Register r1  = {  1 };
+Register r2  = {  2 };
+Register r3  = {  3 };
+Register r4  = {  4 };
+Register r5  = {  5 };
+Register r6  = {  6 };
+Register r7  = {  7 };
+Register r8  = {  8 };
+Register r9  = {  9 };
+Register r10 = { 10 };
+Register fp  = { 11 };
+Register ip  = { 12 };
+Register sp  = { 13 };
+Register lr  = { 14 };
+Register pc  = { 15 };
+
+
+CRegister no_creg = { -1 };
+
+CRegister cr0  = {  0 };
+CRegister cr1  = {  1 };
+CRegister cr2  = {  2 };
+CRegister cr3  = {  3 };
+CRegister cr4  = {  4 };
+CRegister cr5  = {  5 };
+CRegister cr6  = {  6 };
+CRegister cr7  = {  7 };
+CRegister cr8  = {  8 };
+CRegister cr9  = {  9 };
+CRegister cr10 = { 10 };
+CRegister cr11 = { 11 };
+CRegister cr12 = { 12 };
+CRegister cr13 = { 13 };
+CRegister cr14 = { 14 };
+CRegister cr15 = { 15 };
+
+
+// In order to determine the pc store offset, we execute a small code sequence.
+// See ARM Architecture Reference Manual section A-2.4.3
+// Note that 'str pc, [sp]' and 'stmia sp, {pc}' were using different offsets
+// under the QEMU emulator (now fixed), so we are careful to test the actual
+// instruction we are interested in (stmia).
+int PcStoreOffset() {
+#if !defined(__arm__)
+  // Building an ARM emulator based target. The emulator is wired for 8 byte
+  // pc offsets as is the default in the spec.
+  static int pc_store_offset = 8;
+#elif defined(__arm__) && !defined(__thumb__)
+  // __arm__ may be defined in thumb mode.
+  static int pc_store_offset = -1;
+  asm volatile(
+    "sub sp, sp, #4  \n\t"
+    "sub r1, pc, #4  \n\t"
+    "stmia sp, {pc}  \n\t"
+    "ldr r0, [sp]    \n\t"
+    "add sp, sp, #4  \n\t"
+    "sub %0, r0, r1  \n\t"
+    : "=r" (pc_store_offset) : : "r0", "r1", "memory");
+#elif defined(__thumb__)
+  static int pc_store_offset = -1;
+  asm volatile(
+  "@   Enter ARM Mode  \n\t"
+      "adr r2, 1f      \n\t"
+      "bx  r2          \n\t"
+      ".ALIGN 4        \n\t"
+      ".ARM            \n"
+  "1:  sub sp, sp, #4  \n\t"
+      "sub r1, pc, #4  \n\t"
+      "stmia sp, {pc}  \n\t"
+      "ldr r0, [sp]    \n\t"
+      "add sp, sp, #4  \n\t"
+      "sub %0, r0, r1  \n"
+  "@   Enter THUMB Mode\n\t"
+      "adr r2, 2f+1    \n\t"
+      "bx  r2          \n\t"
+      ".THUMB          \n"
+  "2:                  \n\t"
+      : "=r" (pc_store_offset) : : "r0", "r1", "r2", "memory");
+#else
+#error unsupported architecture
+#endif
+  ASSERT(pc_store_offset == 8 || pc_store_offset == 12);
+  return pc_store_offset;
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of RelocInfo
+
+const int RelocInfo::kApplyMask = 0;
+
+
+void RelocInfo::patch_code(byte* instructions, int instruction_count) {
+  // Patch the code at the current address with the supplied instructions.
+  UNIMPLEMENTED();
+}
+
+
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void RelocInfo::patch_code_with_call(Address target, int guard_bytes) {
+  // Patch the code at the current address with a call to the target.
+  UNIMPLEMENTED();
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of Operand and MemOperand
+// See assembler-arm-inl.h for inlined constructors
+
+Operand::Operand(Handle<Object> handle) {
+  rm_ = no_reg;
+  // Verify all Objects referred by code are NOT in new space.
+  Object* obj = *handle;
+  ASSERT(!Heap::InNewSpace(obj));
+  if (obj->IsHeapObject()) {
+    imm32_ = reinterpret_cast<intptr_t>(handle.location());
+    rmode_ = RelocInfo::EMBEDDED_OBJECT;
+  } else {
+    // no relocation needed
+    imm32_ =  reinterpret_cast<intptr_t>(obj);
+    rmode_ = RelocInfo::NONE;
+  }
+}
+
+
+Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
+  ASSERT(is_uint5(shift_imm));
+  ASSERT(shift_op != ROR || shift_imm != 0);  // use RRX if you mean it
+  rm_ = rm;
+  rs_ = no_reg;
+  shift_op_ = shift_op;
+  shift_imm_ = shift_imm & 31;
+  if (shift_op == RRX) {
+    // encoded as ROR with shift_imm == 0
+    ASSERT(shift_imm == 0);
+    shift_op_ = ROR;
+    shift_imm_ = 0;
+  }
+}
+
+
+Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
+  ASSERT(shift_op != RRX);
+  rm_ = rm;
+  rs_ = no_reg;
+  shift_op_ = shift_op;
+  rs_ = rs;
+}
+
+
+MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
+  rn_ = rn;
+  rm_ = no_reg;
+  offset_ = offset;
+  am_ = am;
+}
+
+MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
+  rn_ = rn;
+  rm_ = rm;
+  shift_op_ = LSL;
+  shift_imm_ = 0;
+  am_ = am;
+}
+
+
+MemOperand::MemOperand(Register rn, Register rm,
+                       ShiftOp shift_op, int shift_imm, AddrMode am) {
+  ASSERT(is_uint5(shift_imm));
+  rn_ = rn;
+  rm_ = rm;
+  shift_op_ = shift_op;
+  shift_imm_ = shift_imm & 31;
+  am_ = am;
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of Assembler
+
+// Instruction encoding bits
+enum {
+  H   = 1 << 5,   // halfword (or byte)
+  S6  = 1 << 6,   // signed (or unsigned)
+  L   = 1 << 20,  // load (or store)
+  S   = 1 << 20,  // set condition code (or leave unchanged)
+  W   = 1 << 21,  // writeback base register (or leave unchanged)
+  A   = 1 << 21,  // accumulate in multiply instruction (or not)
+  B   = 1 << 22,  // unsigned byte (or word)
+  N   = 1 << 22,  // long (or short)
+  U   = 1 << 23,  // positive (or negative) offset/index
+  P   = 1 << 24,  // offset/pre-indexed addressing (or post-indexed addressing)
+  I   = 1 << 25,  // immediate shifter operand (or not)
+
+  B4  = 1 << 4,
+  B5  = 1 << 5,
+  B7  = 1 << 7,
+  B8  = 1 << 8,
+  B12 = 1 << 12,
+  B16 = 1 << 16,
+  B20 = 1 << 20,
+  B21 = 1 << 21,
+  B22 = 1 << 22,
+  B23 = 1 << 23,
+  B24 = 1 << 24,
+  B25 = 1 << 25,
+  B26 = 1 << 26,
+  B27 = 1 << 27,
+
+  // Instruction bit masks
+  RdMask     = 15 << 12,  // in str instruction
+  CondMask   = 15 << 28,
+  OpCodeMask = 15 << 21,  // in data-processing instructions
+  Imm24Mask  = (1 << 24) - 1,
+  Off12Mask  = (1 << 12) - 1,
+  // Reserved condition
+  nv = 15 << 28
+};
+
+
+// add(sp, sp, 4) instruction (aka Pop())
+static const Instr kPopInstruction =
+    al | 4 * B21 | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12;
+// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
+// register r is not encoded.
+static const Instr kPushRegPattern =
+    al | B26 | 4 | NegPreIndex | sp.code() * B16;
+// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
+// register r is not encoded.
+static const Instr kPopRegPattern =
+    al | B26 | L | 4 | PostIndex | sp.code() * B16;
+
+// spare_buffer_
+static const int kMinimalBufferSize = 4*KB;
+static byte* spare_buffer_ = NULL;
+
+Assembler::Assembler(void* buffer, int buffer_size) {
+  if (buffer == NULL) {
+    // do our own buffer management
+    if (buffer_size <= kMinimalBufferSize) {
+      buffer_size = kMinimalBufferSize;
+
+      if (spare_buffer_ != NULL) {
+        buffer = spare_buffer_;
+        spare_buffer_ = NULL;
+      }
+    }
+    if (buffer == NULL) {
+      buffer_ = NewArray<byte>(buffer_size);
+    } else {
+      buffer_ = static_cast<byte*>(buffer);
+    }
+    buffer_size_ = buffer_size;
+    own_buffer_ = true;
+
+  } else {
+    // use externally provided buffer instead
+    ASSERT(buffer_size > 0);
+    buffer_ = static_cast<byte*>(buffer);
+    buffer_size_ = buffer_size;
+    own_buffer_ = false;
+  }
+
+  // setup buffer pointers
+  ASSERT(buffer_ != NULL);
+  pc_ = buffer_;
+  reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
+  num_prinfo_ = 0;
+  next_buffer_check_ = 0;
+  no_const_pool_before_ = 0;
+  last_const_pool_end_ = 0;
+  last_bound_pos_ = 0;
+  last_position_ = RelocInfo::kNoPosition;
+  last_position_is_statement_ = false;
+}
+
+
+Assembler::~Assembler() {
+  if (own_buffer_) {
+    if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
+      spare_buffer_ = buffer_;
+    } else {
+      DeleteArray(buffer_);
+    }
+  }
+}
+
+
+void Assembler::GetCode(CodeDesc* desc) {
+  // emit constant pool if necessary
+  CheckConstPool(true, false);
+  ASSERT(num_prinfo_ == 0);
+
+  // setup desc
+  desc->buffer = buffer_;
+  desc->buffer_size = buffer_size_;
+  desc->instr_size = pc_offset();
+  desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
+}
+
+
+void Assembler::Align(int m) {
+  ASSERT(m >= 4 && IsPowerOf2(m));
+  while ((pc_offset() & (m - 1)) != 0) {
+    nop();
+  }
+}
+
+
+// Labels refer to positions in the (to be) generated code.
+// There are bound, linked, and unused labels.
+//
+// Bound labels refer to known positions in the already
+// generated code. pos() is the position the label refers to.
+//
+// Linked labels refer to unknown positions in the code
+// to be generated; pos() is the position of the last
+// instruction using the label.
+
+
+// The link chain is terminated by a negative code position (must be aligned)
+const int kEndOfChain = -4;
+
+
+int Assembler::target_at(int pos)  {
+  Instr instr = instr_at(pos);
+  ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx imm24
+  int imm26 = ((instr & Imm24Mask) << 8) >> 6;
+  if ((instr & CondMask) == nv && (instr & B24) != 0)
+    // blx uses bit 24 to encode bit 2 of imm26
+    imm26 += 2;
+
+  return pos + 8 + imm26;
+}
+
+
+void Assembler::target_at_put(int pos, int target_pos) {
+  int imm26 = target_pos - pos - 8;
+  Instr instr = instr_at(pos);
+  ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx imm24
+  if ((instr & CondMask) == nv) {
+    // blx uses bit 24 to encode bit 2 of imm26
+    ASSERT((imm26 & 1) == 0);
+    instr = (instr & ~(B24 | Imm24Mask)) | ((imm26 & 2) >> 1)*B24;
+  } else {
+    ASSERT((imm26 & 3) == 0);
+    instr &= ~Imm24Mask;
+  }
+  int imm24 = imm26 >> 2;
+  ASSERT(is_int24(imm24));
+  instr_at_put(pos, instr | (imm24 & Imm24Mask));
+}
+
+
+void Assembler::print(Label* L) {
+  if (L->is_unused()) {
+    PrintF("unused label\n");
+  } else if (L->is_bound()) {
+    PrintF("bound label to %d\n", L->pos());
+  } else if (L->is_linked()) {
+    Label l = *L;
+    PrintF("unbound label");
+    while (l.is_linked()) {
+      PrintF("@ %d ", l.pos());
+      Instr instr = instr_at(l.pos());
+      ASSERT((instr & 7*B25) == 5*B25);  // b, bl, or blx
+      int cond = instr & CondMask;
+      const char* b;
+      const char* c;
+      if (cond == nv) {
+        b = "blx";
+        c = "";
+      } else {
+        if ((instr & B24) != 0)
+          b = "bl";
+        else
+          b = "b";
+
+        switch (cond) {
+          case eq: c = "eq"; break;
+          case ne: c = "ne"; break;
+          case hs: c = "hs"; break;
+          case lo: c = "lo"; break;
+          case mi: c = "mi"; break;
+          case pl: c = "pl"; break;
+          case vs: c = "vs"; break;
+          case vc: c = "vc"; break;
+          case hi: c = "hi"; break;
+          case ls: c = "ls"; break;
+          case ge: c = "ge"; break;
+          case lt: c = "lt"; break;
+          case gt: c = "gt"; break;
+          case le: c = "le"; break;
+          case al: c = ""; break;
+          default:
+            c = "";
+            UNREACHABLE();
+        }
+      }
+      PrintF("%s%s\n", b, c);
+      next(&l);
+    }
+  } else {
+    PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
+  }
+}
+
+
+void Assembler::bind_to(Label* L, int pos) {
+  ASSERT(0 <= pos && pos <= pc_offset());  // must have a valid binding position
+  while (L->is_linked()) {
+    int fixup_pos = L->pos();
+    next(L);  // call next before overwriting link with target at fixup_pos
+    target_at_put(fixup_pos, pos);
+  }
+  L->bind_to(pos);
+
+  // Keep track of the last bound label so we don't eliminate any instructions
+  // before a bound label.
+  if (pos > last_bound_pos_)
+    last_bound_pos_ = pos;
+}
+
+
+void Assembler::link_to(Label* L, Label* appendix) {
+  if (appendix->is_linked()) {
+    if (L->is_linked()) {
+      // append appendix to L's list
+      int fixup_pos;
+      int link = L->pos();
+      do {
+        fixup_pos = link;
+        link = target_at(fixup_pos);
+      } while (link > 0);
+      ASSERT(link == kEndOfChain);
+      target_at_put(fixup_pos, appendix->pos());
+    } else {
+      // L is empty, simply use appendix
+      *L = *appendix;
+    }
+  }
+  appendix->Unuse();  // appendix should not be used anymore
+}
+
+
+void Assembler::bind(Label* L) {
+  ASSERT(!L->is_bound());  // label can only be bound once
+  bind_to(L, pc_offset());
+}
+
+
+void Assembler::next(Label* L) {
+  ASSERT(L->is_linked());
+  int link = target_at(L->pos());
+  if (link > 0) {
+    L->link_to(link);
+  } else {
+    ASSERT(link == kEndOfChain);
+    L->Unuse();
+  }
+}
+
+
+// Low-level code emission routines depending on the addressing mode
+static bool fits_shifter(uint32_t imm32,
+                         uint32_t* rotate_imm,
+                         uint32_t* immed_8,
+                         Instr* instr) {
+  // imm32 must be unsigned
+  for (int rot = 0; rot < 16; rot++) {
+    uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot));
+    if ((imm8 <= 0xff)) {
+      *rotate_imm = rot;
+      *immed_8 = imm8;
+      return true;
+    }
+  }
+  // if the opcode is mov or mvn and if ~imm32 fits, change the opcode
+  if (instr != NULL && (*instr & 0xd*B21) == 0xd*B21) {
+    if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
+      *instr ^= 0x2*B21;
+      return true;
+    }
+  }
+  return false;
+}
+
+
+void Assembler::addrmod1(Instr instr,
+                         Register rn,
+                         Register rd,
+                         const Operand& x) {
+  CheckBuffer();
+  ASSERT((instr & ~(CondMask | OpCodeMask | S)) == 0);
+  if (!x.rm_.is_valid()) {
+    // immediate
+    uint32_t rotate_imm;
+    uint32_t immed_8;
+    if ((x.rmode_ != RelocInfo::NONE &&
+         x.rmode_ != RelocInfo::EXTERNAL_REFERENCE) ||
+        !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
+      // The immediate operand cannot be encoded as a shifter operand, so load
+      // it first to register ip and change the original instruction to use ip.
+      // However, if the original instruction is a 'mov rd, x' (not setting the
+      // condition code), then replace it with a 'ldr rd, [pc]'
+      RecordRelocInfo(x.rmode_, x.imm32_);
+      ASSERT(!rn.is(ip));  // rn should never be ip, or will be trashed
+      Condition cond = static_cast<Condition>(instr & CondMask);
+      if ((instr & ~CondMask) == 13*B21) {  // mov, S not set
+        ldr(rd, MemOperand(pc, 0), cond);
+      } else {
+        ldr(ip, MemOperand(pc, 0), cond);
+        addrmod1(instr, rn, rd, Operand(ip));
+      }
+      return;
+    }
+    instr |= I | rotate_imm*B8 | immed_8;
+  } else if (!x.rs_.is_valid()) {
+    // immediate shift
+    instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
+  } else {
+    // register shift
+    ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
+    instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
+  }
+  emit(instr | rn.code()*B16 | rd.code()*B12);
+  if (rn.is(pc) || x.rm_.is(pc))
+    // block constant pool emission for one instruction after reading pc
+    BlockConstPoolBefore(pc_offset() + kInstrSize);
+}
+
+
+void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
+  ASSERT((instr & ~(CondMask | B | L)) == B26);
+  int am = x.am_;
+  if (!x.rm_.is_valid()) {
+    // immediate offset
+    int offset_12 = x.offset_;
+    if (offset_12 < 0) {
+      offset_12 = -offset_12;
+      am ^= U;
+    }
+    if (!is_uint12(offset_12)) {
+      // immediate offset cannot be encoded, load it first to register ip
+      // rn (and rd in a load) should never be ip, or will be trashed
+      ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
+      mov(ip, Operand(x.offset_), LeaveCC,
+          static_cast<Condition>(instr & CondMask));
+      addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
+      return;
+    }
+    ASSERT(offset_12 >= 0);  // no masking needed
+    instr |= offset_12;
+  } else {
+    // register offset (shift_imm_ and shift_op_ are 0) or scaled
+    // register offset the constructors make sure than both shift_imm_
+    // and shift_op_ are initialized
+    ASSERT(!x.rm_.is(pc));
+    instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
+  }
+  ASSERT((am & (P|W)) == P || !x.rn_.is(pc));  // no pc base with writeback
+  emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
+}
+
+
+void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
+  ASSERT((instr & ~(CondMask | L | S6 | H)) == (B4 | B7));
+  ASSERT(x.rn_.is_valid());
+  int am = x.am_;
+  if (!x.rm_.is_valid()) {
+    // immediate offset
+    int offset_8 = x.offset_;
+    if (offset_8 < 0) {
+      offset_8 = -offset_8;
+      am ^= U;
+    }
+    if (!is_uint8(offset_8)) {
+      // immediate offset cannot be encoded, load it first to register ip
+      // rn (and rd in a load) should never be ip, or will be trashed
+      ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
+      mov(ip, Operand(x.offset_), LeaveCC,
+          static_cast<Condition>(instr & CondMask));
+      addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
+      return;
+    }
+    ASSERT(offset_8 >= 0);  // no masking needed
+    instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
+  } else if (x.shift_imm_ != 0) {
+    // scaled register offset not supported, load index first
+    // rn (and rd in a load) should never be ip, or will be trashed
+    ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
+    mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
+        static_cast<Condition>(instr & CondMask));
+    addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
+    return;
+  } else {
+    // register offset
+    ASSERT((am & (P|W)) == P || !x.rm_.is(pc));  // no pc index with writeback
+    instr |= x.rm_.code();
+  }
+  ASSERT((am & (P|W)) == P || !x.rn_.is(pc));  // no pc base with writeback
+  emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
+}
+
+
+void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
+  ASSERT((instr & ~(CondMask | P | U | W | L)) == B27);
+  ASSERT(rl != 0);
+  ASSERT(!rn.is(pc));
+  emit(instr | rn.code()*B16 | rl);
+}
+
+
+void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
+  // unindexed addressing is not encoded by this function
+  ASSERT((instr & ~(CondMask | P | U | N | W | L)) == (B27 | B26));
+  ASSERT(x.rn_.is_valid() && !x.rm_.is_valid());
+  int am = x.am_;
+  int offset_8 = x.offset_;
+  ASSERT((offset_8 & 3) == 0);  // offset must be an aligned word offset
+  offset_8 >>= 2;
+  if (offset_8 < 0) {
+    offset_8 = -offset_8;
+    am ^= U;
+  }
+  ASSERT(is_uint8(offset_8));  // unsigned word offset must fit in a byte
+  ASSERT((am & (P|W)) == P || !x.rn_.is(pc));  // no pc base with writeback
+
+  // post-indexed addressing requires W == 1; different than in addrmod2/3
+  if ((am & P) == 0)
+    am |= W;
+
+  ASSERT(offset_8 >= 0);  // no masking needed
+  emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
+}
+
+
+int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
+  int target_pos;
+  if (L->is_bound()) {
+    target_pos = L->pos();
+  } else {
+    if (L->is_linked()) {
+      target_pos = L->pos();  // L's link
+    } else {
+      target_pos = kEndOfChain;
+    }
+    L->link_to(pc_offset());
+  }
+
+  // Block the emission of the constant pool, since the branch instruction must
+  // be emitted at the pc offset recorded by the label
+  BlockConstPoolBefore(pc_offset() + kInstrSize);
+
+  return target_pos - pc_offset() - 8;
+}
+
+
+// Branch instructions
+void Assembler::b(int branch_offset, Condition cond) {
+  ASSERT((branch_offset & 3) == 0);
+  int imm24 = branch_offset >> 2;
+  ASSERT(is_int24(imm24));
+  emit(cond | B27 | B25 | (imm24 & Imm24Mask));
+
+  if (cond == al)
+    // dead code is a good location to emit the constant pool
+    CheckConstPool(false, false);
+}
+
+
+void Assembler::bl(int branch_offset, Condition cond) {
+  ASSERT((branch_offset & 3) == 0);
+  int imm24 = branch_offset >> 2;
+  ASSERT(is_int24(imm24));
+  emit(cond | B27 | B25 | B24 | (imm24 & Imm24Mask));
+}
+
+
+void Assembler::blx(int branch_offset) {  // v5 and above
+  ASSERT((branch_offset & 1) == 0);
+  int h = ((branch_offset & 2) >> 1)*B24;
+  int imm24 = branch_offset >> 2;
+  ASSERT(is_int24(imm24));
+  emit(15 << 28 | B27 | B25 | h | (imm24 & Imm24Mask));
+}
+
+
+void Assembler::blx(Register target, Condition cond) {  // v5 and above
+  ASSERT(!target.is(pc));
+  emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
+}
+
+
+void Assembler::bx(Register target, Condition cond) {  // v5 and above, plus v4t
+  ASSERT(!target.is(pc));  // use of pc is actually allowed, but discouraged
+  emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
+}
+
+
+// Data-processing instructions
+void Assembler::and_(Register dst, Register src1, const Operand& src2,
+                     SBit s, Condition cond) {
+  addrmod1(cond | 0*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::eor(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 1*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::sub(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 2*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::rsb(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 3*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::add(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 4*B21 | s, src1, dst, src2);
+
+  // Eliminate pattern: push(r), pop()
+  //   str(src, MemOperand(sp, 4, NegPreIndex), al);
+  //   add(sp, sp, Operand(kPointerSize));
+  // Both instructions can be eliminated.
+  int pattern_size = 2 * kInstrSize;
+  if (FLAG_push_pop_elimination &&
+      last_bound_pos_ <= (pc_offset() - pattern_size) &&
+      reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
+      // pattern
+      instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
+      (instr_at(pc_ - 2 * kInstrSize) & ~RdMask) == kPushRegPattern) {
+    pc_ -= 2 * kInstrSize;
+    if (FLAG_print_push_pop_elimination) {
+      PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
+    }
+  }
+}
+
+
+void Assembler::adc(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 5*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::sbc(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 6*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::rsc(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 7*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
+  addrmod1(cond | 8*B21 | S, src1, r0, src2);
+}
+
+
+void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
+  addrmod1(cond | 9*B21 | S, src1, r0, src2);
+}
+
+
+void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
+  addrmod1(cond | 10*B21 | S, src1, r0, src2);
+}
+
+
+void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
+  addrmod1(cond | 11*B21 | S, src1, r0, src2);
+}
+
+
+void Assembler::orr(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 12*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
+  addrmod1(cond | 13*B21 | s, r0, dst, src);
+}
+
+
+void Assembler::bic(Register dst, Register src1, const Operand& src2,
+                    SBit s, Condition cond) {
+  addrmod1(cond | 14*B21 | s, src1, dst, src2);
+}
+
+
+void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
+  addrmod1(cond | 15*B21 | s, r0, dst, src);
+}
+
+
+// Multiply instructions
+void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
+                    SBit s, Condition cond) {
+  ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
+  ASSERT(!dst.is(src1));
+  emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
+       src2.code()*B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::mul(Register dst, Register src1, Register src2,
+                    SBit s, Condition cond) {
+  ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
+  ASSERT(!dst.is(src1));
+  emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::smlal(Register dstL,
+                      Register dstH,
+                      Register src1,
+                      Register src2,
+                      SBit s,
+                      Condition cond) {
+  ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
+  ASSERT(!dstL.is(dstH) && !dstH.is(src1) && !src1.is(dstL));
+  emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
+       src2.code()*B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::smull(Register dstL,
+                      Register dstH,
+                      Register src1,
+                      Register src2,
+                      SBit s,
+                      Condition cond) {
+  ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
+  ASSERT(!dstL.is(dstH) && !dstH.is(src1) && !src1.is(dstL));
+  emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
+       src2.code()*B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::umlal(Register dstL,
+                      Register dstH,
+                      Register src1,
+                      Register src2,
+                      SBit s,
+                      Condition cond) {
+  ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
+  ASSERT(!dstL.is(dstH) && !dstH.is(src1) && !src1.is(dstL));
+  emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
+       src2.code()*B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::umull(Register dstL,
+                      Register dstH,
+                      Register src1,
+                      Register src2,
+                      SBit s,
+                      Condition cond) {
+  ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
+  ASSERT(!dstL.is(dstH) && !dstH.is(src1) && !src1.is(dstL));
+  emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
+       src2.code()*B8 | B7 | B4 | src1.code());
+}
+
+
+// Miscellaneous arithmetic instructions
+void Assembler::clz(Register dst, Register src, Condition cond) {
+  // v5 and above.
+  ASSERT(!dst.is(pc) && !src.is(pc));
+  emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
+       15*B8 | B4 | src.code());
+}
+
+
+// Status register access instructions
+void Assembler::mrs(Register dst, SRegister s, Condition cond) {
+  ASSERT(!dst.is(pc));
+  emit(cond | B24 | s | 15*B16 | dst.code()*B12);
+}
+
+
+void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
+                    Condition cond) {
+  ASSERT(fields >= B16 && fields < B20);  // at least one field set
+  Instr instr;
+  if (!src.rm_.is_valid()) {
+    // immediate
+    uint32_t rotate_imm;
+    uint32_t immed_8;
+    if ((src.rmode_ != RelocInfo::NONE &&
+         src.rmode_ != RelocInfo::EXTERNAL_REFERENCE)||
+        !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
+      // immediate operand cannot be encoded, load it first to register ip
+      RecordRelocInfo(src.rmode_, src.imm32_);
+      ldr(ip, MemOperand(pc, 0), cond);
+      msr(fields, Operand(ip), cond);
+      return;
+    }
+    instr = I | rotate_imm*B8 | immed_8;
+  } else {
+    ASSERT(!src.rs_.is_valid() && src.shift_imm_ == 0);  // only rm allowed
+    instr = src.rm_.code();
+  }
+  emit(cond | instr | B24 | B21 | fields | 15*B12);
+}
+
+
+// Load/Store instructions
+void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
+  addrmod2(cond | B26 | L, dst, src);
+
+  // Eliminate pattern: push(r), pop(r)
+  //   str(r, MemOperand(sp, 4, NegPreIndex), al)
+  //   ldr(r, MemOperand(sp, 4, PostIndex), al)
+  // Both instructions can be eliminated.
+  int pattern_size = 2 * kInstrSize;
+  if (FLAG_push_pop_elimination &&
+      last_bound_pos_ <= (pc_offset() - pattern_size) &&
+      reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
+      // pattern
+      instr_at(pc_ - 1 * kInstrSize) == (kPopRegPattern | dst.code() * B12) &&
+      instr_at(pc_ - 2 * kInstrSize) == (kPushRegPattern | dst.code() * B12)) {
+    pc_ -= 2 * kInstrSize;
+    if (FLAG_print_push_pop_elimination) {
+      PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
+    }
+  }
+}
+
+
+void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
+  addrmod2(cond | B26, src, dst);
+
+  // Eliminate pattern: pop(), push(r)
+  //     add sp, sp, #4 LeaveCC, al; str r, [sp, #-4], al
+  // ->  str r, [sp, 0], al
+  int pattern_size = 2 * kInstrSize;
+  if (FLAG_push_pop_elimination &&
+     last_bound_pos_ <= (pc_offset() - pattern_size) &&
+     reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
+     instr_at(pc_ - 1 * kInstrSize) == (kPushRegPattern | src.code() * B12) &&
+     instr_at(pc_ - 2 * kInstrSize) == kPopInstruction) {
+    pc_ -= 2 * kInstrSize;
+    emit(al | B26 | 0 | Offset | sp.code() * B16 | src.code() * B12);
+    if (FLAG_print_push_pop_elimination) {
+      PrintF("%x pop()/push(reg) eliminated\n", pc_offset());
+    }
+  }
+}
+
+
+void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
+  addrmod2(cond | B26 | B | L, dst, src);
+}
+
+
+void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
+  addrmod2(cond | B26 | B, src, dst);
+}
+
+
+void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
+  addrmod3(cond | L | B7 | H | B4, dst, src);
+}
+
+
+void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
+  addrmod3(cond | B7 | H | B4, src, dst);
+}
+
+
+void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
+  addrmod3(cond | L | B7 | S6 | B4, dst, src);
+}
+
+
+void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
+  addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
+}
+
+
+// Load/Store multiple instructions
+void Assembler::ldm(BlockAddrMode am,
+                    Register base,
+                    RegList dst,
+                    Condition cond) {
+  // ABI stack constraint: ldmxx base, {..sp..}  base != sp  is not restartable
+  ASSERT(base.is(sp) || (dst & sp.bit()) == 0);
+
+  addrmod4(cond | B27 | am | L, base, dst);
+
+  // emit the constant pool after a function return implemented by ldm ..{..pc}
+  if (cond == al && (dst & pc.bit()) != 0) {
+    // There is a slight chance that the ldm instruction was actually a call,
+    // in which case it would be wrong to return into the constant pool; we
+    // recognize this case by checking if the emission of the pool was blocked
+    // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
+    // the case, we emit a jump over the pool.
+    CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
+  }
+}
+
+
+void Assembler::stm(BlockAddrMode am,
+                    Register base,
+                    RegList src,
+                    Condition cond) {
+  addrmod4(cond | B27 | am, base, src);
+}
+
+
+// Semaphore instructions
+void Assembler::swp(Register dst, Register src, Register base, Condition cond) {
+  ASSERT(!dst.is(pc) && !src.is(pc) && !base.is(pc));
+  ASSERT(!dst.is(base) && !src.is(base));
+  emit(cond | P | base.code()*B16 | dst.code()*B12 |
+       B7 | B4 | src.code());
+}
+
+
+void Assembler::swpb(Register dst,
+                     Register src,
+                     Register base,
+                     Condition cond) {
+  ASSERT(!dst.is(pc) && !src.is(pc) && !base.is(pc));
+  ASSERT(!dst.is(base) && !src.is(base));
+  emit(cond | P | B | base.code()*B16 | dst.code()*B12 |
+       B7 | B4 | src.code());
+}
+
+
+// Exception-generating instructions and debugging support
+void Assembler::stop(const char* msg) {
+#if !defined(__arm__)
+  // The simulator handles these special instructions and stops execution.
+  emit(15 << 28 | ((intptr_t) msg));
+#else
+  // Just issue a simple break instruction for now. Alternatively we could use
+  // the swi(0x9f0001) instruction on Linux.
+  bkpt(0);
+#endif
+}
+
+
+void Assembler::bkpt(uint32_t imm16) {  // v5 and above
+  ASSERT(is_uint16(imm16));
+  emit(al | B24 | B21 | (imm16 >> 4)*B8 | 7*B4 | (imm16 & 0xf));
+}
+
+
+void Assembler::swi(uint32_t imm24, Condition cond) {
+  ASSERT(is_uint24(imm24));
+  emit(cond | 15*B24 | imm24);
+}
+
+
+// Coprocessor instructions
+void Assembler::cdp(Coprocessor coproc,
+                    int opcode_1,
+                    CRegister crd,
+                    CRegister crn,
+                    CRegister crm,
+                    int opcode_2,
+                    Condition cond) {
+  ASSERT(is_uint4(opcode_1) && is_uint3(opcode_2));
+  emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
+       crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
+}
+
+
+void Assembler::cdp2(Coprocessor coproc,
+                     int opcode_1,
+                     CRegister crd,
+                     CRegister crn,
+                     CRegister crm,
+                     int opcode_2) {  // v5 and above
+  cdp(coproc, opcode_1, crd, crn, crm, opcode_2, static_cast<Condition>(nv));
+}
+
+
+void Assembler::mcr(Coprocessor coproc,
+                    int opcode_1,
+                    Register rd,
+                    CRegister crn,
+                    CRegister crm,
+                    int opcode_2,
+                    Condition cond) {
+  ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
+  emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
+       rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
+}
+
+
+void Assembler::mcr2(Coprocessor coproc,
+                     int opcode_1,
+                     Register rd,
+                     CRegister crn,
+                     CRegister crm,
+                     int opcode_2) {  // v5 and above
+  mcr(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast<Condition>(nv));
+}
+
+
+void Assembler::mrc(Coprocessor coproc,
+                    int opcode_1,
+                    Register rd,
+                    CRegister crn,
+                    CRegister crm,
+                    int opcode_2,
+                    Condition cond) {
+  ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
+  emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
+       rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
+}
+
+
+void Assembler::mrc2(Coprocessor coproc,
+                     int opcode_1,
+                     Register rd,
+                     CRegister crn,
+                     CRegister crm,
+                     int opcode_2) {  // v5 and above
+  mrc(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast<Condition>(nv));
+}
+
+
+void Assembler::ldc(Coprocessor coproc,
+                    CRegister crd,
+                    const MemOperand& src,
+                    LFlag l,
+                    Condition cond) {
+  addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
+}
+
+
+void Assembler::ldc(Coprocessor coproc,
+                    CRegister crd,
+                    Register rn,
+                    int option,
+                    LFlag l,
+                    Condition cond) {
+  // unindexed addressing
+  ASSERT(is_uint8(option));
+  emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
+       coproc*B8 | (option & 255));
+}
+
+
+void Assembler::ldc2(Coprocessor coproc,
+                     CRegister crd,
+                     const MemOperand& src,
+                     LFlag l) {  // v5 and above
+  ldc(coproc, crd, src, l, static_cast<Condition>(nv));
+}
+
+
+void Assembler::ldc2(Coprocessor coproc,
+                     CRegister crd,
+                     Register rn,
+                     int option,
+                     LFlag l) {  // v5 and above
+  ldc(coproc, crd, rn, option, l, static_cast<Condition>(nv));
+}
+
+
+void Assembler::stc(Coprocessor coproc,
+                    CRegister crd,
+                    const MemOperand& dst,
+                    LFlag l,
+                    Condition cond) {
+  addrmod5(cond | B27 | B26 | l | coproc*B8, crd, dst);
+}
+
+
+void Assembler::stc(Coprocessor coproc,
+                    CRegister crd,
+                    Register rn,
+                    int option,
+                    LFlag l,
+                    Condition cond) {
+  // unindexed addressing
+  ASSERT(is_uint8(option));
+  emit(cond | B27 | B26 | U | l | rn.code()*B16 | crd.code()*B12 |
+       coproc*B8 | (option & 255));
+}
+
+
+void Assembler::stc2(Coprocessor
+                     coproc, CRegister crd,
+                     const MemOperand& dst,
+                     LFlag l) {  // v5 and above
+  stc(coproc, crd, dst, l, static_cast<Condition>(nv));
+}
+
+
+void Assembler::stc2(Coprocessor coproc,
+                     CRegister crd,
+                     Register rn,
+                     int option,
+                     LFlag l) {  // v5 and above
+  stc(coproc, crd, rn, option, l, static_cast<Condition>(nv));
+}
+
+
+// Pseudo instructions
+void Assembler::lea(Register dst,
+                    const MemOperand& x,
+                    SBit s,
+                    Condition cond) {
+  int am = x.am_;
+  if (!x.rm_.is_valid()) {
+    // immediate offset
+    if ((am & P) == 0)  // post indexing
+      mov(dst, Operand(x.rn_), s, cond);
+    else if ((am & U) == 0)  // negative indexing
+      sub(dst, x.rn_, Operand(x.offset_), s, cond);
+    else
+      add(dst, x.rn_, Operand(x.offset_), s, cond);
+  } else {
+    // Register offset (shift_imm_ and shift_op_ are 0) or scaled
+    // register offset the constructors make sure than both shift_imm_
+    // and shift_op_ are initialized.
+    ASSERT(!x.rm_.is(pc));
+    if ((am & P) == 0)  // post indexing
+      mov(dst, Operand(x.rn_), s, cond);
+    else if ((am & U) == 0)  // negative indexing
+      sub(dst, x.rn_, Operand(x.rm_, x.shift_op_, x.shift_imm_), s, cond);
+    else
+      add(dst, x.rn_, Operand(x.rm_, x.shift_op_, x.shift_imm_), s, cond);
+  }
+}
+
+
+// Debugging
+void Assembler::RecordComment(const char* msg) {
+  if (FLAG_debug_code) {
+    CheckBuffer();
+    RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
+  }
+}
+
+
+void Assembler::RecordPosition(int pos) {
+  if (pos == RelocInfo::kNoPosition) return;
+  ASSERT(pos >= 0);
+  if (pos == last_position_) return;
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::POSITION, pos);
+  last_position_ = pos;
+  last_position_is_statement_ = false;
+}
+
+
+void Assembler::RecordStatementPosition(int pos) {
+  if (pos == last_position_) return;
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::STATEMENT_POSITION, pos);
+  last_position_ = pos;
+  last_position_is_statement_ = true;
+}
+
+
+void Assembler::GrowBuffer() {
+  if (!own_buffer_) FATAL("external code buffer is too small");
+
+  // compute new buffer size
+  CodeDesc desc;  // the new buffer
+  if (buffer_size_ < 4*KB) {
+    desc.buffer_size = 4*KB;
+  } else if (buffer_size_ < 1*MB) {
+    desc.buffer_size = 2*buffer_size_;
+  } else {
+    desc.buffer_size = buffer_size_ + 1*MB;
+  }
+  CHECK_GT(desc.buffer_size, 0);  // no overflow
+
+  // setup new buffer
+  desc.buffer = NewArray<byte>(desc.buffer_size);
+
+  desc.instr_size = pc_offset();
+  desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
+
+  // copy the data
+  int pc_delta = desc.buffer - buffer_;
+  int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
+  memmove(desc.buffer, buffer_, desc.instr_size);
+  memmove(reloc_info_writer.pos() + rc_delta,
+          reloc_info_writer.pos(), desc.reloc_size);
+
+  // switch buffers
+  DeleteArray(buffer_);
+  buffer_ = desc.buffer;
+  buffer_size_ = desc.buffer_size;
+  pc_ += pc_delta;
+  reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
+                               reloc_info_writer.last_pc() + pc_delta);
+
+  // none of our relocation types are pc relative pointing outside the code
+  // buffer nor pc absolute pointing inside the code buffer, so there is no need
+  // to relocate any emitted relocation entries
+
+  // relocate pending relocation entries
+  for (int i = 0; i < num_prinfo_; i++) {
+    RelocInfo& rinfo = prinfo_[i];
+    ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
+           rinfo.rmode() != RelocInfo::POSITION);
+    rinfo.set_pc(rinfo.pc() + pc_delta);
+  }
+}
+
+
+void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
+  RelocInfo rinfo(pc_, rmode, data);  // we do not try to reuse pool constants
+  if (rmode >= RelocInfo::COMMENT && rmode <= RelocInfo::STATEMENT_POSITION) {
+    // adjust code for new modes
+    ASSERT(RelocInfo::IsComment(rmode) || RelocInfo::IsPosition(rmode));
+    // these modes do not need an entry in the constant pool
+  } else {
+    ASSERT(num_prinfo_ < kMaxNumPRInfo);
+    prinfo_[num_prinfo_++] = rinfo;
+    // Make sure the constant pool is not emitted in place of the next
+    // instruction for which we just recorded relocation info
+    BlockConstPoolBefore(pc_offset() + kInstrSize);
+  }
+  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;
+    }
+    ASSERT(buffer_space() >= kMaxRelocSize);  // too late to grow buffer here
+    reloc_info_writer.Write(&rinfo);
+  }
+}
+
+
+void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
+  // Calculate the offset of the next check. It will be overwritten
+  // when a const pool is generated or when const pools are being
+  // blocked for a specific range.
+  next_buffer_check_ = pc_offset() + kCheckConstInterval;
+
+  // There is nothing to do if there are no pending relocation info entries
+  if (num_prinfo_ == 0) return;
+
+  // We emit a constant pool at regular intervals of about kDistBetweenPools
+  // or when requested by parameter force_emit (e.g. after each function).
+  // We prefer not to emit a jump unless the max distance is reached or if we
+  // are running low on slots, which can happen if a lot of constants are being
+  // emitted (e.g. --debug-code and many static references).
+  int dist = pc_offset() - last_const_pool_end_;
+  if (!force_emit && dist < kMaxDistBetweenPools &&
+      (require_jump || dist < kDistBetweenPools) &&
+      // TODO(1236125): Cleanup the "magic" number below. We know that
+      // the code generation will test every kCheckConstIntervalInst.
+      // Thus we are safe as long as we generate less than 7 constant
+      // entries per instruction.
+      (num_prinfo_ < (kMaxNumPRInfo - (7 * kCheckConstIntervalInst)))) {
+    return;
+  }
+
+  // If we did not return by now, we need to emit the constant pool soon.
+
+  // However, some small sequences of instructions must not be broken up by the
+  // insertion of a constant pool; such sequences are protected by setting
+  // no_const_pool_before_, which is checked here. Also, recursive calls to
+  // CheckConstPool are blocked by no_const_pool_before_.
+  if (pc_offset() < no_const_pool_before_) {
+    // Emission is currently blocked; make sure we try again as soon as possible
+    next_buffer_check_ = no_const_pool_before_;
+
+    // Something is wrong if emission is forced and blocked at the same time
+    ASSERT(!force_emit);
+    return;
+  }
+
+  int jump_instr = require_jump ? kInstrSize : 0;
+
+  // Check that the code buffer is large enough before emitting the constant
+  // pool and relocation information (include the jump over the pool and the
+  // constant pool marker).
+  int max_needed_space =
+      jump_instr + kInstrSize + num_prinfo_*(kInstrSize + kMaxRelocSize);
+  while (buffer_space() <= (max_needed_space + kGap)) GrowBuffer();
+
+  // Block recursive calls to CheckConstPool
+  BlockConstPoolBefore(pc_offset() + jump_instr + kInstrSize +
+                       num_prinfo_*kInstrSize);
+  // Don't bother to check for the emit calls below.
+  next_buffer_check_ = no_const_pool_before_;
+
+  // Emit jump over constant pool if necessary
+  Label after_pool;
+  if (require_jump) b(&after_pool);
+
+  RecordComment("[ Constant Pool");
+
+  // Put down constant pool marker
+  // "Undefined instruction" as specified by A3.1 Instruction set encoding
+  emit(0x03000000 | num_prinfo_);
+
+  // Emit constant pool entries
+  for (int i = 0; i < num_prinfo_; i++) {
+    RelocInfo& rinfo = prinfo_[i];
+    ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
+           rinfo.rmode() != RelocInfo::POSITION &&
+           rinfo.rmode() != RelocInfo::STATEMENT_POSITION);
+    Instr instr = instr_at(rinfo.pc());
+    // Instruction to patch must be a ldr/str [pc, #offset]
+    // P and U set, B and W clear, Rn == pc, offset12 still 0
+    ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | Off12Mask)) ==
+           (2*B25 | P | U | pc.code()*B16));
+    int delta = pc_ - rinfo.pc() - 8;
+    ASSERT(delta >= -4);  // instr could be ldr pc, [pc, #-4] followed by targ32
+    if (delta < 0) {
+      instr &= ~U;
+      delta = -delta;
+    }
+    ASSERT(is_uint12(delta));
+    instr_at_put(rinfo.pc(), instr + delta);
+    emit(rinfo.data());
+  }
+  num_prinfo_ = 0;
+  last_const_pool_end_ = pc_offset();
+
+  RecordComment("]");
+
+  if (after_pool.is_linked()) {
+    bind(&after_pool);
+  }
+
+  // Since a constant pool was just emitted, move the check offset forward by
+  // the standard interval.
+  next_buffer_check_ = pc_offset() + kCheckConstInterval;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/assembler-arm.h b/regexp2000/src/assembler-arm.h
new file mode 100644 (file)
index 0000000..1aebc42
--- /dev/null
@@ -0,0 +1,784 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+// A light-weight ARM Assembler
+// Generates user mode instructions for the ARM architecture up to version 5
+
+#ifndef V8_ASSEMBLER_ARM_H_
+#define V8_ASSEMBLER_ARM_H_
+
+#include "assembler.h"
+
+namespace v8 { namespace internal {
+
+// CPU Registers.
+//
+// 1) We would prefer to use an enum, but enum values are assignment-
+// compatible with int, which has caused code-generation bugs.
+//
+// 2) We would prefer to use a class instead of a struct but we don't like
+// the register initialization to depend on the particular initialization
+// order (which appears to be different on OS X, Linux, and Windows for the
+// installed versions of C++ we tried). Using a struct permits C-style
+// "initialization". Also, the Register objects cannot be const as this
+// forces initialization stubs in MSVC, making us dependent on initialization
+// order.
+//
+// 3) By not using an enum, we are possibly preventing the compiler from
+// doing certain constant folds, which may significantly reduce the
+// code generated for some assembly instructions (because they boil down
+// to a few constants). If this is a problem, we could change the code
+// such that we use an enum in optimized mode, and the struct in debug
+// mode. This way we get the compile-time error checking in debug mode
+// and best performance in optimized code.
+//
+// Core register
+struct Register {
+  bool is_valid() const  { return 0 <= code_ && code_ < 16; }
+  bool is(Register reg) const  { return code_ == reg.code_; }
+  int code() const  {
+    ASSERT(is_valid());
+    return code_;
+  }
+  int bit() const  {
+    ASSERT(is_valid());
+    return 1 << code_;
+  }
+
+  // (unfortunately we can't make this private in a struct)
+  int code_;
+};
+
+
+extern Register no_reg;
+extern Register r0;
+extern Register r1;
+extern Register r2;
+extern Register r3;
+extern Register r4;
+extern Register r5;
+extern Register r6;
+extern Register r7;
+extern Register r8;
+extern Register r9;
+extern Register r10;
+extern Register fp;
+extern Register ip;
+extern Register sp;
+extern Register lr;
+extern Register pc;
+
+
+// Coprocessor register
+struct CRegister {
+  bool is_valid() const  { return 0 <= code_ && code_ < 16; }
+  bool is(CRegister creg) const  { return code_ == creg.code_; }
+  int code() const  {
+    ASSERT(is_valid());
+    return code_;
+  }
+  int bit() const  {
+    ASSERT(is_valid());
+    return 1 << code_;
+  }
+
+  // (unfortunately we can't make this private in a struct)
+  int code_;
+};
+
+
+extern CRegister no_creg;
+extern CRegister cr0;
+extern CRegister cr1;
+extern CRegister cr2;
+extern CRegister cr3;
+extern CRegister cr4;
+extern CRegister cr5;
+extern CRegister cr6;
+extern CRegister cr7;
+extern CRegister cr8;
+extern CRegister cr9;
+extern CRegister cr10;
+extern CRegister cr11;
+extern CRegister cr12;
+extern CRegister cr13;
+extern CRegister cr14;
+extern CRegister cr15;
+
+
+// Coprocessor number
+enum Coprocessor {
+  p0  = 0,
+  p1  = 1,
+  p2  = 2,
+  p3  = 3,
+  p4  = 4,
+  p5  = 5,
+  p6  = 6,
+  p7  = 7,
+  p8  = 8,
+  p9  = 9,
+  p10 = 10,
+  p11 = 11,
+  p12 = 12,
+  p13 = 13,
+  p14 = 14,
+  p15 = 15
+};
+
+
+// Condition field in instructions
+enum Condition {
+  eq =  0 << 28,
+  ne =  1 << 28,
+  cs =  2 << 28,
+  hs =  2 << 28,
+  cc =  3 << 28,
+  lo =  3 << 28,
+  mi =  4 << 28,
+  pl =  5 << 28,
+  vs =  6 << 28,
+  vc =  7 << 28,
+  hi =  8 << 28,
+  ls =  9 << 28,
+  ge = 10 << 28,
+  lt = 11 << 28,
+  gt = 12 << 28,
+  le = 13 << 28,
+  al = 14 << 28
+};
+
+
+// Returns the equivalent of !cc.
+INLINE(Condition NegateCondition(Condition cc));
+
+
+// Corresponds to transposing the operands of a comparison.
+inline Condition ReverseCondition(Condition cc) {
+  switch (cc) {
+    case lo:
+      return hi;
+    case hi:
+      return lo;
+    case hs:
+      return ls;
+    case ls:
+      return hs;
+    case lt:
+      return gt;
+    case gt:
+      return lt;
+    case ge:
+      return le;
+    case le:
+      return ge;
+    default:
+      return cc;
+  };
+}
+
+
+// The pc store offset may be 8 or 12 depending on the processor implementation.
+int PcStoreOffset();
+
+
+// -----------------------------------------------------------------------------
+// Addressing modes and instruction variants
+
+// Shifter operand shift operation
+enum ShiftOp {
+  LSL = 0 << 5,
+  LSR = 1 << 5,
+  ASR = 2 << 5,
+  ROR = 3 << 5,
+  RRX = -1
+};
+
+
+// Condition code updating mode
+enum SBit {
+  SetCC   = 1 << 20,  // set condition code
+  LeaveCC = 0 << 20   // leave condition code unchanged
+};
+
+
+// Status register selection
+enum SRegister {
+  CPSR = 0 << 22,
+  SPSR = 1 << 22
+};
+
+
+// Status register fields
+enum SRegisterField {
+  CPSR_c = CPSR | 1 << 16,
+  CPSR_x = CPSR | 1 << 17,
+  CPSR_s = CPSR | 1 << 18,
+  CPSR_f = CPSR | 1 << 19,
+  SPSR_c = SPSR | 1 << 16,
+  SPSR_x = SPSR | 1 << 17,
+  SPSR_s = SPSR | 1 << 18,
+  SPSR_f = SPSR | 1 << 19
+};
+
+// Status register field mask (or'ed SRegisterField enum values)
+typedef uint32_t SRegisterFieldMask;
+
+
+// Memory operand addressing mode
+enum AddrMode {
+  // bit encoding P U W
+  Offset       = (8|4|0) << 21,  // offset (without writeback to base)
+  PreIndex     = (8|4|1) << 21,  // pre-indexed addressing with writeback
+  PostIndex    = (0|4|0) << 21,  // post-indexed addressing with writeback
+  NegOffset    = (8|0|0) << 21,  // negative offset (without writeback to base)
+  NegPreIndex  = (8|0|1) << 21,  // negative pre-indexed with writeback
+  NegPostIndex = (0|0|0) << 21   // negative post-indexed with writeback
+};
+
+
+// Load/store multiple addressing mode
+enum BlockAddrMode {
+  // bit encoding P U W
+  da           = (0|0|0) << 21,  // decrement after
+  ia           = (0|4|0) << 21,  // increment after
+  db           = (8|0|0) << 21,  // decrement before
+  ib           = (8|4|0) << 21,  // increment before
+  da_w         = (0|0|1) << 21,  // decrement after with writeback to base
+  ia_w         = (0|4|1) << 21,  // increment after with writeback to base
+  db_w         = (8|0|1) << 21,  // decrement before with writeback to base
+  ib_w         = (8|4|1) << 21   // increment before with writeback to base
+};
+
+
+// Coprocessor load/store operand size
+enum LFlag {
+  Long  = 1 << 22,  // long load/store coprocessor
+  Short = 0 << 22   // short load/store coprocessor
+};
+
+
+// -----------------------------------------------------------------------------
+// Machine instruction Operands
+
+// Class Operand represents a shifter operand in data processing instructions
+class Operand BASE_EMBEDDED {
+ public:
+  // immediate
+  INLINE(explicit Operand(int32_t immediate,
+         RelocInfo::Mode rmode = RelocInfo::NONE));
+  INLINE(explicit Operand(const ExternalReference& f));
+  INLINE(explicit Operand(const char* s));
+  INLINE(explicit Operand(Object** opp));
+  INLINE(explicit Operand(Context** cpp));
+  explicit Operand(Handle<Object> handle);
+  INLINE(explicit Operand(Smi* value));
+
+  // rm
+  INLINE(explicit Operand(Register rm));
+
+  // rm <shift_op> shift_imm
+  explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
+
+  // rm <shift_op> rs
+  explicit Operand(Register rm, ShiftOp shift_op, Register rs);
+
+  // Return true if this is a register operand.
+  INLINE(bool is_reg() const);
+
+  Register rm() const { return rm_; }
+
+ private:
+  Register rm_;
+  Register rs_;
+  ShiftOp shift_op_;
+  int shift_imm_;  // valid if rm_ != no_reg && rs_ == no_reg
+  int32_t imm32_;  // valid if rm_ == no_reg
+  RelocInfo::Mode rmode_;
+
+  friend class Assembler;
+};
+
+
+// Class MemOperand represents a memory operand in load and store instructions
+class MemOperand BASE_EMBEDDED {
+ public:
+  // [rn +/- offset]      Offset/NegOffset
+  // [rn +/- offset]!     PreIndex/NegPreIndex
+  // [rn], +/- offset     PostIndex/NegPostIndex
+  // offset is any signed 32-bit value; offset is first loaded to register ip if
+  // it does not fit the addressing mode (12-bit unsigned and sign bit)
+  explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
+
+  // [rn +/- rm]          Offset/NegOffset
+  // [rn +/- rm]!         PreIndex/NegPreIndex
+  // [rn], +/- rm         PostIndex/NegPostIndex
+  explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
+
+  // [rn +/- rm <shift_op> shift_imm]      Offset/NegOffset
+  // [rn +/- rm <shift_op> shift_imm]!     PreIndex/NegPreIndex
+  // [rn], +/- rm <shift_op> shift_imm     PostIndex/NegPostIndex
+  explicit MemOperand(Register rn, Register rm,
+                      ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
+
+ private:
+  Register rn_;  // base
+  Register rm_;  // register offset
+  int32_t offset_;  // valid if rm_ == no_reg
+  ShiftOp shift_op_;
+  int shift_imm_;  // valid if rm_ != no_reg && rs_ == no_reg
+  AddrMode am_;  // bits P, U, and W
+
+  friend class Assembler;
+};
+
+
+typedef int32_t Instr;
+
+
+class Assembler : public Malloced {
+ public:
+  // Create an assembler. Instructions and relocation information are emitted
+  // into a buffer, with the instructions starting from the beginning and the
+  // relocation information starting from the end of the buffer. See CodeDesc
+  // for a detailed comment on the layout (globals.h).
+  //
+  // If the provided buffer is NULL, the assembler allocates and grows its own
+  // buffer, and buffer_size determines the initial buffer size. The buffer is
+  // owned by the assembler and deallocated upon destruction of the assembler.
+  //
+  // If the provided buffer is not NULL, the assembler uses the provided buffer
+  // for code generation and assumes its size to be buffer_size. If the buffer
+  // is too small, a fatal error occurs. No deallocation of the buffer is done
+  // upon destruction of the assembler.
+  Assembler(void* buffer, int buffer_size);
+  ~Assembler();
+
+  // GetCode emits any pending (non-emitted) code and fills the descriptor
+  // desc. GetCode() is idempotent; it returns the same result if no other
+  // Assembler functions are invoked inbetween GetCode() calls.
+  void GetCode(CodeDesc* desc);
+
+  // Label operations & relative jumps (PPUM Appendix D)
+  //
+  // Takes a branch opcode (cc) and a label (L) and generates
+  // either a backward branch or a forward branch and links it
+  // to the label fixup chain. Usage:
+  //
+  // Label L;    // unbound label
+  // j(cc, &L);  // forward branch to unbound label
+  // bind(&L);   // bind label to the current pc
+  // j(cc, &L);  // backward branch to bound label
+  // bind(&L);   // illegal: a label may be bound only once
+  //
+  // Note: The same Label can be used for forward and backward branches
+  // but it may be bound only once.
+
+  void bind(Label* L);  // binds an unbound label L to the current code position
+
+  // Returns the branch offset to the given label from the current code position
+  // Links the label to the current position if it is still unbound
+  // Manages the jump elimination optimization if the second parameter is true.
+  int branch_offset(Label* L, bool jump_elimination_allowed);
+
+  // Return the address in the constant pool of the code target address used by
+  // the branch/call instruction at pc.
+  INLINE(static Address target_address_address_at(Address pc));
+
+  // Read/Modify the code target address in the branch/call instruction at pc.
+  INLINE(static Address target_address_at(Address pc));
+  INLINE(static void set_target_address_at(Address pc, Address target));
+
+  // Distance between the instruction referring to the address of the call
+  // target (ldr pc, [target addr in const pool]) and the return address
+  static const int kTargetAddrToReturnAddrDist = sizeof(Instr);
+
+
+  // ---------------------------------------------------------------------------
+  // Code generation
+
+  // Insert the smallest number of nop instructions
+  // possible to align the pc offset to a multiple
+  // of m. m must be a power of 2 (>= 4).
+  void Align(int m);
+
+  // Branch instructions
+  void b(int branch_offset, Condition cond = al);
+  void bl(int branch_offset, Condition cond = al);
+  void blx(int branch_offset);  // v5 and above
+  void blx(Register target, Condition cond = al);  // v5 and above
+  void bx(Register target, Condition cond = al);  // v5 and above, plus v4t
+
+  // Convenience branch instructions using labels
+  void b(Label* L, Condition cond = al)  {
+    b(branch_offset(L, cond == al), cond);
+  }
+  void b(Condition cond, Label* L)  { b(branch_offset(L, cond == al), cond); }
+  void bl(Label* L, Condition cond = al)  { bl(branch_offset(L, false), cond); }
+  void bl(Condition cond, Label* L)  { bl(branch_offset(L, false), cond); }
+  void blx(Label* L)  { blx(branch_offset(L, false)); }  // v5 and above
+
+  // Data-processing instructions
+  void and_(Register dst, Register src1, const Operand& src2,
+            SBit s = LeaveCC, Condition cond = al);
+
+  void eor(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void sub(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+  void sub(Register dst, Register src1, Register src2,
+           SBit s = LeaveCC, Condition cond = al) {
+    sub(dst, src1, Operand(src2), s, cond);
+  }
+
+  void rsb(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void add(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void adc(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void sbc(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void rsc(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void tst(Register src1, const Operand& src2, Condition cond = al);
+  void tst(Register src1, Register src2, Condition cond = al) {
+    tst(src1, Operand(src2), cond);
+  }
+
+  void teq(Register src1, const Operand& src2, Condition cond = al);
+
+  void cmp(Register src1, const Operand& src2, Condition cond = al);
+  void cmp(Register src1, Register src2, Condition cond = al) {
+    cmp(src1, Operand(src2), cond);
+  }
+
+  void cmn(Register src1, const Operand& src2, Condition cond = al);
+
+  void orr(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+  void orr(Register dst, Register src1, Register src2,
+           SBit s = LeaveCC, Condition cond = al) {
+    orr(dst, src1, Operand(src2), s, cond);
+  }
+
+  void mov(Register dst, const Operand& src,
+           SBit s = LeaveCC, Condition cond = al);
+  void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
+    mov(dst, Operand(src), s, cond);
+  }
+
+  void bic(Register dst, Register src1, const Operand& src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void mvn(Register dst, const Operand& src,
+           SBit s = LeaveCC, Condition cond = al);
+
+  // Multiply instructions
+
+  void mla(Register dst, Register src1, Register src2, Register srcA,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void mul(Register dst, Register src1, Register src2,
+           SBit s = LeaveCC, Condition cond = al);
+
+  void smlal(Register dstL, Register dstH, Register src1, Register src2,
+             SBit s = LeaveCC, Condition cond = al);
+
+  void smull(Register dstL, Register dstH, Register src1, Register src2,
+             SBit s = LeaveCC, Condition cond = al);
+
+  void umlal(Register dstL, Register dstH, Register src1, Register src2,
+             SBit s = LeaveCC, Condition cond = al);
+
+  void umull(Register dstL, Register dstH, Register src1, Register src2,
+             SBit s = LeaveCC, Condition cond = al);
+
+  // Miscellaneous arithmetic instructions
+
+  void clz(Register dst, Register src, Condition cond = al);  // v5 and above
+
+  // Status register access instructions
+
+  void mrs(Register dst, SRegister s, Condition cond = al);
+  void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
+
+  // Load/Store instructions
+  void ldr(Register dst, const MemOperand& src, Condition cond = al);
+  void str(Register src, const MemOperand& dst, Condition cond = al);
+  void ldrb(Register dst, const MemOperand& src, Condition cond = al);
+  void strb(Register src, const MemOperand& dst, Condition cond = al);
+  void ldrh(Register dst, const MemOperand& src, Condition cond = al);
+  void strh(Register src, const MemOperand& dst, Condition cond = al);
+  void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
+  void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
+
+  // Load/Store multiple instructions
+  void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
+  void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
+
+  // Semaphore instructions
+  void swp(Register dst, Register src, Register base, Condition cond = al);
+  void swpb(Register dst, Register src, Register base, Condition cond = al);
+
+  // Exception-generating instructions and debugging support
+  void stop(const char* msg);
+
+  void bkpt(uint32_t imm16);  // v5 and above
+  void swi(uint32_t imm24, Condition cond = al);
+
+  // Coprocessor instructions
+
+  void cdp(Coprocessor coproc, int opcode_1,
+           CRegister crd, CRegister crn, CRegister crm,
+           int opcode_2, Condition cond = al);
+
+  void cdp2(Coprocessor coproc, int opcode_1,
+            CRegister crd, CRegister crn, CRegister crm,
+            int opcode_2);  // v5 and above
+
+  void mcr(Coprocessor coproc, int opcode_1,
+           Register rd, CRegister crn, CRegister crm,
+           int opcode_2 = 0, Condition cond = al);
+
+  void mcr2(Coprocessor coproc, int opcode_1,
+            Register rd, CRegister crn, CRegister crm,
+            int opcode_2 = 0);  // v5 and above
+
+  void mrc(Coprocessor coproc, int opcode_1,
+           Register rd, CRegister crn, CRegister crm,
+           int opcode_2 = 0, Condition cond = al);
+
+  void mrc2(Coprocessor coproc, int opcode_1,
+            Register rd, CRegister crn, CRegister crm,
+            int opcode_2 = 0);  // v5 and above
+
+  void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
+           LFlag l = Short, Condition cond = al);
+  void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
+           LFlag l = Short, Condition cond = al);
+
+  void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
+            LFlag l = Short);  // v5 and above
+  void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
+            LFlag l = Short);  // v5 and above
+
+  void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
+           LFlag l = Short, Condition cond = al);
+  void stc(Coprocessor coproc, CRegister crd, Register base, int option,
+           LFlag l = Short, Condition cond = al);
+
+  void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
+            LFlag l = Short);  // v5 and above
+  void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
+            LFlag l = Short);  // v5 and above
+
+  // Pseudo instructions
+  void nop()  { mov(r0, Operand(r0)); }
+
+  void push(Register src) {
+    str(src, MemOperand(sp, 4, NegPreIndex), al);
+  }
+
+  void pop(Register dst) {
+    ldr(dst, MemOperand(sp, 4, PostIndex), al);
+  }
+
+  void pop() {
+    add(sp, sp, Operand(kPointerSize));
+  }
+
+  // Load effective address of memory operand x into register dst
+  void lea(Register dst, const MemOperand& x,
+           SBit s = LeaveCC, Condition cond = al);
+
+  // Jump unconditionally to given label.
+  void jmp(Label* L) { b(L, al); }
+
+
+  // Debugging
+
+  // Record a comment relocation entry that can be used by a disassembler.
+  // Use --debug_code to enable.
+  void RecordComment(const char* msg);
+
+  void RecordPosition(int pos);
+  void RecordStatementPosition(int pos);
+
+  int pc_offset() const { return pc_ - buffer_; }
+  int last_position() const { return last_position_; }
+  bool last_position_is_statement() const {
+    return last_position_is_statement_;
+  }
+
+  // Temporary helper function. Used by codegen.cc.
+  int last_statement_position() const { return last_position_; }
+
+ protected:
+  int buffer_space() const { return reloc_info_writer.pos() - pc_; }
+
+  // Read/patch instructions
+  Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
+  void instr_at_put(byte* pc, Instr instr) {
+    *reinterpret_cast<Instr*>(pc) = instr;
+  }
+  Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
+  void instr_at_put(int pos, Instr instr) {
+    *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
+  }
+
+  // Decode branch instruction at pos and return branch target pos
+  int target_at(int pos);
+
+  // Patch branch instruction at pos to branch to given branch target pos
+  void target_at_put(int pos, int target_pos);
+
+ private:
+  // Code buffer:
+  // The buffer into which code and relocation info are generated.
+  byte* buffer_;
+  int buffer_size_;
+  // True if the assembler owns the buffer, false if buffer is external.
+  bool own_buffer_;
+
+  // Buffer size and constant pool distance are checked together at regular
+  // intervals of kBufferCheckInterval emitted bytes
+  static const int kBufferCheckInterval = 1*KB/2;
+  int next_buffer_check_;  // pc offset of next buffer check
+
+  // Code generation
+  static const int kInstrSize = sizeof(Instr);  // signed size
+  // The relocation writer's position is at least kGap bytes below the end of
+  // the generated instructions. This is so that multi-instruction sequences do
+  // not have to check for overflow. The same is true for writes of large
+  // relocation info entries.
+  static const int kGap = 32;
+  byte* pc_;  // the program counter; moves forward
+
+  // Constant pool generation
+  // Pools are emitted in the instruction stream, preferably after unconditional
+  // jumps or after returns from functions (in dead code locations).
+  // If a long code sequence does not contain unconditional jumps, it is
+  // necessary to emit the constant pool before the pool gets too far from the
+  // location it is accessed from. In this case, we emit a jump over the emitted
+  // constant pool.
+  // Constants in the pool may be addresses of functions that gets relocated;
+  // if so, a relocation info entry is associated to the constant pool entry.
+
+  // Repeated checking whether the constant pool should be emitted is rather
+  // expensive. By default we only check again once a number of instructions
+  // has been generated. That also means that the sizing of the buffers is not
+  // an exact science, and that we rely on some slop to not overrun buffers.
+  static const int kCheckConstIntervalInst = 32;
+  static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
+
+
+  // Pools are emitted after function return and in dead code at (more or less)
+  // regular intervals of kDistBetweenPools bytes
+  static const int kDistBetweenPools = 1*KB;
+
+  // Constants in pools are accessed via pc relative addressing, which can
+  // reach +/-4KB thereby defining a maximum distance between the instruction
+  // and the accessed constant. We satisfy this constraint by limiting the
+  // distance between pools.
+  static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
+
+  // Emission of the constant pool may be blocked in some code sequences
+  int no_const_pool_before_;  // block emission before this pc offset
+
+  // Keep track of the last emitted pool to guarantee a maximal distance
+  int last_const_pool_end_;  // pc offset following the last constant pool
+
+  // Relocation info generation
+  // Each relocation is encoded as a variable size value
+  static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
+  RelocInfoWriter reloc_info_writer;
+  // Relocation info records are also used during code generation as temporary
+  // containers for constants and code target addresses until they are emitted
+  // to the constant pool. These pending relocation info records are temporarily
+  // stored in a separate buffer until a constant pool is emitted.
+  // If every instruction in a long sequence is accessing the pool, we need one
+  // pending relocation entry per instruction.
+  static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
+  RelocInfo prinfo_[kMaxNumPRInfo];  // the buffer of pending relocation info
+  int num_prinfo_;  // number of pending reloc info entries in the buffer
+
+  // The bound position, before this we cannot do instruction elimination.
+  int last_bound_pos_;
+
+  // source position information
+  int last_position_;
+  bool last_position_is_statement_;
+
+  // Code emission
+  inline void CheckBuffer();
+  void GrowBuffer();
+  inline void emit(Instr x);
+
+  // Instruction generation
+  void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
+  void addrmod2(Instr instr, Register rd, const MemOperand& x);
+  void addrmod3(Instr instr, Register rd, const MemOperand& x);
+  void addrmod4(Instr instr, Register rn, RegList rl);
+  void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
+
+  // Labels
+  void print(Label* L);
+  void bind_to(Label* L, int pos);
+  void link_to(Label* L, Label* appendix);
+  void next(Label* L);
+
+  // Record reloc info for current pc_
+  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+
+  // Check if is time to emit a constant pool for pending reloc info entries
+  void CheckConstPool(bool force_emit, bool require_jump);
+
+  // Block the emission of the constant pool before pc_offset
+  void BlockConstPoolBefore(int pc_offset) {
+    if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
+  }
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ASSEMBLER_ARM_H_
diff --git a/regexp2000/src/assembler-ia32-inl.h b/regexp2000/src/assembler-ia32-inl.h
new file mode 100644 (file)
index 0000000..9b3567a
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+// A light-weight IA32 Assembler.
+
+#ifndef V8_ASSEMBLER_IA32_INL_H_
+#define V8_ASSEMBLER_IA32_INL_H_
+
+#include "cpu.h"
+
+namespace v8 { namespace internal {
+
+Condition NegateCondition(Condition cc) {
+  return static_cast<Condition>(cc ^ 1);
+}
+
+
+// The modes possibly affected by apply must be in kApplyMask.
+void RelocInfo::apply(int delta) {
+  if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) {
+    int32_t* p = reinterpret_cast<int32_t*>(pc_);
+    *p -= delta;  // relocate entry
+  } else if (rmode_ == JS_RETURN && is_call_instruction()) {
+    // Special handling of js_return when a break point is set (call
+    // instruction has been inserted).
+    int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
+    *p -= delta;  // relocate entry
+  } else if (IsInternalReference(rmode_)) {
+    // absolute code pointer inside code object moves with the code object.
+    int32_t* p = reinterpret_cast<int32_t*>(pc_);
+    *p += delta;  // relocate entry
+  }
+}
+
+
+Address RelocInfo::target_address() {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
+  return Assembler::target_address_at(pc_);
+}
+
+
+void RelocInfo::set_target_address(Address target) {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
+  Assembler::set_target_address_at(pc_, target);
+}
+
+
+Object* RelocInfo::target_object() {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return *reinterpret_cast<Object**>(pc_);
+}
+
+
+Object** RelocInfo::target_object_address() {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return reinterpret_cast<Object**>(pc_);
+}
+
+
+void RelocInfo::set_target_object(Object* target) {
+  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  *reinterpret_cast<Object**>(pc_) = target;
+}
+
+
+Address* RelocInfo::target_reference_address() {
+  ASSERT(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
+  return reinterpret_cast<Address*>(pc_);
+}
+
+
+Address RelocInfo::call_address() {
+  ASSERT(is_call_instruction());
+  return Assembler::target_address_at(pc_ + 1);
+}
+
+
+void RelocInfo::set_call_address(Address target) {
+  ASSERT(is_call_instruction());
+  Assembler::set_target_address_at(pc_ + 1, target);
+}
+
+
+Object* RelocInfo::call_object() {
+  ASSERT(is_call_instruction());
+  return *call_object_address();
+}
+
+
+Object** RelocInfo::call_object_address() {
+  ASSERT(is_call_instruction());
+  return reinterpret_cast<Object**>(pc_ + 1);
+}
+
+
+void RelocInfo::set_call_object(Object* target) {
+  ASSERT(is_call_instruction());
+  *call_object_address() = target;
+}
+
+
+bool RelocInfo::is_call_instruction() {
+  return *pc_ == 0xE8;
+}
+
+
+Immediate::Immediate(int x)  {
+  x_ = x;
+  rmode_ = RelocInfo::NONE;
+}
+
+
+Immediate::Immediate(const ExternalReference& ext) {
+  x_ = reinterpret_cast<int32_t>(ext.address());
+  rmode_ = RelocInfo::EXTERNAL_REFERENCE;
+}
+
+Immediate::Immediate(const char* s) {
+  x_ = reinterpret_cast<int32_t>(s);
+  rmode_ = RelocInfo::EMBEDDED_STRING;
+}
+
+
+Immediate::Immediate(Handle<Object> handle) {
+  // Verify all Objects referred by code are NOT in new space.
+  Object* obj = *handle;
+  ASSERT(!Heap::InNewSpace(obj));
+  if (obj->IsHeapObject()) {
+    x_ = reinterpret_cast<intptr_t>(handle.location());
+    rmode_ = RelocInfo::EMBEDDED_OBJECT;
+  } else {
+    // no relocation needed
+    x_ =  reinterpret_cast<intptr_t>(obj);
+    rmode_ = RelocInfo::NONE;
+  }
+}
+
+
+Immediate::Immediate(Smi* value) {
+  x_ = reinterpret_cast<intptr_t>(value);
+  rmode_ = RelocInfo::NONE;
+}
+
+
+void Assembler::emit(uint32_t x) {
+  *reinterpret_cast<uint32_t*>(pc_) = x;
+  pc_ += sizeof(uint32_t);
+}
+
+
+void Assembler::emit(Handle<Object> handle) {
+  // Verify all Objects referred by code are NOT in new space.
+  Object* obj = *handle;
+  ASSERT(!Heap::InNewSpace(obj));
+  if (obj->IsHeapObject()) {
+    emit(reinterpret_cast<intptr_t>(handle.location()),
+         RelocInfo::EMBEDDED_OBJECT);
+  } else {
+    // no relocation needed
+    emit(reinterpret_cast<intptr_t>(obj));
+  }
+}
+
+
+void Assembler::emit(uint32_t x, RelocInfo::Mode rmode) {
+  if (rmode != RelocInfo::NONE) RecordRelocInfo(rmode);
+  emit(x);
+}
+
+
+void Assembler::emit(const Immediate& x) {
+  if (x.rmode_ != RelocInfo::NONE) RecordRelocInfo(x.rmode_);
+  emit(x.x_);
+}
+
+
+Address Assembler::target_address_at(Address pc) {
+  return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
+}
+
+
+void Assembler::set_target_address_at(Address pc, Address target) {
+  int32_t* p = reinterpret_cast<int32_t*>(pc);
+  *p = target - (pc + sizeof(int32_t));
+  CPU::FlushICache(p, sizeof(int32_t));
+}
+
+
+Displacement Assembler::disp_at(Label* L) {
+  return Displacement(long_at(L->pos()));
+}
+
+
+void Assembler::disp_at_put(Label* L, Displacement disp) {
+  long_at_put(L->pos(), disp.data());
+}
+
+
+void Assembler::emit_disp(Label* L, Displacement::Type type) {
+  Displacement disp(L, type);
+  L->link_to(pc_offset());
+  emit(static_cast<int>(disp.data()));
+}
+
+
+void Operand::set_modrm(int mod,  // reg == 0
+                        Register rm) {
+  ASSERT((mod & -4) == 0);
+  buf_[0] = mod << 6 | rm.code();
+  len_ = 1;
+}
+
+
+void Operand::set_dispr(int32_t disp, RelocInfo::Mode rmode) {
+  ASSERT(len_ == 1 || len_ == 2);
+  *reinterpret_cast<int32_t*>(&buf_[len_]) = disp;
+  len_ += sizeof(int32_t);
+  rmode_ = rmode;
+}
+
+Operand::Operand(Register reg) {
+  // reg
+  set_modrm(3, reg);
+}
+
+
+Operand::Operand(int32_t disp, RelocInfo::Mode rmode) {
+  // [disp/r]
+  set_modrm(0, ebp);
+  set_dispr(disp, rmode);
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_ASSEMBLER_IA32_INL_H_
diff --git a/regexp2000/src/assembler-ia32.cc b/regexp2000/src/assembler-ia32.cc
new file mode 100644 (file)
index 0000000..fbe63de
--- /dev/null
@@ -0,0 +1,2069 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+#include "v8.h"
+
+#include "disassembler.h"
+#include "macro-assembler.h"
+#include "serialize.h"
+
+namespace v8 { namespace internal {
+
+// -----------------------------------------------------------------------------
+// Implementation of Register
+
+Register eax = { 0 };
+Register ecx = { 1 };
+Register edx = { 2 };
+Register ebx = { 3 };
+Register esp = { 4 };
+Register ebp = { 5 };
+Register esi = { 6 };
+Register edi = { 7 };
+Register no_reg = { -1 };
+
+XMMRegister xmm0 = { 0 };
+XMMRegister xmm1 = { 1 };
+XMMRegister xmm2 = { 2 };
+XMMRegister xmm3 = { 3 };
+XMMRegister xmm4 = { 4 };
+XMMRegister xmm5 = { 5 };
+XMMRegister xmm6 = { 6 };
+XMMRegister xmm7 = { 7 };
+
+
+// -----------------------------------------------------------------------------
+// Implementation of CpuFeatures
+
+// Safe default is no features.
+uint32_t CpuFeatures::supported_ = 0;
+uint32_t CpuFeatures::enabled_ = 0;
+
+
+typedef int (*F0)();
+
+// The Probe method needs executable memory, so it uses Heap::CreateCode.
+// Allocation failure is silent and leads to safe default.
+void CpuFeatures::Probe() {
+  supported_ = 0;
+  if (Serializer::enabled()) return;  // No features if we might serialize.
+  Assembler assm(NULL, 0);
+  Label done;
+#define __ assm.
+  // Save old esp, since we are going to modify the stack.
+  __ push(ebp);
+  __ pushfd();
+  __ push(ecx);
+  __ push(edx);
+  __ push(ebx);
+  __ mov(ebp, Operand(esp));
+  // If we can modify bit 21 of the EFLAGS register, then CPUID is supported.
+  __ pushfd();
+  __ pop(eax);
+  __ mov(edx, Operand(eax));
+  __ xor_(eax, 0x200000);  // Flip bit 21.
+  __ push(eax);
+  __ popfd();
+  __ pushfd();
+  __ pop(eax);
+  __ xor_(eax, Operand(edx));  // Different if CPUID is supported.
+  __ j(zero, &done);
+  // Invoke CPUID with 1 in eax to get feature information in edx.
+  __ mov(eax, 1);
+  // Temporarily force CPUID support, since we know it is safe here.
+  supported_ = (1 << CPUID);
+  { Scope fscope(CPUID);
+    __ cpuid();
+  }
+  supported_ = 0;
+  // Return result in eax.
+  __ mov(eax, Operand(edx));
+  __ bind(&done);
+  __ mov(esp, Operand(ebp));
+  __ pop(ebx);
+  __ pop(edx);
+  __ pop(ecx);
+  __ popfd();
+  __ pop(ebp);
+  __ ret(0);
+#undef __
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  if (!code->IsCode()) return;
+  F0 f = FUNCTION_CAST<F0>(Code::cast(code)->entry());
+  uint32_t res = f();
+  supported_ = (res | (1 << CPUID));
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of Displacement
+
+void Displacement::init(Label* L, Type type) {
+  ASSERT(!L->is_bound());
+  int next = 0;
+  if (L->is_linked()) {
+    next = L->pos();
+    ASSERT(next > 0);  // Displacements must be at positions > 0
+  }
+  // Ensure that we _never_ overflow the next field.
+  ASSERT(NextField::is_valid(Assembler::kMaximalBufferSize));
+  data_ = NextField::encode(next) | TypeField::encode(type);
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of RelocInfo
+
+
+const int RelocInfo::kApplyMask =
+  RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY |
+    1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE;
+
+
+void RelocInfo::patch_code(byte* instructions, int instruction_count) {
+  // Patch the code at the current address with the supplied instructions.
+  for (int i = 0; i < instruction_count; i++) {
+    *(pc_ + i) = *(instructions + i);
+  }
+}
+
+
+// Patch the code at the current PC with a call to the target address.
+// Additional guard int3 instructions can be added if required.
+void RelocInfo::patch_code_with_call(Address target, int guard_bytes) {
+  // Call instruction takes up 5 bytes and int3 takes up one byte.
+  int code_size = 5 + guard_bytes;
+
+  // Patch the code.
+  CodePatcher patcher(pc_, code_size);
+  patcher.masm()->call(target, RelocInfo::NONE);
+
+  // Add the requested number of int3 instructions after the call.
+  for (int i = 0; i < guard_bytes; i++) {
+    patcher.masm()->int3();
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of Operand
+
+Operand::Operand(Register base, int32_t disp, RelocInfo::Mode rmode) {
+  // [base + disp/r]
+  if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) {
+    // [base]
+    set_modrm(0, base);
+    if (base.is(esp)) set_sib(times_1, esp, base);
+  } else if (is_int8(disp) && rmode == RelocInfo::NONE) {
+    // [base + disp8]
+    set_modrm(1, base);
+    if (base.is(esp)) set_sib(times_1, esp, base);
+    set_disp8(disp);
+  } else {
+    // [base + disp/r]
+    set_modrm(2, base);
+    if (base.is(esp)) set_sib(times_1, esp, base);
+    set_dispr(disp, rmode);
+  }
+}
+
+
+Operand::Operand(Register base,
+                 Register index,
+                 ScaleFactor scale,
+                 int32_t disp,
+                 RelocInfo::Mode rmode) {
+  ASSERT(!index.is(esp));  // illegal addressing mode
+  // [base + index*scale + disp/r]
+  if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) {
+    // [base + index*scale]
+    set_modrm(0, esp);
+    set_sib(scale, index, base);
+  } else if (is_int8(disp) && rmode == RelocInfo::NONE) {
+    // [base + index*scale + disp8]
+    set_modrm(1, esp);
+    set_sib(scale, index, base);
+    set_disp8(disp);
+  } else {
+    // [base + index*scale + disp/r]
+    set_modrm(2, esp);
+    set_sib(scale, index, base);
+    set_dispr(disp, rmode);
+  }
+}
+
+
+Operand::Operand(Register index,
+                 ScaleFactor scale,
+                 int32_t disp,
+                 RelocInfo::Mode rmode) {
+  ASSERT(!index.is(esp));  // illegal addressing mode
+  // [index*scale + disp/r]
+  set_modrm(0, esp);
+  set_sib(scale, index, ebp);
+  set_dispr(disp, rmode);
+}
+
+
+void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
+  ASSERT(len_ == 1);
+  ASSERT((scale & -4) == 0);
+  buf_[1] = scale << 6 | index.code() << 3 | base.code();
+  len_ = 2;
+}
+
+
+void Operand::set_disp8(int8_t disp) {
+  ASSERT(len_ == 1 || len_ == 2);
+  *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp;
+}
+
+
+void Operand::set_reg(Register reg) const {
+  ASSERT(len_ > 0);
+  buf_[0] = (buf_[0] & ~0x38) | static_cast<byte>(reg.code() << 3);
+}
+
+
+bool Operand::is_reg(Register reg) const {
+  return ((buf_[0] & 0xF8) == 0xC0)  // addressing mode is register only.
+      && ((buf_[0] & 0x07) == reg.code());  // register codes match.
+}
+
+// -----------------------------------------------------------------------------
+// Implementation of Assembler
+
+// Emit a single byte. Must always be inlined.
+#define EMIT(x)                                 \
+  *pc_++ = (x)
+
+
+// spare_buffer_
+static byte* spare_buffer_ = NULL;
+
+Assembler::Assembler(void* buffer, int buffer_size) {
+  if (buffer == NULL) {
+    // do our own buffer management
+    if (buffer_size <= kMinimalBufferSize) {
+      buffer_size = kMinimalBufferSize;
+
+      if (spare_buffer_ != NULL) {
+        buffer = spare_buffer_;
+        spare_buffer_ = NULL;
+      }
+    }
+    if (buffer == NULL) {
+      buffer_ = NewArray<byte>(buffer_size);
+    } else {
+      buffer_ = static_cast<byte*>(buffer);
+    }
+    buffer_size_ = buffer_size;
+    own_buffer_ = true;
+
+  } else {
+    // use externally provided buffer instead
+    ASSERT(buffer_size > 0);
+    buffer_ = static_cast<byte*>(buffer);
+    buffer_size_ = buffer_size;
+    own_buffer_ = false;
+  }
+
+  // Clear the buffer in debug mode unless it was provided by the
+  // caller in which case we can't be sure it's okay to overwrite
+  // existing code in it; see CodePatcher::CodePatcher(...).
+  if (kDebug && own_buffer_) {
+    memset(buffer_, 0xCC, buffer_size);  // int3
+  }
+
+  // setup buffer pointers
+  ASSERT(buffer_ != NULL);
+  pc_ = buffer_;
+  reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
+
+  last_pc_ = NULL;
+  last_position_ = RelocInfo::kNoPosition;
+  last_statement_position_ = RelocInfo::kNoPosition;
+}
+
+
+Assembler::~Assembler() {
+  if (own_buffer_) {
+    if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
+      spare_buffer_ = buffer_;
+    } else {
+      DeleteArray(buffer_);
+    }
+  }
+}
+
+
+void Assembler::GetCode(CodeDesc* desc) {
+  // finalize code
+  // (at this point overflow() may be true, but the gap ensures that
+  // we are still not overlapping instructions and relocation info)
+  ASSERT(pc_ <= reloc_info_writer.pos());  // no overlap
+  // setup desc
+  desc->buffer = buffer_;
+  desc->buffer_size = buffer_size_;
+  desc->instr_size = pc_offset();
+  desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
+
+  Counters::reloc_info_size.Increment(desc->reloc_size);
+}
+
+
+void Assembler::Align(int m) {
+  ASSERT(IsPowerOf2(m));
+  while ((pc_offset() & (m - 1)) != 0) {
+    nop();
+  }
+}
+
+
+void Assembler::cpuid() {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xA2);
+}
+
+
+void Assembler::pushad() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x60);
+}
+
+
+void Assembler::popad() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x61);
+}
+
+
+void Assembler::pushfd() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x9C);
+}
+
+
+void Assembler::popfd() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x9D);
+}
+
+
+void Assembler::push(const Immediate& x) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (x.is_int8()) {
+    EMIT(0x6a);
+    EMIT(x.x_);
+  } else {
+    EMIT(0x68);
+    emit(x);
+  }
+}
+
+
+void Assembler::push(Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x50 | src.code());
+}
+
+
+void Assembler::push(const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFF);
+  emit_operand(esi, src);
+}
+
+
+void Assembler::pop(Register dst) {
+  ASSERT(reloc_info_writer.last_pc() != NULL);
+  if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) {
+    // (last_pc_ != NULL) is rolled into the above check
+    // If a last_pc_ is set, we need to make sure that there has not been any
+    // relocation information generated between the last instruction and this
+    // pop instruction.
+    byte instr = last_pc_[0];
+    if ((instr & ~0x7) == 0x50) {
+      int push_reg_code = instr & 0x7;
+      if (push_reg_code == dst.code()) {
+        pc_ = last_pc_;
+        if (FLAG_print_push_pop_elimination) {
+          PrintF("%d push/pop (same reg) eliminated\n", pc_offset());
+        }
+      } else {
+        // Convert 'push src; pop dst' to 'mov dst, src'.
+        last_pc_[0] = 0x8b;
+        Register src = { push_reg_code };
+        EnsureSpace ensure_space(this);
+        emit_operand(dst, Operand(src));
+        if (FLAG_print_push_pop_elimination) {
+          PrintF("%d push/pop (reg->reg) eliminated\n", pc_offset());
+        }
+      }
+      last_pc_ = NULL;
+      return;
+    } else if (instr == 0xff) {  // push of an operand, convert to a move
+      byte op1 = last_pc_[1];
+      // Check if the operation is really a push
+      if ((op1 & 0x38) == (6 << 3)) {
+        op1 = (op1 & ~0x38) | static_cast<byte>(dst.code() << 3);
+        last_pc_[0] = 0x8b;
+        last_pc_[1] = op1;
+        last_pc_ = NULL;
+        if (FLAG_print_push_pop_elimination) {
+          PrintF("%d push/pop (op->reg) eliminated\n", pc_offset());
+        }
+        return;
+      }
+    } else if ((instr == 0x89) &&
+               (last_pc_[1] == 0x04) &&
+               (last_pc_[2] == 0x24)) {
+      // 0x71283c   396  890424         mov [esp],eax
+      // 0x71283f   399  58             pop eax
+      if (dst.is(eax)) {
+        // change to
+        // 0x710fac   216  83c404         add esp,0x4
+        last_pc_[0] = 0x83;
+        last_pc_[1] = 0xc4;
+        last_pc_[2] = 0x04;
+        last_pc_ = NULL;
+        if (FLAG_print_push_pop_elimination) {
+          PrintF("%d push/pop (mov-pop) eliminated\n", pc_offset());
+        }
+        return;
+      }
+    } else if (instr == 0x6a && dst.is(eax)) {  // push of immediate 8 bit
+      byte imm8 = last_pc_[1];
+      if (imm8 == 0) {
+        // 6a00         push 0x0
+        // 58           pop eax
+        last_pc_[0] = 0x31;
+        last_pc_[1] = 0xc0;
+        // change to
+        // 31c0         xor eax,eax
+        last_pc_ = NULL;
+        if (FLAG_print_push_pop_elimination) {
+          PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset());
+        }
+        return;
+      } else {
+        // 6a00         push 0xXX
+        // 58           pop eax
+        last_pc_[0] = 0xb8;
+        EnsureSpace ensure_space(this);
+        if ((imm8 & 0x80) != 0) {
+          EMIT(0xff);
+          EMIT(0xff);
+          EMIT(0xff);
+          // change to
+          // b8XXffffff   mov eax,0xffffffXX
+        } else {
+          EMIT(0x00);
+          EMIT(0x00);
+          EMIT(0x00);
+          // change to
+          // b8XX000000   mov eax,0x000000XX
+        }
+        last_pc_ = NULL;
+        if (FLAG_print_push_pop_elimination) {
+          PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset());
+        }
+        return;
+      }
+    } else if (instr == 0x68 && dst.is(eax)) {  // push of immediate 32 bit
+      // 68XXXXXXXX   push 0xXXXXXXXX
+      // 58           pop eax
+      last_pc_[0] = 0xb8;
+      last_pc_ = NULL;
+      // change to
+      // b8XXXXXXXX   mov eax,0xXXXXXXXX
+      if (FLAG_print_push_pop_elimination) {
+        PrintF("%d push/pop (imm->reg) eliminated\n", pc_offset());
+      }
+      return;
+    }
+
+    // Other potential patterns for peephole:
+    // 0x712716   102  890424         mov [esp], eax
+    // 0x712719   105  8b1424         mov edx, [esp]
+  }
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x58 | dst.code());
+}
+
+
+void Assembler::pop(const Operand& dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x8F);
+  emit_operand(eax, dst);
+}
+
+
+void Assembler::mov_b(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x8A);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::mov_b(const Operand& dst, int8_t imm8) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xC6);
+  emit_operand(eax, dst);
+  EMIT(imm8);
+}
+
+
+void Assembler::mov_b(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x88);
+  emit_operand(src, dst);
+}
+
+
+void Assembler::mov_w(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x8B);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::mov_w(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x66);
+  EMIT(0x89);
+  emit_operand(src, dst);
+}
+
+
+void Assembler::mov(Register dst, int32_t imm32) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xB8 | dst.code());
+  emit(imm32);
+}
+
+
+void Assembler::mov(Register dst, Handle<Object> handle) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xB8 | dst.code());
+  emit(handle);
+}
+
+
+void Assembler::mov(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x8B);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::mov(const Operand& dst, const Immediate& x) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xC7);
+  emit_operand(eax, dst);
+  emit(x);
+}
+
+
+void Assembler::mov(const Operand& dst, Handle<Object> handle) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xC7);
+  emit_operand(eax, dst);
+  emit(handle);
+}
+
+
+void Assembler::mov(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x89);
+  emit_operand(src, dst);
+}
+
+
+void Assembler::movsx_b(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xBE);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::movsx_w(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xBF);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::movzx_b(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xB6);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::movzx_w(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xB7);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::cmov(Condition cc, Register dst, int32_t imm32) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  UNIMPLEMENTED();
+  USE(cc);
+  USE(dst);
+  USE(imm32);
+}
+
+
+void Assembler::cmov(Condition cc, Register dst, Handle<Object> handle) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  UNIMPLEMENTED();
+  USE(cc);
+  USE(dst);
+  USE(handle);
+}
+
+
+void Assembler::cmov(Condition cc, Register dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CMOV));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  UNIMPLEMENTED();
+  USE(cc);
+  USE(dst);
+  USE(src);
+}
+
+
+void Assembler::adc(Register dst, int32_t imm32) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(2, Operand(dst), Immediate(imm32));
+}
+
+
+void Assembler::adc(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x13);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::add(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x03);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::add(const Operand& dst, const Immediate& x) {
+  ASSERT(reloc_info_writer.last_pc() != NULL);
+  if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) {
+    byte instr = last_pc_[0];
+    if ((instr & 0xf8) == 0x50) {
+      // Last instruction was a push. Check whether this is a pop without a
+      // result.
+      if ((dst.is_reg(esp)) &&
+          (x.x_ == kPointerSize) && (x.rmode_ == RelocInfo::NONE)) {
+        pc_ = last_pc_;
+        last_pc_ = NULL;
+        if (FLAG_print_push_pop_elimination) {
+          PrintF("%d push/pop(noreg) eliminated\n", pc_offset());
+        }
+        return;
+      }
+    }
+  }
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(0, dst, x);
+}
+
+
+void Assembler::and_(Register dst, int32_t imm32) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(4, Operand(dst), Immediate(imm32));
+}
+
+
+void Assembler::and_(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x23);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::and_(const Operand& dst, const Immediate& x) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(4, dst, x);
+}
+
+
+void Assembler::and_(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x21);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::cmp(Register reg, int32_t imm32) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(7, Operand(reg), Immediate(imm32));
+}
+
+
+void Assembler::cmp(Register reg, Handle<Object> handle) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(7, Operand(reg), Immediate(handle));
+}
+
+
+void Assembler::cmp(Register reg, const Operand& op) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x3B);
+  emit_operand(reg, op);
+}
+
+
+void Assembler::cmp(const Operand& op, const Immediate& imm) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(7, op, imm);
+}
+
+
+void Assembler::dec_b(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFE);
+  EMIT(0xC8 | dst.code());
+}
+
+
+void Assembler::dec(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x48 | dst.code());
+}
+
+
+void Assembler::dec(const Operand& dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFF);
+  emit_operand(ecx, dst);
+}
+
+
+void Assembler::cdq() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x99);
+}
+
+
+void Assembler::idiv(Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF7);
+  EMIT(0xF8 | src.code());
+}
+
+
+void Assembler::imul(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xAF);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::imul(Register dst, Register src, int32_t imm32) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (is_int8(imm32)) {
+    EMIT(0x6B);
+    EMIT(0xC0 | dst.code() << 3 | src.code());
+    EMIT(imm32);
+  } else {
+    EMIT(0x69);
+    EMIT(0xC0 | dst.code() << 3 | src.code());
+    emit(imm32);
+  }
+}
+
+
+void Assembler::inc(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x40 | dst.code());
+}
+
+
+void Assembler::inc(const Operand& dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFF);
+  emit_operand(eax, dst);
+}
+
+
+void Assembler::lea(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x8D);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::mul(Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF7);
+  EMIT(0xE0 | src.code());
+}
+
+
+void Assembler::neg(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF7);
+  EMIT(0xD8 | dst.code());
+}
+
+
+void Assembler::not_(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF7);
+  EMIT(0xD0 | dst.code());
+}
+
+
+void Assembler::or_(Register dst, int32_t imm32) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(1, Operand(dst), Immediate(imm32));
+}
+
+
+void Assembler::or_(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0B);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::or_(const Operand& dst, const Immediate& x) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(1, dst, x);
+}
+
+
+void Assembler::or_(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x09);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::rcl(Register dst, uint8_t imm8) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(is_uint5(imm8));  // illegal shift count
+  if (imm8 == 1) {
+    EMIT(0xD1);
+    EMIT(0xD0 | dst.code());
+  } else {
+    EMIT(0xC1);
+    EMIT(0xD0 | dst.code());
+    EMIT(imm8);
+  }
+}
+
+
+void Assembler::sar(Register dst, uint8_t imm8) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(is_uint5(imm8));  // illegal shift count
+  if (imm8 == 1) {
+    EMIT(0xD1);
+    EMIT(0xF8 | dst.code());
+  } else {
+    EMIT(0xC1);
+    EMIT(0xF8 | dst.code());
+    EMIT(imm8);
+  }
+}
+
+
+void Assembler::sar(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD3);
+  EMIT(0xF8 | dst.code());
+}
+
+
+void Assembler::sbb(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x1B);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::shld(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xA5);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::shl(Register dst, uint8_t imm8) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(is_uint5(imm8));  // illegal shift count
+  if (imm8 == 1) {
+    EMIT(0xD1);
+    EMIT(0xE0 | dst.code());
+  } else {
+    EMIT(0xC1);
+    EMIT(0xE0 | dst.code());
+    EMIT(imm8);
+  }
+}
+
+
+void Assembler::shl(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD3);
+  EMIT(0xE0 | dst.code());
+}
+
+
+void Assembler::shrd(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xAD);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::shr(Register dst, uint8_t imm8) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(is_uint5(imm8));  // illegal shift count
+  EMIT(0xC1);
+  EMIT(0xE8 | dst.code());
+  EMIT(imm8);
+}
+
+
+void Assembler::shr(Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD3);
+  EMIT(0xE8 | dst.code());
+}
+
+
+void Assembler::sub(const Operand& dst, const Immediate& x) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(5, dst, x);
+}
+
+
+void Assembler::sub(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x2B);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::sub(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x29);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::test(Register reg, const Immediate& imm) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  // Only use test against byte for registers that have a byte
+  // variant: eax, ebx, ecx, and edx.
+  if (imm.rmode_ == RelocInfo::NONE && is_uint8(imm.x_) && reg.code() < 4) {
+    uint8_t imm8 = imm.x_;
+    if (reg.is(eax)) {
+      EMIT(0xA8);
+      EMIT(imm8);
+    } else {
+      emit_arith_b(0xF6, 0xC0, reg, imm8);
+    }
+  } else {
+    // This is not using emit_arith because test doesn't support
+    // sign-extension of 8-bit operands.
+    if (reg.is(eax)) {
+      EMIT(0xA9);
+    } else {
+      EMIT(0xF7);
+      EMIT(0xC0 | reg.code());
+    }
+    emit(imm);
+  }
+}
+
+
+void Assembler::test(Register reg, const Operand& op) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x85);
+  emit_operand(reg, op);
+}
+
+
+void Assembler::test(const Operand& op, const Immediate& imm) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF7);
+  emit_operand(eax, op);
+  emit(imm);
+}
+
+
+void Assembler::xor_(Register dst, int32_t imm32) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(6, Operand(dst), Immediate(imm32));
+}
+
+
+void Assembler::xor_(Register dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x33);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::xor_(const Operand& src, Register dst) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x31);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::xor_(const Operand& dst, const Immediate& x) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_arith(6, dst, x);
+}
+
+
+void Assembler::bts(const Operand& dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0xAB);
+  emit_operand(src, dst);
+}
+
+
+void Assembler::hlt() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF4);
+}
+
+
+void Assembler::int3() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xCC);
+}
+
+
+void Assembler::nop() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x90);
+}
+
+
+void Assembler::rdtsc() {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::RDTSC));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x0F);
+  EMIT(0x31);
+}
+
+
+void Assembler::ret(int imm16) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(is_uint16(imm16));
+  if (imm16 == 0) {
+    EMIT(0xC3);
+  } else {
+    EMIT(0xC2);
+    EMIT(imm16 & 0xFF);
+    EMIT((imm16 >> 8) & 0xFF);
+  }
+}
+
+
+void Assembler::leave() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xC9);
+}
+
+
+// Labels refer to positions in the (to be) generated code.
+// There are bound, linked, and unused labels.
+//
+// Bound labels refer to known positions in the already
+// generated code. pos() is the position the label refers to.
+//
+// Linked labels refer to unknown positions in the code
+// to be generated; pos() is the position of the 32bit
+// Displacement of the last instruction using the label.
+
+
+void Assembler::print(Label* L) {
+  if (L->is_unused()) {
+    PrintF("unused label\n");
+  } else if (L->is_bound()) {
+    PrintF("bound label to %d\n", L->pos());
+  } else if (L->is_linked()) {
+    Label l = *L;
+    PrintF("unbound label");
+    while (l.is_linked()) {
+      Displacement disp = disp_at(&l);
+      PrintF("@ %d ", l.pos());
+      disp.print();
+      PrintF("\n");
+      disp.next(&l);
+    }
+  } else {
+    PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
+  }
+}
+
+
+void Assembler::bind_to(Label* L, int pos) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = NULL;
+  ASSERT(0 <= pos && pos <= pc_offset());  // must have a valid binding position
+  while (L->is_linked()) {
+    Displacement disp = disp_at(L);
+    int fixup_pos = L->pos();
+    if (disp.type() == Displacement::UNCONDITIONAL_JUMP) {
+      ASSERT(byte_at(fixup_pos - 1) == 0xE9);  // jmp expected
+    }
+    // relative address, relative to point after address
+    int imm32 = pos - (fixup_pos + sizeof(int32_t));
+    long_at_put(fixup_pos, imm32);
+    disp.next(L);
+  }
+  L->bind_to(pos);
+}
+
+
+void Assembler::link_to(Label* L, Label* appendix) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = NULL;
+  if (appendix->is_linked()) {
+    if (L->is_linked()) {
+      // append appendix to L's list
+      Label p;
+      Label q = *L;
+      do {
+        p = q;
+        Displacement disp = disp_at(&q);
+        disp.next(&q);
+      } while (q.is_linked());
+      Displacement disp = disp_at(&p);
+      disp.link_to(appendix);
+      disp_at_put(&p, disp);
+      p.Unuse();  // to avoid assertion failure in ~Label
+    } else {
+      // L is empty, simply use appendix
+      *L = *appendix;
+    }
+  }
+  appendix->Unuse();  // appendix should not be used anymore
+}
+
+
+void Assembler::bind(Label* L) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = NULL;
+  ASSERT(!L->is_bound());  // label can only be bound once
+  bind_to(L, pc_offset());
+}
+
+
+void Assembler::call(Label* L) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (L->is_bound()) {
+    const int long_size = 5;
+    int offs = L->pos() - pc_offset();
+    ASSERT(offs <= 0);
+    // 1110 1000 #32-bit disp
+    EMIT(0xE8);
+    emit(offs - long_size);
+  } else {
+    // 1110 1000 #32-bit disp
+    EMIT(0xE8);
+    emit_disp(L, Displacement::OTHER);
+  }
+}
+
+
+void Assembler::call(byte* entry, RelocInfo::Mode rmode) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(!RelocInfo::IsCodeTarget(rmode));
+  EMIT(0xE8);
+  emit(entry - (pc_ + sizeof(int32_t)), rmode);
+}
+
+
+void Assembler::call(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFF);
+  emit_operand(edx, adr);
+}
+
+
+void Assembler::call(Handle<Code> code,  RelocInfo::Mode rmode) {
+  WriteRecordedPositions();
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  EMIT(0xE8);
+  emit(reinterpret_cast<intptr_t>(code.location()), rmode);
+}
+
+
+void Assembler::jmp(Label* L) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (L->is_bound()) {
+    const int short_size = 2;
+    const int long_size  = 5;
+    int offs = L->pos() - pc_offset();
+    ASSERT(offs <= 0);
+    if (is_int8(offs - short_size)) {
+      // 1110 1011 #8-bit disp
+      EMIT(0xEB);
+      EMIT((offs - short_size) & 0xFF);
+    } else {
+      // 1110 1001 #32-bit disp
+      EMIT(0xE9);
+      emit(offs - long_size);
+    }
+  } else {
+    // 1110 1001 #32-bit disp
+    EMIT(0xE9);
+    emit_disp(L, Displacement::UNCONDITIONAL_JUMP);
+  }
+}
+
+
+void Assembler::jmp(byte* entry, RelocInfo::Mode rmode) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(!RelocInfo::IsCodeTarget(rmode));
+  EMIT(0xE9);
+  emit(entry - (pc_ + sizeof(int32_t)), rmode);
+}
+
+
+void Assembler::jmp(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xFF);
+  emit_operand(esp, adr);
+}
+
+
+void Assembler::jmp(Handle<Code> code, RelocInfo::Mode rmode) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  EMIT(0xE9);
+  emit(reinterpret_cast<intptr_t>(code.location()), rmode);
+}
+
+
+
+void Assembler::j(Condition cc, Label* L, Hint hint) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(0 <= cc && cc < 16);
+  if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint);
+  if (L->is_bound()) {
+    const int short_size = 2;
+    const int long_size  = 6;
+    int offs = L->pos() - pc_offset();
+    ASSERT(offs <= 0);
+    if (is_int8(offs - short_size)) {
+      // 0111 tttn #8-bit disp
+      EMIT(0x70 | cc);
+      EMIT((offs - short_size) & 0xFF);
+    } else {
+      // 0000 1111 1000 tttn #32-bit disp
+      EMIT(0x0F);
+      EMIT(0x80 | cc);
+      emit(offs - long_size);
+    }
+  } else {
+    // 0000 1111 1000 tttn #32-bit disp
+    // Note: could eliminate cond. jumps to this jump if condition
+    //       is the same however, seems to be rather unlikely case.
+    EMIT(0x0F);
+    EMIT(0x80 | cc);
+    emit_disp(L, Displacement::OTHER);
+  }
+}
+
+
+void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT((0 <= cc) && (cc < 16));
+  if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint);
+  // 0000 1111 1000 tttn #32-bit disp
+  EMIT(0x0F);
+  EMIT(0x80 | cc);
+  emit(entry - (pc_ + sizeof(int32_t)), rmode);
+}
+
+
+void Assembler::j(Condition cc, Handle<Code> code, Hint hint) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (FLAG_emit_branch_hints && hint != no_hint) EMIT(hint);
+  // 0000 1111 1000 tttn #32-bit disp
+  EMIT(0x0F);
+  EMIT(0x80 | cc);
+  emit(reinterpret_cast<intptr_t>(code.location()), RelocInfo::CODE_TARGET);
+}
+
+
+// FPU instructions
+
+
+void Assembler::fld(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xD9, 0xC0, i);
+}
+
+
+void Assembler::fld1() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xE8);
+}
+
+
+void Assembler::fldz() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xEE);
+}
+
+
+void Assembler::fld_s(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  emit_operand(eax, adr);
+}
+
+
+void Assembler::fld_d(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDD);
+  emit_operand(eax, adr);
+}
+
+
+void Assembler::fstp_s(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  emit_operand(ebx, adr);
+}
+
+
+void Assembler::fstp_d(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDD);
+  emit_operand(ebx, adr);
+}
+
+
+void Assembler::fild_s(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDB);
+  emit_operand(eax, adr);
+}
+
+
+void Assembler::fild_d(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDF);
+  emit_operand(ebp, adr);
+}
+
+
+void Assembler::fistp_s(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDB);
+  emit_operand(ebx, adr);
+}
+
+
+void Assembler::fist_s(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDB);
+  emit_operand(edx, adr);
+}
+
+
+void Assembler::fistp_d(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDF);
+  emit_operand(edi, adr);
+}
+
+
+void Assembler::fabs() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xE1);
+}
+
+
+void Assembler::fchs() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xE0);
+}
+
+
+void Assembler::fadd(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDC, 0xC0, i);
+}
+
+
+void Assembler::fsub(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDC, 0xE8, i);
+}
+
+
+void Assembler::fisub_s(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDA);
+  emit_operand(esp, adr);
+}
+
+
+void Assembler::fmul(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDC, 0xC8, i);
+}
+
+
+void Assembler::fdiv(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDC, 0xF8, i);
+}
+
+
+void Assembler::faddp(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDE, 0xC0, i);
+}
+
+
+void Assembler::fsubp(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDE, 0xE8, i);
+}
+
+
+void Assembler::fsubrp(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDE, 0xE0, i);
+}
+
+
+void Assembler::fmulp(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDE, 0xC8, i);
+}
+
+
+void Assembler::fdivp(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDE, 0xF8, i);
+}
+
+
+void Assembler::fprem() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xF8);
+}
+
+
+void Assembler::fprem1() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xF5);
+}
+
+
+void Assembler::fxch(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xD9, 0xC8, i);
+}
+
+
+void Assembler::fincstp() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xF7);
+}
+
+
+void Assembler::ffree(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDD, 0xC0, i);
+}
+
+
+void Assembler::ftst() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xE4);
+}
+
+
+void Assembler::fucomp(int i) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_farith(0xDD, 0xE8, i);
+}
+
+
+void Assembler::fucompp() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDA);
+  EMIT(0xE9);
+}
+
+
+void Assembler::fcompp() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDE);
+  EMIT(0xD9);
+}
+
+
+void Assembler::fnstsw_ax() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xdF);
+  EMIT(0xE0);
+}
+
+
+void Assembler::fwait() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x9B);
+}
+
+
+void Assembler::frndint() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xD9);
+  EMIT(0xFC);
+}
+
+
+void Assembler::sahf() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x9E);
+}
+
+
+void Assembler::cvttss2si(Register dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x2C);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::cvttsd2si(Register dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x2C);
+  emit_operand(dst, src);
+}
+
+
+void Assembler::cvtsi2sd(XMMRegister dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x2A);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::addsd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x58);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x59);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::subsd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x5C);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::divsd(XMMRegister dst, XMMRegister src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);
+  EMIT(0x0F);
+  EMIT(0x5E);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::movdbl(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  movsd(dst, src);
+}
+
+
+void Assembler::movdbl(const Operand& dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  movsd(dst, src);
+}
+
+
+void Assembler::movsd(const Operand& dst, XMMRegister src ) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);  // double
+  EMIT(0x0F);
+  EMIT(0x11);  // store
+  emit_sse_operand(src, dst);
+}
+
+
+void Assembler::movsd(XMMRegister dst, const Operand& src) {
+  ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xF2);  // double
+  EMIT(0x0F);
+  EMIT(0x10);  // load
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
+  Register ireg = { reg.code() };
+  emit_operand(ireg, adr);
+}
+
+
+void Assembler::emit_sse_operand(XMMRegister dst, XMMRegister src) {
+  EMIT(0xC0 | dst.code() << 3 | src.code());
+}
+
+
+void Assembler::Print() {
+  Disassembler::Decode(stdout, buffer_, pc_);
+}
+
+
+void Assembler::RecordJSReturn() {
+  WriteRecordedPositions();
+  EnsureSpace ensure_space(this);
+  RecordRelocInfo(RelocInfo::JS_RETURN);
+}
+
+
+void Assembler::RecordComment(const char* msg) {
+  if (FLAG_debug_code) {
+    EnsureSpace ensure_space(this);
+    RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
+  }
+}
+
+
+void Assembler::RecordPosition(int pos) {
+  if (pos == RelocInfo::kNoPosition) return;
+  ASSERT(pos >= 0);
+  last_position_ = pos;
+}
+
+
+void Assembler::RecordStatementPosition(int pos) {
+  if (pos == RelocInfo::kNoPosition) return;
+  ASSERT(pos >= 0);
+  last_statement_position_ = pos;
+}
+
+
+void Assembler::WriteRecordedPositions() {
+  if (last_statement_position_ != RelocInfo::kNoPosition) {
+    EnsureSpace ensure_space(this);
+    RecordRelocInfo(RelocInfo::STATEMENT_POSITION, last_statement_position_);
+  }
+  if ((last_position_ != RelocInfo::kNoPosition) &&
+      (last_position_ != last_statement_position_)) {
+    EnsureSpace ensure_space(this);
+    RecordRelocInfo(RelocInfo::POSITION, last_position_);
+  }
+  last_statement_position_ = RelocInfo::kNoPosition;
+  last_position_ = RelocInfo::kNoPosition;
+}
+
+
+void Assembler::GrowBuffer() {
+  ASSERT(overflow());  // should not call this otherwise
+  if (!own_buffer_) FATAL("external code buffer is too small");
+
+  // compute new buffer size
+  CodeDesc desc;  // the new buffer
+  if (buffer_size_ < 4*KB) {
+    desc.buffer_size = 4*KB;
+  } else {
+    desc.buffer_size = 2*buffer_size_;
+  }
+  // Some internal data structures overflow for very large buffers,
+  // they must ensure that kMaximalBufferSize is not too large.
+  if ((desc.buffer_size > kMaximalBufferSize) ||
+      (desc.buffer_size > Heap::OldGenerationSize())) {
+    V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
+  }
+
+  // setup new buffer
+  desc.buffer = NewArray<byte>(desc.buffer_size);
+  desc.instr_size = pc_offset();
+  desc.reloc_size = (buffer_ + buffer_size_) - (reloc_info_writer.pos());
+
+  // Clear the buffer in debug mode. Use 'int3' instructions to make
+  // sure to get into problems if we ever run uninitialized code.
+  if (kDebug) {
+    memset(desc.buffer, 0xCC, desc.buffer_size);
+  }
+
+  // copy the data
+  int pc_delta = desc.buffer - buffer_;
+  int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
+  memmove(desc.buffer, buffer_, desc.instr_size);
+  memmove(rc_delta + reloc_info_writer.pos(),
+          reloc_info_writer.pos(), desc.reloc_size);
+
+  // switch buffers
+  if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
+    spare_buffer_ = buffer_;
+  } else {
+    DeleteArray(buffer_);
+  }
+  buffer_ = desc.buffer;
+  buffer_size_ = desc.buffer_size;
+  pc_ += pc_delta;
+  if (last_pc_ != NULL) {
+    last_pc_ += pc_delta;
+  }
+  reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
+                               reloc_info_writer.last_pc() + pc_delta);
+
+  // relocate runtime entries
+  for (RelocIterator it(desc); !it.done(); it.next()) {
+    RelocInfo::Mode rmode = it.rinfo()->rmode();
+    if (rmode == RelocInfo::RUNTIME_ENTRY) {
+      int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc());
+      *p -= pc_delta;  // relocate entry
+    } else if (rmode == RelocInfo::INTERNAL_REFERENCE) {
+      int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc());
+      if (*p != 0) {  // 0 means uninitialized.
+        *p += pc_delta;
+      }
+    }
+  }
+
+  ASSERT(!overflow());
+}
+
+
+void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) {
+  ASSERT(is_uint8(op1) && is_uint8(op2));  // wrong opcode
+  ASSERT(is_uint8(imm8));
+  ASSERT((op1 & 0x01) == 0);  // should be 8bit operation
+  EMIT(op1);
+  EMIT(op2 | dst.code());
+  EMIT(imm8);
+}
+
+
+void Assembler::emit_arith(int sel, Operand dst, const Immediate& x) {
+  ASSERT((0 <= sel) && (sel <= 7));
+  Register ireg = { sel };
+  if (x.is_int8()) {
+    EMIT(0x83);  // using a sign-extended 8-bit immediate.
+    emit_operand(ireg, dst);
+    EMIT(x.x_ & 0xFF);
+  } else if (dst.is_reg(eax)) {
+    EMIT((sel << 3) | 0x05);  // short form if the destination is eax.
+    emit(x);
+  } else {
+    EMIT(0x81);  // using a literal 32-bit immediate.
+    emit_operand(ireg, dst);
+    emit(x);
+  }
+}
+
+
+void Assembler::emit_operand(Register reg, const Operand& adr) {
+  adr.set_reg(reg);
+  memmove(pc_, adr.buf_, adr.len_);
+  pc_ += adr.len_;
+  if (adr.len_ >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) {
+    pc_ -= sizeof(int32_t);  // pc_ must be *at* disp32
+    RecordRelocInfo(adr.rmode_);
+    pc_ += sizeof(int32_t);
+  }
+}
+
+
+void Assembler::emit_operand(const Operand& adr, Register reg) {
+  adr.set_reg(reg);
+  memmove(pc_, adr.buf_, adr.len_);
+  pc_ += adr.len_;
+  if (adr.len_ >= sizeof(int32_t) && adr.rmode_ != RelocInfo::NONE) {
+    pc_ -= sizeof(int32_t);  // pc_ must be *at* disp32
+    RecordRelocInfo(adr.rmode_);
+    pc_ += sizeof(int32_t);
+  }
+}
+
+
+void Assembler::emit_farith(int b1, int b2, int i) {
+  ASSERT(is_uint8(b1) && is_uint8(b2));  // wrong opcode
+  ASSERT(0 <= i &&  i < 8);  // illegal stack offset
+  EMIT(b1);
+  EMIT(b2 + i);
+}
+
+
+void Assembler::dd(uint32_t data, RelocInfo::Mode reloc_info) {
+  EnsureSpace ensure_space(this);
+  emit(data, reloc_info);
+}
+
+
+void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
+  ASSERT(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;
+  }
+  RelocInfo rinfo(pc_, rmode, data);
+  reloc_info_writer.Write(&rinfo);
+}
+
+
+void Assembler::WriteInternalReference(int position, const Label& bound_label) {
+  ASSERT(bound_label.is_bound());
+  ASSERT(0 <= position);
+  ASSERT(position + static_cast<int>(sizeof(uint32_t)) <= pc_offset());
+  ASSERT(long_at(position) == 0);  // only initialize once!
+
+  uint32_t label_loc = reinterpret_cast<uint32_t>(addr_at(bound_label.pos()));
+  long_at_put(position, label_loc);
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/assembler-ia32.h b/regexp2000/src/assembler-ia32.h
new file mode 100644 (file)
index 0000000..8413104
--- /dev/null
@@ -0,0 +1,811 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+// A light-weight IA32 Assembler.
+
+#ifndef V8_ASSEMBLER_IA32_H_
+#define V8_ASSEMBLER_IA32_H_
+
+namespace v8 { namespace internal {
+
+// CPU Registers.
+//
+// 1) We would prefer to use an enum, but enum values are assignment-
+// compatible with int, which has caused code-generation bugs.
+//
+// 2) We would prefer to use a class instead of a struct but we don't like
+// the register initialization to depend on the particular initialization
+// order (which appears to be different on OS X, Linux, and Windows for the
+// installed versions of C++ we tried). Using a struct permits C-style
+// "initialization". Also, the Register objects cannot be const as this
+// forces initialization stubs in MSVC, making us dependent on initialization
+// order.
+//
+// 3) By not using an enum, we are possibly preventing the compiler from
+// doing certain constant folds, which may significantly reduce the
+// code generated for some assembly instructions (because they boil down
+// to a few constants). If this is a problem, we could change the code
+// such that we use an enum in optimized mode, and the struct in debug
+// mode. This way we get the compile-time error checking in debug mode
+// and best performance in optimized code.
+//
+struct Register {
+  bool is_valid() const  { return 0 <= code_ && code_ < 8; }
+  bool is(Register reg) const  { return code_ == reg.code_; }
+  int code() const  {
+    ASSERT(is_valid());
+    return code_;
+  }
+  int bit() const  {
+    ASSERT(is_valid());
+    return 1 << code_;
+  }
+
+  // (unfortunately we can't make this private in a struct)
+  int code_;
+};
+
+extern Register eax;
+extern Register ecx;
+extern Register edx;
+extern Register ebx;
+extern Register esp;
+extern Register ebp;
+extern Register esi;
+extern Register edi;
+extern Register no_reg;
+
+
+struct XMMRegister {
+  bool is_valid() const  { return 0 <= code_ && code_ < 2; }  // currently
+  int code() const  {
+    ASSERT(is_valid());
+    return code_;
+  }
+
+  int code_;
+};
+
+extern XMMRegister xmm0;
+extern XMMRegister xmm1;
+extern XMMRegister xmm2;
+extern XMMRegister xmm3;
+extern XMMRegister xmm4;
+extern XMMRegister xmm5;
+extern XMMRegister xmm6;
+extern XMMRegister xmm7;
+
+enum Condition {
+  // any value < 0 is considered no_condition
+  no_condition  = -1,
+
+  overflow      =  0,
+  no_overflow   =  1,
+  below         =  2,
+  above_equal   =  3,
+  equal         =  4,
+  not_equal     =  5,
+  below_equal   =  6,
+  above         =  7,
+  sign          =  8,
+  not_sign      =  9,
+  parity_even   = 10,
+  parity_odd    = 11,
+  less          = 12,
+  greater_equal = 13,
+  less_equal    = 14,
+  greater       = 15,
+
+  // aliases
+  zero          = equal,
+  not_zero      = not_equal,
+  negative      = sign,
+  positive      = not_sign
+};
+
+
+// Returns the equivalent of !cc.
+// Negation of the default no_condition (-1) results in a non-default
+// no_condition value (-2). As long as tests for no_condition check
+// for condition < 0, this will work as expected.
+inline Condition NegateCondition(Condition cc);
+
+// Corresponds to transposing the operands of a comparison.
+inline Condition ReverseCondition(Condition cc) {
+  switch (cc) {
+    case below:
+      return above;
+    case above:
+      return below;
+    case above_equal:
+      return below_equal;
+    case below_equal:
+      return above_equal;
+    case less:
+      return greater;
+    case greater:
+      return less;
+    case greater_equal:
+      return less_equal;
+    case less_equal:
+      return greater_equal;
+    default:
+      return cc;
+  };
+}
+
+enum Hint {
+  no_hint = 0,
+  not_taken = 0x2e,
+  taken = 0x3e
+};
+
+
+// -----------------------------------------------------------------------------
+// Machine instruction Immediates
+
+class Immediate BASE_EMBEDDED {
+ public:
+  inline explicit Immediate(int x);
+  inline explicit Immediate(const char* s);
+  inline explicit Immediate(const ExternalReference& ext);
+  inline explicit Immediate(Handle<Object> handle);
+  inline explicit Immediate(Smi* value);
+
+  bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
+  bool is_int8() const {
+    return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
+  }
+
+ private:
+  int x_;
+  RelocInfo::Mode rmode_;
+
+  friend class Assembler;
+};
+
+
+// -----------------------------------------------------------------------------
+// Machine instruction Operands
+
+enum ScaleFactor {
+  times_1 = 0,
+  times_2 = 1,
+  times_4 = 2,
+  times_8 = 3
+};
+
+
+class Operand BASE_EMBEDDED {
+ public:
+  // reg
+  INLINE(explicit Operand(Register reg));
+
+  // [disp/r]
+  INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode));
+  // disp only must always be relocated
+
+  // [base + disp/r]
+  explicit Operand(Register base, int32_t disp,
+                   RelocInfo::Mode rmode = RelocInfo::NONE);
+
+  // [base + index*scale + disp/r]
+  explicit Operand(Register base,
+                   Register index,
+                   ScaleFactor scale,
+                   int32_t disp,
+                   RelocInfo::Mode rmode = RelocInfo::NONE);
+
+  // [index*scale + disp/r]
+  explicit Operand(Register index,
+                   ScaleFactor scale,
+                   int32_t disp,
+                   RelocInfo::Mode rmode = RelocInfo::NONE);
+
+  static Operand StaticVariable(const ExternalReference& ext) {
+    return Operand(reinterpret_cast<int32_t>(ext.address()),
+                   RelocInfo::EXTERNAL_REFERENCE);
+  }
+
+  static Operand StaticArray(Register index,
+                             ScaleFactor scale,
+                             const ExternalReference& arr) {
+    return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()),
+                   RelocInfo::EXTERNAL_REFERENCE);
+  }
+
+  // Returns true if this Operand is a wrapper for the specified register.
+  bool is_reg(Register reg) const;
+
+ private:
+  // Mutable because reg in ModR/M byte is set by Assembler via set_reg().
+  mutable byte buf_[6];
+  // The number of bytes in buf_.
+  unsigned int len_;
+  // Only valid if len_ > 4.
+  RelocInfo::Mode rmode_;
+
+  inline void set_modrm(int mod,  // reg == 0
+                        Register rm);
+  inline void set_sib(ScaleFactor scale, Register index, Register base);
+  inline void set_disp8(int8_t disp);
+  inline void set_dispr(int32_t disp, RelocInfo::Mode rmode);
+  inline void set_reg(Register reg) const;
+
+  friend class Assembler;
+};
+
+
+// -----------------------------------------------------------------------------
+// A Displacement describes the 32bit immediate field of an instruction which
+// may be used together with a Label in order to refer to a yet unknown code
+// position. Displacements stored in the instruction stream are used to describe
+// the instruction and to chain a list of instructions using the same Label.
+// A Displacement contains 2 different fields:
+//
+// next field: position of next displacement in the chain (0 = end of list)
+// type field: instruction type
+//
+// A next value of null (0) indicates the end of a chain (note that there can
+// be no displacement at position zero, because there is always at least one
+// instruction byte before the displacement).
+//
+// Displacement _data field layout
+//
+// |31.....1| ......0|
+// [  next  |  type  |
+
+class Displacement BASE_EMBEDDED {
+ public:
+  enum Type {
+    UNCONDITIONAL_JUMP,
+    OTHER
+  };
+
+  int data() const { return data_; }
+  Type type() const { return TypeField::decode(data_); }
+  void next(Label* L) const {
+    int n = NextField::decode(data_);
+    n > 0 ? L->link_to(n) : L->Unuse();
+  }
+  void link_to(Label* L) { init(L, type()); }
+
+  explicit Displacement(int data) { data_ = data; }
+
+  Displacement(Label* L, Type type) { init(L, type); }
+
+  void print() {
+    PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"),
+                       NextField::decode(data_));
+  }
+
+ private:
+  int data_;
+
+  class TypeField: public BitField<Type, 0, 1> {};
+  class NextField: public BitField<int,  1, 32-1> {};
+
+  void init(Label* L, Type type);
+};
+
+
+
+// CpuFeatures keeps track of which features are supported by the target CPU.
+// Supported features must be enabled by a Scope before use.
+// Example:
+//   if (CpuFeatures::IsSupported(SSE2)) {
+//     CpuFeatures::Scope fscope(SSE2);
+//     // Generate SSE2 floating point code.
+//   } else {
+//     // Generate standard x87 floating point code.
+//   }
+class CpuFeatures : public AllStatic {
+ public:
+  // Feature flags bit positions. They are mostly based on the CPUID spec.
+  // (We assign CPUID itself to one of the currently reserved bits --
+  // feel free to change this if needed.)
+  enum Feature { SSE2 = 26, CMOV = 15, RDTSC = 4, CPUID = 10 };
+  // Detect features of the target CPU. Set safe defaults if the serializer
+  // is enabled (snapshots must be portable).
+  static void Probe();
+  // Check whether a feature is supported by the target CPU.
+  static bool IsSupported(Feature f) { return supported_ & (1 << f); }
+  // Check whether a feature is currently enabled.
+  static bool IsEnabled(Feature f) { return enabled_ & (1 << f); }
+  // Enable a specified feature within a scope.
+  class Scope BASE_EMBEDDED {
+#ifdef DEBUG
+   public:
+    explicit Scope(Feature f) {
+      ASSERT(CpuFeatures::IsSupported(f));
+      old_enabled_ = CpuFeatures::enabled_;
+      CpuFeatures::enabled_ |= (1 << f);
+    }
+    ~Scope() { CpuFeatures::enabled_ = old_enabled_; }
+   private:
+    uint32_t old_enabled_;
+#else
+   public:
+    explicit Scope(Feature f) {}
+#endif
+  };
+ private:
+  static uint32_t supported_;
+  static uint32_t enabled_;
+};
+
+
+class Assembler : public Malloced {
+ private:
+  // The relocation writer's position is kGap bytes below the end of
+  // the generated instructions. This leaves enough space for the
+  // longest possible ia32 instruction (17 bytes as of 9/26/06) and
+  // allows for a single, fast space check per instruction.
+  static const int kGap = 32;
+
+ public:
+  // Create an assembler. Instructions and relocation information are emitted
+  // into a buffer, with the instructions starting from the beginning and the
+  // relocation information starting from the end of the buffer. See CodeDesc
+  // for a detailed comment on the layout (globals.h).
+  //
+  // If the provided buffer is NULL, the assembler allocates and grows its own
+  // buffer, and buffer_size determines the initial buffer size. The buffer is
+  // owned by the assembler and deallocated upon destruction of the assembler.
+  //
+  // If the provided buffer is not NULL, the assembler uses the provided buffer
+  // for code generation and assumes its size to be buffer_size. If the buffer
+  // is too small, a fatal error occurs. No deallocation of the buffer is done
+  // upon destruction of the assembler.
+  Assembler(void* buffer, int buffer_size);
+  ~Assembler();
+
+  // GetCode emits any pending (non-emitted) code and fills the descriptor
+  // desc. GetCode() is idempotent; it returns the same result if no other
+  // Assembler functions are invoked inbetween GetCode() calls.
+  void GetCode(CodeDesc* desc);
+
+  // Read/Modify the code target in the branch/call instruction at pc.
+  inline static Address target_address_at(Address pc);
+  inline static void set_target_address_at(Address pc, Address target);
+
+  // Distance between the address of the code target in the call instruction
+  // and the return address
+  static const int kTargetAddrToReturnAddrDist = kPointerSize;
+
+
+  // ---------------------------------------------------------------------------
+  // Code generation
+  //
+  // - function names correspond one-to-one to ia32 instruction mnemonics
+  // - unless specified otherwise, instructions operate on 32bit operands
+  // - instructions on 8bit (byte) operands/registers have a trailing '_b'
+  // - instructions on 16bit (word) operands/registers have a trailing '_w'
+  // - naming conflicts with C++ keywords are resolved via a trailing '_'
+
+  // NOTE ON INTERFACE: Currently, the interface is not very consistent
+  // in the sense that some operations (e.g. mov()) can be called in more
+  // the one way to generate the same instruction: The Register argument
+  // can in some cases be replaced with an Operand(Register) argument.
+  // This should be cleaned up and made more othogonal. The questions
+  // is: should we always use Operands instead of Registers where an
+  // Operand is possible, or should we have a Register (overloaded) form
+  // instead? We must be carefull to make sure that the selected instruction
+  // is obvious from the parameters to avoid hard-to-find code generation
+  // bugs.
+
+  // Insert the smallest number of nop instructions
+  // possible to align the pc offset to a multiple
+  // of m. m must be a power of 2.
+  void Align(int m);
+
+  // Stack
+  void pushad();
+  void popad();
+
+  void pushfd();
+  void popfd();
+
+  void push(const Immediate& x);
+  void push(Register src);
+  void push(const Operand& src);
+
+  void pop(Register dst);
+  void pop(const Operand& dst);
+
+  // Moves
+  void mov_b(Register dst, const Operand& src);
+  void mov_b(const Operand& dst, int8_t imm8);
+  void mov_b(const Operand& dst, Register src);
+
+  void mov_w(Register dst, const Operand& src);
+  void mov_w(const Operand& dst, Register src);
+
+  void mov(Register dst, int32_t imm32);
+  void mov(Register dst, Handle<Object> handle);
+  void mov(Register dst, const Operand& src);
+  void mov(const Operand& dst, const Immediate& x);
+  void mov(const Operand& dst, Handle<Object> handle);
+  void mov(const Operand& dst, Register src);
+
+  void movsx_b(Register dst, const Operand& src);
+
+  void movsx_w(Register dst, const Operand& src);
+
+  void movzx_b(Register dst, const Operand& src);
+
+  void movzx_w(Register dst, const Operand& src);
+
+  // Conditional moves
+  void cmov(Condition cc, Register dst, int32_t imm32);
+  void cmov(Condition cc, Register dst, Handle<Object> handle);
+  void cmov(Condition cc, Register dst, const Operand& src);
+
+  // Arithmetics
+  void adc(Register dst, int32_t imm32);
+  void adc(Register dst, const Operand& src);
+
+  void add(Register dst, const Operand& src);
+  void add(const Operand& dst, const Immediate& x);
+
+  void and_(Register dst, int32_t imm32);
+  void and_(Register dst, const Operand& src);
+  void and_(const Operand& src, Register dst);
+  void and_(const Operand& dst, const Immediate& x);
+
+  void cmp(Register reg, int32_t imm32);
+  void cmp(Register reg, Handle<Object> handle);
+  void cmp(Register reg, const Operand& op);
+  void cmp(const Operand& op, const Immediate& imm);
+
+  void dec_b(Register dst);
+
+  void dec(Register dst);
+  void dec(const Operand& dst);
+
+  void cdq();
+
+  void idiv(Register src);
+
+  void imul(Register dst, const Operand& src);
+  void imul(Register dst, Register src, int32_t imm32);
+
+  void inc(Register dst);
+  void inc(const Operand& dst);
+
+  void lea(Register dst, const Operand& src);
+
+  void mul(Register src);
+
+  void neg(Register dst);
+
+  void not_(Register dst);
+
+  void or_(Register dst, int32_t imm32);
+  void or_(Register dst, const Operand& src);
+  void or_(const Operand& dst, Register src);
+  void or_(const Operand& dst, const Immediate& x);
+
+  void rcl(Register dst, uint8_t imm8);
+
+  void sar(Register dst, uint8_t imm8);
+  void sar(Register dst);
+
+  void sbb(Register dst, const Operand& src);
+
+  void shld(Register dst, const Operand& src);
+
+  void shl(Register dst, uint8_t imm8);
+  void shl(Register dst);
+
+  void shrd(Register dst, const Operand& src);
+
+  void shr(Register dst, uint8_t imm8);
+  void shr(Register dst);
+
+  void sub(const Operand& dst, const Immediate& x);
+  void sub(Register dst, const Operand& src);
+  void sub(const Operand& dst, Register src);
+
+  void test(Register reg, const Immediate& imm);
+  void test(Register reg, const Operand& op);
+  void test(const Operand& op, const Immediate& imm);
+
+  void xor_(Register dst, int32_t imm32);
+  void xor_(Register dst, const Operand& src);
+  void xor_(const Operand& src, Register dst);
+  void xor_(const Operand& dst, const Immediate& x);
+
+  // Bit operations.
+  void bts(const Operand& dst, Register src);
+
+  // Miscellaneous
+  void hlt();
+  void int3();
+  void nop();
+  void rdtsc();
+  void ret(int imm16);
+  void leave();
+
+  // Label operations & relative jumps (PPUM Appendix D)
+  //
+  // Takes a branch opcode (cc) and a label (L) and generates
+  // either a backward branch or a forward branch and links it
+  // to the label fixup chain. Usage:
+  //
+  // Label L;    // unbound label
+  // j(cc, &L);  // forward branch to unbound label
+  // bind(&L);   // bind label to the current pc
+  // j(cc, &L);  // backward branch to bound label
+  // bind(&L);   // illegal: a label may be bound only once
+  //
+  // Note: The same Label can be used for forward and backward branches
+  // but it may be bound only once.
+
+  void bind(Label* L);  // binds an unbound label L to the current code position
+
+  // Calls
+  void call(Label* L);
+  void call(byte* entry, RelocInfo::Mode rmode);
+  void call(const Operand& adr);
+  void call(Handle<Code> code, RelocInfo::Mode rmode);
+
+  // Jumps
+  void jmp(Label* L);  // unconditional jump to L
+  void jmp(byte* entry, RelocInfo::Mode rmode);
+  void jmp(const Operand& adr);
+  void jmp(Handle<Code> code, RelocInfo::Mode rmode);
+
+  // Conditional jumps
+  void j(Condition cc, Label* L, Hint hint = no_hint);
+  void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint);
+  void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
+
+  // Floating-point operations
+  void fld(int i);
+
+  void fld1();
+  void fldz();
+
+  void fld_s(const Operand& adr);
+  void fld_d(const Operand& adr);
+
+  void fstp_s(const Operand& adr);
+  void fstp_d(const Operand& adr);
+
+  void fild_s(const Operand& adr);
+  void fild_d(const Operand& adr);
+
+  void fist_s(const Operand& adr);
+
+  void fistp_s(const Operand& adr);
+  void fistp_d(const Operand& adr);
+
+  void fabs();
+  void fchs();
+
+  void fadd(int i);
+  void fsub(int i);
+  void fmul(int i);
+  void fdiv(int i);
+
+  void fisub_s(const Operand& adr);
+
+  void faddp(int i = 1);
+  void fsubp(int i = 1);
+  void fsubrp(int i = 1);
+  void fmulp(int i = 1);
+  void fdivp(int i = 1);
+  void fprem();
+  void fprem1();
+
+  void fxch(int i = 1);
+  void fincstp();
+  void ffree(int i = 0);
+
+  void ftst();
+  void fucomp(int i);
+  void fucompp();
+  void fcompp();
+  void fnstsw_ax();
+  void fwait();
+
+  void frndint();
+
+  void sahf();
+
+  void cpuid();
+
+  // SSE2 instructions
+  void cvttss2si(Register dst, const Operand& src);
+  void cvttsd2si(Register dst, const Operand& src);
+
+  void cvtsi2sd(XMMRegister dst, const Operand& src);
+
+  void addsd(XMMRegister dst, XMMRegister src);
+  void subsd(XMMRegister dst, XMMRegister src);
+  void mulsd(XMMRegister dst, XMMRegister src);
+  void divsd(XMMRegister dst, XMMRegister src);
+
+  // Use either movsd or movlpd.
+  void movdbl(XMMRegister dst, const Operand& src);
+  void movdbl(const Operand& dst, XMMRegister src);
+
+  // Debugging
+  void Print();
+
+  // Check the code size generated from label to here.
+  int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); }
+
+  // Mark address of the ExitJSFrame code.
+  void RecordJSReturn();
+
+  // Record a comment relocation entry that can be used by a disassembler.
+  // Use --debug_code to enable.
+  void RecordComment(const char* msg);
+
+  void RecordPosition(int pos);
+  void RecordStatementPosition(int pos);
+  void WriteRecordedPositions();
+
+  // Writes a single word of data in the code stream.
+  // Used for inline tables, e.g., jump-tables.
+  void dd(uint32_t data, RelocInfo::Mode reloc_info);
+
+  // Writes the absolute address of a bound label at the given position in
+  // the generated code. That positions should have the relocation mode
+  // internal_reference!
+  void WriteInternalReference(int position, const Label& bound_label);
+
+  int pc_offset() const  { return pc_ - buffer_; }
+  int last_statement_position() const  { return last_statement_position_; }
+  int last_position() const  { return last_position_; }
+
+  // Check if there is less than kGap bytes available in the buffer.
+  // If this is the case, we need to grow the buffer before emitting
+  // an instruction or relocation information.
+  inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
+
+  // Get the number of bytes available in the buffer.
+  inline int available_space() const { return reloc_info_writer.pos() - pc_; }
+
+  // Avoid overflows for displacements etc.
+  static const int kMaximalBufferSize = 512*MB;
+  static const int kMinimalBufferSize = 4*KB;
+
+ protected:
+  void movsd(XMMRegister dst, const Operand& src);
+  void movsd(const Operand& dst, XMMRegister src);
+
+  void emit_sse_operand(XMMRegister reg, const Operand& adr);
+  void emit_sse_operand(XMMRegister dst, XMMRegister src);
+
+
+ private:
+  // Code buffer:
+  // The buffer into which code and relocation info are generated.
+  byte* buffer_;
+  int buffer_size_;
+  // True if the assembler owns the buffer, false if buffer is external.
+  bool own_buffer_;
+
+  // code generation
+  byte* pc_;  // the program counter; moves forward
+  RelocInfoWriter reloc_info_writer;
+
+  // push-pop elimination
+  byte* last_pc_;
+
+  // source position information
+  int last_position_;
+  int last_statement_position_;
+
+  byte* addr_at(int pos)  { return buffer_ + pos; }
+  byte byte_at(int pos)  { return buffer_[pos]; }
+  uint32_t long_at(int pos)  {
+    return *reinterpret_cast<uint32_t*>(addr_at(pos));
+  }
+  void long_at_put(int pos, uint32_t x)  {
+    *reinterpret_cast<uint32_t*>(addr_at(pos)) = x;
+  }
+
+  // code emission
+  void GrowBuffer();
+  inline void emit(uint32_t x);
+  inline void emit(Handle<Object> handle);
+  inline void emit(uint32_t x, RelocInfo::Mode rmode);
+  inline void emit(const Immediate& x);
+
+  // instruction generation
+  void emit_arith_b(int op1, int op2, Register dst, int imm8);
+
+  // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81)
+  // with a given destination expression and an immediate operand.  It attempts
+  // to use the shortest encoding possible.
+  // sel specifies the /n in the modrm byte (see the Intel PRM).
+  void emit_arith(int sel, Operand dst, const Immediate& x);
+
+  void emit_operand(Register reg, const Operand& adr);
+  void emit_operand(const Operand& adr, Register reg);
+
+  void emit_farith(int b1, int b2, int i);
+
+  // labels
+  void print(Label* L);
+  void bind_to(Label* L, int pos);
+  void link_to(Label* L, Label* appendix);
+
+  // displacements
+  inline Displacement disp_at(Label* L);
+  inline void disp_at_put(Label* L, Displacement disp);
+  inline void emit_disp(Label* L, Displacement::Type type);
+
+  // record reloc info for current pc_
+  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+
+  friend class CodePatcher;
+  friend class EnsureSpace;
+};
+
+
+// Helper class that ensures that there is enough space for generating
+// instructions and relocation information.  The constructor makes
+// sure that there is enough space and (in debug mode) the destructor
+// checks that we did not generate too much.
+class EnsureSpace BASE_EMBEDDED {
+ public:
+  explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) {
+    if (assembler_->overflow()) assembler_->GrowBuffer();
+#ifdef DEBUG
+    space_before_ = assembler_->available_space();
+#endif
+  }
+
+#ifdef DEBUG
+  ~EnsureSpace() {
+    int bytes_generated = space_before_ - assembler_->available_space();
+    ASSERT(bytes_generated < assembler_->kGap);
+  }
+#endif
+
+ private:
+  Assembler* assembler_;
+#ifdef DEBUG
+  int space_before_;
+#endif
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ASSEMBLER_IA32_H_
diff --git a/regexp2000/src/assembler.cc b/regexp2000/src/assembler.cc
new file mode 100644 (file)
index 0000000..a2930f1
--- /dev/null
@@ -0,0 +1,575 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+#include "v8.h"
+
+#include "arguments.h"
+#include "execution.h"
+#include "ic-inl.h"
+#include "factory.h"
+#include "runtime.h"
+#include "serialize.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+
+// -----------------------------------------------------------------------------
+// Implementation of Label
+
+int Label::pos() const {
+  if (pos_ < 0) return -pos_ - 1;
+  if (pos_ > 0) return  pos_ - 1;
+  UNREACHABLE();
+  return 0;
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of RelocInfoWriter and RelocIterator
+//
+// Encoding
+//
+// The most common modes are given single-byte encodings.  Also, it is
+// easy to identify the type of reloc info and skip unwanted modes in
+// an iteration.
+//
+// The encoding relies on the fact that there are less than 14
+// different relocation modes.
+//
+// embedded_object:    [6 bits pc delta] 00
+//
+// code_taget:         [6 bits pc delta] 01
+//
+// position:           [6 bits pc delta] 10,
+//                     [7 bits signed data delta] 0
+//
+// statement_position: [6 bits pc delta] 10,
+//                     [7 bits signed data delta] 1
+//
+// any nondata mode:   00 [4 bits rmode] 11,  // rmode: 0..13 only
+//                     00 [6 bits pc delta]
+//
+// pc-jump:            00 1111 11,
+//                     00 [6 bits pc delta]
+//
+// pc-jump:            01 1111 11,
+// (variable length)   7 - 26 bit pc delta, written in chunks of 7
+//                     bits, the lowest 7 bits written first.
+//
+// data-jump + pos:    00 1110 11,
+//                     signed int, lowest byte written first
+//
+// data-jump + st.pos: 01 1110 11,
+//                     signed int, lowest byte written first
+//
+// data-jump + comm.:  10 1110 11,
+//                     signed int, lowest byte written first
+//
+const int kMaxRelocModes = 14;
+
+const int kTagBits = 2;
+const int kTagMask = (1 << kTagBits) - 1;
+const int kExtraTagBits = 4;
+const int kPositionTypeTagBits = 1;
+const int kSmallDataBits = kBitsPerByte - kPositionTypeTagBits;
+
+const int kEmbeddedObjectTag = 0;
+const int kCodeTargetTag = 1;
+const int kPositionTag = 2;
+const int kDefaultTag = 3;
+
+const int kPCJumpTag = (1 << kExtraTagBits) - 1;
+
+const int kSmallPCDeltaBits = kBitsPerByte - kTagBits;
+const int kSmallPCDeltaMask = (1 << kSmallPCDeltaBits) - 1;
+
+const int kVariableLengthPCJumpTopTag = 1;
+const int kChunkBits = 7;
+const int kChunkMask = (1 << kChunkBits) - 1;
+const int kLastChunkTagBits = 1;
+const int kLastChunkTagMask = 1;
+const int kLastChunkTag = 1;
+
+
+const int kDataJumpTag = kPCJumpTag - 1;
+
+const int kNonstatementPositionTag = 0;
+const int kStatementPositionTag = 1;
+const int kCommentTag = 2;
+
+
+uint32_t RelocInfoWriter::WriteVariableLengthPCJump(uint32_t pc_delta) {
+  // Return if the pc_delta can fit in kSmallPCDeltaBits bits.
+  // Otherwise write a variable length PC jump for the bits that do
+  // not fit in the kSmallPCDeltaBits bits.
+  if (is_uintn(pc_delta, kSmallPCDeltaBits)) return pc_delta;
+  WriteExtraTag(kPCJumpTag, kVariableLengthPCJumpTopTag);
+  uint32_t pc_jump = pc_delta >> kSmallPCDeltaBits;
+  ASSERT(pc_jump > 0);
+  // Write kChunkBits size chunks of the pc_jump.
+  for (; pc_jump > 0; pc_jump = pc_jump >> kChunkBits) {
+    byte b = pc_jump & kChunkMask;
+    *--pos_ = b << kLastChunkTagBits;
+  }
+  // Tag the last chunk so it can be identified.
+  *pos_ = *pos_ | kLastChunkTag;
+  // Return the remaining kSmallPCDeltaBits of the pc_delta.
+  return pc_delta & kSmallPCDeltaMask;
+}
+
+
+void RelocInfoWriter::WriteTaggedPC(uint32_t pc_delta, int tag) {
+  // Write a byte of tagged pc-delta, possibly preceded by var. length pc-jump.
+  pc_delta = WriteVariableLengthPCJump(pc_delta);
+  *--pos_ = pc_delta << kTagBits | tag;
+}
+
+
+void RelocInfoWriter::WriteTaggedData(int32_t data_delta, int tag) {
+  *--pos_ = data_delta << kPositionTypeTagBits | tag;
+}
+
+
+void RelocInfoWriter::WriteExtraTag(int extra_tag, int top_tag) {
+  *--pos_ = top_tag << (kTagBits + kExtraTagBits) |
+            extra_tag << kTagBits |
+            kDefaultTag;
+}
+
+
+void RelocInfoWriter::WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag) {
+  // Write two-byte tagged pc-delta, possibly preceded by var. length pc-jump.
+  pc_delta = WriteVariableLengthPCJump(pc_delta);
+  WriteExtraTag(extra_tag, 0);
+  *--pos_ = pc_delta;
+}
+
+
+void RelocInfoWriter::WriteExtraTaggedData(int32_t data_delta, int top_tag) {
+  WriteExtraTag(kDataJumpTag, top_tag);
+  for (int i = 0; i < kIntSize; i++) {
+    *--pos_ = data_delta;
+    data_delta = ArithmeticShiftRight(data_delta, kBitsPerByte);
+  }
+}
+
+
+void RelocInfoWriter::Write(const RelocInfo* rinfo) {
+#ifdef DEBUG
+  byte* begin_pos = pos_;
+#endif
+  Counters::reloc_info_count.Increment();
+  ASSERT(rinfo->pc() - last_pc_ >= 0);
+  ASSERT(RelocInfo::NUMBER_OF_MODES < kMaxRelocModes);
+  // Use unsigned delta-encoding for pc.
+  uint32_t pc_delta = rinfo->pc() - last_pc_;
+  RelocInfo::Mode rmode = rinfo->rmode();
+
+  // The two most common modes are given small tags, and usually fit in a byte.
+  if (rmode == RelocInfo::EMBEDDED_OBJECT) {
+    WriteTaggedPC(pc_delta, kEmbeddedObjectTag);
+  } else if (rmode == RelocInfo::CODE_TARGET) {
+    WriteTaggedPC(pc_delta, kCodeTargetTag);
+  } else if (RelocInfo::IsPosition(rmode)) {
+    // Use signed delta-encoding for data.
+    int32_t data_delta = rinfo->data() - last_data_;
+    int pos_type_tag = rmode == RelocInfo::POSITION ? kNonstatementPositionTag
+                                                    : kStatementPositionTag;
+    // Check if data is small enough to fit in a tagged byte.
+    if (is_intn(data_delta, kSmallDataBits)) {
+      WriteTaggedPC(pc_delta, kPositionTag);
+      WriteTaggedData(data_delta, pos_type_tag);
+      last_data_ = rinfo->data();
+    } else {
+      // Otherwise, use costly encoding.
+      WriteExtraTaggedPC(pc_delta, kPCJumpTag);
+      WriteExtraTaggedData(data_delta, pos_type_tag);
+      last_data_ = rinfo->data();
+    }
+  } else if (RelocInfo::IsComment(rmode)) {
+    // Comments are normally not generated, so we use the costly encoding.
+    WriteExtraTaggedPC(pc_delta, kPCJumpTag);
+    WriteExtraTaggedData(rinfo->data() - last_data_, kCommentTag);
+    last_data_ = rinfo->data();
+  } else {
+    // For all other modes we simply use the mode as the extra tag.
+    // None of these modes need a data component.
+    ASSERT(rmode < kPCJumpTag && rmode < kDataJumpTag);
+    WriteExtraTaggedPC(pc_delta, rmode);
+  }
+  last_pc_ = rinfo->pc();
+#ifdef DEBUG
+  ASSERT(begin_pos - pos_ <= kMaxSize);
+#endif
+}
+
+
+inline int RelocIterator::AdvanceGetTag() {
+  return *--pos_ & kTagMask;
+}
+
+
+inline int RelocIterator::GetExtraTag() {
+  return (*pos_ >> kTagBits) & ((1 << kExtraTagBits) - 1);
+}
+
+
+inline int RelocIterator::GetTopTag() {
+  return *pos_ >> (kTagBits + kExtraTagBits);
+}
+
+
+inline void RelocIterator::ReadTaggedPC() {
+  rinfo_.pc_ += *pos_ >> kTagBits;
+}
+
+
+inline void RelocIterator::AdvanceReadPC() {
+  rinfo_.pc_ += *--pos_;
+}
+
+
+void RelocIterator::AdvanceReadData() {
+  int32_t x = 0;
+  for (int i = 0; i < kIntSize; i++) {
+    x |= *--pos_ << i * kBitsPerByte;
+  }
+  rinfo_.data_ += x;
+}
+
+
+void RelocIterator::AdvanceReadVariableLengthPCJump() {
+  // Read the 32-kSmallPCDeltaBits most significant bits of the
+  // pc jump in kChunkBits bit chunks and shift them into place.
+  // Stop when the last chunk is encountered.
+  uint32_t pc_jump = 0;
+  for (int i = 0; i < kIntSize; i++) {
+    byte pc_jump_part = *--pos_;
+    pc_jump |= (pc_jump_part >> kLastChunkTagBits) << i * kChunkBits;
+    if ((pc_jump_part & kLastChunkTagMask) == 1) break;
+  }
+  // The least significant kSmallPCDeltaBits bits will be added
+  // later.
+  rinfo_.pc_ += pc_jump << kSmallPCDeltaBits;
+}
+
+
+inline int RelocIterator::GetPositionTypeTag() {
+  return *pos_ & ((1 << kPositionTypeTagBits) - 1);
+}
+
+
+inline void RelocIterator::ReadTaggedData() {
+  int8_t signed_b = *pos_;
+  rinfo_.data_ += ArithmeticShiftRight(signed_b, kPositionTypeTagBits);
+}
+
+
+inline RelocInfo::Mode RelocIterator::DebugInfoModeFromTag(int tag) {
+  if (tag == kStatementPositionTag) {
+    return RelocInfo::STATEMENT_POSITION;
+  } else if (tag == kNonstatementPositionTag) {
+    return RelocInfo::POSITION;
+  } else {
+    ASSERT(tag == kCommentTag);
+    return RelocInfo::COMMENT;
+  }
+}
+
+
+void RelocIterator::next() {
+  ASSERT(!done());
+  // Basically, do the opposite of RelocInfoWriter::Write.
+  // Reading of data is as far as possible avoided for unwanted modes,
+  // but we must always update the pc.
+  //
+  // We exit this loop by returning when we find a mode we want.
+  while (pos_ > end_) {
+    int tag = AdvanceGetTag();
+    if (tag == kEmbeddedObjectTag) {
+      ReadTaggedPC();
+      if (SetMode(RelocInfo::EMBEDDED_OBJECT)) return;
+    } else if (tag == kCodeTargetTag) {
+      ReadTaggedPC();
+      if (*(reinterpret_cast<int*>(rinfo_.pc())) == 0x61) {
+        tag = 0;
+      }
+      if (SetMode(RelocInfo::CODE_TARGET)) return;
+    } else if (tag == kPositionTag) {
+      ReadTaggedPC();
+      Advance();
+      // Check if we want source positions.
+      if (mode_mask_ & RelocInfo::kPositionMask) {
+        // Check if we want this type of source position.
+        if (SetMode(DebugInfoModeFromTag(GetPositionTypeTag()))) {
+          // Finally read the data before returning.
+          ReadTaggedData();
+          return;
+        }
+      }
+    } else {
+      ASSERT(tag == kDefaultTag);
+      int extra_tag = GetExtraTag();
+      if (extra_tag == kPCJumpTag) {
+        int top_tag = GetTopTag();
+        if (top_tag == kVariableLengthPCJumpTopTag) {
+          AdvanceReadVariableLengthPCJump();
+        } else {
+          AdvanceReadPC();
+        }
+      } else if (extra_tag == kDataJumpTag) {
+        // Check if we want debug modes (the only ones with data).
+        if (mode_mask_ & RelocInfo::kDebugMask) {
+          int top_tag = GetTopTag();
+          AdvanceReadData();
+          if (SetMode(DebugInfoModeFromTag(top_tag))) return;
+        } else {
+          // Otherwise, just skip over the data.
+          Advance(kIntSize);
+        }
+      } else {
+        AdvanceReadPC();
+        if (SetMode(static_cast<RelocInfo::Mode>(extra_tag))) return;
+      }
+    }
+  }
+  done_ = true;
+}
+
+
+RelocIterator::RelocIterator(Code* code, int mode_mask) {
+  rinfo_.pc_ = code->instruction_start();
+  rinfo_.data_ = 0;
+  // relocation info is read backwards
+  pos_ = code->relocation_start() + code->relocation_size();
+  end_ = code->relocation_start();
+  done_ = false;
+  mode_mask_ = mode_mask;
+  if (mode_mask_ == 0) pos_ = end_;
+  next();
+}
+
+
+RelocIterator::RelocIterator(const CodeDesc& desc, int mode_mask) {
+  rinfo_.pc_ = desc.buffer;
+  rinfo_.data_ = 0;
+  // relocation info is read backwards
+  pos_ = desc.buffer + desc.buffer_size;
+  end_ = pos_ - desc.reloc_size;
+  done_ = false;
+  mode_mask_ = mode_mask;
+  if (mode_mask_ == 0) pos_ = end_;
+  next();
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of RelocInfo
+
+
+#ifdef ENABLE_DISASSEMBLER
+const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
+  switch (rmode) {
+    case RelocInfo::NONE:
+      return "no reloc";
+    case RelocInfo::EMBEDDED_OBJECT:
+      return "embedded object";
+    case RelocInfo::EMBEDDED_STRING:
+      return "embedded string";
+    case RelocInfo::CONSTRUCT_CALL:
+      return "code target (js construct call)";
+    case RelocInfo::CODE_TARGET_CONTEXT:
+      return "code target (context)";
+    case RelocInfo::CODE_TARGET:
+      return "code target";
+    case RelocInfo::RUNTIME_ENTRY:
+      return "runtime entry";
+    case RelocInfo::JS_RETURN:
+      return "js return";
+    case RelocInfo::COMMENT:
+      return "comment";
+    case RelocInfo::POSITION:
+      return "position";
+    case RelocInfo::STATEMENT_POSITION:
+      return "statement position";
+    case RelocInfo::EXTERNAL_REFERENCE:
+      return "external reference";
+    case RelocInfo::INTERNAL_REFERENCE:
+      return "internal reference";
+    case RelocInfo::NUMBER_OF_MODES:
+      UNREACHABLE();
+      return "number_of_modes";
+  }
+  return "unknown relocation type";
+}
+
+
+void RelocInfo::Print() {
+  PrintF("%p  %s", pc_, RelocModeName(rmode_));
+  if (IsComment(rmode_)) {
+    PrintF("  (%s)", data_);
+  } else if (rmode_ == EMBEDDED_OBJECT) {
+    PrintF("  (");
+    target_object()->ShortPrint();
+    PrintF(")");
+  } else if (rmode_ == EXTERNAL_REFERENCE) {
+    ExternalReferenceEncoder ref_encoder;
+    PrintF(" (%s)  (%p)",
+           ref_encoder.NameOfAddress(*target_reference_address()),
+           *target_reference_address());
+  } else if (IsCodeTarget(rmode_)) {
+    Code* code = Debug::GetCodeTarget(target_address());
+    PrintF(" (%s)  (%p)", Code::Kind2String(code->kind()), target_address());
+  } else if (IsPosition(rmode_)) {
+    PrintF("  (%d)", data());
+  }
+
+  PrintF("\n");
+}
+#endif  // ENABLE_DISASSEMBLER
+
+
+#ifdef DEBUG
+void RelocInfo::Verify() {
+  switch (rmode_) {
+    case EMBEDDED_OBJECT:
+      Object::VerifyPointer(target_object());
+      break;
+    case CONSTRUCT_CALL:
+    case CODE_TARGET_CONTEXT:
+    case CODE_TARGET: {
+      // convert inline target address to code object
+      Address addr = target_address();
+      ASSERT(addr != NULL);
+      // Check that we can find the right code object.
+      HeapObject* code = HeapObject::FromAddress(addr - Code::kHeaderSize);
+      Object* found = Heap::FindCodeObject(addr);
+      ASSERT(found->IsCode());
+      ASSERT(code->address() == HeapObject::cast(found)->address());
+      break;
+    }
+    case RelocInfo::EMBEDDED_STRING:
+    case RUNTIME_ENTRY:
+    case JS_RETURN:
+    case COMMENT:
+    case POSITION:
+    case STATEMENT_POSITION:
+    case EXTERNAL_REFERENCE:
+    case INTERNAL_REFERENCE:
+    case NONE:
+      break;
+    case NUMBER_OF_MODES:
+      UNREACHABLE();
+      break;
+  }
+}
+#endif  // DEBUG
+
+
+// -----------------------------------------------------------------------------
+// Implementation of ExternalReference
+
+ExternalReference::ExternalReference(Builtins::CFunctionId id)
+  : address_(Builtins::c_function_address(id)) {}
+
+
+ExternalReference::ExternalReference(Builtins::Name name)
+  : address_(Builtins::builtin_address(name)) {}
+
+
+ExternalReference::ExternalReference(Runtime::FunctionId id)
+  : address_(Runtime::FunctionForId(id)->entry) {}
+
+
+ExternalReference::ExternalReference(Runtime::Function* f)
+  : address_(f->entry) {}
+
+
+ExternalReference::ExternalReference(const IC_Utility& ic_utility)
+  : address_(ic_utility.address()) {}
+
+
+ExternalReference::ExternalReference(const Debug_Address& debug_address)
+  : address_(debug_address.address()) {}
+
+
+ExternalReference::ExternalReference(StatsCounter* counter)
+  : address_(reinterpret_cast<Address>(counter->GetInternalPointer())) {}
+
+
+ExternalReference::ExternalReference(Top::AddressId id)
+  : address_(Top::get_address_from_id(id)) {}
+
+
+ExternalReference::ExternalReference(const SCTableReference& table_ref)
+  : address_(table_ref.address()) {}
+
+
+ExternalReference ExternalReference::builtin_passed_function() {
+  return ExternalReference(&Builtins::builtin_passed_function);
+}
+
+ExternalReference ExternalReference::the_hole_value_location() {
+  return ExternalReference(Factory::the_hole_value().location());
+}
+
+
+ExternalReference ExternalReference::address_of_stack_guard_limit() {
+  return ExternalReference(StackGuard::address_of_jslimit());
+}
+
+
+ExternalReference ExternalReference::debug_break() {
+  return ExternalReference(FUNCTION_ADDR(Debug::Break));
+}
+
+
+ExternalReference ExternalReference::new_space_start() {
+  return ExternalReference(Heap::NewSpaceStart());
+}
+
+ExternalReference ExternalReference::new_space_allocation_top_address() {
+  return ExternalReference(Heap::NewSpaceAllocationTopAddress());
+}
+
+ExternalReference ExternalReference::new_space_allocation_limit_address() {
+  return ExternalReference(Heap::NewSpaceAllocationLimitAddress());
+}
+
+ExternalReference ExternalReference::debug_step_in_fp_address() {
+  return ExternalReference(Debug::step_in_fp_addr());
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/assembler.h b/regexp2000/src/assembler.h
new file mode 100644 (file)
index 0000000..137c37c
--- /dev/null
@@ -0,0 +1,476 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// 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.
+//
+// - Redistribution 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 Sun Microsystems or the names of 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.
+
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+#ifndef V8_ASSEMBLER_H_
+#define V8_ASSEMBLER_H_
+
+#include "runtime.h"
+#include "top.h"
+#include "zone-inl.h"
+
+namespace v8 { namespace internal {
+
+
+// -----------------------------------------------------------------------------
+// Labels represent pc locations; they are typically jump or call targets.
+// After declaration, a label can be freely used to denote known or (yet)
+// unknown pc location. Assembler::bind() is used to bind a label to the
+// current pc. A label can be bound only once.
+
+class Label : public ZoneObject {  // LabelShadows are dynamically allocated.
+ public:
+  INLINE(Label())                 { Unuse(); }
+  INLINE(~Label())                { ASSERT(!is_linked()); }
+
+  INLINE(void Unuse())            { pos_ = 0; }
+
+  INLINE(bool is_bound()  const)  { return pos_ <  0; }
+  INLINE(bool is_unused() const)  { return pos_ == 0; }
+  INLINE(bool is_linked() const)  { return pos_ >  0; }
+
+  // Returns the position of bound or linked labels. Cannot be used
+  // for unused labels.
+  int pos() const;
+
+ private:
+  // pos_ encodes both the binding state (via its sign)
+  // and the binding position (via its value) of a label.
+  //
+  // pos_ <  0  bound label, pos() returns the jump target position
+  // pos_ == 0  unused label
+  // pos_ >  0  linked label, pos() returns the last reference position
+  int pos_;
+
+  void bind_to(int pos)  {
+    pos_ = -pos - 1;
+    ASSERT(is_bound());
+  }
+  void link_to(int pos)  {
+    pos_ =  pos + 1;
+    ASSERT(is_linked());
+  }
+
+  friend class Assembler;
+  friend class Displacement;
+  friend class LabelShadow;
+};
+
+
+// A LabelShadow represents a label that is temporarily shadowed by another
+// label (represented by the original label during shadowing). They are used
+// to catch jumps to labels in certain contexts, e.g. try blocks.  After
+// shadowing ends, the formerly shadowed label is again represented by the
+// original label and the LabelShadow can be used as a label in its own
+// right, representing the formerly shadowing label.
+class LabelShadow : public Label {
+ public:
+  explicit LabelShadow(Label* original) {
+    ASSERT(original != NULL);
+    original_label_ = original;
+    original_pos_ = original->pos_;
+    original->Unuse();
+#ifdef DEBUG
+    is_shadowing_ = true;
+#endif
+  }
+
+  ~LabelShadow() {
+    ASSERT(!is_shadowing_);
+  }
+
+  void StopShadowing() {
+    ASSERT(is_shadowing_ && is_unused());
+    pos_ = original_label_->pos_;
+    original_label_->pos_ = original_pos_;
+#ifdef DEBUG
+    is_shadowing_ = false;
+#endif
+  }
+
+  Label* original_label() const { return original_label_; }
+
+ private:
+  // During shadowing, the currently shadowing label.  After shadowing, the
+  // label that was shadowed.
+  Label* original_label_;
+
+  // During shadowing, the saved state of the original label.
+  int original_pos_;
+
+#ifdef DEBUG
+  bool is_shadowing_;
+#endif
+};
+
+
+// -----------------------------------------------------------------------------
+// Relocation information
+
+
+// Relocation information consists of the address (pc) of the datum
+// to which the relocation information applies, the relocation mode
+// (rmode), and an optional data field. The relocation mode may be
+// "descriptive" and not indicate a need for relocation, but simply
+// describe a property of the datum. Such rmodes are useful for GC
+// and nice disassembly output.
+
+class RelocInfo BASE_EMBEDDED {
+ public:
+  // The constant kNoPosition is used with the collecting of source positions
+  // in the relocation information. Two types of source positions are collected
+  // "position" (RelocMode position) and "statement position" (RelocMode
+  // statement_position). The "position" is collected at places in the source
+  // code which are of interest when making stack traces to pin-point the source
+  // location of a stack frame as close as possible. The "statement position" is
+  // collected at the beginning at each statement, and is used to indicate
+  // possible break locations. kNoPosition is used to indicate an
+  // invalid/uninitialized position value.
+  static const int kNoPosition = -1;
+
+  enum Mode {
+    // Please note the order is important (see IsCodeTarget, IsGCRelocMode).
+    CONSTRUCT_CALL,  // code target that is a call to a JavaScript constructor.
+    CODE_TARGET_CONTEXT,  // code target used for contextual loads.
+    CODE_TARGET,         // code target which is not any of the above.
+    EMBEDDED_OBJECT,
+    EMBEDDED_STRING,
+
+    // Everything after runtime_entry (inclusive) is not GC'ed.
+    RUNTIME_ENTRY,
+    JS_RETURN,  // Marks start of the ExitJSFrame code.
+    COMMENT,
+    POSITION,  // See comment for kNoPosition above.
+    STATEMENT_POSITION,  // See comment for kNoPosition above.
+    EXTERNAL_REFERENCE,  // The address of an external C++ function.
+    INTERNAL_REFERENCE,  // An address inside the same function.
+
+    // add more as needed
+    // Pseudo-types
+    NUMBER_OF_MODES,  // must be no greater than 14 - see RelocInfoWriter
+    NONE,  // never recorded
+    LAST_CODE_ENUM = CODE_TARGET,
+    LAST_GCED_ENUM = EMBEDDED_STRING
+  };
+
+
+  RelocInfo() {}
+  RelocInfo(byte* pc, Mode rmode, intptr_t data)
+      : pc_(pc), rmode_(rmode), data_(data) {
+  }
+
+  static inline bool IsConstructCall(Mode mode) {
+    return mode == CONSTRUCT_CALL;
+  }
+  static inline bool IsCodeTarget(Mode mode) {
+    return mode <= LAST_CODE_ENUM;
+  }
+  // Is the relocation mode affected by GC?
+  static inline bool IsGCRelocMode(Mode mode) {
+    return mode <= LAST_GCED_ENUM;
+  }
+  static inline bool IsJSReturn(Mode mode) {
+    return mode == JS_RETURN;
+  }
+  static inline bool IsComment(Mode mode) {
+    return mode == COMMENT;
+  }
+  static inline bool IsPosition(Mode mode) {
+    return mode == POSITION || mode == STATEMENT_POSITION;
+  }
+  static inline bool IsStatementPosition(Mode mode) {
+    return mode == STATEMENT_POSITION;
+  }
+  static inline bool IsExternalReference(Mode mode) {
+    return mode == EXTERNAL_REFERENCE;
+  }
+  static inline bool IsInternalReference(Mode mode) {
+    return mode == INTERNAL_REFERENCE;
+  }
+  static inline int ModeMask(Mode mode) { return 1 << mode; }
+
+  // Accessors
+  byte* pc() const  { return pc_; }
+  void set_pc(byte* pc) { pc_ = pc; }
+  Mode rmode() const {  return rmode_; }
+  intptr_t data() const  { return data_; }
+
+  // Apply a relocation by delta bytes
+  INLINE(void apply(int delta));
+
+  // Read/modify the code target in the branch/call instruction this relocation
+  // applies to; can only be called if IsCodeTarget(rmode_)
+  INLINE(Address target_address());
+  INLINE(void set_target_address(Address target));
+  INLINE(Object* target_object());
+  INLINE(Object** target_object_address());
+  INLINE(void set_target_object(Object* target));
+
+  // Read/modify the reference in the instruction this relocation
+  // applies to; can only be called if rmode_ is external_reference
+  INLINE(Address* target_reference_address());
+
+  // Read/modify the address of a call instruction. This is used to relocate
+  // the break points where straight-line code is patched with a call
+  // instruction.
+  INLINE(Address call_address());
+  INLINE(void set_call_address(Address target));
+  INLINE(Object* call_object());
+  INLINE(Object** call_object_address());
+  INLINE(void set_call_object(Object* target));
+
+  // Patch the code with some other code.
+  void patch_code(byte* instructions, int instruction_count);
+
+  // Patch the code with a call.
+  void patch_code_with_call(Address target, int guard_bytes);
+  INLINE(bool is_call_instruction());
+
+#ifdef ENABLE_DISASSEMBLER
+  // Printing
+  static const char* RelocModeName(Mode rmode);
+  void Print();
+#endif  // ENABLE_DISASSEMBLER
+#ifdef DEBUG
+  // Debugging
+  void Verify();
+#endif
+
+  static const int kCodeTargetMask = (1 << (LAST_CODE_ENUM + 1)) - 1;
+  static const int kPositionMask = 1 << POSITION | 1 << STATEMENT_POSITION;
+  static const int kDebugMask = kPositionMask | 1 << COMMENT;
+  static const int kApplyMask;  // Modes affected by apply. Depends on arch.
+
+ private:
+  // On ARM, note that pc_ is the address of the constant pool entry
+  // to be relocated and not the address of the instruction
+  // referencing the constant pool entry (except when rmode_ ==
+  // comment).
+  byte* pc_;
+  Mode rmode_;
+  intptr_t data_;
+  friend class RelocIterator;
+};
+
+
+// RelocInfoWriter serializes a stream of relocation info. It writes towards
+// lower addresses.
+class RelocInfoWriter BASE_EMBEDDED {
+ public:
+  RelocInfoWriter() : pos_(NULL), last_pc_(NULL), last_data_(0) {}
+  RelocInfoWriter(byte* pos, byte* pc) : pos_(pos), last_pc_(pc),
+                                         last_data_(0) {}
+
+  byte* pos() const { return pos_; }
+  byte* last_pc() const { return last_pc_; }
+
+  void Write(const RelocInfo* rinfo);
+
+  // Update the state of the stream after reloc info buffer
+  // and/or code is moved while the stream is active.
+  void Reposition(byte* pos, byte* pc) {
+    pos_ = pos;
+    last_pc_ = pc;
+  }
+
+  // Max size (bytes) of a written RelocInfo.
+  static const int kMaxSize = 12;
+
+ private:
+  inline uint32_t WriteVariableLengthPCJump(uint32_t pc_delta);
+  inline void WriteTaggedPC(uint32_t pc_delta, int tag);
+  inline void WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag);
+  inline void WriteExtraTaggedData(int32_t data_delta, int top_tag);
+  inline void WriteTaggedData(int32_t data_delta, int tag);
+  inline void WriteExtraTag(int extra_tag, int top_tag);
+
+  byte* pos_;
+  byte* last_pc_;
+  intptr_t last_data_;
+  DISALLOW_COPY_AND_ASSIGN(RelocInfoWriter);
+};
+
+
+// A RelocIterator iterates over relocation information.
+// Typical use:
+//
+//   for (RelocIterator it(code); !it.done(); it.next()) {
+//     // do something with it.rinfo() here
+//   }
+//
+// A mask can be specified to skip unwanted modes.
+class RelocIterator: public Malloced {
+ public:
+  // Create a new iterator positioned at
+  // the beginning of the reloc info.
+  // Relocation information with mode k is included in the
+  // iteration iff bit k of mode_mask is set.
+  explicit RelocIterator(Code* code, int mode_mask = -1);
+  explicit RelocIterator(const CodeDesc& desc, int mode_mask = -1);
+
+  // Iteration
+  bool done() const  { return done_; }
+  void next();
+
+  // Return pointer valid until next next().
+  RelocInfo* rinfo() {
+    ASSERT(!done());
+    return &rinfo_;
+  }
+
+ private:
+  // Advance* moves the position before/after reading.
+  // *Read* reads from current byte(s) into rinfo_.
+  // *Get* just reads and returns info on current byte.
+  void Advance(int bytes = 1) { pos_ -= bytes; }
+  int AdvanceGetTag();
+  int GetExtraTag();
+  int GetTopTag();
+  void ReadTaggedPC();
+  void AdvanceReadPC();
+  void AdvanceReadData();
+  void AdvanceReadVariableLengthPCJump();
+  int GetPositionTypeTag();
+  void ReadTaggedData();
+
+  static RelocInfo::Mode DebugInfoModeFromTag(int tag);
+
+  // If the given mode is wanted, set it in rinfo_ and return true.
+  // Else return false. Used for efficiently skipping unwanted modes.
+  bool SetMode(RelocInfo::Mode mode) {
+    return (mode_mask_ & 1 << mode) ? (rinfo_.rmode_ = mode, true) : false;
+  }
+
+  byte* pos_;
+  byte* end_;
+  RelocInfo rinfo_;
+  bool done_;
+  int mode_mask_;
+  DISALLOW_COPY_AND_ASSIGN(RelocIterator);
+};
+
+
+//------------------------------------------------------------------------------
+// External function
+
+//----------------------------------------------------------------------------
+class IC_Utility;
+class Debug_Address;
+class SCTableReference;
+
+// An ExternalReference represents a C++ address called from the generated
+// code. All references to C++ functions and must be encapsulated in an
+// ExternalReference instance. This is done in order to track the origin of
+// all external references in the code.
+class ExternalReference BASE_EMBEDDED {
+ public:
+  explicit ExternalReference(Builtins::CFunctionId id);
+
+  explicit ExternalReference(Builtins::Name name);
+
+  explicit ExternalReference(Runtime::FunctionId id);
+
+  explicit ExternalReference(Runtime::Function* f);
+
+  explicit ExternalReference(const IC_Utility& ic_utility);
+
+  explicit ExternalReference(const Debug_Address& debug_address);
+
+  explicit ExternalReference(StatsCounter* counter);
+
+  explicit ExternalReference(Top::AddressId id);
+
+  explicit ExternalReference(const SCTableReference& table_ref);
+
+  // One-of-a-kind references. These references are not part of a general
+  // pattern. This means that they have to be added to the
+  // ExternalReferenceTable in serialize.cc manually.
+
+  static ExternalReference builtin_passed_function();
+
+  // Static variable Factory::the_hole_value.location()
+  static ExternalReference the_hole_value_location();
+
+  // Static variable StackGuard::address_of_limit()
+  static ExternalReference address_of_stack_guard_limit();
+
+  // Function Debug::Break()
+  static ExternalReference debug_break();
+
+  // Static variable Heap::NewSpaceStart()
+  static ExternalReference new_space_start();
+
+  // Used for fast allocation in generated code.
+  static ExternalReference new_space_allocation_top_address();
+  static ExternalReference new_space_allocation_limit_address();
+
+  // Used to check if single stepping is enabled in generated code.
+  static ExternalReference debug_step_in_fp_address();
+
+  Address address() const {return address_;}
+
+ private:
+  explicit ExternalReference(void* address)
+    : address_(reinterpret_cast<Address>(address)) {}
+
+  Address address_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Utility functions
+
+// Move these into inline file?
+
+static inline bool is_intn(int x, int n)  {
+  return -(1 << (n-1)) <= x && x < (1 << (n-1));
+}
+
+static inline bool is_int24(int x)  { return is_intn(x, 24); }
+static inline bool is_int8(int x)  { return is_intn(x, 8); }
+
+static inline bool is_uintn(int x, int n) {
+  return (x & -(1 << n)) == 0;
+}
+
+static inline bool is_uint3(int x)  { return is_uintn(x, 3); }
+static inline bool is_uint4(int x)  { return is_uintn(x, 4); }
+static inline bool is_uint5(int x)  { return is_uintn(x, 5); }
+static inline bool is_uint8(int x)  { return is_uintn(x, 8); }
+static inline bool is_uint12(int x)  { return is_uintn(x, 12); }
+static inline bool is_uint16(int x)  { return is_uintn(x, 16); }
+static inline bool is_uint24(int x)  { return is_uintn(x, 24); }
+
+} }  // namespace v8::internal
+
+#endif  // V8_ASSEMBLER_H_
diff --git a/regexp2000/src/ast.cc b/regexp2000/src/ast.cc
new file mode 100644 (file)
index 0000000..915d8fd
--- /dev/null
@@ -0,0 +1,368 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+#include "scopes.h"
+#include "string-stream.h"
+
+namespace v8 { namespace internal {
+
+
+VariableProxySentinel VariableProxySentinel::this_proxy_(true);
+VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
+ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
+Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
+Call Call::sentinel_(NULL, NULL, false, 0);
+
+
+// ----------------------------------------------------------------------------
+// All the Accept member functions for each syntax tree node type.
+
+#define DECL_ACCEPT(type)                \
+  void type::Accept(Visitor* v) {        \
+    if (v->CheckStackOverflow()) return; \
+    v->Visit##type(this);                \
+  }
+NODE_LIST(DECL_ACCEPT)
+#undef DECL_ACCEPT
+
+
+// ----------------------------------------------------------------------------
+// Implementation of other node functionality.
+
+VariableProxy::VariableProxy(Handle<String> name,
+                             bool is_this,
+                             bool inside_with)
+  : name_(name),
+    var_(NULL),
+    is_this_(is_this),
+    inside_with_(inside_with) {
+  // names must be canonicalized for fast equality checks
+  ASSERT(name->IsSymbol());
+  // at least one access, otherwise no need for a VariableProxy
+  var_uses_.RecordAccess(1);
+}
+
+
+VariableProxy::VariableProxy(bool is_this)
+  : is_this_(is_this) {
+}
+
+
+void VariableProxy::BindTo(Variable* var) {
+  ASSERT(var_ == NULL);  // must be bound only once
+  ASSERT(var != NULL);  // must bind
+  ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name()));
+  // Ideally CONST-ness should match. However, this is very hard to achieve
+  // because we don't know the exact semantics of conflicting (const and
+  // non-const) multiple variable declarations, const vars introduced via
+  // eval() etc.  Const-ness and variable declarations are a complete mess
+  // in JS. Sigh...
+  var_ = var;
+  var->var_uses()->RecordUses(&var_uses_);
+  var->obj_uses()->RecordUses(&obj_uses_);
+}
+
+
+#ifdef DEBUG
+
+const char* LoopStatement::OperatorString() const {
+  switch (type()) {
+    case DO_LOOP: return "DO";
+    case FOR_LOOP: return "FOR";
+    case WHILE_LOOP: return "WHILE";
+  }
+  return NULL;
+}
+
+#endif  // DEBUG
+
+
+Token::Value Assignment::binary_op() const {
+  switch (op_) {
+    case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
+    case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
+    case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
+    case Token::ASSIGN_SHL: return Token::SHL;
+    case Token::ASSIGN_SAR: return Token::SAR;
+    case Token::ASSIGN_SHR: return Token::SHR;
+    case Token::ASSIGN_ADD: return Token::ADD;
+    case Token::ASSIGN_SUB: return Token::SUB;
+    case Token::ASSIGN_MUL: return Token::MUL;
+    case Token::ASSIGN_DIV: return Token::DIV;
+    case Token::ASSIGN_MOD: return Token::MOD;
+    default: UNREACHABLE();
+  }
+  return Token::ILLEGAL;
+}
+
+
+bool FunctionLiteral::AllowsLazyCompilation() {
+  return scope()->AllowsLazyCompilation();
+}
+
+
+ObjectLiteral::Property::Property(Literal* key, Expression* value) {
+  key_ = key;
+  value_ = value;
+  Object* k = *key->handle();
+  if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
+    kind_ = PROTOTYPE;
+  } else {
+    kind_ = value_->AsLiteral() == NULL ? COMPUTED : CONSTANT;
+  }
+}
+
+
+ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
+  key_ = new Literal(value->name());
+  value_ = value;
+  kind_ = is_getter ? GETTER : SETTER;
+}
+
+
+void LabelCollector::AddLabel(Label* label) {
+  // Add the label to the collector, but discard duplicates.
+  int length = labels_->length();
+  for (int i = 0; i < length; i++) {
+    if (labels_->at(i) == label) return;
+  }
+  labels_->Add(label);
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of Visitor
+
+
+void Visitor::VisitStatements(ZoneList<Statement*>* statements) {
+  for (int i = 0; i < statements->length(); i++) {
+    Visit(statements->at(i));
+  }
+}
+
+
+void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) {
+  for (int i = 0; i < expressions->length(); i++) {
+    // The variable statement visiting code may pass NULL expressions
+    // to this code. Maybe this should be handled by introducing an
+    // undefined expression or literal?  Revisit this code if this
+    // changes
+    Expression* expression = expressions->at(i);
+    if (expression != NULL) Visit(expression);
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Regular expressions
+
+#define MAKE_ACCEPT(Name)                                            \
+  void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) {   \
+    return visitor->Visit##Name(this, data);                         \
+  }
+FOR_EACH_REG_EXP_NODE_TYPE(MAKE_ACCEPT)
+#undef MAKE_ACCEPT
+
+
+#define MAKE_CONVERSION(Name)                                        \
+  RegExp##Name* RegExpTree::As##Name() {                             \
+    return NULL;                                                     \
+  }
+  FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CONVERSION)
+#undef MAKE_CONVERSION
+
+
+#define MAKE_CONVERSION(Name)                                       \
+RegExp##Name* RegExp##Name::As##Name() {                            \
+  return this;                                                      \
+}
+FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CONVERSION)
+#undef MAKE_CONVERSION
+
+
+
+RegExpEmpty RegExpEmpty::kInstance;
+
+
+// Convert regular expression trees to a simple sexp representation.
+// This representation should be different from the input grammar
+// in as many cases as possible, to make it more difficult for incorrect
+// parses to look as correct ones which is likely if the input and
+// output formats are alike.
+class RegExpUnparser: public RegExpVisitor {
+ public:
+  RegExpUnparser();
+  void VisitCharacterRange(CharacterRange that);
+  SmartPointer<char> ToString() { return stream_.ToCString(); }
+#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
+  FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CASE)
+#undef MAKE_CASE
+ private:
+  StringStream* stream() { return &stream_; }
+  HeapStringAllocator alloc_;
+  StringStream stream_;
+};
+
+
+RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
+}
+
+
+void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
+  stream()->Add("(|");
+  for (int i = 0; i <  that->nodes()->length(); i++) {
+    stream()->Add(" ");
+    that->nodes()->at(i)->Accept(this, data);
+  }
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
+  stream()->Add("(:");
+  for (int i = 0; i <  that->nodes()->length(); i++) {
+    stream()->Add(" ");
+    that->nodes()->at(i)->Accept(this, data);
+  }
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
+  if (that.is_character_class()) {
+    stream()->Add("&%c", that.from());
+  } else if (that.IsSingleton()) {
+    stream()->Add("%c", that.from());
+  } else {
+    stream()->Add("%c-%c", that.from(), that.to());
+  }
+}
+
+
+
+void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
+                                          void* data) {
+  if (that->is_negated())
+    stream()->Add("^");
+  stream()->Add("[");
+  for (int i = 0; i < that->ranges()->length(); i++) {
+    if (i > 0) stream()->Add(" ");
+    VisitCharacterRange(that->ranges()->at(i));
+  }
+  stream()->Add("]");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
+  switch (that->type()) {
+    case RegExpAssertion::START_OF_INPUT:
+      stream()->Add("@^i");
+      break;
+    case RegExpAssertion::END_OF_INPUT:
+      stream()->Add("@$i");
+      break;
+    case RegExpAssertion::START_OF_LINE:
+      stream()->Add("@^l");
+      break;
+    case RegExpAssertion::END_OF_LINE:
+      stream()->Add("@$l");
+       break;
+    case RegExpAssertion::BOUNDARY:
+      stream()->Add("@b");
+      break;
+    case RegExpAssertion::NON_BOUNDARY:
+      stream()->Add("@B");
+      break;
+  }
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
+  stream()->Add("'%w'", that->data());
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
+  stream()->Add("(# %i ", that->min());
+  if (that->max() == RegExpQuantifier::kInfinity) {
+    stream()->Add("- ");
+  } else {
+    stream()->Add("%i ", that->max());
+  }
+  stream()->Add(that->is_greedy() ? "g " : "n ");
+  that->body()->Accept(this, data);
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
+  stream()->Add("(^ ");
+  that->body()->Accept(this, data);
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
+  stream()->Add("(-> ");
+  stream()->Add(that->is_positive() ? "+ " : "- ");
+  that->body()->Accept(this, data);
+  stream()->Add(")");
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitBackreference(RegExpBackreference* that,
+                                         void* data) {
+  stream()->Add("(<- %i)", that->index());
+  return NULL;
+}
+
+
+void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
+  stream()->Put('%');
+  return NULL;
+}
+
+
+SmartPointer<char> RegExpTree::ToString() {
+  RegExpUnparser unparser;
+  Accept(&unparser, NULL);
+  return unparser.ToString();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/ast.h b/regexp2000/src/ast.h
new file mode 100644 (file)
index 0000000..ef37257
--- /dev/null
@@ -0,0 +1,1448 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_AST_H_
+#define V8_AST_H_
+
+#include "execution.h"
+#include "factory.h"
+#include "runtime.h"
+#include "token.h"
+#include "variables.h"
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+// The abstract syntax tree is an intermediate, light-weight
+// representation of the parsed JavaScript code suitable for
+// compilation to native code.
+
+// Nodes are allocated in a separate zone, which allows faster
+// allocation and constant-time deallocation of the entire syntax
+// tree.
+
+
+// ----------------------------------------------------------------------------
+// Nodes of the abstract syntax tree. Only concrete classes are
+// enumerated here.
+
+#define NODE_LIST(V)                            \
+  V(Block)                                      \
+  V(Declaration)                                \
+  V(ExpressionStatement)                        \
+  V(EmptyStatement)                             \
+  V(IfStatement)                                \
+  V(ContinueStatement)                          \
+  V(BreakStatement)                             \
+  V(ReturnStatement)                            \
+  V(WithEnterStatement)                         \
+  V(WithExitStatement)                          \
+  V(SwitchStatement)                            \
+  V(LoopStatement)                              \
+  V(ForInStatement)                             \
+  V(TryCatch)                                   \
+  V(TryFinally)                                 \
+  V(DebuggerStatement)                          \
+  V(FunctionLiteral)                            \
+  V(FunctionBoilerplateLiteral)                 \
+  V(Conditional)                                \
+  V(Slot)                                       \
+  V(VariableProxy)                              \
+  V(Literal)                                    \
+  V(RegExpLiteral)                              \
+  V(ObjectLiteral)                              \
+  V(ArrayLiteral)                               \
+  V(Assignment)                                 \
+  V(Throw)                                      \
+  V(Property)                                   \
+  V(Call)                                       \
+  V(CallNew)                                    \
+  V(CallRuntime)                                \
+  V(UnaryOperation)                             \
+  V(CountOperation)                             \
+  V(BinaryOperation)                            \
+  V(CompareOperation)                           \
+  V(ThisFunction)
+
+
+#define DEF_FORWARD_DECLARATION(type) class type;
+NODE_LIST(DEF_FORWARD_DECLARATION)
+#undef DEF_FORWARD_DECLARATION
+
+
+// Typedef only introduced to avoid unreadable code.
+// Please do appreciate the required space in "> >".
+typedef ZoneList<Handle<String> > ZoneStringList;
+
+
+class Node: public ZoneObject {
+ public:
+  Node(): statement_pos_(RelocInfo::kNoPosition) { }
+  virtual ~Node() { }
+  virtual void Accept(Visitor* v) = 0;
+
+  // Type testing & conversion.
+  virtual Statement* AsStatement() { return NULL; }
+  virtual ExpressionStatement* AsExpressionStatement() { return NULL; }
+  virtual EmptyStatement* AsEmptyStatement() { return NULL; }
+  virtual Expression* AsExpression() { return NULL; }
+  virtual Literal* AsLiteral() { return NULL; }
+  virtual Slot* AsSlot() { return NULL; }
+  virtual VariableProxy* AsVariableProxy() { return NULL; }
+  virtual Property* AsProperty() { return NULL; }
+  virtual Call* AsCall() { return NULL; }
+  virtual LabelCollector* AsLabelCollector() { return NULL; }
+  virtual BreakableStatement* AsBreakableStatement() { return NULL; }
+  virtual IterationStatement* AsIterationStatement() { return NULL; }
+  virtual UnaryOperation* AsUnaryOperation() { return NULL; }
+  virtual BinaryOperation* AsBinaryOperation() { return NULL; }
+  virtual Assignment* AsAssignment() { return NULL; }
+  virtual FunctionLiteral* AsFunctionLiteral() { return NULL; }
+
+  void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
+  int statement_pos() const { return statement_pos_; }
+
+ private:
+  int statement_pos_;
+};
+
+
+class Statement: public Node {
+ public:
+  virtual Statement* AsStatement()  { return this; }
+  virtual ReturnStatement* AsReturnStatement() { return NULL; }
+
+  bool IsEmpty() { return AsEmptyStatement() != NULL; }
+};
+
+
+class Expression: public Node {
+ public:
+  virtual Expression* AsExpression()  { return this; }
+
+  virtual bool IsValidLeftHandSide() { return false; }
+
+  // Mark the expression as being compiled as an expression
+  // statement. This is used to transform postfix increments to
+  // (faster) prefix increments.
+  virtual void MarkAsStatement() { /* do nothing */ }
+};
+
+
+/**
+ * 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:
+  virtual bool IsValidLeftHandSide() { return true; }
+  virtual void Accept(Visitor* v) { UNREACHABLE(); }
+  static ValidLeftHandSideSentinel* instance() { return &instance_; }
+ private:
+  static ValidLeftHandSideSentinel instance_;
+};
+
+
+class BreakableStatement: public Statement {
+ public:
+  enum Type {
+    TARGET_FOR_ANONYMOUS,
+    TARGET_FOR_NAMED_ONLY
+  };
+
+  // The labels associated with this statement. May be NULL;
+  // if it is != NULL, guaranteed to contain at least one entry.
+  ZoneStringList* labels() const { return labels_; }
+
+  // Type testing & conversion.
+  virtual BreakableStatement* AsBreakableStatement() { return this; }
+
+  // Code generation
+  Label* break_target() { return &break_target_; }
+
+  // Used during code generation for restoring the stack when a
+  // break/continue crosses a statement that keeps stuff on the stack.
+  int break_stack_height() { return break_stack_height_; }
+  void set_break_stack_height(int height) { break_stack_height_ = height; }
+
+  // Testers.
+  bool is_target_for_anonymous() const { return type_ == TARGET_FOR_ANONYMOUS; }
+
+ protected:
+  BreakableStatement(ZoneStringList* labels, Type type)
+      : labels_(labels), type_(type) {
+    ASSERT(labels == NULL || labels->length() > 0);
+  }
+
+ private:
+  ZoneStringList* labels_;
+  Type type_;
+  Label break_target_;
+  int break_stack_height_;
+};
+
+
+class Block: public BreakableStatement {
+ public:
+  Block(ZoneStringList* labels, int capacity, bool is_initializer_block)
+      : BreakableStatement(labels, TARGET_FOR_NAMED_ONLY),
+        statements_(capacity),
+        is_initializer_block_(is_initializer_block) { }
+
+  virtual void Accept(Visitor* v);
+
+  void AddStatement(Statement* statement) { statements_.Add(statement); }
+
+  ZoneList<Statement*>* statements() { return &statements_; }
+  bool is_initializer_block() const  { return is_initializer_block_; }
+
+ private:
+  ZoneList<Statement*> statements_;
+  bool is_initializer_block_;
+};
+
+
+class Declaration: public Node {
+ public:
+  Declaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* fun)
+    : proxy_(proxy),
+      mode_(mode),
+      fun_(fun) {
+    ASSERT(mode == Variable::VAR || mode == Variable::CONST);
+    // At the moment there are no "const functions"'s in JavaScript...
+    ASSERT(fun == NULL || mode == Variable::VAR);
+  }
+
+  virtual void Accept(Visitor* v);
+
+  VariableProxy* proxy() const  { return proxy_; }
+  Variable::Mode mode() const  { return mode_; }
+  FunctionLiteral* fun() const  { return fun_; }  // may be NULL
+
+ private:
+  VariableProxy* proxy_;
+  Variable::Mode mode_;
+  FunctionLiteral* fun_;
+};
+
+
+class IterationStatement: public BreakableStatement {
+ public:
+  // Type testing & conversion.
+  virtual IterationStatement* AsIterationStatement() { return this; }
+
+  Statement* body() const { return body_; }
+
+  // Code generation
+  Label* continue_target()  { return &continue_target_; }
+
+ protected:
+  explicit IterationStatement(ZoneStringList* labels)
+    : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), body_(NULL) { }
+
+  void Initialize(Statement* body) {
+    body_ = body;
+  }
+
+ private:
+  Statement* body_;
+  Label continue_target_;
+};
+
+
+class LoopStatement: public IterationStatement {
+ public:
+  enum Type { DO_LOOP, FOR_LOOP, WHILE_LOOP };
+
+  LoopStatement(ZoneStringList* labels, Type type)
+      : IterationStatement(labels), type_(type), init_(NULL),
+        cond_(NULL), next_(NULL) { }
+
+  void Initialize(Statement* init,
+                  Expression* cond,
+                  Statement* next,
+                  Statement* body) {
+    ASSERT(init == NULL || type_ == FOR_LOOP);
+    ASSERT(next == NULL || type_ == FOR_LOOP);
+    IterationStatement::Initialize(body);
+    init_ = init;
+    cond_ = cond;
+    next_ = next;
+  }
+
+  virtual void Accept(Visitor* v);
+
+  Type type() const  { return type_; }
+  Statement* init() const  { return init_; }
+  Expression* cond() const  { return cond_; }
+  Statement* next() const  { return next_; }
+
+#ifdef DEBUG
+  const char* OperatorString() const;
+#endif
+
+ private:
+  Type type_;
+  Statement* init_;
+  Expression* cond_;
+  Statement* next_;
+};
+
+
+class ForInStatement: public IterationStatement {
+ public:
+  explicit ForInStatement(ZoneStringList* labels)
+    : IterationStatement(labels), each_(NULL), enumerable_(NULL) { }
+
+  void Initialize(Expression* each, Expression* enumerable, Statement* body) {
+    IterationStatement::Initialize(body);
+    each_ = each;
+    enumerable_ = enumerable;
+  }
+
+  virtual void Accept(Visitor* v);
+
+  Expression* each() const { return each_; }
+  Expression* enumerable() const { return enumerable_; }
+
+ private:
+  Expression* each_;
+  Expression* enumerable_;
+};
+
+
+class ExpressionStatement: public Statement {
+ public:
+  explicit ExpressionStatement(Expression* expression)
+      : expression_(expression) { }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion.
+  virtual ExpressionStatement* AsExpressionStatement() { return this; }
+
+  void set_expression(Expression* e) { expression_ = e; }
+  Expression* expression() { return expression_; }
+
+ private:
+  Expression* expression_;
+};
+
+
+class ContinueStatement: public Statement {
+ public:
+  explicit ContinueStatement(IterationStatement* target)
+      : target_(target) { }
+
+  virtual void Accept(Visitor* v);
+
+  IterationStatement* target() const  { return target_; }
+
+ private:
+  IterationStatement* target_;
+};
+
+
+class BreakStatement: public Statement {
+ public:
+  explicit BreakStatement(BreakableStatement* target)
+      : target_(target) { }
+
+  virtual void Accept(Visitor* v);
+
+  BreakableStatement* target() const  { return target_; }
+
+ private:
+  BreakableStatement* target_;
+};
+
+
+class ReturnStatement: public Statement {
+ public:
+  explicit ReturnStatement(Expression* expression)
+      : expression_(expression) { }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion.
+  virtual ReturnStatement* AsReturnStatement() { return this; }
+
+  Expression* expression() { return expression_; }
+
+ private:
+  Expression* expression_;
+};
+
+
+class WithEnterStatement: public Statement {
+ public:
+  explicit WithEnterStatement(Expression* expression)
+      : expression_(expression) { }
+
+  virtual void Accept(Visitor* v);
+
+  Expression* expression() const  { return expression_; }
+
+ private:
+  Expression* expression_;
+};
+
+
+class WithExitStatement: public Statement {
+ public:
+  WithExitStatement() { }
+
+  virtual void Accept(Visitor* v);
+};
+
+
+class CaseClause: public ZoneObject {
+ public:
+  CaseClause(Expression* label, ZoneList<Statement*>* statements)
+      : label_(label), statements_(statements) { }
+
+  bool is_default() const  { return label_ == NULL; }
+  Expression* label() const  {
+    CHECK(!is_default());
+    return label_;
+  }
+  ZoneList<Statement*>* statements() const  { return statements_; }
+
+ private:
+  Expression* label_;
+  ZoneList<Statement*>* statements_;
+};
+
+
+class SwitchStatement: public BreakableStatement {
+ public:
+  explicit SwitchStatement(ZoneStringList* labels)
+      : BreakableStatement(labels, TARGET_FOR_ANONYMOUS),
+        tag_(NULL), cases_(NULL) { }
+
+  void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) {
+    tag_ = tag;
+    cases_ = cases;
+  }
+
+  virtual void Accept(Visitor* v);
+
+  Expression* tag() const  { return tag_; }
+  ZoneList<CaseClause*>* cases() const  { return cases_; }
+
+ private:
+  Expression* tag_;
+  ZoneList<CaseClause*>* cases_;
+};
+
+
+// If-statements always have non-null references to their then- and
+// else-parts. When parsing if-statements with no explicit else-part,
+// the parser implicitly creates an empty statement. Use the
+// HasThenStatement() and HasElseStatement() functions to check if a
+// given if-statement has a then- or an else-part containing code.
+class IfStatement: public Statement {
+ public:
+  IfStatement(Expression* condition,
+              Statement* then_statement,
+              Statement* else_statement)
+      : condition_(condition),
+        then_statement_(then_statement),
+        else_statement_(else_statement) { }
+
+  virtual void Accept(Visitor* v);
+
+  bool HasThenStatement() const { return !then_statement()->IsEmpty(); }
+  bool HasElseStatement() const { return !else_statement()->IsEmpty(); }
+
+  Expression* condition() const { return condition_; }
+  Statement* then_statement() const { return then_statement_; }
+  Statement* else_statement() const { return else_statement_; }
+
+ private:
+  Expression* condition_;
+  Statement* then_statement_;
+  Statement* else_statement_;
+};
+
+
+// NOTE: LabelCollectors are represented as nodes to fit in the target
+// stack in the compiler; this should probably be reworked.
+class LabelCollector: public Node {
+ public:
+  explicit LabelCollector(ZoneList<Label*>* labels) : labels_(labels) { }
+
+  // Adds a label to the collector. The collector stores a pointer not
+  // a copy of the label to make binding work, so make sure not to
+  // pass in references to something on the stack.
+  void AddLabel(Label* label);
+
+  // Virtual behaviour. LabelCollectors are never part of the AST.
+  virtual void Accept(Visitor* v) { UNREACHABLE(); }
+  virtual LabelCollector* AsLabelCollector() { return this; }
+
+  ZoneList<Label*>* labels() { return labels_; }
+
+ private:
+  ZoneList<Label*>* labels_;
+};
+
+
+class TryStatement: public Statement {
+ public:
+  explicit TryStatement(Block* try_block)
+      : try_block_(try_block), escaping_labels_(NULL) { }
+
+  void set_escaping_labels(ZoneList<Label*>* labels) {
+    escaping_labels_ = labels;
+  }
+
+  Block* try_block() const { return try_block_; }
+  ZoneList<Label*>* escaping_labels() const { return escaping_labels_; }
+
+ private:
+  Block* try_block_;
+  ZoneList<Label*>* escaping_labels_;
+};
+
+
+class TryCatch: public TryStatement {
+ public:
+  TryCatch(Block* try_block, Expression* catch_var, Block* catch_block)
+      : TryStatement(try_block),
+        catch_var_(catch_var),
+        catch_block_(catch_block) {
+    ASSERT(catch_var->AsVariableProxy() != NULL);
+  }
+
+  virtual void Accept(Visitor* v);
+
+  Expression* catch_var() const  { return catch_var_; }
+  Block* catch_block() const  { return catch_block_; }
+
+ private:
+  Expression* catch_var_;
+  Block* catch_block_;
+};
+
+
+class TryFinally: public TryStatement {
+ public:
+  TryFinally(Block* try_block, Block* finally_block)
+      : TryStatement(try_block),
+        finally_block_(finally_block) { }
+
+  virtual void Accept(Visitor* v);
+
+  Block* finally_block() const { return finally_block_; }
+
+ private:
+  Block* finally_block_;
+};
+
+
+class DebuggerStatement: public Statement {
+ public:
+  virtual void Accept(Visitor* v);
+};
+
+
+class EmptyStatement: public Statement {
+ public:
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion.
+  virtual EmptyStatement* AsEmptyStatement() { return this; }
+};
+
+
+class Literal: public Expression {
+ public:
+  explicit Literal(Handle<Object> handle) : handle_(handle) { }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion.
+  virtual Literal* AsLiteral() { return this; }
+
+  // Check if this literal is identical to the other literal.
+  bool IsIdenticalTo(const Literal* other) const {
+    return handle_.is_identical_to(other->handle_);
+  }
+
+  // Identity testers.
+  bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
+  bool IsTrue() const { return handle_.is_identical_to(Factory::true_value()); }
+  bool IsFalse() const {
+    return handle_.is_identical_to(Factory::false_value());
+  }
+
+  Handle<Object> handle() const { return handle_; }
+
+ private:
+  Handle<Object> handle_;
+};
+
+
+// Base class for literals that needs space in the corresponding JSFunction.
+class MaterializedLiteral: public Expression {
+ public:
+  explicit MaterializedLiteral(int literal_index)
+      : literal_index_(literal_index) {}
+  int literal_index() { return literal_index_; }
+ private:
+  int literal_index_;
+};
+
+
+// An object literal has a boilerplate object that is used
+// for minimizing the work when constructing it at runtime.
+class ObjectLiteral: public MaterializedLiteral {
+ public:
+  // Property is used for passing information
+  // about an object literal's properties from the parser
+  // to the code generator.
+  class Property: public ZoneObject {
+   public:
+
+    enum Kind {
+      CONSTANT,       // Property with constant value (at compile time).
+      COMPUTED,       // Property with computed value (at execution time).
+      GETTER, SETTER,  // Property is an accessor function.
+      PROTOTYPE       // Property is __proto__.
+    };
+
+    Property(Literal* key, Expression* value);
+    Property(bool is_getter, FunctionLiteral* value);
+
+    Literal* key() { return key_; }
+    Expression* value() { return value_; }
+    Kind kind() { return kind_; }
+
+   private:
+    Literal* key_;
+    Expression* value_;
+    Kind kind_;
+  };
+
+  ObjectLiteral(Handle<FixedArray> constant_properties,
+                ZoneList<Property*>* properties,
+                int literal_index)
+      : MaterializedLiteral(literal_index),
+        constant_properties_(constant_properties),
+        properties_(properties) {
+  }
+
+  virtual void Accept(Visitor* v);
+
+  Handle<FixedArray> constant_properties() const {
+    return constant_properties_;
+  }
+  ZoneList<Property*>* properties() const { return properties_; }
+
+ private:
+  Handle<FixedArray> constant_properties_;
+  ZoneList<Property*>* properties_;
+};
+
+
+// Node for capturing a regexp literal.
+class RegExpLiteral: public MaterializedLiteral {
+ public:
+  RegExpLiteral(Handle<String> pattern,
+                Handle<String> flags,
+                int literal_index)
+      : MaterializedLiteral(literal_index),
+        pattern_(pattern),
+        flags_(flags) {}
+
+  virtual void Accept(Visitor* v);
+
+  Handle<String> pattern() const { return pattern_; }
+  Handle<String> flags() const { return flags_; }
+
+ private:
+  Handle<String> pattern_;
+  Handle<String> flags_;
+};
+
+// An array literal has a literals object that is used
+// used for minimizing the work when contructing it at runtime.
+class ArrayLiteral: public Expression {
+ public:
+  ArrayLiteral(Handle<FixedArray> literals,
+               ZoneList<Expression*>* values)
+      : literals_(literals), values_(values) {
+  }
+
+  virtual void Accept(Visitor* v);
+
+  Handle<FixedArray> literals() const { return literals_; }
+  ZoneList<Expression*>* values() const { return values_; }
+
+ private:
+  Handle<FixedArray> literals_;
+  ZoneList<Expression*>* values_;
+};
+
+
+class VariableProxy: public Expression {
+ public:
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion
+  virtual Property* AsProperty() {
+    return var_ == NULL ? NULL : var_->AsProperty();
+  }
+  virtual VariableProxy* AsVariableProxy()  { return this; }
+
+  Variable* AsVariable() {
+    return this == NULL || var_ == NULL ? NULL : var_->AsVariable();
+  }
+  virtual bool IsValidLeftHandSide() {
+    return var_ == NULL ? true : var_->IsValidLeftHandSide();
+  }
+  bool IsVariable(Handle<String> n) {
+    return !is_this() && name().is_identical_to(n);
+  }
+
+  // If this assertion fails it means that some code has tried to
+  // treat the special "this" variable as an ordinary variable with
+  // the name "this".
+  Handle<String> name() const  { return name_; }
+  Variable* var() const  { return var_; }
+  UseCount* var_uses()  { return &var_uses_; }
+  UseCount* obj_uses()  { return &obj_uses_; }
+  bool is_this() const  { return is_this_; }
+  bool inside_with() const  { return inside_with_; }
+
+  // Bind this proxy to the variable var.
+  void BindTo(Variable* var);
+
+ protected:
+  Handle<String> name_;
+  Variable* var_;  // resolved variable, or NULL
+  bool is_this_;
+  bool inside_with_;
+
+  // VariableProxy usage info.
+  UseCount var_uses_;  // uses of the variable value
+  UseCount obj_uses_;  // uses of the object the variable points to
+
+  VariableProxy(Handle<String> name, bool is_this, bool inside_with);
+  explicit VariableProxy(bool is_this);
+
+  friend class Scope;
+};
+
+
+class VariableProxySentinel: public VariableProxy {
+ public:
+  virtual bool IsValidLeftHandSide() { return !is_this(); }
+  static VariableProxySentinel* this_proxy() { return &this_proxy_; }
+  static VariableProxySentinel* identifier_proxy() {
+    return &identifier_proxy_;
+  }
+
+ private:
+  explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
+  static VariableProxySentinel this_proxy_;
+  static VariableProxySentinel identifier_proxy_;
+};
+
+
+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,
+
+    // A property in the global object. var()->name() is
+    // the property name.
+    GLOBAL
+  };
+
+  Slot(Variable* var, Type type, int index)
+    : var_(var), type_(type), index_(index) {
+    ASSERT(var != NULL);
+  }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion
+  virtual Slot* AsSlot()  { return this; }
+
+  // Accessors
+  Variable* var() const  { return var_; }
+  Type type() const  { return type_; }
+  int index() const  { return index_; }
+
+ private:
+  Variable* var_;
+  Type type_;
+  int index_;
+};
+
+
+class Property: public Expression {
+ public:
+  Property(Expression* obj, Expression* key, int pos)
+      : obj_(obj), key_(key), pos_(pos) { }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion
+  virtual Property* AsProperty() { return this; }
+
+  virtual bool IsValidLeftHandSide() { return true; }
+
+  Expression* obj() const { return obj_; }
+  Expression* key() const { return key_; }
+  int position() const { return pos_; }
+
+  // Returns a property singleton property access on 'this'.  Used
+  // during preparsing.
+  static Property* this_property() { return &this_property_; }
+
+ private:
+  Expression* obj_;
+  Expression* key_;
+  int pos_;
+
+  // Dummy property used during preparsing
+  static Property this_property_;
+};
+
+
+class Call: public Expression {
+ public:
+  Call(Expression* expression,
+       ZoneList<Expression*>* arguments,
+       bool is_eval,
+       int pos)
+      : expression_(expression),
+        arguments_(arguments),
+        is_eval_(is_eval),
+        pos_(pos) { }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing and conversion.
+  virtual Call* AsCall() { return this; }
+
+  Expression* expression() const { return expression_; }
+  ZoneList<Expression*>* arguments() const { return arguments_; }
+  bool is_eval()  { return is_eval_; }
+  int position() { return pos_; }
+
+  static Call* sentinel() { return &sentinel_; }
+
+ private:
+  Expression* expression_;
+  ZoneList<Expression*>* arguments_;
+  bool is_eval_;
+  int pos_;
+
+  static Call sentinel_;
+};
+
+
+class CallNew: public Call {
+ public:
+  CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
+      : Call(expression, arguments, false, pos) { }
+
+  virtual void Accept(Visitor* v);
+};
+
+
+// The CallRuntime class does not represent any official JavaScript
+// language construct. Instead it is used to call a C or JS function
+// with a set of arguments. This is used from the builtins that are
+// implemented in JavaScript (see "v8natives.js").
+class CallRuntime: public Expression {
+ public:
+  CallRuntime(Handle<String> name,
+              Runtime::Function* function,
+              ZoneList<Expression*>* arguments)
+      : name_(name), function_(function), arguments_(arguments) { }
+
+  virtual void Accept(Visitor* v);
+
+  Handle<String> name() const { return name_; }
+  Runtime::Function* function() const { return function_; }
+  ZoneList<Expression*>* arguments() const { return arguments_; }
+
+ private:
+  Handle<String> name_;
+  Runtime::Function* function_;
+  ZoneList<Expression*>* arguments_;
+};
+
+
+class UnaryOperation: public Expression {
+ public:
+  UnaryOperation(Token::Value op, Expression* expression)
+    : op_(op), expression_(expression) {
+    ASSERT(Token::IsUnaryOp(op));
+  }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion
+  virtual UnaryOperation* AsUnaryOperation() { return this; }
+
+  Token::Value op() const { return op_; }
+  Expression* expression() const { return expression_; }
+
+ private:
+  Token::Value op_;
+  Expression* expression_;
+};
+
+
+class BinaryOperation: public Expression {
+ public:
+  BinaryOperation(Token::Value op, Expression* left, Expression* right)
+    : op_(op), left_(left), right_(right) {
+    ASSERT(Token::IsBinaryOp(op));
+  }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion
+  virtual BinaryOperation* AsBinaryOperation() { return this; }
+
+  // True iff the result can be safely overwritten (to avoid allocation).
+  // False for operations that can return one of their operands.
+  bool ResultOverwriteAllowed() {
+    switch (op_) {
+      case Token::COMMA:
+      case Token::OR:
+      case Token::AND:
+        return false;
+      case Token::BIT_OR:
+      case Token::BIT_XOR:
+      case Token::BIT_AND:
+      case Token::SHL:
+      case Token::SAR:
+      case Token::SHR:
+      case Token::ADD:
+      case Token::SUB:
+      case Token::MUL:
+      case Token::DIV:
+      case Token::MOD:
+        return true;
+      default:
+        UNREACHABLE();
+    }
+    return false;
+  }
+
+  Token::Value op() const { return op_; }
+  Expression* left() const { return left_; }
+  Expression* right() const { return right_; }
+
+ private:
+  Token::Value op_;
+  Expression* left_;
+  Expression* right_;
+};
+
+
+class CountOperation: public Expression {
+ public:
+  CountOperation(bool is_prefix, Token::Value op, Expression* expression)
+    : is_prefix_(is_prefix), op_(op), expression_(expression) {
+    ASSERT(Token::IsCountOp(op));
+  }
+
+  virtual void Accept(Visitor* v);
+
+  bool is_prefix() const { return is_prefix_; }
+  bool is_postfix() const { return !is_prefix_; }
+  Token::Value op() const { return op_; }
+  Expression* expression() const { return expression_; }
+
+  virtual void MarkAsStatement() { is_prefix_ = true; }
+
+ private:
+  bool is_prefix_;
+  Token::Value op_;
+  Expression* expression_;
+};
+
+
+class CompareOperation: public Expression {
+ public:
+  CompareOperation(Token::Value op, Expression* left, Expression* right)
+    : op_(op), left_(left), right_(right) {
+    ASSERT(Token::IsCompareOp(op));
+  }
+
+  virtual void Accept(Visitor* v);
+
+  Token::Value op() const { return op_; }
+  Expression* left() const { return left_; }
+  Expression* right() const { return right_; }
+
+ private:
+  Token::Value op_;
+  Expression* left_;
+  Expression* right_;
+};
+
+
+class Conditional: public Expression {
+ public:
+  Conditional(Expression* condition,
+              Expression* then_expression,
+              Expression* else_expression)
+      : condition_(condition),
+        then_expression_(then_expression),
+        else_expression_(else_expression) { }
+
+  virtual void Accept(Visitor* v);
+
+  Expression* condition() const { return condition_; }
+  Expression* then_expression() const { return then_expression_; }
+  Expression* else_expression() const { return else_expression_; }
+
+ private:
+  Expression* condition_;
+  Expression* then_expression_;
+  Expression* else_expression_;
+};
+
+
+class Assignment: public Expression {
+ public:
+  Assignment(Token::Value op, Expression* target, Expression* value, int pos)
+    : op_(op), target_(target), value_(value), pos_(pos) {
+    ASSERT(Token::IsAssignmentOp(op));
+  }
+
+  virtual void Accept(Visitor* v);
+  virtual Assignment* AsAssignment() { return this; }
+
+  Token::Value binary_op() const;
+
+  Token::Value op() const { return op_; }
+  Expression* target() const { return target_; }
+  Expression* value() const { return value_; }
+  int position() { return pos_; }
+
+ private:
+  Token::Value op_;
+  Expression* target_;
+  Expression* value_;
+  int pos_;
+};
+
+
+class Throw: public Expression {
+ public:
+  Throw(Expression* exception, int pos)
+      : exception_(exception), pos_(pos) {}
+
+  virtual void Accept(Visitor* v);
+  Expression* exception() const { return exception_; }
+  int position() const { return pos_; }
+
+ private:
+  Expression* exception_;
+  int pos_;
+};
+
+
+class FunctionLiteral: public Expression {
+ public:
+  FunctionLiteral(Handle<String> name,
+                  Scope* scope,
+                  ZoneList<Statement*>* body,
+                  int materialized_literal_count,
+                  bool contains_array_literal,
+                  int expected_property_count,
+                  int num_parameters,
+                  int start_position,
+                  int end_position,
+                  bool is_expression)
+      : name_(name),
+        scope_(scope),
+        body_(body),
+        materialized_literal_count_(materialized_literal_count),
+        contains_array_literal_(contains_array_literal),
+        expected_property_count_(expected_property_count),
+        num_parameters_(num_parameters),
+        start_position_(start_position),
+        end_position_(end_position),
+        is_expression_(is_expression),
+        function_token_position_(RelocInfo::kNoPosition) {
+  }
+
+  virtual void Accept(Visitor* v);
+
+  // Type testing & conversion
+  virtual FunctionLiteral* AsFunctionLiteral()  { return this; }
+
+  Handle<String> name() const  { return name_; }
+  Scope* scope() const  { return scope_; }
+  ZoneList<Statement*>* body() const  { return body_; }
+  void set_function_token_position(int pos) { function_token_position_ = pos; }
+  int function_token_position() const { return function_token_position_; }
+  int start_position() const { return start_position_; }
+  int end_position() const { return end_position_; }
+  bool is_expression() const { return is_expression_; }
+
+  int materialized_literal_count() { return materialized_literal_count_; }
+  bool contains_array_literal() { return contains_array_literal_; }
+  int expected_property_count() { return expected_property_count_; }
+  int num_parameters() { return num_parameters_; }
+
+  bool AllowsLazyCompilation();
+
+ private:
+  Handle<String> name_;
+  Scope* scope_;
+  ZoneList<Statement*>* body_;
+  int materialized_literal_count_;
+  bool contains_array_literal_;
+  int expected_property_count_;
+  int num_parameters_;
+  int start_position_;
+  int end_position_;
+  bool is_expression_;
+  int function_token_position_;
+};
+
+
+class FunctionBoilerplateLiteral: public Expression {
+ public:
+  explicit FunctionBoilerplateLiteral(Handle<JSFunction> boilerplate)
+      : boilerplate_(boilerplate) {
+    ASSERT(boilerplate->IsBoilerplate());
+  }
+
+  Handle<JSFunction> boilerplate() const { return boilerplate_; }
+
+  virtual void Accept(Visitor* v);
+
+ private:
+  Handle<JSFunction> boilerplate_;
+};
+
+
+class ThisFunction: public Expression {
+ public:
+  virtual void Accept(Visitor* v);
+};
+
+
+// ----------------------------------------------------------------------------
+// Regular expressions
+
+
+#define FOR_EACH_REG_EXP_NODE_TYPE(VISIT)                            \
+  VISIT(Disjunction)                                                 \
+  VISIT(Alternative)                                                 \
+  VISIT(Assertion)                                                   \
+  VISIT(CharacterClass)                                              \
+  VISIT(Atom)                                                        \
+  VISIT(Quantifier)                                                  \
+  VISIT(Capture)                                                     \
+  VISIT(Lookahead)                                                   \
+  VISIT(Backreference)                                               \
+  VISIT(Empty)
+
+
+class RegExpVisitor;
+template <typename Char> class RegExpNode;
+#define FORWARD_DECLARE(Name) class RegExp##Name;
+FOR_EACH_REG_EXP_NODE_TYPE(FORWARD_DECLARE)
+#undef FORWARD_DECLARE
+
+
+class RegExpTree: public ZoneObject {
+ public:
+  virtual ~RegExpTree() { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data) = 0;
+  SmartPointer<char> ToString();
+#define MAKE_ASTYPE(Name)  virtual RegExp##Name* As##Name();
+  FOR_EACH_REG_EXP_NODE_TYPE(MAKE_ASTYPE)
+#undef MAKE_ASTYPE
+};
+
+
+class RegExpDisjunction: public RegExpTree {
+ public:
+  explicit RegExpDisjunction(ZoneList<RegExpTree*>* nodes) : nodes_(nodes) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpDisjunction* AsDisjunction();
+  ZoneList<RegExpTree*>* nodes() { return nodes_; }
+ private:
+  ZoneList<RegExpTree*>* nodes_;
+};
+
+
+class RegExpAlternative: public RegExpTree {
+ public:
+  explicit RegExpAlternative(ZoneList<RegExpTree*>* nodes) : nodes_(nodes) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpAlternative* AsAlternative();
+  ZoneList<RegExpTree*>* nodes() { return nodes_; }
+ private:
+  ZoneList<RegExpTree*>* nodes_;
+};
+
+
+class RegExpAssertion: public RegExpTree {
+ public:
+  enum Type {
+    START_OF_LINE, START_OF_INPUT, END_OF_LINE, END_OF_INPUT,
+    BOUNDARY, NON_BOUNDARY
+  };
+  explicit RegExpAssertion(Type type) : type_(type) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpAssertion* AsAssertion();
+  Type type() { return type_; }
+ private:
+  Type type_;
+};
+
+
+class CharacterRange {
+ public:
+  // For compatibility with the CHECK_OK macro
+  CharacterRange(void* null) { ASSERT_EQ(NULL, null); }  //NOLINT
+  CharacterRange(uc32 from, uc32 to, bool is_character_class)
+    : from_(from),
+      to_(to),
+      is_character_class_(is_character_class) {
+    // Assert that truncating doesn't throw away information.
+    ASSERT_EQ(from, from_);
+    ASSERT_EQ(to_, to);
+  }
+  static inline CharacterRange CharacterClass(uc32 tag) {
+    return CharacterRange(tag, tag, true);
+  }
+  static inline CharacterRange Singleton(uc32 value) {
+    return CharacterRange(value, value, false);
+  }
+  static inline CharacterRange Range(uc32 from, uc32 to) {
+    return CharacterRange(from, to, false);
+  }
+  unsigned from() { return from_; }
+  unsigned to() { return to_; }
+  bool is_character_class() { return is_character_class_; }
+  bool IsSingleton() { return (from_ == to_) && !is_character_class(); }
+ private:
+  unsigned from_ : 16;
+  unsigned to_ : 16;
+  bool is_character_class_ : 1;
+};
+
+
+STATIC_CHECK(sizeof(CharacterRange) == 2 * sizeof(int));  // NOLINT
+
+
+class RegExpCharacterClass: public RegExpTree {
+ public:
+  explicit RegExpCharacterClass(CharacterRange range)
+    : ranges_(new ZoneList<CharacterRange>(1)),
+      is_negated_(false) {
+    ranges_->Add(range);
+  }
+  RegExpCharacterClass(ZoneList<CharacterRange>* ranges, bool is_negated)
+    : ranges_(ranges),
+      is_negated_(is_negated) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpCharacterClass* AsCharacterClass();
+  ZoneList<CharacterRange>* ranges() { return ranges_; }
+  bool is_negated() { return is_negated_; }
+ private:
+  ZoneList<CharacterRange>* ranges_;
+  bool is_negated_;
+};
+
+
+class RegExpAtom: public RegExpTree {
+ public:
+  explicit RegExpAtom(Vector<const uc16> data) : data_(data) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpAtom* AsAtom();
+  Vector<const uc16> data() { return data_; }
+ private:
+  Vector<const uc16> data_;
+};
+
+
+class RegExpQuantifier: public RegExpTree {
+ public:
+  RegExpQuantifier(int min, int max, bool is_greedy, RegExpTree* body)
+    : min_(min),
+      max_(max),
+      is_greedy_(is_greedy),
+      body_(body) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpQuantifier* AsQuantifier();
+  int min() { return min_; }
+  int max() { return max_; }
+  bool is_greedy() { return is_greedy_; }
+  RegExpTree* body() { return body_; }
+  // We just use a very large integer value as infinity because 1^31
+  // is infinite in practice.
+  static const int kInfinity = (1 << 31);
+ private:
+  int min_;
+  int max_;
+  bool is_greedy_;
+  RegExpTree* body_;
+};
+
+
+class RegExpCapture: public RegExpTree {
+ public:
+  explicit RegExpCapture(RegExpTree* body)
+    : body_(body) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpCapture* AsCapture();
+  RegExpTree* body() { return body_; }
+ private:
+  RegExpTree* body_;
+};
+
+
+class RegExpLookahead: public RegExpTree {
+ public:
+  RegExpLookahead(RegExpTree* body, bool is_positive)
+    : body_(body),
+      is_positive_(is_positive) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpLookahead* AsLookahead();
+  RegExpTree* body() { return body_; }
+  bool is_positive() { return is_positive_; }
+ private:
+  RegExpTree* body_;
+  bool is_positive_;
+};
+
+
+class RegExpBackreference: public RegExpTree {
+ public:
+  explicit RegExpBackreference(int index) : index_(index) { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpBackreference* AsBackreference();
+  int index() { return index_; }
+ private:
+  int index_;
+};
+
+
+class RegExpEmpty: public RegExpTree {
+ public:
+  RegExpEmpty() { }
+  virtual void* Accept(RegExpVisitor* visitor, void* data);
+  virtual RegExpEmpty* AsEmpty();
+  static RegExpEmpty* GetInstance() { return &kInstance; }
+ private:
+  static RegExpEmpty kInstance;
+};
+
+
+class RegExpVisitor BASE_EMBEDDED {
+ public:
+  virtual ~RegExpVisitor() { }
+#define MAKE_CASE(Name)                                              \
+  virtual void* Visit##Name(RegExp##Name*, void* data) = 0;
+  FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CASE)
+#undef MAKE_CASE
+};
+
+
+// ----------------------------------------------------------------------------
+// Basic visitor
+// - leaf node visitors are abstract.
+
+class Visitor BASE_EMBEDDED {
+ public:
+  Visitor() : stack_overflow_(false) { }
+  virtual ~Visitor() { }
+
+  // Dispatch
+  void Visit(Node* node) { node->Accept(this); }
+
+  // Iteration
+  virtual void VisitStatements(ZoneList<Statement*>* statements);
+  virtual void VisitExpressions(ZoneList<Expression*>* expressions);
+
+  // Stack overflow tracking support.
+  bool HasStackOverflow() const { return stack_overflow_; }
+  bool CheckStackOverflow() {
+    if (stack_overflow_) return true;
+    StackLimitCheck check;
+    if (!check.HasOverflowed()) return false;
+    return (stack_overflow_ = true);
+  }
+
+  // If a stack-overflow exception is encountered when visiting a
+  // node, calling SetStackOverflow will make sure that the visitor
+  // bails out without visiting more nodes.
+  void SetStackOverflow() { stack_overflow_ = true; }
+
+
+  // Individual nodes
+#define DEF_VISIT(type)                         \
+  virtual void Visit##type(type* node) = 0;
+  NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+ private:
+  bool stack_overflow_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_AST_H_
diff --git a/regexp2000/src/bootstrapper.cc b/regexp2000/src/bootstrapper.cc
new file mode 100644 (file)
index 0000000..0562c23
--- /dev/null
@@ -0,0 +1,1457 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "accessors.h"
+#include "api.h"
+#include "bootstrapper.h"
+#include "compiler.h"
+#include "debug.h"
+#include "execution.h"
+#include "global-handles.h"
+#include "macro-assembler.h"
+#include "natives.h"
+
+namespace v8 { namespace internal {
+
+// A SourceCodeCache uses a FixedArray to store pairs of
+// (AsciiString*, JSFunction*), mapping names of native code files
+// (runtime.js, etc.) to precompiled functions. Instead of mapping
+// names to functions it might make sense to let the JS2C tool
+// generate an index for each native JS file.
+class SourceCodeCache BASE_EMBEDDED {
+ public:
+  explicit SourceCodeCache(ScriptType type): type_(type) { }
+
+  void Initialize(bool create_heap_objects) {
+    if (create_heap_objects) {
+      cache_ = Heap::empty_fixed_array();
+    } else {
+      cache_ = NULL;
+    }
+  }
+
+  void Iterate(ObjectVisitor* v) {
+    v->VisitPointer(bit_cast<Object**, FixedArray**>(&cache_));
+  }
+
+
+  bool Lookup(Vector<const char> name, Handle<JSFunction>* handle) {
+    for (int i = 0; i < cache_->length(); i+=2) {
+      SeqAsciiString* str = SeqAsciiString::cast(cache_->get(i));
+      if (str->IsEqualTo(name)) {
+        *handle = Handle<JSFunction>(JSFunction::cast(cache_->get(i + 1)));
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+  void Add(Vector<const char> name, Handle<JSFunction> fun) {
+    ASSERT(fun->IsBoilerplate());
+    HandleScope scope;
+    int length = cache_->length();
+    Handle<FixedArray> new_array =
+        Factory::NewFixedArray(length + 2, TENURED);
+    cache_->CopyTo(0, *new_array, 0, cache_->length());
+    cache_ = *new_array;
+    Handle<String> str = Factory::NewStringFromAscii(name, TENURED);
+    cache_->set(length, *str);
+    cache_->set(length + 1, *fun);
+    Script::cast(fun->shared()->script())->set_type(Smi::FromInt(type_));
+  }
+
+ private:
+  ScriptType type_;
+  FixedArray* cache_;
+  DISALLOW_COPY_AND_ASSIGN(SourceCodeCache);
+};
+
+static SourceCodeCache natives_cache(SCRIPT_TYPE_NATIVE);
+static SourceCodeCache extensions_cache(SCRIPT_TYPE_EXTENSION);
+
+
+Handle<String> Bootstrapper::NativesSourceLookup(int index) {
+  ASSERT(0 <= index && index < Natives::GetBuiltinsCount());
+  if (Heap::natives_source_cache()->get(index)->IsUndefined()) {
+    Handle<String> source_code =
+      Factory::NewStringFromAscii(Natives::GetScriptSource(index));
+    Heap::natives_source_cache()->set(index, *source_code);
+  }
+  Handle<Object> cached_source(Heap::natives_source_cache()->get(index));
+  return Handle<String>::cast(cached_source);
+}
+
+
+bool Bootstrapper::NativesCacheLookup(Vector<const char> name,
+                                      Handle<JSFunction>* handle) {
+  return natives_cache.Lookup(name, handle);
+}
+
+
+void Bootstrapper::NativesCacheAdd(Vector<const char> name,
+                                   Handle<JSFunction> fun) {
+  natives_cache.Add(name, fun);
+}
+
+
+void Bootstrapper::Initialize(bool create_heap_objects) {
+  natives_cache.Initialize(create_heap_objects);
+  extensions_cache.Initialize(create_heap_objects);
+}
+
+
+void Bootstrapper::TearDown() {
+  natives_cache.Initialize(false);  // Yes, symmetrical
+  extensions_cache.Initialize(false);
+}
+
+
+// Pending fixups are code positions that have refer to builtin code
+// objects that were not available at the time the code was generated.
+// The pending list is processed whenever an environment has been
+// created.
+class PendingFixups : public AllStatic {
+ public:
+  static void Add(Code* code, MacroAssembler* masm);
+  static bool Process(Handle<JSBuiltinsObject> builtins);
+
+  static void Iterate(ObjectVisitor* v);
+
+ private:
+  static List<Object*> code_;
+  static List<const char*> name_;
+  static List<int> pc_;
+  static List<uint32_t> flags_;
+
+  static void Clear();
+};
+
+
+List<Object*> PendingFixups::code_(0);
+List<const char*> PendingFixups::name_(0);
+List<int> PendingFixups::pc_(0);
+List<uint32_t> PendingFixups::flags_(0);
+
+
+void PendingFixups::Add(Code* code, MacroAssembler* masm) {
+  // Note this code is not only called during bootstrapping.
+  List<MacroAssembler::Unresolved>* unresolved = masm->unresolved();
+  int n = unresolved->length();
+  for (int i = 0; i < n; i++) {
+    const char* name = unresolved->at(i).name;
+    code_.Add(code);
+    name_.Add(name);
+    pc_.Add(unresolved->at(i).pc);
+    flags_.Add(unresolved->at(i).flags);
+    LOG(StringEvent("unresolved", name));
+  }
+}
+
+
+bool PendingFixups::Process(Handle<JSBuiltinsObject> builtins) {
+  HandleScope scope;
+  // NOTE: Extra fixups may be added to the list during the iteration
+  // due to lazy compilation of functions during the processing. Do not
+  // cache the result of getting the length of the code list.
+  for (int i = 0; i < code_.length(); i++) {
+    const char* name = name_[i];
+    uint32_t flags = flags_[i];
+    Handle<String> symbol = Factory::LookupAsciiSymbol(name);
+    Object* o = builtins->GetProperty(*symbol);
+#ifdef DEBUG
+    if (!o->IsJSFunction()) {
+      V8_Fatal(__FILE__, __LINE__, "Cannot resolve call to builtin %s", name);
+    }
+#endif
+    Handle<JSFunction> f = Handle<JSFunction>(JSFunction::cast(o));
+    // Make sure the number of parameters match the formal parameter count.
+    int argc = Bootstrapper::FixupFlagsArgumentsCount::decode(flags);
+    USE(argc);
+    ASSERT(f->shared()->formal_parameter_count() == argc);
+    if (!f->is_compiled()) {
+      // Do lazy compilation and check for stack overflows.
+      if (!CompileLazy(f, CLEAR_EXCEPTION)) {
+        Clear();
+        return false;
+      }
+    }
+    Code* code = Code::cast(code_[i]);
+    Address pc = code->instruction_start() + pc_[i];
+    bool is_pc_relative = Bootstrapper::FixupFlagsIsPCRelative::decode(flags);
+    if (is_pc_relative) {
+      Assembler::set_target_address_at(pc, f->code()->instruction_start());
+    } else {
+      *reinterpret_cast<Object**>(pc) = f->code();
+    }
+    LOG(StringEvent("resolved", name));
+  }
+  Clear();
+
+  // TODO(1240818): We should probably try to avoid doing this for all
+  // the V8 builtin JS files. It should only happen after running
+  // runtime.js - just like there shouldn't be any fixups left after
+  // that.
+  for (int i = 0; i < Builtins::NumberOfJavaScriptBuiltins(); i++) {
+    Builtins::JavaScript id = static_cast<Builtins::JavaScript>(i);
+    Handle<String> name = Factory::LookupAsciiSymbol(Builtins::GetName(id));
+    JSFunction* function = JSFunction::cast(builtins->GetProperty(*name));
+    builtins->set_javascript_builtin(id, function);
+  }
+
+  return true;
+}
+
+
+void PendingFixups::Clear() {
+  code_.Clear();
+  name_.Clear();
+  pc_.Clear();
+  flags_.Clear();
+}
+
+
+void PendingFixups::Iterate(ObjectVisitor* v) {
+  if (!code_.is_empty()) {
+    v->VisitPointers(&code_[0], &code_[0] + code_.length());
+  }
+}
+
+
+class Genesis BASE_EMBEDDED {
+ public:
+  Genesis(Handle<Object> global_object,
+          v8::Handle<v8::ObjectTemplate> global_template,
+          v8::ExtensionConfiguration* extensions);
+  ~Genesis();
+
+  Handle<Context> result() { return result_; }
+
+  Genesis* previous() { return previous_; }
+  static Genesis* current() { return current_; }
+
+ private:
+  Handle<Context> global_context_;
+
+  // There may be more than one active genesis object: When GC is
+  // triggered during environment creation there may be weak handle
+  // processing callbacks which may create new environments.
+  Genesis* previous_;
+  static Genesis* current_;
+
+  Handle<Context> global_context() { return global_context_; }
+
+  void CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
+                   Handle<Object> global_object);
+  void InstallNativeFunctions();
+  bool InstallNatives();
+  bool InstallExtensions(v8::ExtensionConfiguration* extensions);
+  bool InstallExtension(const char* name);
+  bool InstallExtension(v8::RegisteredExtension* current);
+  bool InstallSpecialObjects();
+  bool ConfigureApiObject(Handle<JSObject> object,
+                          Handle<ObjectTemplateInfo> object_template);
+  bool ConfigureGlobalObjects(v8::Handle<v8::ObjectTemplate> global_template);
+
+  // Migrates all properties from the 'from' object to the 'to'
+  // object and overrides the prototype in 'to' with the one from
+  // 'from'.
+  void TransferObject(Handle<JSObject> from, Handle<JSObject> to);
+  void TransferNamedProperties(Handle<JSObject> from, Handle<JSObject> to);
+  void TransferIndexedProperties(Handle<JSObject> from, Handle<JSObject> to);
+
+  Handle<DescriptorArray> ComputeFunctionInstanceDescriptor(
+      bool make_prototype_read_only,
+      bool make_prototype_enumerable = false);
+  void MakeFunctionInstancePrototypeWritable();
+
+  void AddSpecialFunction(Handle<JSObject> prototype,
+                          const char* name,
+                          Handle<Code> code);
+
+  void BuildSpecialFunctionTable();
+
+  static bool CompileBuiltin(int index);
+  static bool CompileNative(Vector<const char> name, Handle<String> source);
+  static bool CompileScriptCached(Vector<const char> name,
+                                  Handle<String> source,
+                                  SourceCodeCache* cache,
+                                  v8::Extension* extension,
+                                  bool use_runtime_context);
+
+  Handle<Context> result_;
+};
+
+Genesis* Genesis::current_ = NULL;
+
+
+void Bootstrapper::Iterate(ObjectVisitor* v) {
+  natives_cache.Iterate(v);
+  extensions_cache.Iterate(v);
+  PendingFixups::Iterate(v);
+}
+
+
+// While setting up the environment, we collect code positions that
+// need to be patched before we can run any code in the environment.
+void Bootstrapper::AddFixup(Code* code, MacroAssembler* masm) {
+  PendingFixups::Add(code, masm);
+}
+
+
+bool Bootstrapper::IsActive() {
+  return Genesis::current() != NULL;
+}
+
+
+Handle<Context> Bootstrapper::CreateEnvironment(
+    Handle<Object> global_object,
+    v8::Handle<v8::ObjectTemplate> global_template,
+    v8::ExtensionConfiguration* extensions) {
+  Genesis genesis(global_object, global_template, extensions);
+  return genesis.result();
+}
+
+
+static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
+  // object.__proto__ = proto;
+  Handle<Map> old_to_map = Handle<Map>(object->map());
+  Handle<Map> new_to_map = Factory::CopyMapDropTransitions(old_to_map);
+  new_to_map->set_prototype(*proto);
+  object->set_map(*new_to_map);
+}
+
+
+void Bootstrapper::DetachGlobal(Handle<Context> env) {
+  JSGlobalProxy::cast(env->global_proxy())->set_context(*Factory::null_value());
+  SetObjectPrototype(Handle<JSObject>(env->global_proxy()),
+                     Factory::null_value());
+  env->set_global_proxy(env->global());
+  env->global()->set_global_receiver(env->global());
+}
+
+
+Genesis::~Genesis() {
+  ASSERT(current_ == this);
+  current_ = previous_;
+}
+
+
+static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
+                                          const char* name,
+                                          InstanceType type,
+                                          int instance_size,
+                                          Handle<JSObject> prototype,
+                                          Builtins::Name call,
+                                          bool is_ecma_native) {
+  Handle<String> symbol = Factory::LookupAsciiSymbol(name);
+  Handle<Code> call_code = Handle<Code>(Builtins::builtin(call));
+  Handle<JSFunction> function =
+    Factory::NewFunctionWithPrototype(symbol,
+                                      type,
+                                      instance_size,
+                                      prototype,
+                                      call_code,
+                                      is_ecma_native);
+  SetProperty(target, symbol, function, DONT_ENUM);
+  if (is_ecma_native) {
+    function->shared()->set_instance_class_name(*symbol);
+  }
+  return function;
+}
+
+
+Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
+    bool make_prototype_read_only,
+    bool make_prototype_enumerable) {
+  Handle<DescriptorArray> result = Factory::empty_descriptor_array();
+
+  // Add prototype.
+  PropertyAttributes attributes = static_cast<PropertyAttributes>(
+      (make_prototype_enumerable ? 0 : DONT_ENUM)
+      | DONT_DELETE
+      | (make_prototype_read_only ? READ_ONLY : 0));
+  result =
+      Factory::CopyAppendProxyDescriptor(
+          result,
+          Factory::prototype_symbol(),
+          Factory::NewProxy(&Accessors::FunctionPrototype),
+          attributes);
+
+  attributes =
+      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+  // Add length.
+  result =
+      Factory::CopyAppendProxyDescriptor(
+          result,
+          Factory::length_symbol(),
+          Factory::NewProxy(&Accessors::FunctionLength),
+          attributes);
+
+  // Add name.
+  result =
+      Factory::CopyAppendProxyDescriptor(
+          result,
+          Factory::name_symbol(),
+          Factory::NewProxy(&Accessors::FunctionName),
+          attributes);
+
+  // Add arguments.
+  result =
+      Factory::CopyAppendProxyDescriptor(
+          result,
+          Factory::arguments_symbol(),
+          Factory::NewProxy(&Accessors::FunctionArguments),
+          attributes);
+
+  // Add caller.
+  result =
+      Factory::CopyAppendProxyDescriptor(
+          result,
+          Factory::caller_symbol(),
+          Factory::NewProxy(&Accessors::FunctionCaller),
+          attributes);
+
+  return result;
+}
+
+
+void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
+                          Handle<Object> global_object) {
+  HandleScope scope;
+  // Allocate the global context FixedArray first and then patch the
+  // closure and extension object later (we need the empty function
+  // and the global object, but in order to create those, we need the
+  // global context).
+  global_context_ =
+      Handle<Context>::cast(
+          GlobalHandles::Create(*Factory::NewGlobalContext()));
+  Top::set_context(*global_context());
+
+  // Allocate the message listeners object.
+  v8::NeanderArray listeners;
+  global_context()->set_message_listeners(*listeners.value());
+
+  // Allocate the debug event listeners object.
+  v8::NeanderArray debug_event_listeners;
+  global_context()->set_debug_event_listeners(*debug_event_listeners.value());
+
+  // Allocate the map for function instances.
+  Handle<Map> fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+  global_context()->set_function_instance_map(*fm);
+  // Please note that the prototype property for function instances must be
+  // writable.
+  Handle<DescriptorArray> function_map_descriptors =
+      ComputeFunctionInstanceDescriptor(false, true);
+  fm->set_instance_descriptors(*function_map_descriptors);
+
+  // Allocate the function map first and then patch the prototype later
+  fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+  global_context()->set_function_map(*fm);
+  function_map_descriptors = ComputeFunctionInstanceDescriptor(true);
+  fm->set_instance_descriptors(*function_map_descriptors);
+
+  Handle<String> object_name = Handle<String>(Heap::Object_symbol());
+
+  {  // --- O b j e c t ---
+    Handle<JSFunction> object_fun =
+        Factory::NewFunction(object_name, Factory::null_value());
+    Handle<Map> object_function_map =
+        Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    object_fun->set_initial_map(*object_function_map);
+    object_function_map->set_constructor(*object_fun);
+
+    global_context()->set_object_function(*object_fun);
+
+    // Allocate a new prototype for the object function.
+    Handle<JSObject> prototype = Factory::NewJSObject(Top::object_function(),
+                                                      TENURED);
+
+    global_context()->set_initial_object_prototype(*prototype);
+    SetPrototype(object_fun, prototype);
+    object_function_map->
+      set_instance_descriptors(Heap::empty_descriptor_array());
+  }
+
+  // Allocate the empty function as the prototype for function ECMAScript
+  // 262 15.3.4.
+  Handle<String> symbol = Factory::LookupAsciiSymbol("Empty");
+  Handle<JSFunction> empty_function =
+      Factory::NewFunction(symbol, Factory::null_value());
+
+  {  // --- E m p t y ---
+    Handle<Code> code =
+        Handle<Code>(Builtins::builtin(Builtins::EmptyFunction));
+    Handle<String> source = Factory::NewStringFromAscii(CStrVector("() {}"));
+
+    empty_function->set_code(*code);
+    empty_function->shared()->set_script(*Factory::NewScript(source));
+    empty_function->shared()->set_start_position(0);
+    empty_function->shared()->set_end_position(source->length());
+    empty_function->shared()->DontAdaptArguments();
+    global_context()->function_map()->set_prototype(*empty_function);
+    global_context()->function_instance_map()->set_prototype(*empty_function);
+
+    // Allocate the function map first and then patch the prototype later
+    Handle<Map> empty_fm = Factory::CopyMap(fm);
+    empty_fm->set_instance_descriptors(*function_map_descriptors);
+    empty_fm->set_prototype(global_context()->object_function()->prototype());
+    empty_function->set_map(*empty_fm);
+  }
+
+  {  // --- G l o b a l ---
+    // Step 1: create a fresh inner JSGlobalObject
+    Handle<JSGlobalObject> object;
+    {
+      Handle<JSFunction> js_global_function;
+      Handle<ObjectTemplateInfo> js_global_template;
+      if (!global_template.IsEmpty()) {
+        // Get prototype template of the global_template
+        Handle<ObjectTemplateInfo> data =
+            v8::Utils::OpenHandle(*global_template);
+        Handle<FunctionTemplateInfo> global_constructor =
+            Handle<FunctionTemplateInfo>(
+                FunctionTemplateInfo::cast(data->constructor()));
+        Handle<Object> proto_template(global_constructor->prototype_template());
+        if (!proto_template->IsUndefined()) {
+          js_global_template =
+              Handle<ObjectTemplateInfo>::cast(proto_template);
+        }
+      }
+
+      if (js_global_template.is_null()) {
+        Handle<String> name = Handle<String>(Heap::empty_symbol());
+        Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+        js_global_function =
+            Factory::NewFunction(name, JS_GLOBAL_OBJECT_TYPE,
+                                 JSGlobalObject::kSize, code, true);
+        // Change the constructor property of the prototype of the
+        // hidden global function to refer to the Object function.
+        Handle<JSObject> prototype =
+            Handle<JSObject>(
+                JSObject::cast(js_global_function->instance_prototype()));
+        SetProperty(prototype, Factory::constructor_symbol(),
+                    Top::object_function(), NONE);
+      } else {
+        Handle<FunctionTemplateInfo> js_global_constructor(
+            FunctionTemplateInfo::cast(js_global_template->constructor()));
+        js_global_function =
+            Factory::CreateApiFunction(js_global_constructor,
+                                       Factory::InnerGlobalObject);
+      }
+
+      js_global_function->initial_map()->set_is_hidden_prototype();
+      SetExpectedNofProperties(js_global_function, 100);
+      object = Handle<JSGlobalObject>::cast(
+          Factory::NewJSObject(js_global_function, TENURED));
+    }
+
+    // Set the global context for the global object.
+    object->set_global_context(*global_context());
+
+    // Step 2: create or re-initialize the global proxy object.
+    Handle<JSGlobalProxy> global_proxy;
+    {
+      Handle<JSFunction> global_proxy_function;
+      if (global_template.IsEmpty()) {
+        Handle<String> name = Handle<String>(Heap::empty_symbol());
+        Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+        global_proxy_function =
+            Factory::NewFunction(name, JS_GLOBAL_PROXY_TYPE,
+                                 JSGlobalProxy::kSize, code, true);
+      } else {
+        Handle<ObjectTemplateInfo> data =
+            v8::Utils::OpenHandle(*global_template);
+        Handle<FunctionTemplateInfo> global_constructor(
+                FunctionTemplateInfo::cast(data->constructor()));
+        global_proxy_function =
+            Factory::CreateApiFunction(global_constructor,
+                                       Factory::OuterGlobalObject);
+      }
+
+      Handle<String> global_name = Factory::LookupAsciiSymbol("global");
+      global_proxy_function->shared()->set_instance_class_name(*global_name);
+      global_proxy_function->initial_map()->set_is_access_check_needed();
+
+      // Set global_proxy.__proto__ to js_global after ConfigureGlobalObjects
+
+      if (global_object.location() != NULL) {
+        ASSERT(global_object->IsJSGlobalProxy());
+        global_proxy =
+            ReinitializeJSGlobalProxy(
+                global_proxy_function,
+                Handle<JSGlobalProxy>::cast(global_object));
+      } else {
+        global_proxy = Handle<JSGlobalProxy>::cast(
+            Factory::NewJSObject(global_proxy_function, TENURED));
+      }
+
+      // Security setup: Set the security token of the global object to
+      // its the inner global. This makes the security check between two
+      // different contexts fail by default even in case of global
+      // object reinitialization.
+      object->set_global_receiver(*global_proxy);
+      global_proxy->set_context(*global_context());
+    }
+
+    {  // --- G l o b a l   C o n t e x t ---
+      // use the empty function as closure (no scope info)
+      global_context()->set_closure(*empty_function);
+      global_context()->set_fcontext(*global_context());
+      global_context()->set_previous(NULL);
+
+      // set extension and global object
+      global_context()->set_extension(*object);
+      global_context()->set_global(*object);
+      global_context()->set_global_proxy(*global_proxy);
+      // use inner global object as security token by default
+      global_context()->set_security_token(*object);
+    }
+
+    Handle<JSObject> global = Handle<JSObject>(global_context()->global());
+    SetProperty(global, object_name, Top::object_function(), DONT_ENUM);
+  }
+
+  Handle<JSObject> global = Handle<JSObject>(global_context()->global());
+
+  // Install global Function object
+  InstallFunction(global, "Function", JS_FUNCTION_TYPE, JSFunction::kSize,
+                  empty_function, Builtins::Illegal, true);  // ECMA native.
+
+  {  // --- A r r a y ---
+    Handle<JSFunction> array_function =
+        InstallFunction(global, "Array", JS_ARRAY_TYPE, JSArray::kSize,
+                        Top::initial_object_prototype(), Builtins::ArrayCode,
+                        true);
+    array_function->shared()->DontAdaptArguments();
+
+    // This seems a bit hackish, but we need to make sure Array.length
+    // is 1.
+    array_function->shared()->set_length(1);
+    Handle<DescriptorArray> array_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            Factory::empty_descriptor_array(),
+            Factory::length_symbol(),
+            Factory::NewProxy(&Accessors::ArrayLength),
+            static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE));
+
+    // Cache the fast JavaScript array map
+    global_context()->set_js_array_map(array_function->initial_map());
+    global_context()->js_array_map()->set_instance_descriptors(
+        *array_descriptors);
+    // array_function is used internally. JS code creating array object should
+    // search for the 'Array' property on the global object and use that one
+    // as the constructor. 'Array' property on a global object can be
+    // overwritten by JS code.
+    global_context()->set_array_function(*array_function);
+  }
+
+  {  // --- N u m b e r ---
+    Handle<JSFunction> number_fun =
+        InstallFunction(global, "Number", JS_VALUE_TYPE, JSValue::kSize,
+                        Top::initial_object_prototype(), Builtins::Illegal,
+                        true);
+    global_context()->set_number_function(*number_fun);
+  }
+
+  {  // --- B o o l e a n ---
+    Handle<JSFunction> boolean_fun =
+        InstallFunction(global, "Boolean", JS_VALUE_TYPE, JSValue::kSize,
+                        Top::initial_object_prototype(), Builtins::Illegal,
+                        true);
+    global_context()->set_boolean_function(*boolean_fun);
+  }
+
+  {  // --- S t r i n g ---
+    Handle<JSFunction> string_fun =
+        InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize,
+                        Top::initial_object_prototype(), Builtins::Illegal,
+                        true);
+    global_context()->set_string_function(*string_fun);
+    // Add 'length' property to strings.
+    Handle<DescriptorArray> string_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            Factory::empty_descriptor_array(),
+            Factory::length_symbol(),
+            Factory::NewProxy(&Accessors::StringLength),
+            static_cast<PropertyAttributes>(DONT_ENUM |
+                                            DONT_DELETE |
+                                            READ_ONLY));
+
+    Handle<Map> string_map =
+        Handle<Map>(global_context()->string_function()->initial_map());
+    string_map->set_instance_descriptors(*string_descriptors);
+  }
+
+  {  // --- D a t e ---
+    // Builtin functions for Date.prototype.
+    Handle<JSFunction> date_fun =
+        InstallFunction(global, "Date", JS_VALUE_TYPE, JSValue::kSize,
+                        Top::initial_object_prototype(), Builtins::Illegal,
+                        true);
+
+    global_context()->set_date_function(*date_fun);
+  }
+
+
+  {  // -- R e g E x p
+    // Builtin functions for RegExp.prototype.
+    Handle<JSFunction> regexp_fun =
+        InstallFunction(global, "RegExp", JS_REGEXP_TYPE, JSRegExp::kSize,
+                        Top::initial_object_prototype(), Builtins::Illegal,
+                        true);
+
+    global_context()->set_regexp_function(*regexp_fun);
+  }
+
+  {  // --- arguments_boilerplate_
+    // Make sure we can recognize argument objects at runtime.
+    // This is done by introducing an anonymous function with
+    // class_name equals 'Arguments'.
+    Handle<String> symbol = Factory::LookupAsciiSymbol("Arguments");
+    Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+    Handle<JSObject> prototype =
+        Handle<JSObject>(
+            JSObject::cast(global_context()->object_function()->prototype()));
+
+    Handle<JSFunction> function =
+        Factory::NewFunctionWithPrototype(symbol,
+                                          JS_OBJECT_TYPE,
+                                          JSObject::kHeaderSize,
+                                          prototype,
+                                          code,
+                                          false);
+    ASSERT(!function->has_initial_map());
+    function->shared()->set_instance_class_name(*symbol);
+    function->shared()->set_expected_nof_properties(2);
+    Handle<JSObject> result = Factory::NewJSObject(function);
+
+    global_context()->set_arguments_boilerplate(*result);
+    // Note: callee must be added as the first property and
+    //       length must be added as the second property.
+    SetProperty(result, Factory::callee_symbol(),
+                Factory::undefined_value(),
+                DONT_ENUM);
+    SetProperty(result, Factory::length_symbol(),
+                Factory::undefined_value(),
+                DONT_ENUM);
+
+#ifdef DEBUG
+    LookupResult lookup;
+    result->LocalLookup(Heap::callee_symbol(), &lookup);
+    ASSERT(lookup.IsValid() && (lookup.type() == FIELD));
+    ASSERT(lookup.GetFieldIndex() == Heap::arguments_callee_index);
+
+    result->LocalLookup(Heap::length_symbol(), &lookup);
+    ASSERT(lookup.IsValid() && (lookup.type() == FIELD));
+    ASSERT(lookup.GetFieldIndex() == Heap::arguments_length_index);
+
+    ASSERT(result->map()->inobject_properties() > Heap::arguments_callee_index);
+    ASSERT(result->map()->inobject_properties() > Heap::arguments_length_index);
+
+    // Check the state of the object.
+    ASSERT(result->HasFastProperties());
+    ASSERT(result->HasFastElements());
+#endif
+  }
+
+  {  // --- context extension
+    // Create a function for the context extension objects.
+    Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+    Handle<JSFunction> context_extension_fun =
+        Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
+                             JSObject::kHeaderSize, code, true);
+
+    Handle<String> name = Factory::LookupAsciiSymbol("context_extension");
+    context_extension_fun->shared()->set_instance_class_name(*name);
+    global_context()->set_context_extension_function(*context_extension_fun);
+  }
+
+  // Setup the call-as-function delegate.
+  Handle<Code> code =
+      Handle<Code>(Builtins::builtin(Builtins::HandleApiCallAsFunction));
+  Handle<JSFunction> delegate =
+      Factory::NewFunction(Factory::empty_symbol(), JS_OBJECT_TYPE,
+                           JSObject::kHeaderSize, code, true);
+  global_context()->set_call_as_function_delegate(*delegate);
+  delegate->shared()->DontAdaptArguments();
+
+  global_context()->set_special_function_table(Heap::empty_fixed_array());
+
+  // Initialize the out of memory slot.
+  global_context()->set_out_of_memory(Heap::false_value());
+}
+
+
+bool Genesis::CompileBuiltin(int index) {
+  Vector<const char> name = Natives::GetScriptName(index);
+  Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
+  return CompileNative(name, source_code);
+}
+
+
+bool Genesis::CompileNative(Vector<const char> name, Handle<String> source) {
+  HandleScope scope;
+  Debugger::set_compiling_natives(true);
+  bool result =
+      CompileScriptCached(name, source, &natives_cache, NULL, true);
+  ASSERT(Top::has_pending_exception() != result);
+  if (!result) Top::clear_pending_exception();
+  Debugger::set_compiling_natives(false);
+  return result;
+}
+
+
+bool Genesis::CompileScriptCached(Vector<const char> name,
+                                  Handle<String> source,
+                                  SourceCodeCache* cache,
+                                  v8::Extension* extension,
+                                  bool use_runtime_context) {
+  HandleScope scope;
+  Handle<JSFunction> boilerplate;
+
+  // If we can't find the function in the cache, we compile a new
+  // function and insert it into the cache.
+  if (!cache->Lookup(name, &boilerplate)) {
+#ifdef DEBUG
+    ASSERT(source->IsAsciiRepresentation());
+#endif
+    Handle<String> script_name = Factory::NewStringFromUtf8(name);
+    boilerplate =
+        Compiler::Compile(source, script_name, 0, 0, extension, NULL);
+    if (boilerplate.is_null()) return false;
+    cache->Add(name, boilerplate);
+  }
+
+  // Setup the function context. Conceptually, we should clone the
+  // function before overwriting the context but since we're in a
+  // single-threaded environment it is not strictly necessary.
+  ASSERT(Top::context()->IsGlobalContext());
+  Handle<Context> context =
+      Handle<Context>(use_runtime_context
+                      ? Top::context()->runtime_context()
+                      : Top::context());
+  Handle<JSFunction> fun =
+      Factory::NewFunctionFromBoilerplate(boilerplate, context);
+
+  // Call function using the either the runtime object or the global
+  // object as the receiver. Provide no parameters.
+  Handle<Object> receiver =
+      Handle<Object>(use_runtime_context
+                     ? Top::context()->builtins()
+                     : Top::context()->global());
+  bool has_pending_exception;
+  Handle<Object> result =
+      Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
+  if (has_pending_exception) return false;
+  return PendingFixups::Process(
+      Handle<JSBuiltinsObject>(Top::context()->builtins()));
+}
+
+
+#define INSTALL_NATIVE(Type, name, var)                                  \
+  Handle<String> var##_name = Factory::LookupAsciiSymbol(name);          \
+  global_context()->set_##var(Type::cast(global_context()->              \
+                                           builtins()->                  \
+                                             GetProperty(*var##_name)));
+
+void Genesis::InstallNativeFunctions() {
+  HandleScope scope;
+  INSTALL_NATIVE(JSFunction, "CreateDate", create_date_fun);
+  INSTALL_NATIVE(JSFunction, "ToNumber", to_number_fun);
+  INSTALL_NATIVE(JSFunction, "ToString", to_string_fun);
+  INSTALL_NATIVE(JSFunction, "ToDetailString", to_detail_string_fun);
+  INSTALL_NATIVE(JSFunction, "ToObject", to_object_fun);
+  INSTALL_NATIVE(JSFunction, "ToInteger", to_integer_fun);
+  INSTALL_NATIVE(JSFunction, "ToUint32", to_uint32_fun);
+  INSTALL_NATIVE(JSFunction, "ToInt32", to_int32_fun);
+  INSTALL_NATIVE(JSFunction, "ToBoolean", to_boolean_fun);
+  INSTALL_NATIVE(JSFunction, "Instantiate", instantiate_fun);
+  INSTALL_NATIVE(JSFunction, "ConfigureTemplateInstance",
+                 configure_instance_fun);
+  INSTALL_NATIVE(JSFunction, "MakeMessage", make_message_fun);
+  INSTALL_NATIVE(JSFunction, "GetStackTraceLine", get_stack_trace_line_fun);
+  INSTALL_NATIVE(JSObject, "functionCache", function_cache);
+}
+
+#undef INSTALL_NATIVE
+
+
+bool Genesis::InstallNatives() {
+  HandleScope scope;
+
+  // Create a function for the builtins object. Allocate space for the
+  // JavaScript builtins, a reference to the builtins object
+  // (itself) and a reference to the global_context directly in the object.
+  Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
+  Handle<JSFunction> builtins_fun =
+      Factory::NewFunction(Factory::empty_symbol(), JS_BUILTINS_OBJECT_TYPE,
+                           JSBuiltinsObject::kSize, code, true);
+
+  Handle<String> name = Factory::LookupAsciiSymbol("builtins");
+  builtins_fun->shared()->set_instance_class_name(*name);
+  SetExpectedNofProperties(builtins_fun, 100);
+
+  // Allocate the builtins object.
+  Handle<JSBuiltinsObject> builtins =
+      Handle<JSBuiltinsObject>::cast(Factory::NewJSObject(builtins_fun,
+                                                          TENURED));
+  builtins->set_builtins(*builtins);
+  builtins->set_global_context(*global_context());
+  builtins->set_global_receiver(*builtins);
+
+  // Setup the 'global' properties of the builtins object. The
+  // 'global' property that refers to the global object is the only
+  // way to get from code running in the builtins context to the
+  // global object.
+  static const PropertyAttributes attributes =
+      static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
+  SetProperty(builtins, Factory::LookupAsciiSymbol("global"),
+              Handle<Object>(global_context()->global()), attributes);
+
+  // Setup the reference from the global object to the builtins object.
+  JSGlobalObject::cast(global_context()->global())->set_builtins(*builtins);
+
+  // Create a bridge function that has context in the global context.
+  Handle<JSFunction> bridge =
+      Factory::NewFunction(Factory::empty_symbol(), Factory::undefined_value());
+  ASSERT(bridge->context() == *Top::global_context());
+
+  // Allocate the builtins context.
+  Handle<Context> context =
+    Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, bridge);
+  context->set_global(*builtins);  // override builtins global object
+
+  global_context()->set_runtime_context(*context);
+
+  {  // -- S c r i p t
+    // Builtin functions for Script.
+    Handle<JSFunction> script_fun =
+        InstallFunction(builtins, "Script", JS_VALUE_TYPE, JSValue::kSize,
+                        Top::initial_object_prototype(), Builtins::Illegal,
+                        false);
+    Handle<JSObject> prototype =
+        Factory::NewJSObject(Top::object_function(), TENURED);
+    SetPrototype(script_fun, prototype);
+    global_context()->set_script_function(*script_fun);
+
+    // Add 'source' and 'data' property to scripts.
+    PropertyAttributes common_attributes =
+        static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+    Handle<Proxy> proxy_source = Factory::NewProxy(&Accessors::ScriptSource);
+    Handle<DescriptorArray> script_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            Factory::empty_descriptor_array(),
+            Factory::LookupAsciiSymbol("source"),
+            proxy_source,
+            common_attributes);
+    Handle<Proxy> proxy_data = Factory::NewProxy(&Accessors::ScriptName);
+    script_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            script_descriptors,
+            Factory::LookupAsciiSymbol("name"),
+            proxy_data,
+            common_attributes);
+    Handle<Proxy> proxy_line_offset =
+        Factory::NewProxy(&Accessors::ScriptLineOffset);
+    script_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            script_descriptors,
+            Factory::LookupAsciiSymbol("line_offset"),
+            proxy_line_offset,
+            common_attributes);
+    Handle<Proxy> proxy_column_offset =
+        Factory::NewProxy(&Accessors::ScriptColumnOffset);
+    script_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            script_descriptors,
+            Factory::LookupAsciiSymbol("column_offset"),
+            proxy_column_offset,
+            common_attributes);
+    Handle<Proxy> proxy_type = Factory::NewProxy(&Accessors::ScriptType);
+    script_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            script_descriptors,
+            Factory::LookupAsciiSymbol("type"),
+            proxy_type,
+            common_attributes);
+
+    Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
+    script_map->set_instance_descriptors(*script_descriptors);
+
+    // Allocate the empty script.
+    Handle<Script> script = Factory::NewScript(Factory::empty_string());
+    global_context()->set_empty_script(*script);
+  }
+
+  if (FLAG_natives_file == NULL) {
+    // Without natives file, install default natives.
+    for (int i = Natives::GetDelayCount();
+         i < Natives::GetBuiltinsCount();
+         i++) {
+      if (!CompileBuiltin(i)) return false;
+    }
+
+    // Setup natives with lazy loading.
+    SetupLazy(Handle<JSFunction>(global_context()->date_function()),
+              Natives::GetIndex("date"),
+              Top::global_context(),
+              Handle<Context>(Top::context()->runtime_context()));
+    SetupLazy(Handle<JSFunction>(global_context()->regexp_function()),
+              Natives::GetIndex("regexp"),
+              Top::global_context(),
+              Handle<Context>(Top::context()->runtime_context()));
+
+  } else if (strlen(FLAG_natives_file) != 0) {
+    // Otherwise install natives from natives file if file exists and
+    // compiles.
+    bool exists;
+    Vector<const char> source = ReadFile(FLAG_natives_file, &exists);
+    Handle<String> source_string = Factory::NewStringFromAscii(source);
+    if (source.is_empty()) return false;
+    bool result = CompileNative(CStrVector(FLAG_natives_file), source_string);
+    if (!result) return false;
+
+  } else {
+    // Empty natives file name - do not install any natives.
+    PrintF("Warning: Running without installed natives!\n");
+    return true;
+  }
+
+  InstallNativeFunctions();
+
+  // Install Function.prototype.call and apply.
+  { Handle<String> key = Factory::function_class_symbol();
+    Handle<JSFunction> function =
+        Handle<JSFunction>::cast(GetProperty(Top::global(), key));
+    Handle<JSObject> proto =
+        Handle<JSObject>(JSObject::cast(function->instance_prototype()));
+
+    // Install the call and the apply functions.
+    Handle<JSFunction> call =
+        InstallFunction(proto, "call", JS_OBJECT_TYPE, JSObject::kHeaderSize,
+                        Factory::NewJSObject(Top::object_function(), TENURED),
+                        Builtins::FunctionCall,
+                        false);
+    Handle<JSFunction> apply =
+        InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
+                        Factory::NewJSObject(Top::object_function(), TENURED),
+                        Builtins::FunctionApply,
+                        false);
+
+    // Make sure that Function.prototype.call appears to be compiled.
+    // The code will never be called, but inline caching for call will
+    // only work if it appears to be compiled.
+    call->shared()->DontAdaptArguments();
+    ASSERT(call->is_compiled());
+
+    // Set the expected paramters for apply to 2; required by builtin.
+    apply->shared()->set_formal_parameter_count(2);
+
+    // Set the lengths for the functions to satisfy ECMA-262.
+    call->shared()->set_length(1);
+    apply->shared()->set_length(2);
+  }
+
+  // Make sure that the builtins object has fast properties.
+  // If the ASSERT below fails, please increase the expected number of
+  // properties for the builtins object.
+  ASSERT(builtins->HasFastProperties());
+#ifdef DEBUG
+  builtins->Verify();
+#endif
+  return true;
+}
+
+
+bool Genesis::InstallSpecialObjects() {
+  HandleScope scope;
+  Handle<JSGlobalObject> js_global(
+      JSGlobalObject::cast(global_context()->global()));
+  // Expose the natives in global if a name for it is specified.
+  if (FLAG_expose_natives_as != NULL && strlen(FLAG_expose_natives_as) != 0) {
+    Handle<String> natives_string =
+        Factory::LookupAsciiSymbol(FLAG_expose_natives_as);
+    SetProperty(js_global, natives_string,
+                Handle<JSObject>(js_global->builtins()), DONT_ENUM);
+  }
+
+  // Expose the debug global object in global if a name for it is specified.
+  if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) {
+    // If loading fails we just bail out without installing the
+    // debugger but without tanking the whole context.
+    if (!Debug::Load())
+      return true;
+    // Set the security token for the debugger context to the same as
+    // the shell global context to allow calling between these (otherwise
+    // exposing debug global object doesn't make much sense).
+    Debug::debug_context()->set_security_token(
+        global_context()->security_token());
+
+    Handle<String> debug_string =
+        Factory::LookupAsciiSymbol(FLAG_expose_debug_as);
+    SetProperty(js_global, debug_string,
+        Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM);
+  }
+
+  return true;
+}
+
+
+bool Genesis::InstallExtensions(v8::ExtensionConfiguration* extensions) {
+  // Clear coloring of extension list
+  v8::RegisteredExtension* current = v8::RegisteredExtension::first_extension();
+  while (current != NULL) {
+    current->set_state(v8::UNVISITED);
+    current = current->next();
+  }
+  // Install auto extensions
+  current = v8::RegisteredExtension::first_extension();
+  while (current != NULL) {
+    if (current->extension()->auto_enable())
+      InstallExtension(current);
+    current = current->next();
+  }
+
+  if (FLAG_expose_gc) InstallExtension("v8/gc");
+
+  if (extensions == NULL) return true;
+  // Install required extensions
+  int count = v8::ImplementationUtilities::GetNameCount(extensions);
+  const char** names = v8::ImplementationUtilities::GetNames(extensions);
+  for (int i = 0; i < count; i++) {
+    if (!InstallExtension(names[i]))
+      return false;
+  }
+
+  return true;
+}
+
+
+// Installs a named extension.  This methods is unoptimized and does
+// not scale well if we want to support a large number of extensions.
+bool Genesis::InstallExtension(const char* name) {
+  v8::RegisteredExtension* current = v8::RegisteredExtension::first_extension();
+  // Loop until we find the relevant extension
+  while (current != NULL) {
+    if (strcmp(name, current->extension()->name()) == 0) break;
+    current = current->next();
+  }
+  // Didn't find the extension; fail.
+  if (current == NULL) {
+    v8::Utils::ReportApiFailure(
+        "v8::Context::New()", "Cannot find required extension");
+    return false;
+  }
+  return InstallExtension(current);
+}
+
+
+bool Genesis::InstallExtension(v8::RegisteredExtension* current) {
+  HandleScope scope;
+
+  if (current->state() == v8::INSTALLED) return true;
+  // The current node has already been visited so there must be a
+  // cycle in the dependency graph; fail.
+  if (current->state() == v8::VISITED) {
+    v8::Utils::ReportApiFailure(
+        "v8::Context::New()", "Circular extension dependency");
+    return false;
+  }
+  ASSERT(current->state() == v8::UNVISITED);
+  current->set_state(v8::VISITED);
+  v8::Extension* extension = current->extension();
+  // Install the extension's dependencies
+  for (int i = 0; i < extension->dependency_count(); i++) {
+    if (!InstallExtension(extension->dependencies()[i])) return false;
+  }
+  Vector<const char> source = CStrVector(extension->source());
+  Handle<String> source_code = Factory::NewStringFromAscii(source);
+  bool result = CompileScriptCached(CStrVector(extension->name()),
+                                    source_code,
+                                    &extensions_cache, extension,
+                                    false);
+  ASSERT(Top::has_pending_exception() != result);
+  if (!result) {
+    Top::clear_pending_exception();
+    v8::Utils::ReportApiFailure(
+        "v8::Context::New()", "Error installing extension");
+  }
+  current->set_state(v8::INSTALLED);
+  return result;
+}
+
+
+bool Genesis::ConfigureGlobalObjects(
+    v8::Handle<v8::ObjectTemplate> global_proxy_template) {
+  Handle<JSObject> global_proxy(
+      JSObject::cast(global_context()->global_proxy()));
+  Handle<JSObject> js_global(JSObject::cast(global_context()->global()));
+
+  if (!global_proxy_template.IsEmpty()) {
+    // Configure the global proxy object.
+    Handle<ObjectTemplateInfo> proxy_data =
+        v8::Utils::OpenHandle(*global_proxy_template);
+    if (!ConfigureApiObject(global_proxy, proxy_data)) return false;
+
+    // Configure the inner global object.
+    Handle<FunctionTemplateInfo> proxy_constructor(
+        FunctionTemplateInfo::cast(proxy_data->constructor()));
+    if (!proxy_constructor->prototype_template()->IsUndefined()) {
+      Handle<ObjectTemplateInfo> inner_data(
+          ObjectTemplateInfo::cast(proxy_constructor->prototype_template()));
+      if (!ConfigureApiObject(js_global, inner_data)) return false;
+    }
+  }
+
+  SetObjectPrototype(global_proxy, js_global);
+  return true;
+}
+
+
+bool Genesis::ConfigureApiObject(Handle<JSObject> object,
+    Handle<ObjectTemplateInfo> object_template) {
+  ASSERT(!object_template.is_null());
+  ASSERT(object->IsInstanceOf(
+      FunctionTemplateInfo::cast(object_template->constructor())));
+
+  bool pending_exception = false;
+  Handle<JSObject> obj =
+      Execution::InstantiateObject(object_template, &pending_exception);
+  if (pending_exception) {
+    ASSERT(Top::has_pending_exception());
+    Top::clear_pending_exception();
+    return false;
+  }
+  TransferObject(obj, object);
+  return true;
+}
+
+
+void Genesis::TransferNamedProperties(Handle<JSObject> from,
+                                      Handle<JSObject> to) {
+  if (from->HasFastProperties()) {
+    Handle<DescriptorArray> descs =
+        Handle<DescriptorArray>(from->map()->instance_descriptors());
+    int offset = 0;
+    while (true) {
+      // Iterating through the descriptors is not gc safe so we have to
+      // store the value in a handle and create a new stream for each entry.
+      DescriptorReader stream(*descs, offset);
+      if (stream.eos()) break;
+      // We have to read out the next offset before we do anything that may
+      // cause a gc, since the DescriptorReader is not gc safe.
+      offset = stream.next_position();
+      PropertyDetails details = stream.GetDetails();
+      switch (details.type()) {
+        case FIELD: {
+          HandleScope inner;
+          Handle<String> key = Handle<String>(stream.GetKey());
+          int index = stream.GetFieldIndex();
+          Handle<Object> value = Handle<Object>(from->FastPropertyAt(index));
+          SetProperty(to, key, value, details.attributes());
+          break;
+        }
+        case CONSTANT_FUNCTION: {
+          HandleScope inner;
+          Handle<String> key = Handle<String>(stream.GetKey());
+          Handle<JSFunction> fun =
+              Handle<JSFunction>(stream.GetConstantFunction());
+          SetProperty(to, key, fun, details.attributes());
+          break;
+        }
+        case CALLBACKS: {
+          LookupResult result;
+          to->LocalLookup(stream.GetKey(), &result);
+          // If the property is already there we skip it
+          if (result.IsValid()) continue;
+          HandleScope inner;
+          Handle<DescriptorArray> inst_descs =
+              Handle<DescriptorArray>(to->map()->instance_descriptors());
+          Handle<String> key = Handle<String>(stream.GetKey());
+          Handle<Object> entry = Handle<Object>(stream.GetCallbacksObject());
+          inst_descs = Factory::CopyAppendProxyDescriptor(inst_descs,
+                                                          key,
+                                                          entry,
+                                                          details.attributes());
+          to->map()->set_instance_descriptors(*inst_descs);
+          break;
+        }
+        case MAP_TRANSITION:
+        case CONSTANT_TRANSITION:
+        case NULL_DESCRIPTOR:
+          // Ignore non-properties.
+          break;
+        case NORMAL:
+          // Do not occur since the from object has fast properties.
+        case INTERCEPTOR:
+          // No element in instance descriptors have interceptor type.
+          UNREACHABLE();
+          break;
+      }
+    }
+  } else {
+    Handle<Dictionary> properties =
+        Handle<Dictionary>(from->property_dictionary());
+    int capacity = properties->Capacity();
+    for (int i = 0; i < capacity; i++) {
+      Object* raw_key(properties->KeyAt(i));
+      if (properties->IsKey(raw_key)) {
+        ASSERT(raw_key->IsString());
+        // If the property is already there we skip it.
+        LookupResult result;
+        to->LocalLookup(String::cast(raw_key), &result);
+        if (result.IsValid()) continue;
+        // Set the property.
+        Handle<String> key = Handle<String>(String::cast(raw_key));
+        Handle<Object> value = Handle<Object>(properties->ValueAt(i));
+        PropertyDetails details = properties->DetailsAt(i);
+        SetProperty(to, key, value, details.attributes());
+      }
+    }
+  }
+}
+
+
+void Genesis::TransferIndexedProperties(Handle<JSObject> from,
+                                        Handle<JSObject> to) {
+  // Cloning the elements array is sufficient.
+  Handle<FixedArray> from_elements =
+      Handle<FixedArray>(FixedArray::cast(from->elements()));
+  Handle<FixedArray> to_elements = Factory::CopyFixedArray(from_elements);
+  to->set_elements(*to_elements);
+}
+
+
+void Genesis::TransferObject(Handle<JSObject> from, Handle<JSObject> to) {
+  HandleScope outer;
+
+  ASSERT(!from->IsJSArray());
+  ASSERT(!to->IsJSArray());
+
+  TransferNamedProperties(from, to);
+  TransferIndexedProperties(from, to);
+
+  // Transfer the prototype (new map is needed).
+  Handle<Map> old_to_map = Handle<Map>(to->map());
+  Handle<Map> new_to_map = Factory::CopyMapDropTransitions(old_to_map);
+  new_to_map->set_prototype(from->map()->prototype());
+  to->set_map(*new_to_map);
+}
+
+
+void Genesis::MakeFunctionInstancePrototypeWritable() {
+  // Make a new function map so all future functions
+  // will have settable and enumerable prototype properties.
+  HandleScope scope;
+
+  Handle<DescriptorArray> function_map_descriptors =
+      ComputeFunctionInstanceDescriptor(false, true);
+  Handle<Map> fm = Factory::CopyMap(Top::function_map());
+  fm->set_instance_descriptors(*function_map_descriptors);
+  Top::context()->global_context()->set_function_map(*fm);
+}
+
+
+void Genesis::AddSpecialFunction(Handle<JSObject> prototype,
+                                 const char* name,
+                                 Handle<Code> code) {
+  Handle<String> key = Factory::LookupAsciiSymbol(name);
+  Handle<Object> value = Handle<Object>(prototype->GetProperty(*key));
+  if (value->IsJSFunction()) {
+    Handle<JSFunction> optimized = Factory::NewFunction(key,
+                                                        JS_OBJECT_TYPE,
+                                                        JSObject::kHeaderSize,
+                                                        code,
+                                                        false);
+    optimized->shared()->DontAdaptArguments();
+    int len = global_context()->special_function_table()->length();
+    Handle<FixedArray> new_array = Factory::NewFixedArray(len + 3);
+    for (int index = 0; index < len; index++) {
+      new_array->set(index,
+                     global_context()->special_function_table()->get(index));
+    }
+    new_array->set(len+0, *prototype);
+    new_array->set(len+1, *value);
+    new_array->set(len+2, *optimized);
+    global_context()->set_special_function_table(*new_array);
+  }
+}
+
+
+void Genesis::BuildSpecialFunctionTable() {
+  HandleScope scope;
+  Handle<JSObject> global = Handle<JSObject>(global_context()->global());
+  // Add special versions for Array.prototype.pop and push.
+  Handle<JSFunction> function =
+      Handle<JSFunction>(
+          JSFunction::cast(global->GetProperty(Heap::Array_symbol())));
+  Handle<JSObject> prototype =
+      Handle<JSObject>(JSObject::cast(function->prototype()));
+  AddSpecialFunction(prototype, "pop",
+                     Handle<Code>(Builtins::builtin(Builtins::ArrayPop)));
+  AddSpecialFunction(prototype, "push",
+                     Handle<Code>(Builtins::builtin(Builtins::ArrayPush)));
+}
+
+
+Genesis::Genesis(Handle<Object> global_object,
+                 v8::Handle<v8::ObjectTemplate> global_template,
+                 v8::ExtensionConfiguration* extensions) {
+  // Link this genesis object into the stacked genesis chain. This
+  // must be done before any early exits because the deconstructor
+  // will always do unlinking.
+  previous_ = current_;
+  current_  = this;
+  result_ = NULL;
+
+  // If V8 hasn't been and cannot be initialized, just return.
+  if (!V8::HasBeenSetup() && !V8::Initialize(NULL)) return;
+
+  // Before creating the roots we must save the context and restore it
+  // on all function exits.
+  HandleScope scope;
+  SaveContext context;
+
+  CreateRoots(global_template, global_object);
+  if (!InstallNatives()) return;
+
+  MakeFunctionInstancePrototypeWritable();
+  BuildSpecialFunctionTable();
+
+  if (!ConfigureGlobalObjects(global_template)) return;
+
+  if (!InstallExtensions(extensions)) return;
+
+  if (!InstallSpecialObjects()) return;
+
+  result_ = global_context_;
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/bootstrapper.h b/regexp2000/src/bootstrapper.h
new file mode 100644 (file)
index 0000000..0b0784e
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef V8_BOOTSTRAPPER_H_
+#define V8_BOOTSTRAPPER_H_
+
+namespace v8 { namespace internal {
+
+// The Boostrapper is the public interface for creating a JavaScript global
+// context.
+class Bootstrapper : public AllStatic {
+ public:
+  // Requires: Heap::Setup has been called.
+  static void Initialize(bool create_heap_objects);
+  static void TearDown();
+
+  // Creates a JavaScript Global Context with initial object graph.
+  // The returned value is a global handle casted to V8Environment*.
+  static Handle<Context> CreateEnvironment(
+      Handle<Object> global_object,
+      v8::Handle<v8::ObjectTemplate> global_template,
+      v8::ExtensionConfiguration* extensions);
+
+  // Detach the environment from its outer global object.
+  static void DetachGlobal(Handle<Context> env);
+
+  // Traverses the pointers for memory manangment.
+  static void Iterate(ObjectVisitor* v);
+
+  // Accessors for the native scripts cache. Used in lazy loading.
+  static Handle<String> NativesSourceLookup(int index);
+  static bool NativesCacheLookup(Vector<const char> name,
+                                 Handle<JSFunction>* handle);
+  static void NativesCacheAdd(Vector<const char> name, Handle<JSFunction> fun);
+
+  // Append code that needs fixup at the end of boot strapping.
+  static void AddFixup(Code* code, MacroAssembler* masm);
+
+  // Tells whether boostrapping is active.
+  static bool IsActive();
+
+  // Encoding/decoding support for fixup flags.
+  class FixupFlagsIsPCRelative: public BitField<bool, 0, 1> {};
+  class FixupFlagsArgumentsCount: public BitField<uint32_t, 1, 32-1> {};
+};
+
+}}  // namespace v8::internal
+
+#endif  // V8_BOOTSTRAPPER_H_
diff --git a/regexp2000/src/builtins-arm.cc b/regexp2000/src/builtins-arm.cc
new file mode 100644 (file)
index 0000000..c1b654f
--- /dev/null
@@ -0,0 +1,821 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "debug.h"
+#include "runtime.h"
+
+namespace v8 { namespace internal {
+
+
+#define __ masm->
+
+
+void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
+  // TODO(1238487): Don't pass the function in a static variable.
+  __ mov(ip, Operand(ExternalReference::builtin_passed_function()));
+  __ str(r1, MemOperand(ip, 0));
+
+  // The actual argument count has already been loaded into register
+  // r0, but JumpToBuiltin expects r0 to contain the number of
+  // arguments including the receiver.
+  __ add(r0, r0, Operand(1));
+  __ JumpToBuiltin(ExternalReference(id));
+}
+
+
+void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0     : number of arguments
+  //  -- r1     : constructor function
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+
+  // Enter a construct frame.
+  __ EnterConstructFrame();
+
+  // Preserve the two incoming parameters
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+  __ push(r0);  // smi-tagged arguments count
+  __ push(r1);  // constructor function
+
+  // Allocate the new receiver object.
+  __ push(r1);  // argument for Runtime_NewObject
+  __ CallRuntime(Runtime::kNewObject, 1);
+  __ push(r0);  // save the receiver
+
+  // Push the function and the allocated receiver from the stack.
+  // sp[0]: receiver (newly allocated object)
+  // sp[1]: constructor function
+  // sp[2]: number of arguments (smi-tagged)
+  __ ldr(r1, MemOperand(sp, kPointerSize));
+  __ push(r1);  // function
+  __ push(r0);  // receiver
+
+  // Reload the number of arguments from the stack.
+  // r1: constructor function
+  // sp[0]: receiver
+  // sp[1]: constructor function
+  // sp[2]: receiver
+  // sp[3]: constructor function
+  // sp[4]: number of arguments (smi-tagged)
+  __ ldr(r3, MemOperand(sp, 4 * kPointerSize));
+
+  // Setup pointer to last argument.
+  __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
+
+  // Setup number of arguments for function call below
+  __ mov(r0, Operand(r3, LSR, kSmiTagSize));
+
+  // Copy arguments and receiver to the expression stack.
+  // r0: number of arguments
+  // r2: address of last argument (caller sp)
+  // r1: constructor function
+  // r3: number of arguments (smi-tagged)
+  // sp[0]: receiver
+  // sp[1]: constructor function
+  // sp[2]: receiver
+  // sp[3]: constructor function
+  // sp[4]: number of arguments (smi-tagged)
+  Label loop, entry;
+  __ b(&entry);
+  __ bind(&loop);
+  __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1));
+  __ push(ip);
+  __ bind(&entry);
+  __ sub(r3, r3, Operand(2), SetCC);
+  __ b(ge, &loop);
+
+  // Call the function.
+  // r0: number of arguments
+  // r1: constructor function
+  ParameterCount actual(r0);
+  __ InvokeFunction(r1, actual, CALL_FUNCTION);
+
+  // Pop the function from the stack.
+  // sp[0]: constructor function
+  // sp[2]: receiver
+  // sp[3]: constructor function
+  // sp[4]: number of arguments (smi-tagged)
+  __ pop();
+
+  // Restore context from the frame.
+  // r0: result
+  // sp[0]: receiver
+  // sp[1]: constructor function
+  // sp[2]: number of arguments (smi-tagged)
+  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+  // If the result is an object (in the ECMA sense), we should get rid
+  // of the receiver and use the result; see ECMA-262 section 13.2.2-7
+  // on page 74.
+  Label use_receiver, exit;
+
+  // If the result is a smi, it is *not* an object in the ECMA sense.
+  // r0: result
+  // sp[0]: receiver (newly allocated object)
+  // sp[1]: constructor function
+  // sp[2]: number of arguments (smi-tagged)
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &use_receiver);
+
+  // If the type of the result (stored in its map) is less than
+  // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
+  __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+  __ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE));
+  __ b(ge, &exit);
+
+  // Throw away the result of the constructor invocation and use the
+  // on-stack receiver as the result.
+  __ bind(&use_receiver);
+  __ ldr(r0, MemOperand(sp));
+
+  // Remove receiver from the stack, remove caller arguments, and
+  // return.
+  __ bind(&exit);
+  // r0: result
+  // sp[0]: receiver (newly allocated object)
+  // sp[1]: constructor function
+  // sp[2]: number of arguments (smi-tagged)
+  __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
+  __ LeaveConstructFrame();
+  __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
+  __ add(sp, sp, Operand(kPointerSize));
+  __ mov(pc, Operand(lr));
+}
+
+
+static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
+                                             bool is_construct) {
+  // Called from Generate_JS_Entry
+  // r0: code entry
+  // r1: function
+  // r2: receiver
+  // r3: argc
+  // r4: argv
+  // r5-r7, cp may be clobbered
+
+  // Clear the context before we push it when entering the JS frame.
+  __ mov(cp, Operand(0));
+
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Setup the context from the function argument.
+  __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+
+  // Push the function and the receiver onto the stack.
+  __ push(r1);
+  __ push(r2);
+
+  // Copy arguments to the stack in a loop.
+  // r1: function
+  // r3: argc
+  // r4: argv, i.e. points to first arg
+  Label loop, entry;
+  __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2));
+  // r2 points past last arg.
+  __ b(&entry);
+  __ bind(&loop);
+  __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex));  // read next parameter
+  __ ldr(r0, MemOperand(r0));  // dereference handle
+  __ push(r0);  // push parameter
+  __ bind(&entry);
+  __ cmp(r4, Operand(r2));
+  __ b(ne, &loop);
+
+  // Initialize all JavaScript callee-saved registers, since they will be seen
+  // by the garbage collector as part of handlers.
+  __ mov(r4, Operand(Factory::undefined_value()));
+  __ mov(r5, Operand(r4));
+  __ mov(r6, Operand(r4));
+  __ mov(r7, Operand(r4));
+  if (kR9Available == 1)
+    __ mov(r9, Operand(r4));
+
+  // Invoke the code and pass argc as r0.
+  __ mov(r0, Operand(r3));
+  if (is_construct) {
+    __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+            RelocInfo::CODE_TARGET);
+  } else {
+    ParameterCount actual(r0);
+    __ InvokeFunction(r1, actual, CALL_FUNCTION);
+  }
+
+  // Exit the JS frame and remove the parameters (except function), and return.
+  // Respect ABI stack constraint.
+  __ LeaveInternalFrame();
+  __ mov(pc, lr);
+
+  // r0: result
+}
+
+
+void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, true);
+}
+
+
+void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
+  // 1. Make sure we have at least one argument.
+  // r0: actual number of argument
+  { Label done;
+    __ tst(r0, Operand(r0));
+    __ b(ne, &done);
+    __ mov(r2, Operand(Factory::undefined_value()));
+    __ push(r2);
+    __ add(r0, r0, Operand(1));
+    __ bind(&done);
+  }
+
+  // 2. Get the function to call from the stack.
+  // r0: actual number of argument
+  { Label done, non_function, function;
+    __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+    __ tst(r1, Operand(kSmiTagMask));
+    __ b(eq, &non_function);
+    __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+    __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+    __ cmp(r2, Operand(JS_FUNCTION_TYPE));
+    __ b(eq, &function);
+
+    // Non-function called: Clear the function to force exception.
+    __ bind(&non_function);
+    __ mov(r1, Operand(0));
+    __ b(&done);
+
+    // Change the context eagerly because it will be used below to get the
+    // right global object.
+    __ bind(&function);
+    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+
+    __ bind(&done);
+  }
+
+  // 3. Make sure first argument is an object; convert if necessary.
+  // r0: actual number of arguments
+  // r1: function
+  { Label call_to_object, use_global_receiver, patch_receiver, done;
+    __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
+    __ ldr(r2, MemOperand(r2, -kPointerSize));
+
+    // r0: actual number of arguments
+    // r1: function
+    // r2: first argument
+    __ tst(r2, Operand(kSmiTagMask));
+    __ b(eq, &call_to_object);
+
+    __ mov(r3, Operand(Factory::null_value()));
+    __ cmp(r2, r3);
+    __ b(eq, &use_global_receiver);
+    __ mov(r3, Operand(Factory::undefined_value()));
+    __ cmp(r2, r3);
+    __ b(eq, &use_global_receiver);
+
+    __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
+    __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+    __ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE));
+    __ b(lt, &call_to_object);
+    __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE));
+    __ b(le, &done);
+
+    __ bind(&call_to_object);
+    __ EnterInternalFrame();
+
+    // Store number of arguments and function across the call into the runtime.
+    __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+    __ push(r0);
+    __ push(r1);
+
+    __ push(r2);
+    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
+    __ mov(r2, r0);
+
+    // Restore number of arguments and function.
+    __ pop(r1);
+    __ pop(r0);
+    __ mov(r0, Operand(r0, ASR, kSmiTagSize));
+
+    __ LeaveInternalFrame();
+    __ b(&patch_receiver);
+
+    // Use the global receiver object from the called function as the receiver.
+    __ bind(&use_global_receiver);
+    const int kGlobalIndex =
+        Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+    __ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
+    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
+
+    __ bind(&patch_receiver);
+    __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
+    __ str(r2, MemOperand(r3, -kPointerSize));
+
+    __ bind(&done);
+  }
+
+  // 4. Shift stuff one slot down the stack
+  // r0: actual number of arguments (including call() receiver)
+  // r1: function
+  { Label loop;
+    // Calculate the copy start address (destination). Copy end address is sp.
+    __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
+    __ add(r2, r2, Operand(kPointerSize));  // copy receiver too
+
+    __ bind(&loop);
+    __ ldr(ip, MemOperand(r2, -kPointerSize));
+    __ str(ip, MemOperand(r2));
+    __ sub(r2, r2, Operand(kPointerSize));
+    __ cmp(r2, sp);
+    __ b(ne, &loop);
+  }
+
+  // 5. Adjust the actual number of arguments and remove the top element.
+  // r0: actual number of arguments (including call() receiver)
+  // r1: function
+  __ sub(r0, r0, Operand(1));
+  __ add(sp, sp, Operand(kPointerSize));
+
+  // 6. Get the code for the function or the non-function builtin.
+  //    If number of expected arguments matches, then call. Otherwise restart
+  //    the arguments adaptor stub.
+  // r0: actual number of arguments
+  // r1: function
+  { Label invoke;
+    __ tst(r1, r1);
+    __ b(ne, &invoke);
+    __ mov(r2, Operand(0));  // expected arguments is 0 for CALL_NON_FUNCTION
+    __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
+    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+                         RelocInfo::CODE_TARGET);
+
+    __ bind(&invoke);
+    __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+    __ ldr(r2,
+           FieldMemOperand(r3,
+                           SharedFunctionInfo::kFormalParameterCountOffset));
+    __ ldr(r3,
+           MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
+    __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
+    __ cmp(r2, r0);  // Check formal and actual parameter counts.
+    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+                         RelocInfo::CODE_TARGET, ne);
+
+    // 7. Jump to the code in r3 without checking arguments.
+    ParameterCount expected(0);
+    __ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
+  }
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  const int kIndexOffset    = -5 * kPointerSize;
+  const int kLimitOffset    = -4 * kPointerSize;
+  const int kArgsOffset     =  2 * kPointerSize;
+  const int kRecvOffset     =  3 * kPointerSize;
+  const int kFunctionOffset =  4 * kPointerSize;
+
+  __ EnterInternalFrame();
+
+  __ ldr(r0, MemOperand(fp, kFunctionOffset));  // get the function
+  __ push(r0);
+  __ ldr(r0, MemOperand(fp, kArgsOffset));  // get the args array
+  __ push(r0);
+  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS);
+
+  // Eagerly check for stack-overflow before starting to push the arguments.
+  // r0: number of arguments
+  Label okay;
+  ExternalReference stack_guard_limit_address =
+      ExternalReference::address_of_stack_guard_limit();
+  __ mov(r2, Operand(stack_guard_limit_address));
+  __ ldr(r2, MemOperand(r2));
+  __ sub(r2, sp, r2);
+  __ sub(r2, r2, Operand(3 * kPointerSize));  // limit, index, receiver
+
+  __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
+  __ b(hi, &okay);
+
+  // Out of stack space.
+  __ ldr(r1, MemOperand(fp, kFunctionOffset));
+  __ push(r1);
+  __ push(r0);
+  __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS);
+
+  // Push current limit and index.
+  __ bind(&okay);
+  __ push(r0);  // limit
+  __ mov(r1, Operand(0));  // initial index
+  __ push(r1);
+
+  // Change context eagerly to get the right global object if necessary.
+  __ ldr(r0, MemOperand(fp, kFunctionOffset));
+  __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
+
+  // Compute the receiver.
+  Label call_to_object, use_global_receiver, push_receiver;
+  __ ldr(r0, MemOperand(fp, kRecvOffset));
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &call_to_object);
+  __ mov(r1, Operand(Factory::null_value()));
+  __ cmp(r0, r1);
+  __ b(eq, &use_global_receiver);
+  __ mov(r1, Operand(Factory::undefined_value()));
+  __ cmp(r0, r1);
+  __ b(eq, &use_global_receiver);
+
+  // Check if the receiver is already a JavaScript object.
+  // r0: receiver
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
+  __ b(lt, &call_to_object);
+  __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
+  __ b(le, &push_receiver);
+
+  // Convert the receiver to a regular object.
+  // r0: receiver
+  __ bind(&call_to_object);
+  __ push(r0);
+  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
+  __ b(&push_receiver);
+
+  // Use the current global receiver object as the receiver.
+  __ bind(&use_global_receiver);
+  const int kGlobalOffset =
+      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+  __ ldr(r0, FieldMemOperand(cp, kGlobalOffset));
+  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
+
+  // Push the receiver.
+  // r0: receiver
+  __ bind(&push_receiver);
+  __ push(r0);
+
+  // Copy all arguments from the array to the stack.
+  Label entry, loop;
+  __ ldr(r0, MemOperand(fp, kIndexOffset));
+  __ b(&entry);
+
+  // Load the current argument from the arguments array and push it to the
+  // stack.
+  // r0: current argument index
+  __ bind(&loop);
+  __ ldr(r1, MemOperand(fp, kArgsOffset));
+  __ push(r1);
+  __ push(r0);
+
+  // Call the runtime to access the property in the arguments array.
+  __ CallRuntime(Runtime::kGetProperty, 2);
+  __ push(r0);
+
+  // Use inline caching to access the arguments.
+  __ ldr(r0, MemOperand(fp, kIndexOffset));
+  __ add(r0, r0, Operand(1 << kSmiTagSize));
+  __ str(r0, MemOperand(fp, kIndexOffset));
+
+  // Test if the copy loop has finished copying all the elements from the
+  // arguments object.
+  __ bind(&entry);
+  __ ldr(r1, MemOperand(fp, kLimitOffset));
+  __ cmp(r0, r1);
+  __ b(ne, &loop);
+
+  // Invoke the function.
+  ParameterCount actual(r0);
+  __ mov(r0, Operand(r0, ASR, kSmiTagSize));
+  __ ldr(r1, MemOperand(fp, kFunctionOffset));
+  __ InvokeFunction(r1, actual, CALL_FUNCTION);
+
+  // Tear down the internal frame and remove function, receiver and args.
+  __ LeaveInternalFrame();
+  __ add(sp, sp, Operand(3 * kPointerSize));
+  __ mov(pc, lr);
+}
+
+
+static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+  __ mov(r4, Operand(ArgumentsAdaptorFrame::SENTINEL));
+  __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit());
+  __ add(fp, sp, Operand(3 * kPointerSize));
+}
+
+
+static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0 : result being passed through
+  // -----------------------------------
+  // Get the number of arguments passed (as a smi), tear down the frame and
+  // then tear down the parameters.
+  __ ldr(r1, MemOperand(fp, -3 * kPointerSize));
+  __ mov(sp, fp);
+  __ ldm(ia_w, sp, fp.bit() | lr.bit());
+  __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
+  __ add(sp, sp, Operand(kPointerSize));  // adjust for receiver
+}
+
+
+void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0 : actual number of arguments
+  //  -- r1 : function (passed through to callee)
+  //  -- r2 : expected number of arguments
+  //  -- r3 : code entry to call
+  // -----------------------------------
+
+  Label invoke, dont_adapt_arguments;
+
+  Label enough, too_few;
+  __ cmp(r0, Operand(r2));
+  __ b(lt, &too_few);
+  __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
+  __ b(eq, &dont_adapt_arguments);
+
+  {  // Enough parameters: actual >= excpected
+    __ bind(&enough);
+    EnterArgumentsAdaptorFrame(masm);
+
+    // Calculate copy start address into r0 and copy end address into r2.
+    // r0: actual number of arguments as a smi
+    // r1: function
+    // r2: expected number of arguments
+    // r3: code entry to call
+    __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
+    // adjust for return address and receiver
+    __ add(r0, r0, Operand(2 * kPointerSize));
+    __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2));
+
+    // Copy the arguments (including the receiver) to the new stack frame.
+    // r0: copy start address
+    // r1: function
+    // r2: copy end address
+    // r3: code entry to call
+
+    Label copy;
+    __ bind(&copy);
+    __ ldr(ip, MemOperand(r0, 0));
+    __ push(ip);
+    __ cmp(r0, r2);  // Compare before moving to next argument.
+    __ sub(r0, r0, Operand(kPointerSize));
+    __ b(ne, &copy);
+
+    __ b(&invoke);
+  }
+
+  {  // Too few parameters: Actual < expected
+    __ bind(&too_few);
+    EnterArgumentsAdaptorFrame(masm);
+
+    // Calculate copy start address into r0 and copy end address is fp.
+    // r0: actual number of arguments as a smi
+    // r1: function
+    // r2: expected number of arguments
+    // r3: code entry to call
+    __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
+
+    // Copy the arguments (including the receiver) to the new stack frame.
+    // r0: copy start address
+    // r1: function
+    // r2: expected number of arguments
+    // r3: code entry to call
+    Label copy;
+    __ bind(&copy);
+    // Adjust load for return address and receiver.
+    __ ldr(ip, MemOperand(r0, 2 * kPointerSize));
+    __ push(ip);
+    __ cmp(r0, fp);  // Compare before moving to next argument.
+    __ sub(r0, r0, Operand(kPointerSize));
+    __ b(ne, &copy);
+
+    // Fill the remaining expected arguments with undefined.
+    // r1: function
+    // r2: expected number of arguments
+    // r3: code entry to call
+    __ mov(ip, Operand(Factory::undefined_value()));
+    __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2));
+    __ sub(r2, r2, Operand(4 * kPointerSize));  // Adjust for frame.
+
+    Label fill;
+    __ bind(&fill);
+    __ push(ip);
+    __ cmp(sp, r2);
+    __ b(ne, &fill);
+  }
+
+  // Call the entry point.
+  __ bind(&invoke);
+  __ Call(r3);
+
+  // Exit frame and return.
+  LeaveArgumentsAdaptorFrame(masm);
+  __ mov(pc, lr);
+
+
+  // -------------------------------------------
+  // Dont adapt arguments.
+  // -------------------------------------------
+  __ bind(&dont_adapt_arguments);
+  __ mov(pc, r3);
+}
+
+
+static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
+                                          RegList pointer_regs) {
+  // Save the content of all general purpose registers in memory. This copy in
+  // memory is later pushed onto the JS expression stack for the fake JS frame
+  // generated and also to the C frame generated on top of that. In the JS
+  // frame ONLY the registers containing pointers will be pushed on the
+  // expression stack. This causes the GC to update these  pointers so that
+  // they will have the correct value when returning from the debugger.
+  __ SaveRegistersToMemory(kJSCallerSaved);
+
+  // This is a direct call from a debug breakpoint. To build a fake JS frame
+  // with no parameters push a function and a receiver, keep the current
+  // return address in lr, and set r0 to zero.
+  __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
+  __ ldr(r3, MemOperand(ip));
+  __ mov(r0, Operand(0));  // Null receiver and zero arguments.
+  __ stm(db_w, sp, r0.bit() | r3.bit());  // push function and receiver
+
+  // r0: number of arguments.
+  // What follows is an inlined version of EnterJSFrame(0, 0).
+  // It needs to be kept in sync if any calling conventions are changed.
+
+  // Compute parameter pointer before making changes
+  // ip = sp + kPointerSize*(args_len+1);  // +1 for receiver, args_len == 0
+  __ add(ip, sp, Operand(kPointerSize));
+
+  __ mov(r3, Operand(0));  // args_len to be saved
+  __ mov(r2, Operand(cp));  // context to be saved
+
+  // push in reverse order: context (r2), args_len (r3), caller_pp, caller_fp,
+  // sp_on_exit (ip == pp), return address
+  __ stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() |
+         ip.bit() | lr.bit());
+  // Setup new frame pointer.
+  __ add(fp, sp, Operand(-StandardFrameConstants::kContextOffset));
+  __ mov(pp, Operand(ip));  // setup new parameter pointer
+  // r0 is already set to 0 as spare slot to store caller code object during GC
+  __ push(r0);  // code pointer
+
+  // Inlined EnterJSFrame ends here.
+
+  // Store the registers containing object pointers on the expression stack to
+  // make sure that these are correctly updated during GC.
+  // Use sp as base to push.
+  __ CopyRegistersFromMemoryToStack(sp, pointer_regs);
+
+#ifdef DEBUG
+  __ RecordComment("// Calling from debug break to runtime - come in - over");
+#endif
+  // r0 is already 0, no arguments
+  __ mov(r1, Operand(ExternalReference::debug_break()));
+
+  CEntryDebugBreakStub ceb;
+  __ CallStub(&ceb);
+
+  // Restore the register values containing object pointers from the expression
+  // stack in the reverse order as they where pushed.
+  // Use sp as base to pop.
+  __ CopyRegistersFromStackToMemory(sp, r3, pointer_regs);
+
+  // What follows is an inlined version of ExitJSFrame(0).
+  // It needs to be kept in sync if any calling conventions are changed.
+  // NOTE: loading the return address to lr and discarding the (fake) function
+  //       is an addition to this inlined copy.
+
+  __ mov(sp, Operand(fp));  // respect ABI stack constraint
+  __ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | lr.bit());
+  __ pop();  // discard fake function
+
+  // Inlined ExitJSFrame ends here.
+
+  // Finally restore all registers.
+  __ RestoreRegistersFromMemory(kJSCallerSaved);
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  __ mov(ip, Operand(ExternalReference(Debug_Address::AfterBreakTarget())));
+  __ ldr(ip, MemOperand(ip));
+  __ Jump(ip);
+}
+
+
+void Builtins::Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC load (from ic-arm.cc).
+  // ----------- S t a t e -------------
+  //  -- r0    : receiver
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+  // Registers r0 and r2 contain objects that needs to be pushed on the
+  // expression stack of the fake JS frame.
+  Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());
+}
+
+
+void Builtins::Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC store (from ic-arm.cc).
+  // ----------- S t a t e -------------
+  //  -- r0    : receiver
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+  // Registers r0 and r2 contain objects that needs to be pushed on the
+  // expression stack of the fake JS frame.
+  Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());
+}
+
+
+void Builtins::Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
+  // Keyed load IC not implemented on ARM.
+}
+
+
+void Builtins::Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
+  // Keyed store IC not implemented on ARM.
+}
+
+
+void Builtins::Generate_CallIC_DebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC call (from ic-arm.cc)
+  // ----------- S t a t e -------------
+  //  -- r0: number of arguments
+  //  -- r1: receiver
+  //  -- lr: return address
+  // -----------------------------------
+  // Register r1 contains an object that needs to be pushed on the expression
+  // stack of the fake JS frame. r0 is the actual number of arguments not
+  // encoded as a smi, therefore it cannot be on the expression stack of the
+  // fake JS frame as it can easily be an invalid pointer (e.g. 1). r0 will be
+  // pushed on the stack of the C frame and restored from there.
+  Generate_DebugBreakCallHelper(masm, r1.bit());
+}
+
+
+void Builtins::Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
+  // In places other than IC call sites it is expected that r0 is TOS which
+  // is an object - this is not generally the case so this should be used with
+  // care.
+  Generate_DebugBreakCallHelper(masm, r0.bit());
+}
+
+
+void Builtins::Generate_Return_DebugBreak(MacroAssembler* masm) {
+  // In places other than IC call sites it is expected that r0 is TOS which
+  // is an object - this is not generally the case so this should be used with
+  // care.
+  Generate_DebugBreakCallHelper(masm, r0.bit());
+}
+
+
+void Builtins::Generate_Return_DebugBreakEntry(MacroAssembler* masm) {
+  // Generate nothing as this handling of debug break return is not done this
+  // way on ARM  - yet.
+}
+
+void Builtins::Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
+  // Generate nothing as CodeStub CallFunction is not used on ARM.
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/builtins-ia32.cc b/regexp2000/src/builtins-ia32.cc
new file mode 100644 (file)
index 0000000..0de381c
--- /dev/null
@@ -0,0 +1,902 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "debug.h"
+#include "runtime.h"
+
+namespace v8 { namespace internal {
+
+
+#define __ masm->
+
+
+void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
+  // TODO(1238487): Don't pass the function in a static variable.
+  ExternalReference passed = ExternalReference::builtin_passed_function();
+  __ mov(Operand::StaticVariable(passed), edi);
+
+  // The actual argument count has already been loaded into register
+  // eax, but JumpToBuiltin expects eax to contain the number of
+  // arguments including the receiver.
+  __ inc(eax);
+  __ JumpToBuiltin(ExternalReference(id));
+}
+
+
+void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax: number of arguments
+  //  -- edi: constructor function
+  // -----------------------------------
+
+  // Enter a construct frame.
+  __ EnterConstructFrame();
+
+  // Store a smi-tagged arguments count on the stack.
+  __ shl(eax, kSmiTagSize);
+  __ push(eax);
+
+  // Push the function to invoke on the stack.
+  __ push(edi);
+
+  // Try to allocate the object without transitioning into C code. If any of the
+  // preconditions is not met, the code bails out to the runtime call.
+  Label rt_call, allocated;
+  if (FLAG_inline_new) {
+    Label undo_allocation;
+    ExternalReference debug_step_in_fp =
+        ExternalReference::debug_step_in_fp_address();
+    __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
+    __ j(not_equal, &rt_call);
+    // Check that function is not a Smi.
+    __ test(edi, Immediate(kSmiTagMask));
+    __ j(zero, &rt_call);
+    // Check that function is a JSFunction
+    __ mov(eax, FieldOperand(edi, JSFunction::kMapOffset));
+    __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
+    __ cmp(eax, JS_FUNCTION_TYPE);
+    __ j(not_equal, &rt_call);
+
+    // Verified that the constructor is a JSFunction.
+    // Load the initial map and verify that it is in fact a map.
+    // edi: constructor
+    __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
+    // Will both indicate a NULL and a Smi
+    __ test(eax, Immediate(kSmiTagMask));
+    __ j(zero, &rt_call);
+    // edi: constructor
+    // eax: initial map (if proven valid below)
+    __ mov(ebx, FieldOperand(eax, JSFunction::kMapOffset));
+    __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+    __ cmp(ebx, MAP_TYPE);
+    __ j(not_equal, &rt_call);
+
+    // Check that the constructor is not constructing a JSFunction (see comments
+    // in Runtime_NewObject in runtime.cc). In which case the initial map's
+    // instance type would be JS_FUNCTION_TYPE.
+    // edi: constructor
+    // eax: initial map
+    __ movzx_b(ebx, FieldOperand(eax, Map::kInstanceTypeOffset));
+    __ cmp(ebx, JS_FUNCTION_TYPE);
+    __ j(equal, &rt_call);
+
+    // Now allocate the JSObject on the heap.
+    // edi: constructor
+    // eax: initial map
+    __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
+    __ shl(edi, kPointerSizeLog2);
+    // Make sure that the maximum heap object size will never cause us
+    // problem here, because it is always greater than the maximum
+    // instance size that can be represented in a byte.
+    ASSERT(Heap::MaxHeapObjectSize() >= (1 << kBitsPerByte));
+    ExternalReference new_space_allocation_top =
+        ExternalReference::new_space_allocation_top_address();
+    __ mov(ebx, Operand::StaticVariable(new_space_allocation_top));
+    __ add(edi, Operand(ebx));  // Calculate new top
+    ExternalReference new_space_allocation_limit =
+        ExternalReference::new_space_allocation_limit_address();
+    __ cmp(edi, Operand::StaticVariable(new_space_allocation_limit));
+    __ j(greater_equal, &rt_call);
+    // Allocated the JSObject, now initialize the fields.
+    // eax: initial map
+    // ebx: JSObject
+    // edi: start of next object
+    __ mov(Operand(ebx, JSObject::kMapOffset), eax);
+    __ mov(Operand(ecx), Factory::empty_fixed_array());
+    __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
+    __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
+    // Set extra fields in the newly allocated object.
+    // eax: initial map
+    // ebx: JSObject
+    // edi: start of next object
+    { Label loop, entry;
+      __ mov(Operand(edx), Factory::undefined_value());
+      __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
+      __ jmp(&entry);
+      __ bind(&loop);
+      __ mov(Operand(ecx, 0), edx);
+      __ add(Operand(ecx), Immediate(kPointerSize));
+      __ bind(&entry);
+      __ cmp(ecx, Operand(edi));
+      __ j(less, &loop);
+    }
+
+    // Mostly done with the JSObject. Add the heap tag and store the new top, so
+    // that we can continue and jump into the continuation code at any time from
+    // now on. Any failures need to undo the setting of the new top, so that the
+    // heap is in a consistent state and verifiable.
+    // eax: initial map
+    // ebx: JSObject
+    // edi: start of next object
+    __ or_(Operand(ebx), Immediate(kHeapObjectTag));
+    __ mov(Operand::StaticVariable(new_space_allocation_top), edi);
+
+    // Check if a properties array should be setup and allocate one if needed.
+    // Otherwise initialize the properties to the empty_fixed_array as well.
+    // eax: initial map
+    // ebx: JSObject
+    // edi: start of next object
+    __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
+    __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
+    // Calculate unused properties past the end of the in-object properties.
+    __ sub(edx, Operand(ecx));
+    __ test(edx, Operand(edx));
+    // Done if no extra properties are to be allocated.
+    __ j(zero, &allocated);
+
+    // Scale the number of elements by pointer size and add the header for
+    // FixedArrays to the start of the next object calculation from above.
+    // eax: initial map
+    // ebx: JSObject
+    // edi: start of next object (will be start of FixedArray)
+    // edx: number of elements in properties array
+    ASSERT(Heap::MaxHeapObjectSize() >
+           (FixedArray::kHeaderSize + 255*kPointerSize));
+    __ lea(ecx, Operand(edi, edx, times_4, FixedArray::kHeaderSize));
+    __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
+    __ j(greater_equal, &undo_allocation);
+    __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
+
+    // Initialize the FixedArray.
+    // ebx: JSObject
+    // edi: FixedArray
+    // edx: number of elements
+    // ecx: start of next object
+    __ mov(eax, Factory::fixed_array_map());
+    __ mov(Operand(edi, JSObject::kMapOffset), eax);  // setup the map
+    __ mov(Operand(edi, Array::kLengthOffset), edx);  // and length
+
+    // Initialize the fields to undefined.
+    // ebx: JSObject
+    // edi: FixedArray
+    // ecx: start of next object
+    { Label loop, entry;
+      __ mov(Operand(edx), Factory::undefined_value());
+      __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
+      __ jmp(&entry);
+      __ bind(&loop);
+      __ mov(Operand(eax, 0), edx);
+      __ add(Operand(eax), Immediate(kPointerSize));
+      __ bind(&entry);
+      __ cmp(eax, Operand(ecx));
+      __ j(less, &loop);
+    }
+
+    // Store the initialized FixedArray into the properties field of
+    // the JSObject
+    // ebx: JSObject
+    // edi: FixedArray
+    __ or_(Operand(edi), Immediate(kHeapObjectTag));  // add the heap tag
+    __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
+
+
+    // Continue with JSObject being successfully allocated
+    // ebx: JSObject
+    __ jmp(&allocated);
+
+    // Undo the setting of the new top so that the heap is verifiable. For
+    // example, the map's unused properties potentially do not match the
+    // allocated objects unused properties.
+    // ebx: JSObject (previous new top)
+    __ bind(&undo_allocation);
+    __ xor_(Operand(ebx), Immediate(kHeapObjectTag));  // clear the heap tag
+    __ mov(Operand::StaticVariable(new_space_allocation_top), ebx);
+  }
+
+  // Allocate the new receiver object using the runtime call.
+  // edi: function (constructor)
+  __ bind(&rt_call);
+  // Must restore edi (constructor) before calling runtime.
+  __ mov(edi, Operand(esp, 0));
+  __ push(edi);
+  __ CallRuntime(Runtime::kNewObject, 1);
+  __ mov(ebx, Operand(eax));  // store result in ebx
+
+  // New object allocated.
+  // ebx: newly allocated object
+  __ bind(&allocated);
+  // Retrieve the function from the stack.
+  __ pop(edi);
+
+  // Retrieve smi-tagged arguments count from the stack.
+  __ mov(eax, Operand(esp, 0));
+  __ shr(eax, kSmiTagSize);
+
+  // Push the allocated receiver to the stack. We need two copies
+  // because we may have to return the original one and the calling
+  // conventions dictate that the called function pops the receiver.
+  __ push(ebx);
+  __ push(ebx);
+
+  // Setup pointer to last argument.
+  __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
+
+  // Copy arguments and receiver to the expression stack.
+  Label loop, entry;
+  __ mov(ecx, Operand(eax));
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ push(Operand(ebx, ecx, times_4, 0));
+  __ bind(&entry);
+  __ dec(ecx);
+  __ j(greater_equal, &loop);
+
+  // Call the function.
+  ParameterCount actual(eax);
+  __ InvokeFunction(edi, actual, CALL_FUNCTION);
+
+  // Restore context from the frame.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+
+  // If the result is an object (in the ECMA sense), we should get rid
+  // of the receiver and use the result; see ECMA-262 section 13.2.2-7
+  // on page 74.
+  Label use_receiver, exit;
+
+  // If the result is a smi, it is *not* an object in the ECMA sense.
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &use_receiver, not_taken);
+
+  // If the type of the result (stored in its map) is less than
+  // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
+  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(greater_equal, &exit, not_taken);
+
+  // Throw away the result of the constructor invocation and use the
+  // on-stack receiver as the result.
+  __ bind(&use_receiver);
+  __ mov(eax, Operand(esp, 0));
+
+  // Restore the arguments count and leave the construct frame.
+  __ bind(&exit);
+  __ mov(ebx, Operand(esp, kPointerSize));  // get arguments count
+  __ LeaveConstructFrame();
+
+  // Remove caller arguments from the stack and return.
+  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+  __ pop(ecx);
+  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
+  __ push(ecx);
+  __ ret(0);
+}
+
+
+static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
+                                             bool is_construct) {
+  // Clear the context before we push it when entering the JS frame.
+  __ xor_(esi, Operand(esi));  // clear esi
+
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Load the previous frame pointer (ebx) to access C arguments
+  __ mov(ebx, Operand(ebp, 0));
+
+  // Get the function from the frame and setup the context.
+  __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
+  __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
+
+  // Push the function and the receiver onto the stack.
+  __ push(ecx);
+  __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
+
+  // Load the number of arguments and setup pointer to the arguments.
+  __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
+  __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
+
+  // Copy arguments to the stack in a loop.
+  Label loop, entry;
+  __ xor_(ecx, Operand(ecx));  // clear ecx
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ mov(edx, Operand(ebx, ecx, times_4, 0));  // push parameter from argv
+  __ push(Operand(edx, 0));  // dereference handle
+  __ inc(Operand(ecx));
+  __ bind(&entry);
+  __ cmp(ecx, Operand(eax));
+  __ j(not_equal, &loop);
+
+  // Get the function from the stack and call it.
+  __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize));  // +1 ~ receiver
+
+  // Invoke the code.
+  if (is_construct) {
+    __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+            RelocInfo::CODE_TARGET);
+  } else {
+    ParameterCount actual(eax);
+    __ InvokeFunction(edi, actual, CALL_FUNCTION);
+  }
+
+  // Exit the JS frame. Notice that this also removes the empty
+  // context and the function left on the stack by the code
+  // invocation.
+  __ LeaveInternalFrame();
+  __ ret(1 * kPointerSize);  // remove receiver
+}
+
+
+void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, true);
+}
+
+
+void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
+  // 1. Make sure we have at least one argument.
+  { Label done;
+    __ test(eax, Operand(eax));
+    __ j(not_zero, &done, taken);
+    __ pop(ebx);
+    __ push(Immediate(Factory::undefined_value()));
+    __ push(ebx);
+    __ inc(eax);
+    __ bind(&done);
+  }
+
+  // 2. Get the function to call from the stack.
+  { Label done, non_function, function;
+    // +1 ~ return address.
+    __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize));
+    __ test(edi, Immediate(kSmiTagMask));
+    __ j(zero, &non_function, not_taken);
+    __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));  // get the map
+    __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+    __ cmp(ecx, JS_FUNCTION_TYPE);
+    __ j(equal, &function, taken);
+
+    // Non-function called: Clear the function to force exception.
+    __ bind(&non_function);
+    __ xor_(edi, Operand(edi));
+    __ jmp(&done);
+
+    // Function called: Change context eagerly to get the right global object.
+    __ bind(&function);
+    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+
+    __ bind(&done);
+  }
+
+  // 3. Make sure first argument is an object; convert if necessary.
+  { Label call_to_object, use_global_receiver, patch_receiver, done;
+    __ mov(ebx, Operand(esp, eax, times_4, 0));
+
+    __ test(ebx, Immediate(kSmiTagMask));
+    __ j(zero, &call_to_object);
+
+    __ cmp(ebx, Factory::null_value());
+    __ j(equal, &use_global_receiver);
+    __ cmp(ebx, Factory::undefined_value());
+    __ j(equal, &use_global_receiver);
+
+    __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
+    __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+    __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+    __ j(less, &call_to_object);
+    __ cmp(ecx, LAST_JS_OBJECT_TYPE);
+    __ j(less_equal, &done);
+
+    __ bind(&call_to_object);
+    __ EnterInternalFrame();  // preserves eax, ebx, edi
+
+    // Store the arguments count on the stack (smi tagged).
+    ASSERT(kSmiTag == 0);
+    __ shl(eax, kSmiTagSize);
+    __ push(eax);
+
+    __ push(edi);  // save edi across the call
+    __ push(ebx);
+    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+    __ mov(Operand(ebx), eax);
+    __ pop(edi);  // restore edi after the call
+
+    // Get the arguments count and untag it.
+    __ pop(eax);
+    __ shr(eax, kSmiTagSize);
+
+    __ LeaveInternalFrame();
+    __ jmp(&patch_receiver);
+
+    // Use the global receiver object from the called function as the receiver.
+    __ bind(&use_global_receiver);
+    const int kGlobalIndex =
+        Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+    __ mov(ebx, FieldOperand(esi, kGlobalIndex));
+    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
+
+    __ bind(&patch_receiver);
+    __ mov(Operand(esp, eax, times_4, 0), ebx);
+
+    __ bind(&done);
+  }
+
+  // 4. Shift stuff one slot down the stack.
+  { Label loop;
+    __ lea(ecx, Operand(eax, +1));  // +1 ~ copy receiver too
+    __ bind(&loop);
+    __ mov(ebx, Operand(esp, ecx, times_4, 0));
+    __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
+    __ dec(ecx);
+    __ j(not_zero, &loop);
+  }
+
+  // 5. Remove TOS (copy of last arguments), but keep return address.
+  __ pop(ebx);
+  __ pop(ecx);
+  __ push(ebx);
+  __ dec(eax);
+
+  // 6. Check that function really was a function and get the code to
+  //    call from the function and check that the number of expected
+  //    arguments matches what we're providing.
+  { Label invoke;
+    __ test(edi, Operand(edi));
+    __ j(not_zero, &invoke, taken);
+    __ xor_(ebx, Operand(ebx));
+    __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
+    __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+           RelocInfo::CODE_TARGET);
+
+    __ bind(&invoke);
+    __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+    __ mov(ebx,
+           FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
+    __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
+    __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
+    __ cmp(eax, Operand(ebx));
+    __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
+  }
+
+  // 7. Jump (tail-call) to the code in register edx without checking arguments.
+  ParameterCount expected(0);
+  __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  __ EnterInternalFrame();
+
+  __ push(Operand(ebp, 4 * kPointerSize));  // push this
+  __ push(Operand(ebp, 2 * kPointerSize));  // push arguments
+  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+
+  if (FLAG_check_stack) {
+    // We need to catch preemptions right here, otherwise an unlucky preemption
+    // could show up as a failed apply.
+    ExternalReference stack_guard_limit =
+        ExternalReference::address_of_stack_guard_limit();
+    Label retry_preemption;
+    Label no_preemption;
+    __ bind(&retry_preemption);
+    __ mov(edi, Operand::StaticVariable(stack_guard_limit));
+    __ cmp(esp, Operand(edi));
+    __ j(above, &no_preemption, taken);
+
+    // Preemption!
+    // Because builtins always remove the receiver from the stack, we
+    // have to fake one to avoid underflowing the stack.
+    __ push(eax);
+    __ push(Immediate(Smi::FromInt(0)));
+
+    // Do call to runtime routine.
+    __ CallRuntime(Runtime::kStackGuard, 1);
+    __ pop(eax);
+    __ jmp(&retry_preemption);
+
+    __ bind(&no_preemption);
+
+    Label okay;
+    // Make ecx the space we have left.
+    __ mov(ecx, Operand(esp));
+    __ sub(ecx, Operand(edi));
+    // Make edx the space we need for the array when it is unrolled onto the
+    // stack.
+    __ mov(edx, Operand(eax));
+    __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
+    __ cmp(ecx, Operand(edx));
+    __ j(greater, &okay, taken);
+
+    // Too bad: Out of stack space.
+    __ push(Operand(ebp, 4 * kPointerSize));  // push this
+    __ push(eax);
+    __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
+    __ bind(&okay);
+  }
+
+  // Push current index and limit.
+  const int kLimitOffset =
+      StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
+  const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
+  __ push(eax);  // limit
+  __ push(Immediate(0));  // index
+
+  // Change context eagerly to get the right global object if
+  // necessary.
+  __ mov(edi, Operand(ebp, 4 * kPointerSize));
+  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+
+  // Compute the receiver.
+  Label call_to_object, use_global_receiver, push_receiver;
+  __ mov(ebx, Operand(ebp, 3 * kPointerSize));
+  __ test(ebx, Immediate(kSmiTagMask));
+  __ j(zero, &call_to_object);
+  __ cmp(ebx, Factory::null_value());
+  __ j(equal, &use_global_receiver);
+  __ cmp(ebx, Factory::undefined_value());
+  __ j(equal, &use_global_receiver);
+
+  // If given receiver is already a JavaScript object then there's no
+  // reason for converting it.
+  __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(less, &call_to_object);
+  __ cmp(ecx, LAST_JS_OBJECT_TYPE);
+  __ j(less_equal, &push_receiver);
+
+  // Convert the receiver to an object.
+  __ bind(&call_to_object);
+  __ push(ebx);
+  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+  __ mov(ebx, Operand(eax));
+  __ jmp(&push_receiver);
+
+  // Use the current global receiver object as the receiver.
+  __ bind(&use_global_receiver);
+  const int kGlobalOffset =
+      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+  __ mov(ebx, FieldOperand(esi, kGlobalOffset));
+  __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
+
+  // Push the receiver.
+  __ bind(&push_receiver);
+  __ push(ebx);
+
+  // Copy all arguments from the array to the stack.
+  Label entry, loop;
+  __ mov(eax, Operand(ebp, kIndexOffset));
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ mov(ecx, Operand(ebp, 2 * kPointerSize));  // load arguments
+  __ push(ecx);
+  __ push(eax);
+
+  // Use inline caching to speed up access to arguments.
+  Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+  __ call(ic, RelocInfo::CODE_TARGET);
+
+  // Remove IC arguments from the stack and push the nth argument.
+  __ add(Operand(esp), Immediate(2 * kPointerSize));
+  __ push(eax);
+
+  // Update the index on the stack and in register eax.
+  __ mov(eax, Operand(ebp, kIndexOffset));
+  __ add(Operand(eax), Immediate(1 << kSmiTagSize));
+  __ mov(Operand(ebp, kIndexOffset), eax);
+
+  __ bind(&entry);
+  __ cmp(eax, Operand(ebp, kLimitOffset));
+  __ j(not_equal, &loop);
+
+  // Invoke the function.
+  ParameterCount actual(eax);
+  __ shr(eax, kSmiTagSize);
+  __ mov(edi, Operand(ebp, 4 * kPointerSize));
+  __ InvokeFunction(edi, actual, CALL_FUNCTION);
+
+  __ LeaveInternalFrame();
+  __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
+}
+
+
+static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
+  __ push(ebp);
+  __ mov(ebp, Operand(esp));
+
+  // Store the arguments adaptor context sentinel.
+  __ push(Immediate(ArgumentsAdaptorFrame::SENTINEL));
+
+  // Push the function on the stack.
+  __ push(edi);
+
+  // Preserve the number of arguments on the stack. Must preserve both
+  // eax and ebx because these registers are used when copying the
+  // arguments and the receiver.
+  ASSERT(kSmiTagSize == 1);
+  __ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
+  __ push(Operand(ecx));
+}
+
+
+static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
+  // Retrieve the number of arguments from the stack.
+  __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
+
+  // Leave the frame.
+  __ leave();
+
+  // Remove caller arguments from the stack.
+  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+  __ pop(ecx);
+  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
+  __ push(ecx);
+}
+
+
+void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax : actual number of arguments
+  //  -- ebx : expected number of arguments
+  //  -- edx : code entry to call
+  // -----------------------------------
+
+  Label invoke, dont_adapt_arguments;
+  __ IncrementCounter(&Counters::arguments_adaptors, 1);
+
+  Label enough, too_few;
+  __ cmp(eax, Operand(ebx));
+  __ j(less, &too_few);
+  __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
+  __ j(equal, &dont_adapt_arguments);
+
+  {  // Enough parameters: Actual >= expected.
+    __ bind(&enough);
+    EnterArgumentsAdaptorFrame(masm);
+
+    // Copy receiver and all expected arguments.
+    const int offset = StandardFrameConstants::kCallerSPOffset;
+    __ lea(eax, Operand(ebp, eax, times_4, offset));
+    __ mov(ecx, -1);  // account for receiver
+
+    Label copy;
+    __ bind(&copy);
+    __ inc(ecx);
+    __ push(Operand(eax, 0));
+    __ sub(Operand(eax), Immediate(kPointerSize));
+    __ cmp(ecx, Operand(ebx));
+    __ j(less, &copy);
+    __ jmp(&invoke);
+  }
+
+  {  // Too few parameters: Actual < expected.
+    __ bind(&too_few);
+    EnterArgumentsAdaptorFrame(masm);
+
+    // Copy receiver and all actual arguments.
+    const int offset = StandardFrameConstants::kCallerSPOffset;
+    __ lea(edi, Operand(ebp, eax, times_4, offset));
+    __ mov(ecx, -1);  // account for receiver
+
+    Label copy;
+    __ bind(&copy);
+    __ inc(ecx);
+    __ push(Operand(edi, 0));
+    __ sub(Operand(edi), Immediate(kPointerSize));
+    __ cmp(ecx, Operand(eax));
+    __ j(less, &copy);
+
+    // Fill remaining expected arguments with undefined values.
+    Label fill;
+    __ bind(&fill);
+    __ inc(ecx);
+    __ push(Immediate(Factory::undefined_value()));
+    __ cmp(ecx, Operand(ebx));
+    __ j(less, &fill);
+
+    // Restore function pointer.
+    __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+  }
+
+  // Call the entry point.
+  __ bind(&invoke);
+  __ call(Operand(edx));
+
+  // Leave frame and return.
+  LeaveArgumentsAdaptorFrame(masm);
+  __ ret(0);
+
+  // -------------------------------------------
+  // Dont adapt arguments.
+  // -------------------------------------------
+  __ bind(&dont_adapt_arguments);
+  __ jmp(Operand(edx));
+}
+
+
+static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
+                                          RegList pointer_regs,
+                                          bool convert_call_to_jmp) {
+  // Save the content of all general purpose registers in memory. This copy in
+  // memory is later pushed onto the JS expression stack for the fake JS frame
+  // generated and also to the C frame generated on top of that. In the JS
+  // frame ONLY the registers containing pointers will be pushed on the
+  // expression stack. This causes the GC to update these pointers so that
+  // they will have the correct value when returning from the debugger.
+  __ SaveRegistersToMemory(kJSCallerSaved);
+
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Store the registers containing object pointers on the expression stack to
+  // make sure that these are correctly updated during GC.
+  __ PushRegistersFromMemory(pointer_regs);
+
+#ifdef DEBUG
+  __ RecordComment("// Calling from debug break to runtime - come in - over");
+#endif
+  __ Set(eax, Immediate(0));  // no arguments
+  __ mov(Operand(ebx), Immediate(ExternalReference::debug_break()));
+
+  CEntryDebugBreakStub ceb;
+  __ CallStub(&ceb);
+
+  // Restore the register values containing object pointers from the expression
+  // stack in the reverse order as they where pushed.
+  __ PopRegistersToMemory(pointer_regs);
+
+  // Get rid of the internal frame.
+  __ LeaveInternalFrame();
+
+  // If this call did not replace a call but patched other code then there will
+  // be an unwanted return address left on the stack. Here we get rid of that.
+  if (convert_call_to_jmp) {
+    __ pop(eax);
+  }
+
+  // Finally restore all registers.
+  __ RestoreRegistersFromMemory(kJSCallerSaved);
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference(Debug_Address::AfterBreakTarget());
+  __ jmp(Operand::StaticVariable(after_break_target));
+}
+
+
+void Builtins::Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
+  // Register state for IC load call (from ic-ia32.cc).
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, ecx.bit(), false);
+}
+
+
+void Builtins::Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
+  // REgister state for IC store call (from ic-ia32.cc).
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : name
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), false);
+}
+
+
+void Builtins::Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
+  // Register state for keyed IC load call (from ic-ia32.cc).
+  // ----------- S t a t e -------------
+  //  No registers used on entry.
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, 0, false);
+}
+
+
+void Builtins::Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
+  // Register state for keyed IC load call (from ic-ia32.cc).
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  // -----------------------------------
+  // Register eax contains an object that needs to be pushed on the
+  // expression stack of the fake JS frame.
+  Generate_DebugBreakCallHelper(masm, eax.bit(), false);
+}
+
+
+void Builtins::Generate_CallIC_DebugBreak(MacroAssembler* masm) {
+  // Register state for keyed IC call call (from ic-ia32.cc)
+  // ----------- S t a t e -------------
+  //  -- eax: number of arguments
+  // -----------------------------------
+  // The number of arguments in eax is not smi encoded.
+  Generate_DebugBreakCallHelper(masm, 0, false);
+}
+
+
+void Builtins::Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
+  // Register state just before return from JS function (from codegen-ia32.cc).
+  // eax is the actual number of arguments not encoded as a smi see comment
+  // above IC call.
+  // ----------- S t a t e -------------
+  //  -- eax: number of arguments
+  // -----------------------------------
+  // The number of arguments in eax is not smi encoded.
+  Generate_DebugBreakCallHelper(masm, 0, false);
+}
+
+
+void Builtins::Generate_Return_DebugBreak(MacroAssembler* masm) {
+  // Register state just before return from JS function (from codegen-ia32.cc).
+  // ----------- S t a t e -------------
+  //  -- eax: return value
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, eax.bit(), true);
+}
+
+
+void Builtins::Generate_Return_DebugBreakEntry(MacroAssembler* masm) {
+  // OK to clobber ebx as we are returning from a JS function in the code
+  // generated by Ia32CodeGenerator::ExitJSFrame.
+  ExternalReference debug_break_return =
+      ExternalReference(Debug_Address::DebugBreakReturn());
+  __ mov(ebx, Operand::StaticVariable(debug_break_return));
+  __ add(Operand(ebx), Immediate(Code::kHeaderSize - kHeapObjectTag));
+  __ jmp(Operand(ebx));
+}
+
+
+void Builtins::Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
+  // Register state for stub CallFunction (from CallFunctionStub in ic-ia32.cc).
+  // ----------- S t a t e -------------
+  //  No registers used on entry.
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, 0, false);
+}
+
+#undef __
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/builtins.cc b/regexp2000/src/builtins.cc
new file mode 100644 (file)
index 0000000..03bce65
--- /dev/null
@@ -0,0 +1,714 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "bootstrapper.h"
+#include "builtins.h"
+#include "ic-inl.h"
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// Support macros for defining builtins in C.
+// ----------------------------------------------------------------------------
+//
+// A builtin function is defined by writing:
+//
+//   BUILTIN(name) {
+//     ...
+//   }
+//   BUILTIN_END
+//
+// In the body of the builtin function, the variable 'receiver' is visible.
+// The arguments can be accessed through:
+//
+//   BUILTIN_ARG(0): Receiver (also available as 'receiver')
+//   BUILTIN_ARG(1): First argument
+//     ...
+//   BUILTIN_ARG(n): Last argument
+//
+// and they evaluate to undefined values if too few arguments were
+// passed to the builtin function invocation.
+//
+// __argc__ is the number of arguments including the receiver.
+// ----------------------------------------------------------------------------
+
+
+// TODO(1238487): We should consider passing whether or not the
+// builtin was invoked as a constructor as part of the
+// arguments. Maybe we also want to pass the called function?
+#define BUILTIN(name)                                                   \
+  static Object* Builtin_##name(int __argc__, Object** __argv__) {      \
+    Handle<Object> receiver(&__argv__[0]);
+
+
+// Use an inline function to avoid evaluating the index (n) more than
+// once in the BUILTIN_ARG macro.
+static inline Object* __builtin_arg__(int n, int argc, Object** argv) {
+  ASSERT(n >= 0);
+  return (argc > n) ? argv[-n] : Heap::undefined_value();
+}
+
+
+// NOTE: Argument 0 is the receiver. The first 'real' argument is
+// argument 1 - BUILTIN_ARG(1).
+#define BUILTIN_ARG(n) (__builtin_arg__(n, __argc__, __argv__))
+
+
+#define BUILTIN_END                             \
+  return Heap::undefined_value();               \
+}
+
+
+// TODO(1238487): Get rid of this function that determines if the
+// builtin is called as a constructor. This may be a somewhat slow
+// operation due to the stack frame iteration.
+static inline bool CalledAsConstructor() {
+  StackFrameIterator it;
+  ASSERT(it.frame()->is_exit());
+  it.Advance();
+  StackFrame* frame = it.frame();
+  return frame->is_construct();
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
+  Code* code = Builtins::builtin(Builtins::Illegal);
+  *resolved = false;
+
+  if (Top::context() != NULL) {
+    Object* object = Top::builtins()->javascript_builtin(id);
+    if (object->IsJSFunction()) {
+      Handle<JSFunction> function(JSFunction::cast(object));
+      // Make sure the number of parameters match the formal parameter count.
+      ASSERT(function->shared()->formal_parameter_count() ==
+             Builtins::GetArgumentsCount(id));
+      if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
+        code = function->code();
+        *resolved = true;
+      }
+    }
+  }
+
+  return Handle<Code>(code);
+}
+
+
+BUILTIN(Illegal) {
+  UNREACHABLE();
+}
+BUILTIN_END
+
+
+BUILTIN(EmptyFunction) {
+}
+BUILTIN_END
+
+
+BUILTIN(ArrayCode) {
+  JSArray* array;
+  if (CalledAsConstructor()) {
+    array = JSArray::cast(*receiver);
+  } else {
+    // Allocate the JS Array
+    JSFunction* constructor =
+        Top::context()->global_context()->array_function();
+    Object* obj = Heap::AllocateJSObject(constructor);
+    if (obj->IsFailure()) return obj;
+    array = JSArray::cast(obj);
+  }
+
+  // 'array' now contains the JSArray we should initialize.
+
+  // Optimize the case where there is one argument and the argument is a
+  // small smi.
+  if (__argc__ == 2) {
+    Object* obj = BUILTIN_ARG(1);
+    if (obj->IsSmi()) {
+      int len = Smi::cast(obj)->value();
+      if (len >= 0 && len < JSObject::kMaxFastElementsLength) {
+        Object* obj = Heap::AllocateFixedArrayWithHoles(len);
+        if (obj->IsFailure()) return obj;
+        array->SetContent(FixedArray::cast(obj));
+        return array;
+      }
+    }
+    // Take the argument as the length.
+    obj = array->Initialize(0);
+    if (obj->IsFailure()) return obj;
+    if (__argc__ == 2) return array->SetElementsLength(BUILTIN_ARG(1));
+  }
+
+  // Optimize the case where there are no parameters passed.
+  if (__argc__ == 1) return array->Initialize(4);
+
+  // Take the arguments as elements.
+  int number_of_elements = __argc__ - 1;
+  Smi* len = Smi::FromInt(number_of_elements);
+  Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
+  if (obj->IsFailure()) return obj;
+  FixedArray* elms = FixedArray::cast(obj);
+  WriteBarrierMode mode = elms->GetWriteBarrierMode();
+  // Fill in the content
+  for (int index = 0; index < number_of_elements; index++) {
+    elms->set(index, BUILTIN_ARG(index+1), mode);
+  }
+
+  // Set length and elements on the array.
+  array->set_elements(FixedArray::cast(obj));
+  array->set_length(len, SKIP_WRITE_BARRIER);
+
+  return array;
+}
+BUILTIN_END
+
+
+BUILTIN(ArrayPush) {
+  JSArray* array = JSArray::cast(*receiver);
+  ASSERT(array->HasFastElements());
+
+  // Make sure we have space for the elements.
+  int len = Smi::cast(array->length())->value();
+
+  // Set new length.
+  int new_length = len + __argc__ - 1;
+  FixedArray* elms = FixedArray::cast(array->elements());
+
+  if (new_length <= elms->length()) {
+    // Backing storage has extra space for the provided values.
+    for (int index = 0; index < __argc__ - 1; index++) {
+      elms->set(index + len, BUILTIN_ARG(index+1));
+    }
+  } else {
+    // New backing storage is needed.
+    int capacity = new_length + (new_length >> 1) + 16;
+    Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+    if (obj->IsFailure()) return obj;
+    FixedArray* new_elms = FixedArray::cast(obj);
+    WriteBarrierMode mode = new_elms->GetWriteBarrierMode();
+    // Fill out the new array with old elements.
+    for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
+    // Add the provided values.
+    for (int index = 0; index < __argc__ - 1; index++) {
+      new_elms->set(index + len, BUILTIN_ARG(index+1), mode);
+    }
+    // Set the new backing storage.
+    array->set_elements(new_elms);
+  }
+  // Set the length.
+  array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
+  return array->length();
+}
+BUILTIN_END
+
+
+BUILTIN(ArrayPop) {
+  JSArray* array = JSArray::cast(*receiver);
+  ASSERT(array->HasFastElements());
+  Object* undefined = Heap::undefined_value();
+
+  int len = Smi::cast(array->length())->value();
+  if (len == 0) return undefined;
+
+  // Get top element
+  FixedArray* elms = FixedArray::cast(array->elements());
+  Object* top = elms->get(len - 1);
+
+  // Set the length.
+  array->set_length(Smi::FromInt(len - 1), SKIP_WRITE_BARRIER);
+
+  if (!top->IsTheHole()) {
+    // Delete the top element.
+    elms->set_the_hole(len - 1);
+    return top;
+  }
+
+  // Remember to check the prototype chain.
+  JSFunction* array_function =
+      Top::context()->global_context()->array_function();
+  JSObject* prototype = JSObject::cast(array_function->prototype());
+  top = prototype->GetElement(len - 1);
+
+  return top;
+}
+BUILTIN_END
+
+
+// -----------------------------------------------------------------------------
+//
+
+
+// Returns the holder JSObject if the function can legally be called
+// with this receiver.  Returns Heap::null_value() if the call is
+// illegal.  Any arguments that don't fit the expected type is
+// overwritten with undefined.  Arguments that do fit the expected
+// type is overwritten with the object in the prototype chain that
+// actually has that type.
+static inline Object* TypeCheck(int argc,
+                                Object** argv,
+                                FunctionTemplateInfo* info) {
+  Object* recv = argv[0];
+  Object* sig_obj = info->signature();
+  if (sig_obj->IsUndefined()) return recv;
+  SignatureInfo* sig = SignatureInfo::cast(sig_obj);
+  // If necessary, check the receiver
+  Object* recv_type = sig->receiver();
+
+  Object* holder = recv;
+  if (!recv_type->IsUndefined()) {
+    for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
+      if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
+        break;
+      }
+    }
+    if (holder == Heap::null_value()) return holder;
+  }
+  Object* args_obj = sig->args();
+  // If there is no argument signature we're done
+  if (args_obj->IsUndefined()) return holder;
+  FixedArray* args = FixedArray::cast(args_obj);
+  int length = args->length();
+  if (argc <= length) length = argc - 1;
+  for (int i = 0; i < length; i++) {
+    Object* argtype = args->get(i);
+    if (argtype->IsUndefined()) continue;
+    Object** arg = &argv[-1 - i];
+    Object* current = *arg;
+    for (; current != Heap::null_value(); current = current->GetPrototype()) {
+      if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
+        *arg = current;
+        break;
+      }
+    }
+    if (current == Heap::null_value()) *arg = Heap::undefined_value();
+  }
+  return holder;
+}
+
+
+BUILTIN(HandleApiCall) {
+  HandleScope scope;
+  bool is_construct = CalledAsConstructor();
+
+  // TODO(1238487): This is not nice. We need to get rid of this
+  // kludgy behavior and start handling API calls in a more direct
+  // way - maybe compile specialized stubs lazily?.
+  Handle<JSFunction> function =
+      Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
+
+  if (is_construct) {
+    Handle<FunctionTemplateInfo> desc =
+        Handle<FunctionTemplateInfo>(
+            FunctionTemplateInfo::cast(function->shared()->function_data()));
+    bool pending_exception = false;
+    Factory::ConfigureInstance(desc, Handle<JSObject>::cast(receiver),
+                               &pending_exception);
+    ASSERT(Top::has_pending_exception() == pending_exception);
+    if (pending_exception) return Failure::Exception();
+  }
+
+  FunctionTemplateInfo* fun_data =
+      FunctionTemplateInfo::cast(function->shared()->function_data());
+  Object* raw_holder = TypeCheck(__argc__, __argv__, fun_data);
+
+  if (raw_holder->IsNull()) {
+    // This function cannot be called with the given receiver.  Abort!
+    Handle<Object> obj =
+        Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
+    return Top::Throw(*obj);
+  }
+
+  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();
+    v8::InvocationCallback callback =
+        v8::ToCData<v8::InvocationCallback>(callback_obj);
+    Object* data_obj = call_data->data();
+    Object* result;
+
+    v8::Local<v8::Object> self =
+        v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
+    Handle<Object> data_handle(data_obj);
+    v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
+    ASSERT(raw_holder->IsJSObject());
+    v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
+    Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
+    v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
+    LOG(ApiObjectAccess("call", JSObject::cast(*receiver)));
+    v8::Arguments args = v8::ImplementationUtilities::NewArguments(
+        data,
+        holder,
+        callee,
+        is_construct,
+        reinterpret_cast<void**>(__argv__ - 1),
+        __argc__ - 1);
+
+    v8::Handle<v8::Value> value;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      value = callback(args);
+    }
+    if (value.IsEmpty()) {
+      result = Heap::undefined_value();
+    } else {
+      result = *reinterpret_cast<Object**>(*value);
+    }
+
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (!is_construct || result->IsJSObject()) return result;
+  }
+
+  return *receiver;
+}
+BUILTIN_END
+
+
+// Handle calls to non-function objects created through the API that
+// support calls.
+BUILTIN(HandleApiCallAsFunction) {
+  // Non-functions are never called as constructors.
+  ASSERT(!CalledAsConstructor());
+
+  // Get the object called.
+  JSObject* obj = JSObject::cast(*receiver);
+
+  // Get the invocation callback from the function descriptor that was
+  // used to create the called object.
+  ASSERT(obj->map()->has_instance_call_handler());
+  JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
+  Object* template_info = constructor->shared()->function_data();
+  Object* handler =
+      FunctionTemplateInfo::cast(template_info)->instance_call_handler();
+  ASSERT(!handler->IsUndefined());
+  CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
+  Object* callback_obj = call_data->callback();
+  v8::InvocationCallback callback =
+      v8::ToCData<v8::InvocationCallback>(callback_obj);
+
+  // Get the data for the call and perform the callback.
+  Object* data_obj = call_data->data();
+  Object* result;
+  { HandleScope scope;
+    v8::Local<v8::Object> self =
+        v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
+    Handle<Object> data_handle(data_obj);
+    v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
+    Handle<JSFunction> callee_handle(constructor);
+    v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
+    LOG(ApiObjectAccess("call non-function", JSObject::cast(*receiver)));
+    v8::Arguments args = v8::ImplementationUtilities::NewArguments(
+        data,
+        self,
+        callee,
+        false,
+        reinterpret_cast<void**>(__argv__ - 1),
+        __argc__ - 1);
+    v8::Handle<v8::Value> value;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      value = callback(args);
+    }
+    if (value.IsEmpty()) {
+      result = Heap::undefined_value();
+    } else {
+      result = *reinterpret_cast<Object**>(*value);
+    }
+  }
+  // Check for exceptions and return result.
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return result;
+}
+BUILTIN_END
+
+
+// TODO(1238487): This is a nasty hack. We need to improve the way we
+// call builtins considerable to get rid of this and the hairy macros
+// in builtins.cc.
+Object* Builtins::builtin_passed_function;
+
+
+
+static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
+  LoadIC::GenerateArrayLength(masm);
+}
+
+
+static void Generate_LoadIC_ShortStringLength(MacroAssembler* masm) {
+  LoadIC::GenerateShortStringLength(masm);
+}
+
+
+static void Generate_LoadIC_MediumStringLength(MacroAssembler* masm) {
+  LoadIC::GenerateMediumStringLength(masm);
+}
+
+
+static void Generate_LoadIC_LongStringLength(MacroAssembler* masm) {
+  LoadIC::GenerateLongStringLength(masm);
+}
+
+
+static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
+  LoadIC::GenerateFunctionPrototype(masm);
+}
+
+
+static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
+  LoadIC::GenerateInitialize(masm);
+}
+
+
+static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
+  LoadIC::GeneratePreMonomorphic(masm);
+}
+
+
+static void Generate_LoadIC_Miss(MacroAssembler* masm) {
+  LoadIC::GenerateMiss(masm);
+}
+
+
+static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
+  LoadIC::GenerateMegamorphic(masm);
+}
+
+
+static void Generate_LoadIC_Normal(MacroAssembler* masm) {
+  LoadIC::GenerateNormal(masm);
+}
+
+
+static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
+  KeyedLoadIC::GenerateInitialize(masm);
+}
+
+
+static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
+  KeyedLoadIC::GenerateMiss(masm);
+}
+
+
+static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
+  KeyedLoadIC::GenerateGeneric(masm);
+}
+
+
+static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
+  KeyedLoadIC::GeneratePreMonomorphic(masm);
+}
+
+
+static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
+  StoreIC::GenerateInitialize(masm);
+}
+
+
+static void Generate_StoreIC_Miss(MacroAssembler* masm) {
+  StoreIC::GenerateMiss(masm);
+}
+
+
+static void Generate_StoreIC_ExtendStorage(MacroAssembler* masm) {
+  StoreIC::GenerateExtendStorage(masm);
+}
+
+static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
+  StoreIC::GenerateMegamorphic(masm);
+}
+
+
+static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
+  KeyedStoreIC::GenerateGeneric(masm);
+}
+
+
+static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
+  KeyedStoreIC::GenerateExtendStorage(masm);
+}
+
+
+static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
+  KeyedStoreIC::GenerateMiss(masm);
+}
+
+
+static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
+  KeyedStoreIC::GenerateInitialize(masm);
+}
+
+
+Object* Builtins::builtins_[builtin_count] = { NULL, };
+const char* Builtins::names_[builtin_count] = { NULL, };
+
+#define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name),
+  Address Builtins::c_functions_[cfunction_count] = {
+    BUILTIN_LIST_C(DEF_ENUM_C)
+  };
+#undef DEF_ENUM_C
+
+#define DEF_JS_NAME(name, ignore) #name,
+#define DEF_JS_ARGC(ignore, argc) argc,
+const char* Builtins::javascript_names_[id_count] = {
+  BUILTINS_LIST_JS(DEF_JS_NAME)
+};
+
+int Builtins::javascript_argc_[id_count] = {
+  BUILTINS_LIST_JS(DEF_JS_ARGC)
+};
+#undef DEF_JS_NAME
+#undef DEF_JS_ARGC
+
+static bool is_initialized = false;
+void Builtins::Setup(bool create_heap_objects) {
+  ASSERT(!is_initialized);
+
+  // Create a scope for the handles in the builtins.
+  HandleScope scope;
+
+  struct BuiltinDesc {
+    byte* generator;
+    byte* c_code;
+    const char* s_name;  // name is only used for generating log information.
+    int name;
+    Code::Flags flags;
+  };
+
+#define DEF_FUNCTION_PTR_C(name)         \
+    { FUNCTION_ADDR(Generate_Adaptor),   \
+      FUNCTION_ADDR(Builtin_##name),     \
+      #name,                             \
+      c_##name,                          \
+      Code::ComputeFlags(Code::BUILTIN)  \
+    },
+
+#define DEF_FUNCTION_PTR_A(name, kind, state) \
+    { FUNCTION_ADDR(Generate_##name),         \
+      NULL,                                   \
+      #name,                                  \
+      name,                                   \
+      Code::ComputeFlags(Code::kind, state)   \
+    },
+
+  // Define array of pointers to generators and C builtin functions.
+  static BuiltinDesc functions[] = {
+      BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
+      BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
+      // Terminator:
+      { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0) }
+  };
+
+#undef DEF_FUNCTION_PTR_C
+#undef DEF_FUNCTION_PTR_A
+
+  // For now we generate builtin adaptor code into a stack-allocated
+  // buffer, before copying it into individual code objects.
+  byte buffer[4*KB];
+
+  // Traverse the list of builtins and generate an adaptor in a
+  // separate code object for each one.
+  for (int i = 0; i < builtin_count; i++) {
+    if (create_heap_objects) {
+      MacroAssembler masm(buffer, sizeof buffer);
+      // Generate the code/adaptor.
+      typedef void (*Generator)(MacroAssembler*, int);
+      Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
+      // We pass all arguments to the generator, but it may not use all of
+      // them.  This works because the first arguments are on top of the
+      // stack.
+      g(&masm, functions[i].name);
+      // Move the code into the object heap.
+      CodeDesc desc;
+      masm.GetCode(&desc);
+      Code::Flags flags =  functions[i].flags;
+      Object* code = Heap::CreateCode(desc, NULL, flags);
+      if (code->IsFailure()) {
+        if (code->IsRetryAfterGC()) {
+          CHECK(Heap::CollectGarbage(Failure::cast(code)->requested(),
+                                     Failure::cast(code)->allocation_space()));
+          code = Heap::CreateCode(desc, NULL, flags);
+        }
+        if (code->IsFailure()) {
+          v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
+        }
+      }
+      // Add any unresolved jumps or calls to the fixup list in the
+      // bootstrapper.
+      Bootstrapper::AddFixup(Code::cast(code), &masm);
+      // Log the event and add the code to the builtins array.
+      LOG(CodeCreateEvent("Builtin", Code::cast(code), functions[i].s_name));
+      builtins_[i] = code;
+#ifdef DEBUG
+      if (FLAG_print_builtin_code) {
+        PrintF("Builtin: %s\n", functions[i].s_name);
+        code->Print();
+        PrintF("\n");
+      }
+#endif
+    } else {
+      // Deserializing. The values will be filled in during IterateBuiltins.
+      builtins_[i] = NULL;
+    }
+    names_[i] = functions[i].s_name;
+  }
+
+  // Mark as initialized.
+  is_initialized = true;
+}
+
+
+void Builtins::TearDown() {
+  is_initialized = false;
+}
+
+
+void Builtins::IterateBuiltins(ObjectVisitor* v) {
+  v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
+}
+
+
+const char* Builtins::Lookup(byte* pc) {
+  if (is_initialized) {  // may be called during initialization (disassembler!)
+    for (int i = 0; i < builtin_count; i++) {
+      Code* entry = Code::cast(builtins_[i]);
+      if (entry->contains(pc)) {
+        return names_[i];
+      }
+    }
+  }
+  return NULL;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/builtins.h b/regexp2000/src/builtins.h
new file mode 100644 (file)
index 0000000..80a897d
--- /dev/null
@@ -0,0 +1,227 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_BUILTINS_H_
+#define V8_BUILTINS_H_
+
+namespace v8 { namespace internal {
+
+// Define list of builtins implemented in C.
+#define BUILTIN_LIST_C(V)                          \
+  V(Illegal)                                       \
+                                                   \
+  V(EmptyFunction)                                 \
+                                                   \
+  V(ArrayCode)                                     \
+                                                   \
+  V(ArrayPush)                                     \
+  V(ArrayPop)                                      \
+                                                   \
+  V(HandleApiCall)                                 \
+  V(HandleApiCallAsFunction)
+
+
+// Define list of builtins implemented in assembly.
+#define BUILTIN_LIST_A(V)                                      \
+  V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED)        \
+  V(JSConstructCall,            BUILTIN, UNINITIALIZED)        \
+  V(JSEntryTrampoline,          BUILTIN, UNINITIALIZED)        \
+  V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED)        \
+                                                               \
+  V(Return_DebugBreak,          BUILTIN, DEBUG_BREAK)          \
+  V(Return_DebugBreakEntry,     BUILTIN, DEBUG_BREAK)          \
+  V(ConstructCall_DebugBreak,   BUILTIN, DEBUG_BREAK)          \
+  V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK)          \
+                                                               \
+  V(LoadIC_Miss,                BUILTIN, UNINITIALIZED)        \
+  V(KeyedLoadIC_Miss,           BUILTIN, UNINITIALIZED)        \
+  V(StoreIC_Miss,               BUILTIN, UNINITIALIZED)        \
+  V(KeyedStoreIC_Miss,          BUILTIN, UNINITIALIZED)        \
+                                                               \
+  V(StoreIC_ExtendStorage,      BUILTIN, UNINITIALIZED)        \
+  V(KeyedStoreIC_ExtendStorage, BUILTIN, UNINITIALIZED)        \
+                                                               \
+  V(LoadIC_Initialize,          LOAD_IC, UNINITIALIZED)        \
+  V(LoadIC_PreMonomorphic,      LOAD_IC, PREMONOMORPHIC)       \
+  V(LoadIC_Normal,              LOAD_IC, MONOMORPHIC)          \
+  V(LoadIC_ArrayLength,         LOAD_IC, MONOMORPHIC)          \
+  V(LoadIC_ShortStringLength,   LOAD_IC, MONOMORPHIC)          \
+  V(LoadIC_MediumStringLength,  LOAD_IC, MONOMORPHIC)          \
+  V(LoadIC_LongStringLength,    LOAD_IC, MONOMORPHIC)          \
+  V(LoadIC_FunctionPrototype,   LOAD_IC, MONOMORPHIC)          \
+  V(LoadIC_Megamorphic,         LOAD_IC, MEGAMORPHIC)          \
+  V(LoadIC_DebugBreak,          LOAD_IC, DEBUG_BREAK)          \
+                                                               \
+  V(KeyedLoadIC_Initialize,     KEYED_LOAD_IC, UNINITIALIZED)  \
+  V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
+  V(KeyedLoadIC_Generic,        KEYED_LOAD_IC, MEGAMORPHIC)    \
+  V(KeyedLoadIC_DebugBreak,     KEYED_LOAD_IC, DEBUG_BREAK)    \
+                                                               \
+  V(StoreIC_Initialize,         STORE_IC, UNINITIALIZED)       \
+  V(StoreIC_Megamorphic,        STORE_IC, MEGAMORPHIC)         \
+  V(StoreIC_DebugBreak,         STORE_IC, DEBUG_BREAK)         \
+                                                               \
+  V(KeyedStoreIC_Initialize,    KEYED_STORE_IC, UNINITIALIZED) \
+  V(KeyedStoreIC_Generic,       KEYED_STORE_IC, MEGAMORPHIC)   \
+  V(KeyedStoreIC_DebugBreak,    KEYED_STORE_IC, DEBUG_BREAK)   \
+                                                               \
+  /* Uses KeyedLoadIC_Initialize; must be after in list. */    \
+  V(FunctionCall,               BUILTIN, UNINITIALIZED)        \
+  V(FunctionApply,              BUILTIN, UNINITIALIZED)
+
+
+// Define list of builtins implemented in JavaScript.
+#define BUILTINS_LIST_JS(V)    \
+  V(EQUALS, 1)                 \
+  V(STRICT_EQUALS, 1)          \
+  V(COMPARE, 2)                \
+  V(ADD, 1)                    \
+  V(SUB, 1)                    \
+  V(MUL, 1)                    \
+  V(DIV, 1)                    \
+  V(MOD, 1)                    \
+  V(INC, 0)                    \
+  V(DEC, 0)                    \
+  V(BIT_OR, 1)                 \
+  V(BIT_AND, 1)                \
+  V(BIT_XOR, 1)                \
+  V(UNARY_MINUS, 0)            \
+  V(BIT_NOT, 0)                \
+  V(SHL, 1)                    \
+  V(SAR, 1)                    \
+  V(SHR, 1)                    \
+  V(DELETE, 1)                 \
+  V(IN, 1)                     \
+  V(INSTANCE_OF, 1)            \
+  V(GET_KEYS, 0)               \
+  V(FILTER_KEY, 1)             \
+  V(CALL_NON_FUNCTION, 0)      \
+  V(TO_OBJECT, 0)              \
+  V(TO_NUMBER, 0)              \
+  V(TO_STRING, 0)              \
+  V(APPLY_PREPARE, 1)          \
+  V(APPLY_OVERFLOW, 1)
+
+
+class ObjectVisitor;
+
+
+class Builtins : public AllStatic {
+ public:
+  // Generate all builtin code objects. Should be called once during
+  // VM initialization.
+  static void Setup(bool create_heap_objects);
+  static void TearDown();
+
+  // Garbage collection support.
+  static void IterateBuiltins(ObjectVisitor* v);
+
+  // Disassembler support.
+  static const char* Lookup(byte* pc);
+
+  enum Name {
+#define DEF_ENUM_C(name) name,
+#define DEF_ENUM_A(name, kind, state) name,
+    BUILTIN_LIST_C(DEF_ENUM_C)
+    BUILTIN_LIST_A(DEF_ENUM_A)
+#undef DEF_ENUM_C
+#undef DEF_ENUM_A
+    builtin_count
+  };
+
+  enum CFunctionId {
+#define DEF_ENUM_C(name) c_##name,
+    BUILTIN_LIST_C(DEF_ENUM_C)
+#undef DEF_ENUM_C
+    cfunction_count
+  };
+
+  enum JavaScript {
+#define DEF_ENUM(name, ignore) name,
+    BUILTINS_LIST_JS(DEF_ENUM)
+#undef DEF_ENUM
+    id_count
+  };
+
+  static Code* builtin(Name name) {
+    // Code::cast cannot be used here since we access builtins
+    // during the marking phase of mark sweep. See IC::Clear.
+    return reinterpret_cast<Code*>(builtins_[name]);
+  }
+
+  static Address builtin_address(Name name) {
+    return reinterpret_cast<Address>(&builtins_[name]);
+  }
+
+  static Address c_function_address(CFunctionId id) {
+    return c_functions_[id];
+  }
+
+  static const char* GetName(JavaScript id) { return javascript_names_[id]; }
+  static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
+  static Handle<Code> GetCode(JavaScript id, bool* resolved);
+  static int NumberOfJavaScriptBuiltins() { return id_count; }
+
+  // Called from stub-cache.cc.
+  static void Generate_CallIC_DebugBreak(MacroAssembler* masm);
+
+  static Object* builtin_passed_function;
+
+ private:
+  // The external C++ functions called from the code.
+  static Address c_functions_[cfunction_count];
+
+  // Note: These are always Code objects, but to conform with
+  // IterateBuiltins() above which assumes Object**'s for the callback
+  // function f, we use an Object* array here.
+  static Object* builtins_[builtin_count];
+  static const char* names_[builtin_count];
+  static const char* javascript_names_[id_count];
+  static int javascript_argc_[id_count];
+
+  static void Generate_Adaptor(MacroAssembler* masm, CFunctionId id);
+  static void Generate_JSConstructCall(MacroAssembler* masm);
+  static void Generate_JSEntryTrampoline(MacroAssembler* masm);
+  static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
+  static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
+
+  static void Generate_FunctionCall(MacroAssembler* masm);
+  static void Generate_FunctionApply(MacroAssembler* masm);
+
+  static void Generate_LoadIC_DebugBreak(MacroAssembler* masm);
+  static void Generate_StoreIC_DebugBreak(MacroAssembler* masm);
+  static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm);
+  static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm);
+  static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm);
+  static void Generate_Return_DebugBreak(MacroAssembler* masm);
+  static void Generate_Return_DebugBreakEntry(MacroAssembler* masm);
+  static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_BUILTINS_H_
diff --git a/regexp2000/src/char-predicates-inl.h b/regexp2000/src/char-predicates-inl.h
new file mode 100644 (file)
index 0000000..b575bdf
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CHAR_PREDICATES_INL_H_
+#define V8_CHAR_PREDICATES_INL_H_
+
+#include "char-predicates.h"
+
+namespace v8 { namespace internal {
+
+
+inline bool IsCarriageReturn(uc32 c) {
+  return c == 0x000D;
+}
+
+
+inline bool IsLineFeed(uc32 c) {
+  return c == 0x000A;
+}
+
+
+inline bool IsDecimalDigit(uc32 c) {
+  // ECMA-262, 3rd, 7.8.3 (p 16)
+  return
+    '0' <= c && c <= '9';
+}
+
+
+inline bool IsHexDigit(uc32 c) {
+  // ECMA-262, 3rd, 7.6 (p 15)
+  return
+    ('0' <= c && c <= '9') ||
+    ('A' <= c && c <= 'F') ||
+    ('a' <= c && c <= 'f');
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_CHAR_PREDICATES_INL_H_
diff --git a/regexp2000/src/char-predicates.h b/regexp2000/src/char-predicates.h
new file mode 100644 (file)
index 0000000..3fcaeb6
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CHAR_PREDICATES_H_
+#define V8_CHAR_PREDICATES_H_
+
+namespace v8 { namespace internal {
+
+// Unicode character predicates as defined by ECMA-262, 3rd,
+// used for lexical analysis.
+
+inline bool IsCarriageReturn(uc32 c);
+inline bool IsLineFeed(uc32 c);
+inline bool IsDecimalDigit(uc32 c);
+inline bool IsHexDigit(uc32 c);
+
+struct IdentifierStart {
+  static inline bool Is(uc32 c) {
+    switch (c) {
+      case '$': case '_': case '\\': return true;
+      default: return unibrow::Letter::Is(c);
+    }
+  }
+};
+
+
+struct IdentifierPart {
+  static inline bool Is(uc32 c) {
+    return IdentifierStart::Is(c)
+        || unibrow::Number::Is(c)
+        || unibrow::CombiningMark::Is(c)
+        || unibrow::ConnectorPunctuation::Is(c);
+  }
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_CHAR_PREDICATES_H_
diff --git a/regexp2000/src/checks.cc b/regexp2000/src/checks.cc
new file mode 100644 (file)
index 0000000..2f25456
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdarg.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "top.h"
+
+using namespace v8::internal;
+
+static int fatal_error_handler_nesting_depth = 0;
+
+// Contains protection against recursive calls (faults while handling faults).
+extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
+  fatal_error_handler_nesting_depth++;
+  // First time we try to print an error message
+  if (fatal_error_handler_nesting_depth < 2) {
+    OS::PrintError("\n\n#\n# Fatal error in %s, line %d\n# ", file, line);
+    va_list arguments;
+    va_start(arguments, format);
+    OS::VPrintError(format, arguments);
+    va_end(arguments);
+    OS::PrintError("\n#\n\n");
+  }
+  // First two times we may try to print a stack dump.
+  if (fatal_error_handler_nesting_depth < 3) {
+    if (FLAG_stack_trace_on_abort) {
+      // Call this one twice on double fault
+      Top::PrintStack();
+    }
+  }
+  OS::Abort();
+}
+
+
+void CheckEqualsHelper(const char* file,
+                       int line,
+                       const char* expected_source,
+                       v8::Handle<v8::Value> expected,
+                       const char* value_source,
+                       v8::Handle<v8::Value> value) {
+  if (!expected->Equals(value)) {
+    v8::String::Utf8Value value_str(value);
+    v8::String::Utf8Value expected_str(expected);
+    V8_Fatal(file, line,
+             "CHECK_EQ(%s, %s) failed\n#   Expected: %s\n#   Found: %s",
+             expected_source, value_source, *expected_str, *value_str);
+  }
+}
+
+
+void CheckNonEqualsHelper(const char* file,
+                          int line,
+                          const char* unexpected_source,
+                          v8::Handle<v8::Value> unexpected,
+                          const char* value_source,
+                          v8::Handle<v8::Value> value) {
+  if (unexpected->Equals(value)) {
+    v8::String::Utf8Value value_str(value);
+    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %s",
+             unexpected_source, value_source, *value_str);
+  }
+}
+
+
+void API_Fatal(const char* location, const char* format, ...) {
+  OS::PrintError("\n#\n# Fatal error in %s\n# ", location);
+  va_list arguments;
+  va_start(arguments, format);
+  OS::VPrintError(format, arguments);
+  va_end(arguments);
+  OS::PrintError("\n#\n\n");
+  OS::Abort();
+}
diff --git a/regexp2000/src/checks.h b/regexp2000/src/checks.h
new file mode 100644 (file)
index 0000000..13075f8
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CHECKS_H_
+#define V8_CHECKS_H_
+
+#include <string.h>
+
+#include "flags.h"
+
+extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
+void API_Fatal(const char* location, const char* format, ...);
+
+// The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during
+// development, but they should not be relied on in the final product.
+#ifdef DEBUG
+#define FATAL(msg)                              \
+  V8_Fatal(__FILE__, __LINE__, "%s", (msg))
+#define UNIMPLEMENTED()                         \
+  V8_Fatal(__FILE__, __LINE__, "unimplemented code")
+#define UNREACHABLE()                           \
+  V8_Fatal(__FILE__, __LINE__, "unreachable code")
+#else
+#define FATAL(msg)                              \
+  V8_Fatal("", 0, "%s", (msg))
+#define UNIMPLEMENTED()                         \
+  V8_Fatal("", 0, "unimplemented code")
+#define UNREACHABLE() ((void) 0)
+#endif
+
+
+// Used by the CHECK macro -- should not be called directly.
+static inline void CheckHelper(const char* file,
+                               int line,
+                               const char* source,
+                               bool condition) {
+  if (!condition)
+    V8_Fatal(file, line, "CHECK(%s) failed", source);
+}
+
+
+// The CHECK macro checks that the given condition is true; if not, it
+// prints a message to stderr and aborts.
+#define CHECK(condition) CheckHelper(__FILE__, __LINE__, #condition, condition)
+
+
+// Helper function used by the CHECK_EQ function when given int
+// arguments.  Should not be called directly.
+static inline void CheckEqualsHelper(const char* file, int line,
+                                     const char* expected_source, int expected,
+                                     const char* value_source, int value) {
+  if (expected != value) {
+    V8_Fatal(file, line,
+             "CHECK_EQ(%s, %s) failed\n#   Expected: %i\n#   Found: %i",
+             expected_source, value_source, expected, value);
+  }
+}
+
+
+// Helper function used by the CHECK_NE function when given int
+// arguments.  Should not be called directly.
+static inline void CheckNonEqualsHelper(const char* file,
+                                        int line,
+                                        const char* unexpected_source,
+                                        int unexpected,
+                                        const char* value_source,
+                                        int value) {
+  if (unexpected == value) {
+    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %i",
+             unexpected_source, value_source, value);
+  }
+}
+
+
+// Helper function used by the CHECK function when given string
+// arguments.  Should not be called directly.
+static inline void CheckEqualsHelper(const char* file,
+                                     int line,
+                                     const char* expected_source,
+                                     const char* expected,
+                                     const char* value_source,
+                                     const char* value) {
+  if (strcmp(expected, value) != 0) {
+    V8_Fatal(file, line,
+             "CHECK_EQ(%s, %s) failed\n#   Expected: %s\n#   Found: %s",
+             expected_source, value_source, expected, value);
+  }
+}
+
+
+static inline void CheckNonEqualsHelper(const char* file,
+                                        int line,
+                                        const char* expected_source,
+                                        const char* expected,
+                                        const char* value_source,
+                                        const char* value) {
+  if (expected == value ||
+      (expected != NULL && value != NULL && strcmp(expected, value) == 0)) {
+    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %s",
+             expected_source, value_source, value);
+  }
+}
+
+
+// Helper function used by the CHECK function when given pointer
+// arguments.  Should not be called directly.
+static inline void CheckEqualsHelper(const char* file,
+                                     int line,
+                                     const char* expected_source,
+                                     void* expected,
+                                     const char* value_source,
+                                     void* value) {
+  if (expected != value) {
+    V8_Fatal(file, line,
+             "CHECK_EQ(%s, %s) failed\n#   Expected: %i\n#   Found: %i",
+             expected_source, value_source,
+             reinterpret_cast<int>(expected), reinterpret_cast<int>(value));
+  }
+}
+
+
+static inline void CheckNonEqualsHelper(const char* file,
+                                        int line,
+                                        const char* expected_source,
+                                        void* expected,
+                                        const char* value_source,
+                                        void* value) {
+  if (expected == value) {
+    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %i",
+             expected_source, value_source, reinterpret_cast<int>(value));
+  }
+}
+
+
+// Helper function used by the CHECK function when given floating
+// point arguments.  Should not be called directly.
+static inline void CheckEqualsHelper(const char* file,
+                                     int line,
+                                     const char* expected_source,
+                                     double expected,
+                                     const char* value_source,
+                                     double value) {
+  // Force values to 64 bit memory to truncate 80 bit precision on IA32.
+  volatile double* exp = new double[1];
+  *exp = expected;
+  volatile double* val = new double[1];
+  *val = value;
+  if (*exp != *val) {
+    V8_Fatal(file, line,
+             "CHECK_EQ(%s, %s) failed\n#   Expected: %f\n#   Found: %f",
+             expected_source, value_source, *exp, *val);
+  }
+  delete[] exp;
+  delete[] val;
+}
+
+
+namespace v8 {
+  class Value;
+  template <class T> class Handle;
+}
+
+
+void CheckNonEqualsHelper(const char* file,
+                          int line,
+                          const char* unexpected_source,
+                          v8::Handle<v8::Value> unexpected,
+                          const char* value_source,
+                          v8::Handle<v8::Value> value);
+
+
+void CheckEqualsHelper(const char* file,
+                       int line,
+                       const char* expected_source,
+                       v8::Handle<v8::Value> expected,
+                       const char* value_source,
+                       v8::Handle<v8::Value> value);
+
+
+#define CHECK_EQ(expected, value) CheckEqualsHelper(__FILE__, __LINE__, \
+  #expected, expected, #value, value)
+
+
+#define CHECK_NE(unexpected, value) CheckNonEqualsHelper(__FILE__, __LINE__, \
+  #unexpected, unexpected, #value, value)
+
+
+#define CHECK_GT(a, b) CHECK((a) > (b))
+#define CHECK_GE(a, b) CHECK((a) >= (b))
+
+
+// This is inspired by the static assertion facility in boost.  This
+// is pretty magical.  If it causes you trouble on a platform you may
+// find a fix in the boost code.
+template <bool> class StaticAssertion;
+template <> class StaticAssertion<true> { };
+// This macro joins two tokens.  If one of the tokens is a macro the
+// helper call causes it to be resolved before joining.
+#define SEMI_STATIC_JOIN(a, b) SEMI_STATIC_JOIN_HELPER(a, b)
+#define SEMI_STATIC_JOIN_HELPER(a, b) a##b
+// Causes an error during compilation of the condition is not
+// statically known to be true.  It is formulated as a typedef so that
+// it can be used wherever a typedef can be used.  Beware that this
+// actually causes each use to introduce a new defined type with a
+// name depending on the source line.
+template <int> class StaticAssertionHelper { };
+#define STATIC_CHECK(test)                                                  \
+  typedef                                                                   \
+    StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>(test)>)> \
+    SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)
+
+
+// The ASSERT macro is equivalent to CHECK except that it only
+// generates code in debug builds.  Ditto STATIC_ASSERT.
+#ifdef DEBUG
+#define ASSERT(condition)    CHECK(condition)
+#define ASSERT_EQ(v1, v2)    CHECK_EQ(v1, v2)
+#define ASSERT_NE(v1, v2)   CHECK_NE(v1, v2)
+#define STATIC_ASSERT(test)  STATIC_CHECK(test)
+#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
+#else
+#define ASSERT(condition)      ((void) 0)
+#define ASSERT_EQ(v1, v2)      ((void) 0)
+#define ASSERT_NE(v1, v2)     ((void) 0)
+#define STATIC_ASSERT(test)    ((void) 0)
+#define SLOW_ASSERT(condition) ((void) 0)
+#endif
+
+
+#define ASSERT_TAG_ALIGNED(address) \
+  ASSERT((reinterpret_cast<int>(address) & kHeapObjectTagMask) == 0)
+
+#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
+
+#endif  // V8_CHECKS_H_
diff --git a/regexp2000/src/code-stubs.cc b/regexp2000/src/code-stubs.cc
new file mode 100644 (file)
index 0000000..2ead1b3
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "code-stubs.h"
+#include "factory.h"
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+Handle<Code> CodeStub::GetCode() {
+  uint32_t key = GetKey();
+  int index = Heap::code_stubs()->FindNumberEntry(key);
+  if (index == -1) {
+    HandleScope scope;
+
+    // Update the static counter each time a new code stub is generated.
+    Counters::code_stubs.Increment();
+
+    // Generate the new code.
+    MacroAssembler masm(NULL, 256);
+
+    // Nested stubs are not allowed for leafs.
+    masm.set_allow_stub_calls(AllowsStubCalls());
+
+    // Generate the code for the stub.
+    masm.set_generating_stub(true);
+    Generate(&masm);
+
+    // Create the code object.
+    CodeDesc desc;
+    masm.GetCode(&desc);
+
+    // Copy the generated code into a heap object, and store the major key.
+    Code::Flags flags = Code::ComputeFlags(Code::STUB);
+    Handle<Code> code = Factory::NewCode(desc, NULL, flags);
+    code->set_major_key(MajorKey());
+
+    // Add unresolved entries in the code to the fixup list.
+    Bootstrapper::AddFixup(*code, &masm);
+
+    LOG(CodeCreateEvent("Stub", *code, GetName()));
+    Counters::total_stubs_code_size.Increment(code->instruction_size());
+
+#ifdef DEBUG
+    if (FLAG_print_code_stubs) {
+      Print();
+      code->Print();
+      PrintF("\n");
+    }
+#endif
+
+    // Update the dictionary and the root in Heap.
+    Handle<Dictionary> dict =
+        Factory::DictionaryAtNumberPut(Handle<Dictionary>(Heap::code_stubs()),
+                                       key,
+                                       code);
+    Heap::set_code_stubs(*dict);
+    index = Heap::code_stubs()->FindNumberEntry(key);
+  }
+  ASSERT(index != -1);
+
+  return Handle<Code>(Code::cast(Heap::code_stubs()->ValueAt(index)));
+}
+
+
+const char* CodeStub::MajorName(CodeStub::Major major_key) {
+  switch (major_key) {
+    case CallFunction:
+      return "CallFunction";
+    case GenericBinaryOp:
+      return "GenericBinaryOp";
+    case SmiOp:
+      return "SmiOp";
+    case Compare:
+      return "Compare";
+    case RecordWrite:
+      return "RecordWrite";
+    case StackCheck:
+      return "StackCheck";
+    case UnarySub:
+      return "UnarySub";
+    case RevertToNumber:
+      return "RevertToNumber";
+    case ToBoolean:
+      return "ToBoolean";
+    case Instanceof:
+      return "Instanceof";
+    case CounterOp:
+      return "CounterOp";
+    case ArgumentsAccess:
+      return "ArgumentsAccess";
+    case Runtime:
+      return "Runtime";
+    case CEntry:
+      return "CEntry";
+    case JSEntry:
+      return "JSEntry";
+    case GetProperty:
+      return "GetProperty";
+    case SetProperty:
+      return "SetProperty";
+    case InvokeBuiltin:
+      return "InvokeBuiltin";
+    case JSExit:
+      return "JSExit";
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/code-stubs.h b/regexp2000/src/code-stubs.h
new file mode 100644 (file)
index 0000000..d21b0ee
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CODE_STUBS_H_
+#define V8_CODE_STUBS_H_
+
+namespace v8 { namespace internal {
+
+
+// Stub is base classes of all stubs.
+class CodeStub BASE_EMBEDDED {
+ public:
+  enum Major {
+    CallFunction,
+    GenericBinaryOp,
+    SmiOp,
+    Compare,
+    RecordWrite,  // Last stub that allows stub calls inside.
+    StackCheck,
+    UnarySub,
+    RevertToNumber,
+    ToBoolean,
+    Instanceof,
+    CounterOp,
+    ArgumentsAccess,
+    Runtime,
+    CEntry,
+    JSEntry,
+    GetProperty,   // ARM only
+    SetProperty,   // ARM only
+    InvokeBuiltin,  // ARM only
+    JSExit,        // ARM only
+    NUMBER_OF_IDS
+  };
+
+  // Retrieve the code for the stub. Generate the code if needed.
+  Handle<Code> GetCode();
+
+  static Major MajorKeyFromKey(uint32_t key) {
+    return static_cast<Major>(MajorKeyBits::decode(key));
+  };
+  static int MinorKeyFromKey(uint32_t key) {
+    return MinorKeyBits::decode(key);
+  };
+  static const char* MajorName(Major major_key);
+
+  virtual ~CodeStub() {}
+
+ protected:
+  static const int kMajorBits = 5;
+  static const int kMinorBits = kBitsPerPointer - kMajorBits - kSmiTagSize;
+
+ private:
+  // Generates the assembler code for the stub.
+  virtual void Generate(MacroAssembler* masm) = 0;
+
+  // Returns information for computing the number key.
+  virtual Major MajorKey() = 0;
+  virtual int MinorKey() = 0;
+
+  // Returns a name for logging/debugging purposes.
+  virtual const char* GetName() { return MajorName(MajorKey()); }
+
+#ifdef DEBUG
+  virtual void Print() { PrintF("%s\n", GetName()); }
+#endif
+
+  // Computes the key based on major and minor.
+  uint32_t GetKey() {
+    ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
+    return MinorKeyBits::encode(MinorKey()) |
+           MajorKeyBits::encode(MajorKey());
+  }
+
+  bool AllowsStubCalls() { return MajorKey() <= RecordWrite; }
+
+  class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {};
+  class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {};
+
+  friend class BreakPointIterator;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_CODE_STUBS_H_
diff --git a/regexp2000/src/code.h b/regexp2000/src/code.h
new file mode 100644 (file)
index 0000000..87e0794
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CODE_H_
+#define V8_CODE_H_
+
+namespace v8 { namespace internal {
+
+
+// Wrapper class for passing expected and actual parameter counts as
+// either registers or immediate values. Used to make sure that the
+// caller provides exactly the expected number of parameters to the
+// callee.
+class ParameterCount BASE_EMBEDDED {
+ public:
+  explicit ParameterCount(Register reg)
+      : reg_(reg), immediate_(0) { }
+  explicit ParameterCount(int immediate)
+      : reg_(no_reg), immediate_(immediate) { }
+
+  bool is_reg() const { return !reg_.is(no_reg); }
+  bool is_immediate() const { return !is_reg(); }
+
+  Register reg() const {
+    ASSERT(is_reg());
+    return reg_;
+  }
+  int immediate() const {
+    ASSERT(is_immediate());
+    return immediate_;
+  }
+
+ private:
+  const Register reg_;
+  const int immediate_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterCount);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_CODE_H_
diff --git a/regexp2000/src/codegen-arm.cc b/regexp2000/src/codegen-arm.cc
new file mode 100644 (file)
index 0000000..c0b0e2a
--- /dev/null
@@ -0,0 +1,4193 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "codegen-inl.h"
+#include "debug.h"
+#include "scopes.h"
+#include "runtime.h"
+
+namespace v8 { namespace internal {
+
+// -------------------------------------------------------------------------
+// CodeGenState implementation.
+
+CodeGenState::CodeGenState(CodeGenerator* owner)
+    : owner_(owner),
+      typeof_state_(NOT_INSIDE_TYPEOF),
+      true_target_(NULL),
+      false_target_(NULL),
+      previous_(NULL) {
+  owner_->set_state(this);
+}
+
+
+CodeGenState::CodeGenState(CodeGenerator* owner,
+                           TypeofState typeof_state,
+                           Label* true_target,
+                           Label* false_target)
+    : owner_(owner),
+      typeof_state_(typeof_state),
+      true_target_(true_target),
+      false_target_(false_target),
+      previous_(owner->state()) {
+  owner_->set_state(this);
+}
+
+
+CodeGenState::~CodeGenState() {
+  ASSERT(owner_->state() == this);
+  owner_->set_state(previous_);
+}
+
+
+// -----------------------------------------------------------------------------
+// CodeGenerator implementation
+
+#define __ masm_->
+
+CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
+                             bool is_eval)
+    : is_eval_(is_eval),
+      script_(script),
+      deferred_(8),
+      masm_(new MacroAssembler(NULL, buffer_size)),
+      scope_(NULL),
+      cc_reg_(al),
+      state_(NULL),
+      break_stack_height_(0) {
+}
+
+
+// Calling conventions:
+
+// r0: the number of arguments
+// fp: frame pointer
+// sp: stack pointer
+// pp: caller's parameter pointer
+// cp: callee's context
+
+void CodeGenerator::GenCode(FunctionLiteral* fun) {
+  Scope* scope = fun->scope();
+  ZoneList<Statement*>* body = fun->body();
+
+  // Initialize state.
+  { CodeGenState state(this);
+    scope_ = scope;
+    cc_reg_ = al;
+
+    // Entry
+    // stack: function, receiver, arguments, return address
+    // r0: number of arguments
+    // sp: stack pointer
+    // fp: frame pointer
+    // pp: caller's parameter pointer
+    // cp: callee's context
+
+    { Comment cmnt(masm_, "[ enter JS frame");
+      EnterJSFrame();
+    }
+    // tos: code slot
+#ifdef DEBUG
+    if (strlen(FLAG_stop_at) > 0 &&
+        fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+      __ stop("stop-at");
+    }
+#endif
+
+    // Allocate space for locals and initialize them.
+    if (scope->num_stack_slots() > 0) {
+      Comment cmnt(masm_, "[ allocate space for locals");
+      // Initialize stack slots with 'undefined' value.
+      __ mov(ip, Operand(Factory::undefined_value()));
+      for (int i = 0; i < scope->num_stack_slots(); i++) {
+        __ push(ip);
+      }
+    }
+
+    if (scope->num_heap_slots() > 0) {
+      // Allocate local context.
+      // Get outer context and create a new context based on it.
+      __ ldr(r0, FunctionOperand());
+      __ push(r0);
+      __ CallRuntime(Runtime::kNewContext, 1);  // r0 holds the result
+
+      if (kDebug) {
+        Label verified_true;
+        __ cmp(r0, Operand(cp));
+        __ b(eq, &verified_true);
+        __ stop("NewContext: r0 is expected to be the same as cp");
+        __ bind(&verified_true);
+      }
+      // Update context local.
+      __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    }
+
+    // TODO(1241774): Improve this code!!!
+    // 1) only needed if we have a context
+    // 2) no need to recompute context ptr every single time
+    // 3) don't copy parameter operand code from SlotOperand!
+    {
+      Comment cmnt2(masm_, "[ copy context parameters into .context");
+
+      // Note that iteration order is relevant here! If we have the same
+      // parameter twice (e.g., function (x, y, x)), and that parameter
+      // needs to be copied into the context, it must be the last argument
+      // passed to the parameter that needs to be copied. This is a rare
+      // case so we don't check for it, instead we rely on the copying
+      // order: such a parameter is copied repeatedly into the same
+      // context location and thus the last value is what is seen inside
+      // the function.
+      for (int i = 0; i < scope->num_parameters(); i++) {
+        Variable* par = scope->parameter(i);
+        Slot* slot = par->slot();
+        if (slot != NULL && slot->type() == Slot::CONTEXT) {
+          ASSERT(!scope->is_global_scope());  // no parameters in global scope
+          __ ldr(r1, ParameterOperand(i));
+          // Loads r2 with context; used below in RecordWrite.
+          __ str(r1, SlotOperand(slot, r2));
+          // Load the offset into r3.
+          int slot_offset =
+              FixedArray::kHeaderSize + slot->index() * kPointerSize;
+          __ mov(r3, Operand(slot_offset));
+          __ RecordWrite(r2, r3, r1);
+        }
+      }
+    }
+
+    // Store the arguments object.
+    // This must happen after context initialization because
+    // the arguments array may be stored in the context!
+    if (scope->arguments() != NULL) {
+      ASSERT(scope->arguments_shadow() != NULL);
+      Comment cmnt(masm_, "[ allocate arguments object");
+      { Reference shadow_ref(this, scope->arguments_shadow());
+        { Reference arguments_ref(this, scope->arguments());
+          ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+          __ ldr(r2, FunctionOperand());
+          // The receiver is below the arguments, the return address,
+          // and the frame pointer on the stack.
+          const int kReceiverDisplacement = 2 + scope->num_parameters();
+          __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
+          __ mov(r0, Operand(Smi::FromInt(scope->num_parameters())));
+          __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
+          __ CallStub(&stub);
+          __ push(r0);
+          arguments_ref.SetValue(NOT_CONST_INIT);
+        }
+        shadow_ref.SetValue(NOT_CONST_INIT);
+      }
+      __ pop(r0);  // Value is no longer needed.
+    }
+
+    // Generate code to 'execute' declarations and initialize
+    // functions (source elements). In case of an illegal
+    // redeclaration we need to handle that instead of processing the
+    // declarations.
+    if (scope->HasIllegalRedeclaration()) {
+      Comment cmnt(masm_, "[ illegal redeclarations");
+      scope->VisitIllegalRedeclaration(this);
+    } else {
+      Comment cmnt(masm_, "[ declarations");
+      // ProcessDeclarations calls DeclareGlobals indirectly
+      ProcessDeclarations(scope->declarations());
+
+      // Bail out if a stack-overflow exception occurred when
+      // processing declarations.
+      if (HasStackOverflow()) return;
+    }
+
+    if (FLAG_trace) {
+      // Push a valid value as the parameter. The runtime call only uses
+      // it as the return value to indicate non-failure.
+      __ CallRuntime(Runtime::kTraceEnter, 0);
+    }
+    CheckStack();
+
+    // Compile the body of the function in a vanilla state. Don't
+    // bother compiling all the code if the scope has an illegal
+    // redeclaration.
+    if (!scope->HasIllegalRedeclaration()) {
+      Comment cmnt(masm_, "[ function body");
+#ifdef DEBUG
+      bool is_builtin = Bootstrapper::IsActive();
+      bool should_trace =
+          is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
+      if (should_trace) {
+        __ CallRuntime(Runtime::kDebugTrace, 0);
+      }
+#endif
+      VisitStatements(body);
+    }
+  }
+
+  // exit
+  // r0: result
+  // sp: stack pointer
+  // fp: frame pointer
+  // pp: parameter pointer
+  // cp: callee's context
+  __ mov(r0, Operand(Factory::undefined_value()));
+
+  __ bind(&function_return_);
+  if (FLAG_trace) {
+    // Push the return value on the stack as the parameter.
+    // Runtime::TraceExit returns the parameter as it is.
+    __ push(r0);
+    __ CallRuntime(Runtime::kTraceExit, 1);
+  }
+
+  // Tear down the frame which will restore the caller's frame pointer and the
+  // link register.
+  ExitJSFrame();
+
+  __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
+  __ mov(pc, lr);
+
+  // Code generation state must be reset.
+  scope_ = NULL;
+  ASSERT(!has_cc());
+  ASSERT(state_ == NULL);
+}
+
+
+MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+  // Currently, this assertion will fail if we try to assign to
+  // a constant variable that is constant because it is read-only
+  // (such as the variable referring to a named function expression).
+  // We need to implement assignments to read-only variables.
+  // Ideally, we should do this during AST generation (by converting
+  // such assignments into expression statements); however, in general
+  // we may not be able to make the decision until past AST generation,
+  // that is when the entire program is known.
+  ASSERT(slot != NULL);
+  int index = slot->index();
+  switch (slot->type()) {
+    case Slot::PARAMETER:
+      return ParameterOperand(index);
+
+    case Slot::LOCAL: {
+      ASSERT(0 <= index && index < scope()->num_stack_slots());
+      const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset;
+      return MemOperand(fp, kLocalOffset - index * kPointerSize);
+    }
+
+    case Slot::CONTEXT: {
+      // Follow the context chain if necessary.
+      ASSERT(!tmp.is(cp));  // do not overwrite context register
+      Register context = cp;
+      int chain_length = scope()->ContextChainLength(slot->var()->scope());
+      for (int i = chain_length; i-- > 0;) {
+        // Load the closure.
+        // (All contexts, even 'with' contexts, have a closure,
+        // and it is the same for all contexts inside a function.
+        // There is no need to go to the function context first.)
+        __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
+        // Load the function context (which is the incoming, outer context).
+        __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
+        context = tmp;
+      }
+      // We may have a 'with' context now. Get the function context.
+      // (In fact this mov may never be the needed, since the scope analysis
+      // may not permit a direct context access in this case and thus we are
+      // always at a function context. However it is safe to dereference be-
+      // cause the function context of a function context is itself. Before
+      // deleting this mov we should try to create a counter-example first,
+      // though...)
+      __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
+      return ContextOperand(tmp, index);
+    }
+
+    default:
+      UNREACHABLE();
+      return MemOperand(r0, 0);
+  }
+}
+
+
+// Loads a value on the stack. If it is a boolean value, the result may have
+// been (partially) translated into branches, or it may have set the condition
+// code register. If force_cc is set, the value is forced to set the condition
+// code register and no value is pushed. If the condition code register was set,
+// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
+void CodeGenerator::LoadCondition(Expression* x,
+                                     TypeofState typeof_state,
+                                     Label* true_target,
+                                     Label* false_target,
+                                     bool force_cc) {
+  ASSERT(!has_cc());
+
+  { CodeGenState new_state(this, typeof_state, true_target, false_target);
+    Visit(x);
+  }
+  if (force_cc && !has_cc()) {
+    // Convert the TOS value to a boolean in the condition code register.
+    ToBoolean(true_target, false_target);
+  }
+  ASSERT(has_cc() || !force_cc);
+}
+
+
+void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
+  Label true_target;
+  Label false_target;
+  LoadCondition(x, typeof_state, &true_target, &false_target, false);
+
+  if (has_cc()) {
+    // convert cc_reg_ into a bool
+    Label loaded, materialize_true;
+    __ b(cc_reg_, &materialize_true);
+    __ mov(r0, Operand(Factory::false_value()));
+    __ push(r0);
+    __ b(&loaded);
+    __ bind(&materialize_true);
+    __ mov(r0, Operand(Factory::true_value()));
+    __ push(r0);
+    __ bind(&loaded);
+    cc_reg_ = al;
+  }
+
+  if (true_target.is_linked() || false_target.is_linked()) {
+    // we have at least one condition value
+    // that has been "translated" into a branch,
+    // thus it needs to be loaded explicitly again
+    Label loaded;
+    __ b(&loaded);  // don't lose current TOS
+    bool both = true_target.is_linked() && false_target.is_linked();
+    // reincarnate "true", if necessary
+    if (true_target.is_linked()) {
+      __ bind(&true_target);
+      __ mov(r0, Operand(Factory::true_value()));
+      __ push(r0);
+    }
+    // if both "true" and "false" need to be reincarnated,
+    // jump across code for "false"
+    if (both)
+      __ b(&loaded);
+    // reincarnate "false", if necessary
+    if (false_target.is_linked()) {
+      __ bind(&false_target);
+      __ mov(r0, Operand(Factory::false_value()));
+      __ push(r0);
+    }
+    // everything is loaded at this point
+    __ bind(&loaded);
+  }
+  ASSERT(!has_cc());
+}
+
+
+void CodeGenerator::LoadGlobal() {
+  __ ldr(r0, GlobalObject());
+  __ push(r0);
+}
+
+
+void CodeGenerator::LoadGlobalReceiver(Register s) {
+  __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX));
+  __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset));
+  __ push(s);
+}
+
+
+// TODO(1241834): Get rid of this function in favor of just using Load, now
+// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
+// variables w/o reference errors elsewhere.
+void CodeGenerator::LoadTypeofExpression(Expression* x) {
+  Variable* variable = x->AsVariableProxy()->AsVariable();
+  if (variable != NULL && !variable->is_this() && variable->is_global()) {
+    // NOTE: This is somewhat nasty. We force the compiler to load
+    // the variable as if through '<global>.<variable>' to make sure we
+    // do not get reference errors.
+    Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
+    Literal key(variable->name());
+    // TODO(1241834): Fetch the position from the variable instead of using
+    // no position.
+    Property property(&global, &key, RelocInfo::kNoPosition);
+    Load(&property);
+  } else {
+    Load(x, INSIDE_TYPEOF);
+  }
+}
+
+
+Reference::Reference(CodeGenerator* cgen, Expression* expression)
+    : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
+  cgen->LoadReference(this);
+}
+
+
+Reference::~Reference() {
+  cgen_->UnloadReference(this);
+}
+
+
+void CodeGenerator::LoadReference(Reference* ref) {
+  Comment cmnt(masm_, "[ LoadReference");
+
+  Expression* e = ref->expression();
+  Property* property = e->AsProperty();
+  Variable* var = e->AsVariableProxy()->AsVariable();
+
+  if (property != NULL) {
+    // The expression is either a property or a variable proxy that rewrites
+    // to a property.
+    Load(property->obj());
+    // We use a named reference if the key is a literal symbol, unless it is
+    // a string that can be legally parsed as an integer.  This is because
+    // otherwise we will not get into the slow case code that handles [] on
+    // String objects.
+    Literal* literal = property->key()->AsLiteral();
+    uint32_t dummy;
+    if (literal != NULL &&
+        literal->handle()->IsSymbol() &&
+        !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
+      ref->set_type(Reference::NAMED);
+    } else {
+      Load(property->key());
+      ref->set_type(Reference::KEYED);
+    }
+  } else if (var != NULL) {
+    // The expression is a variable proxy that does not rewrite to a
+    // property.  Global variables are treated as named property references.
+    if (var->is_global()) {
+      LoadGlobal();
+      ref->set_type(Reference::NAMED);
+    } else {
+      ASSERT(var->slot() != NULL);
+      ref->set_type(Reference::SLOT);
+    }
+  } else {
+    // Anything else is a runtime error.
+    Load(e);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+  }
+}
+
+
+void CodeGenerator::UnloadReference(Reference* ref) {
+  Comment cmnt(masm_, "[ UnloadReference");
+
+  int size = ref->size();
+  if (size <= 0) {
+    // Do nothing. No popping is necessary.
+  } else {
+    __ pop(r0);
+    __ add(sp, sp, Operand(size * kPointerSize));
+    __ push(r0);
+  }
+}
+
+
+// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
+// register to a boolean in the condition code register. The code
+// may jump to 'false_target' in case the register converts to 'false'.
+void CodeGenerator::ToBoolean(Label* true_target,
+                                 Label* false_target) {
+  // Note: The generated code snippet does not change stack variables.
+  //       Only the condition code should be set.
+  __ pop(r0);
+
+  // Fast case checks
+
+  // Check if the value is 'false'.
+  __ cmp(r0, Operand(Factory::false_value()));
+  __ b(eq, false_target);
+
+  // Check if the value is 'true'.
+  __ cmp(r0, Operand(Factory::true_value()));
+  __ b(eq, true_target);
+
+  // Check if the value is 'undefined'.
+  __ cmp(r0, Operand(Factory::undefined_value()));
+  __ b(eq, false_target);
+
+  // Check if the value is a smi.
+  __ cmp(r0, Operand(Smi::FromInt(0)));
+  __ b(eq, false_target);
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, true_target);
+
+  // Slow case: call the runtime.
+  __ push(r0);
+  __ CallRuntime(Runtime::kToBool, 1);
+
+  // Convert result (r0) to condition code
+  __ cmp(r0, Operand(Factory::false_value()));
+
+  cc_reg_ = ne;
+}
+
+
+class GetPropertyStub : public CodeStub {
+ public:
+  GetPropertyStub() { }
+
+ private:
+  Major MajorKey() { return GetProperty; }
+  int MinorKey() { return 0; }
+  void Generate(MacroAssembler* masm);
+};
+
+
+class SetPropertyStub : public CodeStub {
+ public:
+  SetPropertyStub() { }
+
+ private:
+  Major MajorKey() { return SetProperty; }
+  int MinorKey() { return 0; }
+  void Generate(MacroAssembler* masm);
+};
+
+
+class GenericBinaryOpStub : public CodeStub {
+ public:
+  explicit GenericBinaryOpStub(Token::Value op) : op_(op) { }
+
+ private:
+  Token::Value op_;
+
+  Major MajorKey() { return GenericBinaryOp; }
+  int MinorKey() { return static_cast<int>(op_); }
+  void Generate(MacroAssembler* masm);
+
+  const char* GetName() {
+    switch (op_) {
+      case Token::ADD: return "GenericBinaryOpStub_ADD";
+      case Token::SUB: return "GenericBinaryOpStub_SUB";
+      case Token::MUL: return "GenericBinaryOpStub_MUL";
+      case Token::DIV: return "GenericBinaryOpStub_DIV";
+      case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
+      case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
+      case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
+      case Token::SAR: return "GenericBinaryOpStub_SAR";
+      case Token::SHL: return "GenericBinaryOpStub_SHL";
+      case Token::SHR: return "GenericBinaryOpStub_SHR";
+      default:         return "GenericBinaryOpStub";
+    }
+  }
+
+#ifdef DEBUG
+  void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); }
+#endif
+};
+
+
+class InvokeBuiltinStub : public CodeStub {
+ public:
+  enum Kind { Inc, Dec, ToNumber };
+  InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { }
+
+ private:
+  Kind kind_;
+  int argc_;
+
+  Major MajorKey() { return InvokeBuiltin; }
+  int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); }
+  void Generate(MacroAssembler* masm);
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n",
+           static_cast<int>(kind_),
+           argc_);
+  }
+#endif
+};
+
+
+void CodeGenerator::GenericBinaryOperation(Token::Value op) {
+  // sp[0] : y
+  // sp[1] : x
+  // result : r0
+
+  // Stub is entered with a call: 'return address' is in lr.
+  switch (op) {
+    case Token::ADD:  // fall through.
+    case Token::SUB:  // fall through.
+    case Token::MUL:
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
+      __ pop(r0);  // r0 : y
+      __ pop(r1);  // r1 : x
+      GenericBinaryOpStub stub(op);
+      __ CallStub(&stub);
+      break;
+    }
+
+    case Token::DIV: {
+      __ mov(r0, Operand(1));
+      __ InvokeBuiltin(Builtins::DIV, CALL_JS);
+      break;
+    }
+
+    case Token::MOD: {
+      __ mov(r0, Operand(1));
+      __ InvokeBuiltin(Builtins::MOD, CALL_JS);
+      break;
+    }
+
+    case Token::COMMA:
+      __ pop(r0);
+      // simply discard left value
+      __ pop();
+      break;
+
+    default:
+      // Other cases should have been handled before this point.
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+class DeferredInlinedSmiOperation: public DeferredCode {
+ public:
+  DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op,
+                              int value, bool reversed) :
+      DeferredCode(generator), op_(op), value_(value), reversed_(reversed) {
+    set_comment("[ DeferredInlinedSmiOperation");
+  }
+
+  virtual void Generate() {
+    switch (op_) {
+      case Token::ADD: {
+        if (reversed_) {
+          // revert optimistic add
+          __ sub(r0, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r1, Operand(Smi::FromInt(value_)));  // x
+        } else {
+          // revert optimistic add
+          __ sub(r1, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        }
+        break;
+      }
+
+      case Token::SUB: {
+        if (reversed_) {
+          // revert optimistic sub
+          __ rsb(r0, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r1, Operand(Smi::FromInt(value_)));
+        } else {
+          __ add(r1, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        }
+        break;
+      }
+
+      case Token::BIT_OR:
+      case Token::BIT_XOR:
+      case Token::BIT_AND: {
+        if (reversed_) {
+          __ mov(r1, Operand(Smi::FromInt(value_)));
+        } else {
+          __ mov(r1, Operand(r0));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        }
+        break;
+      }
+
+      case Token::SHL:
+      case Token::SHR:
+      case Token::SAR: {
+        if (!reversed_) {
+          __ mov(r1, Operand(r0));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        } else {
+          UNREACHABLE();  // should have been handled in SmiOperation
+        }
+        break;
+      }
+
+      default:
+        // other cases should have been handled before this point.
+        UNREACHABLE();
+        break;
+    }
+
+    GenericBinaryOpStub igostub(op_);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  Token::Value op_;
+  int value_;
+  bool reversed_;
+};
+
+
+void CodeGenerator::SmiOperation(Token::Value op,
+                                    Handle<Object> value,
+                                    bool reversed) {
+  // NOTE: This is an attempt to inline (a bit) more of the code for
+  // some possible smi operations (like + and -) when (at least) one
+  // of the operands is a literal smi. With this optimization, the
+  // performance of the system is increased by ~15%, and the generated
+  // code size is increased by ~1% (measured on a combination of
+  // different benchmarks).
+
+  // sp[0] : operand
+
+  int int_value = Smi::cast(*value)->value();
+
+  Label exit;
+  __ pop(r0);
+
+  switch (op) {
+    case Token::ADD: {
+      DeferredCode* deferred =
+        new DeferredInlinedSmiOperation(this, op, int_value, reversed);
+
+      __ add(r0, r0, Operand(value), SetCC);
+      __ b(vs, deferred->enter());
+      __ tst(r0, Operand(kSmiTagMask));
+      __ b(ne, deferred->enter());
+      __ bind(deferred->exit());
+      break;
+    }
+
+    case Token::SUB: {
+      DeferredCode* deferred =
+        new DeferredInlinedSmiOperation(this, op, int_value, reversed);
+
+      if (!reversed) {
+        __ sub(r0, r0, Operand(value), SetCC);
+      } else {
+        __ rsb(r0, r0, Operand(value), SetCC);
+      }
+      __ b(vs, deferred->enter());
+      __ tst(r0, Operand(kSmiTagMask));
+      __ b(ne, deferred->enter());
+      __ bind(deferred->exit());
+      break;
+    }
+
+    case Token::BIT_OR:
+    case Token::BIT_XOR:
+    case Token::BIT_AND: {
+      DeferredCode* deferred =
+        new DeferredInlinedSmiOperation(this, op, int_value, reversed);
+      __ tst(r0, Operand(kSmiTagMask));
+      __ b(ne, deferred->enter());
+      switch (op) {
+        case Token::BIT_OR:  __ orr(r0, r0, Operand(value)); break;
+        case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
+        case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
+        default: UNREACHABLE();
+      }
+      __ bind(deferred->exit());
+      break;
+    }
+
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
+      if (reversed) {
+        __ mov(ip, Operand(value));
+        __ push(ip);
+        __ push(r0);
+        GenericBinaryOperation(op);
+
+      } else {
+        int shift_value = int_value & 0x1f;  // least significant 5 bits
+        DeferredCode* deferred =
+          new DeferredInlinedSmiOperation(this, op, shift_value, false);
+        __ tst(r0, Operand(kSmiTagMask));
+        __ b(ne, deferred->enter());
+        __ mov(r2, Operand(r0, ASR, kSmiTagSize));  // remove tags
+        switch (op) {
+          case Token::SHL: {
+            __ mov(r2, Operand(r2, LSL, shift_value));
+            // check that the *unsigned* result fits in a smi
+            __ add(r3, r2, Operand(0x40000000), SetCC);
+            __ b(mi, deferred->enter());
+            break;
+          }
+          case Token::SHR: {
+            // LSR by immediate 0 means shifting 32 bits.
+            if (shift_value != 0) {
+              __ mov(r2, Operand(r2, LSR, shift_value));
+            }
+            // check that the *unsigned* result fits in a smi
+            // neither of the two high-order bits can be set:
+            // - 0x80000000: high bit would be lost when smi tagging
+            // - 0x40000000: this number would convert to negative when
+            // smi tagging these two cases can only happen with shifts
+            // by 0 or 1 when handed a valid smi
+            __ and_(r3, r2, Operand(0xc0000000), SetCC);
+            __ b(ne, deferred->enter());
+            break;
+          }
+          case Token::SAR: {
+            if (shift_value != 0) {
+              // ASR by immediate 0 means shifting 32 bits.
+              __ mov(r2, Operand(r2, ASR, shift_value));
+            }
+            break;
+          }
+          default: UNREACHABLE();
+        }
+        __ mov(r0, Operand(r2, LSL, kSmiTagSize));
+        __ bind(deferred->exit());
+      }
+      break;
+    }
+
+    default:
+      if (!reversed) {
+        __ push(r0);
+        __ mov(r0, Operand(value));
+        __ push(r0);
+      } else {
+        __ mov(ip, Operand(value));
+        __ push(ip);
+        __ push(r0);
+      }
+      GenericBinaryOperation(op);
+      break;
+  }
+
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::Comparison(Condition cc, bool strict) {
+  // sp[0] : y
+  // sp[1] : x
+  // result : cc register
+
+  // Strict only makes sense for equality comparisons.
+  ASSERT(!strict || cc == eq);
+
+  Label exit, smi;
+  // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
+  if (cc == gt || cc == le) {
+    cc = ReverseCondition(cc);
+    __ pop(r1);
+    __ pop(r0);
+  } else {
+    __ pop(r0);
+    __ pop(r1);
+  }
+  __ orr(r2, r0, Operand(r1));
+  __ tst(r2, Operand(kSmiTagMask));
+  __ b(eq, &smi);
+
+  // Perform non-smi comparison by runtime call.
+  __ push(r1);
+
+  // Figure out which native to call and setup the arguments.
+  Builtins::JavaScript native;
+  int argc;
+  if (cc == eq) {
+    native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+    argc = 1;
+  } else {
+    native = Builtins::COMPARE;
+    int ncr;  // NaN compare result
+    if (cc == lt || cc == le) {
+      ncr = GREATER;
+    } else {
+      ASSERT(cc == gt || cc == ge);  // remaining cases
+      ncr = LESS;
+    }
+    __ push(r0);
+    __ mov(r0, Operand(Smi::FromInt(ncr)));
+    argc = 2;
+  }
+
+  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+  // tagged as a small integer.
+  __ push(r0);
+  __ mov(r0, Operand(argc));
+  __ InvokeBuiltin(native, CALL_JS);
+  __ cmp(r0, Operand(0));
+  __ b(&exit);
+
+  // test smi equality by pointer comparison.
+  __ bind(&smi);
+  __ cmp(r1, Operand(r0));
+
+  __ bind(&exit);
+  cc_reg_ = cc;
+}
+
+
+class CallFunctionStub: public CodeStub {
+ public:
+  explicit CallFunctionStub(int argc) : argc_(argc) {}
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  int argc_;
+
+#if defined(DEBUG)
+  void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
+#endif  // defined(DEBUG)
+
+  Major MajorKey() { return CallFunction; }
+  int MinorKey() { return argc_; }
+};
+
+
+// Call the function on the stack with the given arguments.
+void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
+                                         int position) {
+  // Push the arguments ("left-to-right") on the stack.
+  for (int i = 0; i < args->length(); i++) {
+    Load(args->at(i));
+  }
+
+  // Record the position for debugging purposes.
+  __ RecordPosition(position);
+
+  // Use the shared code stub to call the function.
+  CallFunctionStub call_function(args->length());
+  __ CallStub(&call_function);
+
+  // Restore context and pop function from the stack.
+  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ pop();  // discard the TOS
+}
+
+
+void CodeGenerator::Branch(bool if_true, Label* L) {
+  ASSERT(has_cc());
+  Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
+  __ b(cc, L);
+  cc_reg_ = al;
+}
+
+
+void CodeGenerator::CheckStack() {
+  if (FLAG_check_stack) {
+    Comment cmnt(masm_, "[ check stack");
+    StackCheckStub stub;
+    __ CallStub(&stub);
+  }
+}
+
+
+void CodeGenerator::VisitBlock(Block* node) {
+  Comment cmnt(masm_, "[ Block");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  node->set_break_stack_height(break_stack_height_);
+  VisitStatements(node->statements());
+  __ bind(node->break_target());
+}
+
+
+void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+  __ mov(r0, Operand(pairs));
+  __ push(r0);
+  __ push(cp);
+  __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
+  __ push(r0);
+  __ CallRuntime(Runtime::kDeclareGlobals, 3);
+  // The result is discarded.
+}
+
+
+void CodeGenerator::VisitDeclaration(Declaration* node) {
+  Comment cmnt(masm_, "[ Declaration");
+  Variable* var = node->proxy()->var();
+  ASSERT(var != NULL);  // must have been resolved
+  Slot* slot = var->slot();
+
+  // 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) {
+    // Variables with a "LOOKUP" slot were introduced as non-locals
+    // during variable resolution and must have mode DYNAMIC.
+    ASSERT(var->mode() == Variable::DYNAMIC);
+    // For now, just do a runtime call.
+    __ push(cp);
+    __ mov(r0, Operand(var->name()));
+    __ push(r0);
+    // Declaration nodes are always declared in only two modes.
+    ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
+    PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
+    __ mov(r0, Operand(Smi::FromInt(attr)));
+    __ push(r0);
+    // Push initial value, if any.
+    // 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 (node->mode() == Variable::CONST) {
+      __ mov(r0, Operand(Factory::the_hole_value()));
+      __ push(r0);
+    } else if (node->fun() != NULL) {
+      Load(node->fun());
+    } else {
+      __ mov(r0, Operand(0));  // no initial value!
+      __ push(r0);
+    }
+    __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+    // Ignore the return value (declarations are statements).
+    return;
+  }
+
+  ASSERT(!var->is_global());
+
+  // If we have a function or a constant, we need to initialize the variable.
+  Expression* val = NULL;
+  if (node->mode() == Variable::CONST) {
+    val = new Literal(Factory::the_hole_value());
+  } else {
+    val = node->fun();  // NULL if we don't have a function
+  }
+
+  if (val != NULL) {
+    // Set initial value.
+    Reference target(this, node->proxy());
+    ASSERT(target.is_slot());
+    Load(val);
+    target.SetValue(NOT_CONST_INIT);
+    // Get rid of the assigned value (declarations are statements).  It's
+    // safe to pop the value lying on top of the reference before unloading
+    // the reference itself (which preserves the top of stack) because we
+    // know it is a zero-sized reference.
+    __ pop();
+  }
+}
+
+
+void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
+  Comment cmnt(masm_, "[ ExpressionStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  Expression* expression = node->expression();
+  expression->MarkAsStatement();
+  Load(expression);
+  __ pop();
+}
+
+
+void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
+  Comment cmnt(masm_, "// EmptyStatement");
+  // nothing to do
+}
+
+
+void CodeGenerator::VisitIfStatement(IfStatement* node) {
+  Comment cmnt(masm_, "[ IfStatement");
+  // Generate different code depending on which
+  // parts of the if statement are present or not.
+  bool has_then_stm = node->HasThenStatement();
+  bool has_else_stm = node->HasElseStatement();
+
+  if (FLAG_debug_info) RecordStatementPosition(node);
+
+  Label exit;
+  if (has_then_stm && has_else_stm) {
+    Comment cmnt(masm_, "[ IfThenElse");
+    Label then;
+    Label else_;
+    // if (cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
+    Branch(false, &else_);
+    // then
+    __ bind(&then);
+    Visit(node->then_statement());
+    __ b(&exit);
+    // else
+    __ bind(&else_);
+    Visit(node->else_statement());
+
+  } else if (has_then_stm) {
+    Comment cmnt(masm_, "[ IfThen");
+    ASSERT(!has_else_stm);
+    Label then;
+    // if (cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
+    Branch(false, &exit);
+    // then
+    __ bind(&then);
+    Visit(node->then_statement());
+
+  } else if (has_else_stm) {
+    Comment cmnt(masm_, "[ IfElse");
+    ASSERT(!has_then_stm);
+    Label else_;
+    // if (!cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
+    Branch(true, &exit);
+    // else
+    __ bind(&else_);
+    Visit(node->else_statement());
+
+  } else {
+    Comment cmnt(masm_, "[ If");
+    ASSERT(!has_then_stm && !has_else_stm);
+    // if (cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
+    if (has_cc()) {
+      cc_reg_ = al;
+    } else {
+      __ pop(r0);  // __ Pop(no_reg)
+    }
+  }
+
+  // end
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::CleanStack(int num_bytes) {
+  ASSERT(num_bytes >= 0);
+  if (num_bytes > 0) {
+    __ add(sp, sp, Operand(num_bytes));
+  }
+}
+
+
+void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
+  Comment cmnt(masm_, "[ ContinueStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  CleanStack(break_stack_height_ - node->target()->break_stack_height());
+  __ b(node->target()->continue_target());
+}
+
+
+void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
+  Comment cmnt(masm_, "[ BreakStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  CleanStack(break_stack_height_ - node->target()->break_stack_height());
+  __ b(node->target()->break_target());
+}
+
+
+void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
+  Comment cmnt(masm_, "[ ReturnStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  Load(node->expression());
+  // Move the function result into r0.
+  __ pop(r0);
+
+  __ b(&function_return_);
+}
+
+
+void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
+  Comment cmnt(masm_, "[ WithEnterStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  Load(node->expression());
+  __ CallRuntime(Runtime::kPushContext, 1);
+  if (kDebug) {
+    Label verified_true;
+    __ cmp(r0, Operand(cp));
+    __ b(eq, &verified_true);
+    __ stop("PushContext: r0 is expected to be the same as cp");
+    __ bind(&verified_true);
+  }
+  // Update context local.
+  __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+}
+
+
+void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
+  Comment cmnt(masm_, "[ WithExitStatement");
+  // Pop context.
+  __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
+  // Update context local.
+  __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+}
+
+
+int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
+    return kFastSwitchMaxOverheadFactor;
+}
+
+int CodeGenerator::FastCaseSwitchMinCaseCount() {
+    return kFastSwitchMinCaseCount;
+}
+
+
+void CodeGenerator::GenerateFastCaseSwitchJumpTable(
+    SwitchStatement* node,
+    int min_index,
+    int range,
+    Label* fail_label,
+    Vector<Label*> case_targets,
+    Vector<Label> case_labels) {
+
+  ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
+
+  __ pop(r0);
+  if (min_index != 0) {
+    // small positive numbers can be immediate operands.
+    if (min_index < 0) {
+      __ add(r0, r0, Operand(Smi::FromInt(-min_index)));
+    } else {
+      __ sub(r0, r0, Operand(Smi::FromInt(min_index)));
+    }
+  }
+  __ tst(r0, Operand(0x80000000 | kSmiTagMask));
+  __ b(ne, fail_label);
+  __ cmp(r0, Operand(Smi::FromInt(range)));
+  __ b(ge, fail_label);
+  __ add(pc, pc, Operand(r0, LSL, 2 - kSmiTagSize));
+  // One extra instruction offsets the table, so the table's start address is
+  // the pc-register at the above add.
+  __ stop("Unreachable: Switch table alignment");
+
+  // table containing branch operations.
+  for (int i = 0; i < range; i++) {
+    __ b(case_targets[i]);
+  }
+
+  GenerateFastCaseSwitchCases(node, case_labels);
+}
+
+
+void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
+  Comment cmnt(masm_, "[ SwitchStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  node->set_break_stack_height(break_stack_height_);
+
+  Load(node->tag());
+
+  if (TryGenerateFastCaseSwitchStatement(node)) {
+      return;
+  }
+
+  Label next, fall_through, default_case;
+  ZoneList<CaseClause*>* cases = node->cases();
+  int length = cases->length();
+
+  for (int i = 0; i < length; i++) {
+    CaseClause* clause = cases->at(i);
+
+    Comment cmnt(masm_, "[ case clause");
+
+    if (clause->is_default()) {
+      // Continue matching cases. The program will execute the default case's
+      // statements if it does not match any of the cases.
+      __ b(&next);
+
+      // Bind the default case label, so we can branch to it when we
+      // have compared against all other cases.
+      ASSERT(default_case.is_unused());  // at most one default clause
+      __ bind(&default_case);
+    } else {
+      __ bind(&next);
+      next.Unuse();
+      __ ldr(r0, MemOperand(sp, 0));
+      __ push(r0);  // duplicate TOS
+      Load(clause->label());
+      Comparison(eq, true);
+      Branch(false, &next);
+    }
+
+    // Entering the case statement for the first time. Remove the switch value
+    // from the stack.
+    __ pop(r0);
+
+    // Generate code for the body.
+    // This is also the target for the fall through from the previous case's
+    // statements which has to skip over the matching code and the popping of
+    // the switch value.
+    __ bind(&fall_through);
+    fall_through.Unuse();
+    VisitStatements(clause->statements());
+    __ b(&fall_through);
+  }
+
+  __ bind(&next);
+  // Reached the end of the case statements without matching any of the cases.
+  if (default_case.is_bound()) {
+    // A default case exists -> execute its statements.
+    __ b(&default_case);
+  } else {
+    // Remove the switch value from the stack.
+    __ pop(r0);
+  }
+
+  __ bind(&fall_through);
+  __ bind(node->break_target());
+}
+
+
+void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
+  Comment cmnt(masm_, "[ LoopStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  node->set_break_stack_height(break_stack_height_);
+
+  // simple condition analysis
+  enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
+  if (node->cond() == NULL) {
+    ASSERT(node->type() == LoopStatement::FOR_LOOP);
+    info = ALWAYS_TRUE;
+  } else {
+    Literal* lit = node->cond()->AsLiteral();
+    if (lit != NULL) {
+      if (lit->IsTrue()) {
+        info = ALWAYS_TRUE;
+      } else if (lit->IsFalse()) {
+        info = ALWAYS_FALSE;
+      }
+    }
+  }
+
+  Label loop, entry;
+
+  // init
+  if (node->init() != NULL) {
+    ASSERT(node->type() == LoopStatement::FOR_LOOP);
+    Visit(node->init());
+  }
+  if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) {
+    __ b(&entry);
+  }
+
+  // body
+  __ bind(&loop);
+  Visit(node->body());
+
+  // next
+  __ bind(node->continue_target());
+  if (node->next() != NULL) {
+    // Record source position of the statement as this code which is after the
+    // code for the body actually belongs to the loop statement and not the
+    // body.
+    if (FLAG_debug_info) __ RecordPosition(node->statement_pos());
+    ASSERT(node->type() == LoopStatement::FOR_LOOP);
+    Visit(node->next());
+  }
+
+  // cond
+  __ bind(&entry);
+  switch (info) {
+    case ALWAYS_TRUE:
+      CheckStack();  // TODO(1222600): ignore if body contains calls.
+      __ b(&loop);
+      break;
+    case ALWAYS_FALSE:
+      break;
+    case DONT_KNOW:
+      CheckStack();  // TODO(1222600): ignore if body contains calls.
+      LoadCondition(node->cond(),
+                    NOT_INSIDE_TYPEOF,
+                    &loop,
+                    node->break_target(),
+                    true);
+      Branch(true, &loop);
+      break;
+  }
+
+  // exit
+  __ bind(node->break_target());
+}
+
+
+void CodeGenerator::VisitForInStatement(ForInStatement* node) {
+  Comment cmnt(masm_, "[ ForInStatement");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+
+  // We keep stuff on the stack while the body is executing.
+  // Record it, so that a break/continue crossing this statement
+  // can restore the stack.
+  const int kForInStackSize = 5 * kPointerSize;
+  break_stack_height_ += kForInStackSize;
+  node->set_break_stack_height(break_stack_height_);
+
+  Label loop, next, entry, cleanup, exit, primitive, jsobject;
+  Label filter_key, end_del_check, fixed_array, non_string;
+
+  // Get the object to enumerate over (converted to JSObject).
+  Load(node->enumerable());
+  __ pop(r0);
+
+  // Both SpiderMonkey and kjs ignore null and undefined in contrast
+  // to the specification.  12.6.4 mandates a call to ToObject.
+  __ cmp(r0, Operand(Factory::undefined_value()));
+  __ b(eq, &exit);
+  __ cmp(r0, Operand(Factory::null_value()));
+  __ b(eq, &exit);
+
+  // Stack layout in body:
+  // [iteration counter (Smi)]
+  // [length of array]
+  // [FixedArray]
+  // [Map or 0]
+  // [Object]
+
+  // Check if enumerable is already a JSObject
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &primitive);
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
+  __ b(hs, &jsobject);
+
+  __ bind(&primitive);
+  __ push(r0);
+  __ mov(r0, Operand(0));
+  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
+
+
+  __ bind(&jsobject);
+
+  // Get the set of properties (as a FixedArray or Map).
+  __ push(r0);  // duplicate the object being enumerated
+  __ push(r0);
+  __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+
+  // If we got a Map, we can do a fast modification check.
+  // Otherwise, we got a FixedArray, and we have to do a slow check.
+  __ mov(r2, Operand(r0));
+  __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
+  __ cmp(r1, Operand(Factory::meta_map()));
+  __ b(ne, &fixed_array);
+
+  // Get enum cache
+  __ mov(r1, Operand(r0));
+  __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
+  __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
+  __ ldr(r2,
+         FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
+
+  __ push(r0);  // map
+  __ push(r2);  // enum cache bridge cache
+  __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+  __ push(r0);
+  __ mov(r0, Operand(Smi::FromInt(0)));
+  __ push(r0);
+  __ b(&entry);
+
+
+  __ bind(&fixed_array);
+
+  __ mov(r1, Operand(Smi::FromInt(0)));
+  __ push(r1);  // insert 0 in place of Map
+  __ push(r0);
+
+  // Push the length of the array and the initial index onto the stack.
+  __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+  __ push(r0);
+  __ mov(r0, Operand(Smi::FromInt(0)));  // init index
+  __ push(r0);
+
+  __ b(&entry);
+
+  // Body.
+  __ bind(&loop);
+  Visit(node->body());
+
+  // Next.
+  __ bind(node->continue_target());
+  __ bind(&next);
+  __ pop(r0);
+  __ add(r0, r0, Operand(Smi::FromInt(1)));
+  __ push(r0);
+
+  // Condition.
+  __ bind(&entry);
+
+  // sp[0] : index
+  // sp[1] : array/enum cache length
+  // sp[2] : array or enum cache
+  // sp[3] : 0 or map
+  // sp[4] : enumerable
+  __ ldr(r0, MemOperand(sp, 0 * kPointerSize));  // load the current count
+  __ ldr(r1, MemOperand(sp, 1 * kPointerSize));  // load the length
+  __ cmp(r0, Operand(r1));  // compare to the array length
+  __ b(hs, &cleanup);
+
+  __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
+
+  // Get the i'th entry of the array.
+  __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
+  __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
+
+  // Get Map or 0.
+  __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
+  // Check if this (still) matches the map of the enumerable.
+  // If not, we have to filter the key.
+  __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
+  __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ cmp(r1, Operand(r2));
+  __ b(eq, &end_del_check);
+
+  // Convert the entry to a string (or null if it isn't a property anymore).
+  __ ldr(r0, MemOperand(sp, 4 * kPointerSize));  // push enumerable
+  __ push(r0);
+  __ push(r3);  // push entry
+  __ mov(r0, Operand(1));
+  __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS);
+  __ mov(r3, Operand(r0));
+
+  // If the property has been removed while iterating, we just skip it.
+  __ cmp(r3, Operand(Factory::null_value()));
+  __ b(eq, &next);
+
+
+  __ bind(&end_del_check);
+
+  // Store the entry in the 'each' expression and take another spin in the loop.
+  // r3: i'th entry of the enum cache (or string there of)
+  __ push(r3);  // push entry
+  { Reference each(this, node->each());
+    if (!each.is_illegal()) {
+      if (each.size() > 0) {
+        __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
+        __ push(r0);
+      }
+      // If the reference was to a slot we rely on the convenient property
+      // that it doesn't matter whether a value (eg, r3 pushed above) is
+      // right on top of or right underneath a zero-sized reference.
+      each.SetValue(NOT_CONST_INIT);
+      if (each.size() > 0) {
+        // It's safe to pop the value lying on top of the reference before
+        // unloading the reference itself (which preserves the top of stack,
+        // ie, now the topmost value of the non-zero sized reference), since
+        // we will discard the top of stack after unloading the reference
+        // anyway.
+        __ pop(r0);
+      }
+    }
+  }
+  // Discard the i'th entry pushed above or else the remainder of the
+  // reference, whichever is currently on top of the stack.
+  __ pop();
+  CheckStack();  // TODO(1222600): ignore if body contains calls.
+  __ jmp(&loop);
+
+  // Cleanup.
+  __ bind(&cleanup);
+  __ bind(node->break_target());
+  __ add(sp, sp, Operand(5 * kPointerSize));
+
+  // Exit.
+  __ bind(&exit);
+
+  break_stack_height_ -= kForInStackSize;
+}
+
+
+void CodeGenerator::VisitTryCatch(TryCatch* node) {
+  Comment cmnt(masm_, "[ TryCatch");
+
+  Label try_block, exit;
+
+  __ bl(&try_block);
+
+  // --- Catch block ---
+
+  // Store the caught exception in the catch variable.
+  __ push(r0);
+  { Reference ref(this, node->catch_var());
+    ASSERT(ref.is_slot());
+    // Here we make use of the convenient property that it doesn't matter
+    // whether a value is immediately on top of or underneath a zero-sized
+    // reference.
+    ref.SetValue(NOT_CONST_INIT);
+  }
+
+  // Remove the exception from the stack.
+  __ pop();
+
+  VisitStatements(node->catch_block()->statements());
+  __ b(&exit);
+
+
+  // --- Try block ---
+  __ bind(&try_block);
+
+  __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
+
+  // Shadow the labels for all escapes from the try block, including
+  // returns. During shadowing, the original label is hidden as the
+  // LabelShadow and operations on the original actually affect the
+  // shadowing label.
+  //
+  // We should probably try to unify the escaping labels and the return
+  // label.
+  int nof_escapes = node->escaping_labels()->length();
+  List<LabelShadow*> shadows(1 + nof_escapes);
+  shadows.Add(new LabelShadow(&function_return_));
+  for (int i = 0; i < nof_escapes; i++) {
+    shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
+  }
+
+  // Generate code for the statements in the try block.
+  VisitStatements(node->try_block()->statements());
+  __ pop(r0);  // Discard the result.
+
+  // Stop the introduced shadowing and count the number of required unlinks.
+  // After shadowing stops, the original labels are unshadowed and the
+  // LabelShadows represent the formerly shadowing labels.
+  int nof_unlinks = 0;
+  for (int i = 0; i <= nof_escapes; i++) {
+    shadows[i]->StopShadowing();
+    if (shadows[i]->is_linked()) nof_unlinks++;
+  }
+
+  // Unlink from try chain.
+  // TOS contains code slot
+  const int kNextOffset = StackHandlerConstants::kNextOffset +
+      StackHandlerConstants::kAddressDisplacement;
+  __ ldr(r1, MemOperand(sp, kNextOffset));  // read next_sp
+  __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+  __ str(r1, MemOperand(r3));
+  ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
+  __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+  // Code slot popped.
+  if (nof_unlinks > 0) __ b(&exit);
+
+  // Generate unlink code for the (formerly) shadowing labels that have been
+  // jumped to.
+  for (int i = 0; i <= nof_escapes; i++) {
+    if (shadows[i]->is_linked()) {
+      // Unlink from try chain;
+      __ bind(shadows[i]);
+
+      // Reload sp from the top handler, because some statements that we
+      // break from (eg, for...in) may have left stuff on the stack.
+      __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+      __ ldr(sp, MemOperand(r3));
+
+      __ ldr(r1, MemOperand(sp, kNextOffset));
+      __ str(r1, MemOperand(r3));
+      ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
+      __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+      // Code slot popped.
+
+      __ b(shadows[i]->original_label());
+    }
+  }
+
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::VisitTryFinally(TryFinally* node) {
+  Comment cmnt(masm_, "[ TryFinally");
+
+  // State: Used to keep track of reason for entering the finally
+  // block. Should probably be extended to hold information for
+  // break/continue from within the try block.
+  enum { FALLING, THROWING, JUMPING };
+
+  Label exit, unlink, try_block, finally_block;
+
+  __ bl(&try_block);
+
+  __ push(r0);  // save exception object on the stack
+  // In case of thrown exceptions, this is where we continue.
+  __ mov(r2, Operand(Smi::FromInt(THROWING)));
+  __ b(&finally_block);
+
+
+  // --- Try block ---
+  __ bind(&try_block);
+
+  __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
+
+  // Shadow the labels for all escapes from the try block, including
+  // returns.  Shadowing hides the original label as the LabelShadow and
+  // operations on the original actually affect the shadowing label.
+  //
+  // We should probably try to unify the escaping labels and the return
+  // label.
+  int nof_escapes = node->escaping_labels()->length();
+  List<LabelShadow*> shadows(1 + nof_escapes);
+  shadows.Add(new LabelShadow(&function_return_));
+  for (int i = 0; i < nof_escapes; i++) {
+    shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
+  }
+
+  // Generate code for the statements in the try block.
+  VisitStatements(node->try_block()->statements());
+
+  // Stop the introduced shadowing and count the number of required unlinks.
+  // After shadowing stops, the original labels are unshadowed and the
+  // LabelShadows represent the formerly shadowing labels.
+  int nof_unlinks = 0;
+  for (int i = 0; i <= nof_escapes; i++) {
+    shadows[i]->StopShadowing();
+    if (shadows[i]->is_linked()) nof_unlinks++;
+  }
+
+  // Set the state on the stack to FALLING.
+  __ mov(r0, Operand(Factory::undefined_value()));  // fake TOS
+  __ push(r0);
+  __ mov(r2, Operand(Smi::FromInt(FALLING)));
+  if (nof_unlinks > 0) __ b(&unlink);
+
+  // Generate code to set the state for the (formerly) shadowing labels that
+  // have been jumped to.
+  for (int i = 0; i <= nof_escapes; i++) {
+    if (shadows[i]->is_linked()) {
+      __ bind(shadows[i]);
+      if (shadows[i]->original_label() == &function_return_) {
+        // If this label shadowed the function return, materialize the
+        // return value on the stack.
+        __ push(r0);
+      } else {
+        // Fake TOS for labels that shadowed breaks and continues.
+        __ mov(r0, Operand(Factory::undefined_value()));
+        __ push(r0);
+      }
+      __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
+      __ b(&unlink);
+    }
+  }
+
+  // Unlink from try chain;
+  __ bind(&unlink);
+
+  __ pop(r0);  // Store TOS in r0 across stack manipulation
+  // Reload sp from the top handler, because some statements that we
+  // break from (eg, for...in) may have left stuff on the stack.
+  __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+  __ ldr(sp, MemOperand(r3));
+  const int kNextOffset = StackHandlerConstants::kNextOffset +
+      StackHandlerConstants::kAddressDisplacement;
+  __ ldr(r1, MemOperand(sp, kNextOffset));
+  __ str(r1, MemOperand(r3));
+  ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
+  __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+  // Code slot popped.
+  __ push(r0);
+
+  // --- Finally block ---
+  __ bind(&finally_block);
+
+  // Push the state on the stack.
+  __ push(r2);
+
+  // We keep two elements on the stack - the (possibly faked) result
+  // and the state - while evaluating the finally block. Record it, so
+  // that a break/continue crossing this statement can restore the
+  // stack.
+  const int kFinallyStackSize = 2 * kPointerSize;
+  break_stack_height_ += kFinallyStackSize;
+
+  // Generate code for the statements in the finally block.
+  VisitStatements(node->finally_block()->statements());
+
+  // Restore state and return value or faked TOS.
+  __ pop(r2);
+  __ pop(r0);
+  break_stack_height_ -= kFinallyStackSize;
+
+  // Generate code to jump to the right destination for all used (formerly)
+  // shadowing labels.
+  for (int i = 0; i <= nof_escapes; i++) {
+    if (shadows[i]->is_bound()) {
+      __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
+      if (shadows[i]->original_label() != &function_return_) {
+        Label next;
+        __ b(ne, &next);
+        __ b(shadows[i]->original_label());
+        __ bind(&next);
+      } else {
+        __ b(eq, shadows[i]->original_label());
+      }
+    }
+  }
+
+  // Check if we need to rethrow the exception.
+  __ cmp(r2, Operand(Smi::FromInt(THROWING)));
+  __ b(ne, &exit);
+
+  // Rethrow exception.
+  __ push(r0);
+  __ CallRuntime(Runtime::kReThrow, 1);
+
+  // Done.
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
+  Comment cmnt(masm_, "[ DebuggerStatament");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  __ CallRuntime(Runtime::kDebugBreak, 0);
+  // Ignore the return value.
+}
+
+
+void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
+  ASSERT(boilerplate->IsBoilerplate());
+
+  // Push the boilerplate on the stack.
+  __ mov(r0, Operand(boilerplate));
+  __ push(r0);
+
+  // Create a new closure.
+  __ push(cp);
+  __ CallRuntime(Runtime::kNewClosure, 2);
+  __ push(r0);
+}
+
+
+void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
+  Comment cmnt(masm_, "[ FunctionLiteral");
+
+  // Build the function boilerplate and instantiate it.
+  Handle<JSFunction> boilerplate = BuildBoilerplate(node);
+  // Check for stack-overflow exception.
+  if (HasStackOverflow()) return;
+  InstantiateBoilerplate(boilerplate);
+}
+
+
+void CodeGenerator::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* node) {
+  Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
+  InstantiateBoilerplate(node->boilerplate());
+}
+
+
+void CodeGenerator::VisitConditional(Conditional* node) {
+  Comment cmnt(masm_, "[ Conditional");
+  Label then, else_, exit;
+  LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
+  Branch(false, &else_);
+  __ bind(&then);
+  Load(node->then_expression(), typeof_state());
+  __ b(&exit);
+  __ bind(&else_);
+  Load(node->else_expression(), typeof_state());
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
+  if (slot->type() == Slot::LOOKUP) {
+    ASSERT(slot->var()->mode() == Variable::DYNAMIC);
+
+    // For now, just do a runtime call.
+    __ push(cp);
+    __ mov(r0, Operand(slot->var()->name()));
+    __ push(r0);
+
+    if (typeof_state == INSIDE_TYPEOF) {
+      __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
+    } else {
+      __ CallRuntime(Runtime::kLoadContextSlot, 2);
+    }
+    __ push(r0);
+
+  } else {
+    // Note: We would like to keep the assert below, but it fires because of
+    // some nasty code in LoadTypeofExpression() which should be removed...
+    // ASSERT(slot->var()->mode() != Variable::DYNAMIC);
+
+    // Special handling for locals allocated in registers.
+    __ ldr(r0, SlotOperand(slot, r2));
+    __ push(r0);
+    if (slot->var()->mode() == Variable::CONST) {
+      // Const slots may contain 'the hole' value (the constant hasn't been
+      // initialized yet) which needs to be converted into the 'undefined'
+      // value.
+      Comment cmnt(masm_, "[ Unhole const");
+      __ pop(r0);
+      __ cmp(r0, Operand(Factory::the_hole_value()));
+      __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
+      __ push(r0);
+    }
+  }
+}
+
+
+void CodeGenerator::VisitSlot(Slot* node) {
+  Comment cmnt(masm_, "[ Slot");
+  LoadFromSlot(node, typeof_state());
+}
+
+
+void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
+  Comment cmnt(masm_, "[ VariableProxy");
+
+  Variable* var = node->var();
+  Expression* expr = var->rewrite();
+  if (expr != NULL) {
+    Visit(expr);
+  } else {
+    ASSERT(var->is_global());
+    Reference ref(this, node);
+    ref.GetValue(typeof_state());
+  }
+}
+
+
+void CodeGenerator::VisitLiteral(Literal* node) {
+  Comment cmnt(masm_, "[ Literal");
+  __ mov(r0, Operand(node->handle()));
+  __ push(r0);
+}
+
+
+void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
+  Comment cmnt(masm_, "[ RexExp Literal");
+
+  // Retrieve the literal array and check the allocated entry.
+
+  // Load the function of this activation.
+  __ ldr(r1, FunctionOperand());
+
+  // Load the literals array of the function.
+  __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
+
+  // Load the literal at the ast saved index.
+  int literal_offset =
+      FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
+  __ ldr(r2, FieldMemOperand(r1, literal_offset));
+
+  Label done;
+  __ cmp(r2, Operand(Factory::undefined_value()));
+  __ b(ne, &done);
+
+  // If the entry is undefined we call the runtime system to computed
+  // the literal.
+  __ push(r1);  // literal array  (0)
+  __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
+  __ push(r0);  // literal index  (1)
+  __ mov(r0, Operand(node->pattern()));  // RegExp pattern (2)
+  __ push(r0);
+  __ mov(r0, Operand(node->flags()));  // RegExp flags   (3)
+  __ push(r0);
+  __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
+  __ mov(r2, Operand(r0));
+
+  __ bind(&done);
+  // Push the literal.
+  __ push(r2);
+}
+
+
+// This deferred code stub will be used for creating the boilerplate
+// by calling Runtime_CreateObjectLiteral.
+// Each created boilerplate is stored in the JSFunction and they are
+// therefore context dependent.
+class ObjectLiteralDeferred: public DeferredCode {
+ public:
+  ObjectLiteralDeferred(CodeGenerator* generator, ObjectLiteral* node)
+      : DeferredCode(generator), node_(node) {
+    set_comment("[ ObjectLiteralDeferred");
+  }
+  virtual void Generate();
+ private:
+  ObjectLiteral* node_;
+};
+
+
+void ObjectLiteralDeferred::Generate() {
+  // If the entry is undefined we call the runtime system to computed
+  // the literal.
+
+  // Literal array (0).
+  __ push(r1);
+  // Literal index (1).
+  __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
+  __ push(r0);
+  // Constant properties (2).
+  __ mov(r0, Operand(node_->constant_properties()));
+  __ push(r0);
+  __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
+  __ mov(r2, Operand(r0));
+}
+
+
+void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
+  Comment cmnt(masm_, "[ ObjectLiteral");
+
+  ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
+
+  // Retrieve the literal array and check the allocated entry.
+
+  // Load the function of this activation.
+  __ ldr(r1, FunctionOperand());
+
+  // Load the literals array of the function.
+  __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
+
+  // Load the literal at the ast saved index.
+  int literal_offset =
+      FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
+  __ ldr(r2, FieldMemOperand(r1, literal_offset));
+
+  // Check whether we need to materialize the object literal boilerplate.
+  // If so, jump to the deferred code.
+  __ cmp(r2, Operand(Factory::undefined_value()));
+  __ b(eq, deferred->enter());
+  __ bind(deferred->exit());
+
+  // Push the object literal boilerplate.
+  __ push(r2);
+
+  // Clone the boilerplate object.
+  __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
+  __ push(r0);  // save the result
+  // r0: cloned object literal
+
+  for (int i = 0; i < node->properties()->length(); i++) {
+    ObjectLiteral::Property* property = node->properties()->at(i);
+    Literal* key = property->key();
+    Expression* value = property->value();
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT: break;
+      case ObjectLiteral::Property::COMPUTED:  // fall through
+      case ObjectLiteral::Property::PROTOTYPE: {
+        __ push(r0);  // dup the result
+        Load(key);
+        Load(value);
+        __ CallRuntime(Runtime::kSetProperty, 3);
+        // restore r0
+        __ ldr(r0, MemOperand(sp, 0));
+        break;
+      }
+      case ObjectLiteral::Property::SETTER: {
+        __ push(r0);
+        Load(key);
+        __ mov(r0, Operand(Smi::FromInt(1)));
+        __ push(r0);
+        Load(value);
+        __ CallRuntime(Runtime::kDefineAccessor, 4);
+        __ ldr(r0, MemOperand(sp, 0));
+        break;
+      }
+      case ObjectLiteral::Property::GETTER: {
+        __ push(r0);
+        Load(key);
+        __ mov(r0, Operand(Smi::FromInt(0)));
+        __ push(r0);
+        Load(value);
+        __ CallRuntime(Runtime::kDefineAccessor, 4);
+        __ ldr(r0, MemOperand(sp, 0));
+        break;
+      }
+    }
+  }
+}
+
+
+void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
+  Comment cmnt(masm_, "[ ArrayLiteral");
+
+  // Call runtime to create the array literal.
+  __ mov(r0, Operand(node->literals()));
+  __ push(r0);
+  // Load the function of this frame.
+  __ ldr(r0, FunctionOperand());
+  __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
+  __ push(r0);
+  __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
+
+  // Push the resulting array literal on the stack.
+  __ push(r0);
+
+  // Generate code to set the elements in the array that are not
+  // literals.
+  for (int i = 0; i < node->values()->length(); i++) {
+    Expression* value = node->values()->at(i);
+
+    // If value is literal the property value is already
+    // set in the boilerplate object.
+    if (value->AsLiteral() == NULL) {
+      // The property must be set by generated code.
+      Load(value);
+      __ pop(r0);
+
+      // Fetch the object literal
+      __ ldr(r1, MemOperand(sp, 0));
+        // Get the elements array.
+      __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
+
+      // Write to the indexed properties array.
+      int offset = i * kPointerSize + Array::kHeaderSize;
+      __ str(r0, FieldMemOperand(r1, offset));
+
+      // Update the write barrier for the array address.
+      __ mov(r3, Operand(offset));
+      __ RecordWrite(r1, r3, r2);
+    }
+  }
+}
+
+
+void CodeGenerator::VisitAssignment(Assignment* node) {
+  Comment cmnt(masm_, "[ Assignment");
+  if (FLAG_debug_info) RecordStatementPosition(node);
+
+  Reference target(this, node->target());
+  if (target.is_illegal()) return;
+
+  if (node->op() == Token::ASSIGN ||
+      node->op() == Token::INIT_VAR ||
+      node->op() == Token::INIT_CONST) {
+    Load(node->value());
+
+  } else {
+    target.GetValue(NOT_INSIDE_TYPEOF);
+    Literal* literal = node->value()->AsLiteral();
+    if (literal != NULL && literal->handle()->IsSmi()) {
+      SmiOperation(node->binary_op(), literal->handle(), false);
+      __ push(r0);
+
+    } else {
+      Load(node->value());
+      GenericBinaryOperation(node->binary_op());
+      __ push(r0);
+    }
+  }
+
+  Variable* var = node->target()->AsVariableProxy()->AsVariable();
+  if (var != NULL &&
+      (var->mode() == Variable::CONST) &&
+      node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
+    // Assignment ignored - leave the value on the stack.
+
+  } else {
+    __ RecordPosition(node->position());
+    if (node->op() == Token::INIT_CONST) {
+      // Dynamic constant initializations must use the function context
+      // and initialize the actual constant declared. Dynamic variable
+      // initializations are simply assignments and use SetValue.
+      target.SetValue(CONST_INIT);
+    } else {
+      target.SetValue(NOT_CONST_INIT);
+    }
+  }
+}
+
+
+void CodeGenerator::VisitThrow(Throw* node) {
+  Comment cmnt(masm_, "[ Throw");
+
+  Load(node->exception());
+  __ RecordPosition(node->position());
+  __ CallRuntime(Runtime::kThrow, 1);
+  __ push(r0);
+}
+
+
+void CodeGenerator::VisitProperty(Property* node) {
+  Comment cmnt(masm_, "[ Property");
+
+  Reference property(this, node);
+  property.GetValue(typeof_state());
+}
+
+
+void CodeGenerator::VisitCall(Call* node) {
+  Comment cmnt(masm_, "[ Call");
+
+  ZoneList<Expression*>* args = node->arguments();
+
+  if (FLAG_debug_info) RecordStatementPosition(node);
+  // Standard function call.
+
+  // Check if the function is a variable or a property.
+  Expression* function = node->expression();
+  Variable* var = function->AsVariableProxy()->AsVariable();
+  Property* property = function->AsProperty();
+
+  // ------------------------------------------------------------------------
+  // Fast-case: Use inline caching.
+  // ---
+  // According to ECMA-262, section 11.2.3, page 44, the function to call
+  // must be resolved after the arguments have been evaluated. The IC code
+  // automatically handles this by loading the arguments before the function
+  // is resolved in cache misses (this also holds for megamorphic calls).
+  // ------------------------------------------------------------------------
+
+  if (var != NULL && !var->is_this() && var->is_global()) {
+    // ----------------------------------
+    // JavaScript example: 'foo(1, 2, 3)'  // foo is global
+    // ----------------------------------
+
+    // Push the name of the function and the receiver onto the stack.
+    __ mov(r0, Operand(var->name()));
+    __ push(r0);
+
+    // TODO(120): Use global object for function lookup and inline
+    // cache, and use global proxy as 'this' for invocation.
+    LoadGlobalReceiver(r0);
+
+    // Load the arguments.
+    for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
+    // Setup the receiver register and call the IC initialization code.
+    Handle<Code> stub = ComputeCallInitialize(args->length());
+    __ RecordPosition(node->position());
+    __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT);
+    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Remove the function from the stack.
+    __ pop();
+    __ push(r0);
+
+  } else if (var != NULL && var->slot() != NULL &&
+             var->slot()->type() == Slot::LOOKUP) {
+    // ----------------------------------
+    // JavaScript example: 'with (obj) foo(1, 2, 3)'  // foo is in obj
+    // ----------------------------------
+
+    // Load the function
+    __ push(cp);
+    __ mov(r0, Operand(var->name()));
+    __ push(r0);
+    __ CallRuntime(Runtime::kLoadContextSlot, 2);
+    // r0: slot value; r1: receiver
+
+    // Load the receiver.
+    __ push(r0);  // function
+    __ push(r1);  // receiver
+
+    // Call the function.
+    CallWithArguments(args, node->position());
+    __ push(r0);
+
+  } else if (property != NULL) {
+    // Check if the key is a literal string.
+    Literal* literal = property->key()->AsLiteral();
+
+    if (literal != NULL && literal->handle()->IsSymbol()) {
+      // ------------------------------------------------------------------
+      // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
+      // ------------------------------------------------------------------
+
+      // Push the name of the function and the receiver onto the stack.
+      __ mov(r0, Operand(literal->handle()));
+      __ push(r0);
+      Load(property->obj());
+
+      // Load the arguments.
+      for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
+      // Set the receiver register and call the IC initialization code.
+      Handle<Code> stub = ComputeCallInitialize(args->length());
+      __ RecordPosition(node->position());
+      __ Call(stub, RelocInfo::CODE_TARGET);
+      __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+      // Remove the function from the stack.
+      __ pop();
+
+      __ push(r0);  // push after get rid of function from the stack
+
+    } else {
+      // -------------------------------------------
+      // JavaScript example: 'array[index](1, 2, 3)'
+      // -------------------------------------------
+
+      // Load the function to call from the property through a reference.
+      Reference ref(this, property);
+      ref.GetValue(NOT_INSIDE_TYPEOF);  // receiver
+
+      // Pass receiver to called function.
+      __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
+      __ push(r0);
+      // Call the function.
+      CallWithArguments(args, node->position());
+      __ push(r0);
+    }
+
+  } else {
+    // ----------------------------------
+    // JavaScript example: 'foo(1, 2, 3)'  // foo is not global
+    // ----------------------------------
+
+    // Load the function.
+    Load(function);
+
+    // Pass the global proxy as the receiver.
+    LoadGlobalReceiver(r0);
+
+    // Call the function.
+    CallWithArguments(args, node->position());
+    __ push(r0);
+  }
+}
+
+
+void CodeGenerator::VisitCallNew(CallNew* node) {
+  Comment cmnt(masm_, "[ CallNew");
+
+  // According to ECMA-262, section 11.2.2, page 44, the function
+  // expression in new calls must be evaluated before the
+  // arguments. This is different from ordinary calls, where the
+  // actual function to call is resolved after the arguments have been
+  // evaluated.
+
+  // Compute function to call and use the global object as the
+  // receiver. There is no need to use the global proxy here because
+  // it will always be replaced with a newly allocated object.
+  Load(node->expression());
+  LoadGlobal();
+
+  // Push the arguments ("left-to-right") on the stack.
+  ZoneList<Expression*>* args = node->arguments();
+  for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
+  // r0: the number of arguments.
+  __ mov(r0, Operand(args->length()));
+
+  // Load the function into r1 as per calling convention.
+  __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
+
+  // Call the construct call builtin that handles allocation and
+  // constructor invocation.
+  __ RecordPosition(RelocInfo::POSITION);
+  __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+          RelocInfo::CONSTRUCT_CALL);
+
+  // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
+  __ str(r0, MemOperand(sp, 0 * kPointerSize));
+}
+
+
+void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Label leave;
+  Load(args->at(0));
+  __ pop(r0);  // r0 contains object.
+  // if (object->IsSmi()) return the object.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &leave);
+  // It is a heap object - get map.
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  // if (!object->IsJSValue()) return the object.
+  __ cmp(r1, Operand(JS_VALUE_TYPE));
+  __ b(ne, &leave);
+  // Load the value.
+  __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
+  __ bind(&leave);
+  __ push(r0);
+}
+
+
+void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  Label leave;
+  Load(args->at(0));  // Load the object.
+  Load(args->at(1));  // Load the value.
+  __ pop(r0);  // r0 contains value
+  __ pop(r1);  // r1 contains object
+  // if (object->IsSmi()) return object.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &leave);
+  // It is a heap object - get map.
+  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+  // if (!object->IsJSValue()) return object.
+  __ cmp(r2, Operand(JS_VALUE_TYPE));
+  __ b(ne, &leave);
+  // Store the value.
+  __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
+  // Update the write barrier.
+  __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
+  __ RecordWrite(r1, r2, r3);
+  // Leave.
+  __ bind(&leave);
+  __ push(r0);
+}
+
+
+void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  __ pop(r0);
+  __ tst(r0, Operand(kSmiTagMask));
+  cc_reg_ = eq;
+}
+
+
+void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  __ pop(r0);
+  __ tst(r0, Operand(kSmiTagMask | 0x80000000));
+  cc_reg_ = eq;
+}
+
+
+// This should generate code that performs a charCodeAt() call or returns
+// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
+// It is not yet implemented on ARM, so it always goes to the slow case.
+void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  __ mov(r0, Operand(Factory::undefined_value()));
+  __ push(r0);
+}
+
+
+void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Label answer;
+  // We need the CC bits to come out as not_equal in the case where the
+  // object is a smi.  This can't be done with the usual test opcode so
+  // we use XOR to get the right CC bits.
+  __ pop(r0);
+  __ and_(r1, r0, Operand(kSmiTagMask));
+  __ eor(r1, r1, Operand(kSmiTagMask), SetCC);
+  __ b(ne, &answer);
+  // It is a heap object - get the map.
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  // Check if the object is a JS array or not.
+  __ cmp(r1, Operand(JS_ARRAY_TYPE));
+  __ bind(&answer);
+  cc_reg_ = eq;
+}
+
+
+void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 0);
+
+  // Seed the result with the formal parameters count, which will be used
+  // in case no arguments adaptor frame is found below the current frame.
+  __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
+
+  // Call the shared stub to get to the arguments.length.
+  ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
+  __ CallStub(&stub);
+  __ push(r0);
+}
+
+
+void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+
+  // Satisfy contract with ArgumentsAccessStub:
+  // Load the key into r1 and the formal parameters count into r0.
+  Load(args->at(0));
+  __ pop(r1);
+  __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
+
+  // Call the shared stub to get to arguments[key].
+  ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
+  __ CallStub(&stub);
+  __ push(r0);
+}
+
+
+void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+
+  // Load the two objects into registers and perform the comparison.
+  Load(args->at(0));
+  Load(args->at(1));
+  __ pop(r0);
+  __ pop(r1);
+  __ cmp(r0, Operand(r1));
+  cc_reg_ = eq;
+}
+
+
+void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
+  if (CheckForInlineRuntimeCall(node)) return;
+
+  ZoneList<Expression*>* args = node->arguments();
+  Comment cmnt(masm_, "[ CallRuntime");
+  Runtime::Function* function = node->function();
+
+  if (function != NULL) {
+    // Push the arguments ("left-to-right").
+    for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
+    // Call the C runtime function.
+    __ CallRuntime(function, args->length());
+    __ push(r0);
+
+  } else {
+    // Prepare stack for calling JS runtime function.
+    __ mov(r0, Operand(node->name()));
+    __ push(r0);
+    // Push the builtins object found in the current global object.
+    __ ldr(r1, GlobalObject());
+    __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
+    __ push(r0);
+
+    for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
+    // Call the JS runtime function.
+    Handle<Code> stub = ComputeCallInitialize(args->length());
+    __ Call(stub, RelocInfo::CODE_TARGET);
+    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ pop();
+    __ push(r0);
+  }
+}
+
+
+void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
+  Comment cmnt(masm_, "[ UnaryOperation");
+
+  Token::Value op = node->op();
+
+  if (op == Token::NOT) {
+    LoadCondition(node->expression(),
+                  NOT_INSIDE_TYPEOF,
+                  false_target(),
+                  true_target(),
+                  true);
+    cc_reg_ = NegateCondition(cc_reg_);
+
+  } else if (op == Token::DELETE) {
+    Property* property = node->expression()->AsProperty();
+    Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
+    if (property != NULL) {
+      Load(property->obj());
+      Load(property->key());
+      __ mov(r0, Operand(1));  // not counting receiver
+      __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
+
+    } else if (variable != NULL) {
+      Slot* slot = variable->slot();
+      if (variable->is_global()) {
+        LoadGlobal();
+        __ mov(r0, Operand(variable->name()));
+        __ push(r0);
+        __ mov(r0, Operand(1));  // not counting receiver
+        __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
+
+      } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
+        // lookup the context holding the named variable
+        __ push(cp);
+        __ mov(r0, Operand(variable->name()));
+        __ push(r0);
+        __ CallRuntime(Runtime::kLookupContext, 2);
+        // r0: context
+        __ push(r0);
+        __ mov(r0, Operand(variable->name()));
+        __ push(r0);
+        __ mov(r0, Operand(1));  // not counting receiver
+        __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
+
+      } else {
+        // Default: Result of deleting non-global, not dynamically
+        // introduced variables is false.
+        __ mov(r0, Operand(Factory::false_value()));
+      }
+
+    } else {
+      // Default: Result of deleting expressions is true.
+      Load(node->expression());  // may have side-effects
+      __ pop();
+      __ mov(r0, Operand(Factory::true_value()));
+    }
+    __ push(r0);
+
+  } else if (op == Token::TYPEOF) {
+    // Special case for loading the typeof expression; see comment on
+    // LoadTypeofExpression().
+    LoadTypeofExpression(node->expression());
+    __ CallRuntime(Runtime::kTypeof, 1);
+    __ push(r0);  // r0 has result
+
+  } else {
+    Load(node->expression());
+    __ pop(r0);
+    switch (op) {
+      case Token::NOT:
+      case Token::DELETE:
+      case Token::TYPEOF:
+        UNREACHABLE();  // handled above
+        break;
+
+      case Token::SUB: {
+        UnarySubStub stub;
+        __ CallStub(&stub);
+        break;
+      }
+
+      case Token::BIT_NOT: {
+        // smi check
+        Label smi_label;
+        Label continue_label;
+        __ tst(r0, Operand(kSmiTagMask));
+        __ b(eq, &smi_label);
+
+        __ push(r0);
+        __ mov(r0, Operand(0));  // not counting receiver
+        __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS);
+
+        __ b(&continue_label);
+        __ bind(&smi_label);
+        __ mvn(r0, Operand(r0));
+        __ bic(r0, r0, Operand(kSmiTagMask));  // bit-clear inverted smi-tag
+        __ bind(&continue_label);
+        break;
+      }
+
+      case Token::VOID:
+        // since the stack top is cached in r0, popping and then
+        // pushing a value can be done by just writing to r0.
+        __ mov(r0, Operand(Factory::undefined_value()));
+        break;
+
+      case Token::ADD: {
+        // Smi check.
+        Label continue_label;
+        __ tst(r0, Operand(kSmiTagMask));
+        __ b(eq, &continue_label);
+        __ push(r0);
+        __ mov(r0, Operand(0));  // not counting receiver
+        __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
+        __ bind(&continue_label);
+        break;
+      }
+      default:
+        UNREACHABLE();
+    }
+    __ push(r0);  // r0 has result
+  }
+}
+
+
+void CodeGenerator::VisitCountOperation(CountOperation* node) {
+  Comment cmnt(masm_, "[ CountOperation");
+
+  bool is_postfix = node->is_postfix();
+  bool is_increment = node->op() == Token::INC;
+
+  Variable* var = node->expression()->AsVariableProxy()->AsVariable();
+  bool is_const = (var != NULL && var->mode() == Variable::CONST);
+
+  // Postfix: Make room for the result.
+  if (is_postfix) {
+     __ mov(r0, Operand(0));
+     __ push(r0);
+  }
+
+  { Reference target(this, node->expression());
+    if (target.is_illegal()) return;
+    target.GetValue(NOT_INSIDE_TYPEOF);
+    __ pop(r0);
+
+    Label slow, exit;
+
+    // Load the value (1) into register r1.
+    __ mov(r1, Operand(Smi::FromInt(1)));
+
+    // Check for smi operand.
+    __ tst(r0, Operand(kSmiTagMask));
+    __ b(ne, &slow);
+
+    // Postfix: Store the old value as the result.
+    if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
+
+    // Perform optimistic increment/decrement.
+    if (is_increment) {
+      __ add(r0, r0, Operand(r1), SetCC);
+    } else {
+      __ sub(r0, r0, Operand(r1), SetCC);
+    }
+
+    // If the increment/decrement didn't overflow, we're done.
+    __ b(vc, &exit);
+
+    // Revert optimistic increment/decrement.
+    if (is_increment) {
+      __ sub(r0, r0, Operand(r1));
+    } else {
+      __ add(r0, r0, Operand(r1));
+    }
+
+    // Slow case: Convert to number.
+    __ bind(&slow);
+
+    // Postfix: Convert the operand to a number and store it as the result.
+    if (is_postfix) {
+      InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
+      __ CallStub(&stub);
+      // Store to result (on the stack).
+      __ str(r0, MemOperand(sp, target.size() * kPointerSize));
+    }
+
+    // Compute the new value by calling the right JavaScript native.
+    if (is_increment) {
+      InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
+      __ CallStub(&stub);
+    } else {
+      InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
+      __ CallStub(&stub);
+    }
+
+    // Store the new value in the target if not const.
+    __ bind(&exit);
+    __ push(r0);
+    if (!is_const) target.SetValue(NOT_CONST_INIT);
+  }
+
+  // Postfix: Discard the new value and use the old.
+  if (is_postfix) __ pop(r0);
+}
+
+
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+  Comment cmnt(masm_, "[ BinaryOperation");
+  Token::Value op = node->op();
+
+  // According to ECMA-262 section 11.11, page 58, the binary logical
+  // operators must yield the result of one of the two expressions
+  // before any ToBoolean() conversions. This means that the value
+  // produced by a && or || operator is not necessarily a boolean.
+
+  // NOTE: If the left hand side produces a materialized value (not in
+  // the CC register), we force the right hand side to do the
+  // same. This is necessary because we may have to branch to the exit
+  // after evaluating the left hand side (due to the shortcut
+  // semantics), but the compiler must (statically) know if the result
+  // of compiling the binary operation is materialized or not.
+
+  if (op == Token::AND) {
+    Label is_true;
+    LoadCondition(node->left(),
+                  NOT_INSIDE_TYPEOF,
+                  &is_true,
+                  false_target(),
+                  false);
+    if (has_cc()) {
+      Branch(false, false_target());
+
+      // Evaluate right side expression.
+      __ bind(&is_true);
+      LoadCondition(node->right(),
+                    NOT_INSIDE_TYPEOF,
+                    true_target(),
+                    false_target(),
+                    false);
+
+    } else {
+      Label pop_and_continue, exit;
+
+      __ ldr(r0, MemOperand(sp, 0));  // dup the stack top
+      __ push(r0);
+      // Avoid popping the result if it converts to 'false' using the
+      // standard ToBoolean() conversion as described in ECMA-262,
+      // section 9.2, page 30.
+      ToBoolean(&pop_and_continue, &exit);
+      Branch(false, &exit);
+
+      // Pop the result of evaluating the first part.
+      __ bind(&pop_and_continue);
+      __ pop(r0);
+
+      // Evaluate right side expression.
+      __ bind(&is_true);
+      Load(node->right());
+
+      // Exit (always with a materialized value).
+      __ bind(&exit);
+    }
+
+  } else if (op == Token::OR) {
+    Label is_false;
+    LoadCondition(node->left(),
+                  NOT_INSIDE_TYPEOF,
+                  true_target(),
+                  &is_false,
+                  false);
+    if (has_cc()) {
+      Branch(true, true_target());
+
+      // Evaluate right side expression.
+      __ bind(&is_false);
+      LoadCondition(node->right(),
+                    NOT_INSIDE_TYPEOF,
+                    true_target(),
+                    false_target(),
+                    false);
+
+    } else {
+      Label pop_and_continue, exit;
+
+      __ ldr(r0, MemOperand(sp, 0));
+      __ push(r0);
+      // Avoid popping the result if it converts to 'true' using the
+      // standard ToBoolean() conversion as described in ECMA-262,
+      // section 9.2, page 30.
+      ToBoolean(&exit, &pop_and_continue);
+      Branch(true, &exit);
+
+      // Pop the result of evaluating the first part.
+      __ bind(&pop_and_continue);
+      __ pop(r0);
+
+      // Evaluate right side expression.
+      __ bind(&is_false);
+      Load(node->right());
+
+      // Exit (always with a materialized value).
+      __ bind(&exit);
+    }
+
+  } else {
+    // Optimize for the case where (at least) one of the expressions
+    // is a literal small integer.
+    Literal* lliteral = node->left()->AsLiteral();
+    Literal* rliteral = node->right()->AsLiteral();
+
+    if (rliteral != NULL && rliteral->handle()->IsSmi()) {
+      Load(node->left());
+      SmiOperation(node->op(), rliteral->handle(), false);
+
+    } else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
+      Load(node->right());
+      SmiOperation(node->op(), lliteral->handle(), true);
+
+    } else {
+      Load(node->left());
+      Load(node->right());
+      GenericBinaryOperation(node->op());
+    }
+    __ push(r0);
+  }
+}
+
+
+void CodeGenerator::VisitThisFunction(ThisFunction* node) {
+  __ ldr(r0, FunctionOperand());
+  __ push(r0);
+}
+
+
+void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
+  Comment cmnt(masm_, "[ CompareOperation");
+
+  // Get the expressions from the node.
+  Expression* left = node->left();
+  Expression* right = node->right();
+  Token::Value op = node->op();
+
+  // NOTE: To make null checks efficient, we check if either left or
+  // right is the literal 'null'. If so, we optimize the code by
+  // inlining a null check instead of calling the (very) general
+  // runtime routine for checking equality.
+
+  if (op == Token::EQ || op == Token::EQ_STRICT) {
+    bool left_is_null =
+      left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
+    bool right_is_null =
+      right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
+    // The 'null' value is only equal to 'null' or 'undefined'.
+    if (left_is_null || right_is_null) {
+      Load(left_is_null ? right : left);
+      Label exit, undetectable;
+      __ pop(r0);
+      __ cmp(r0, Operand(Factory::null_value()));
+
+      // The 'null' value is only equal to 'undefined' if using
+      // non-strict comparisons.
+      if (op != Token::EQ_STRICT) {
+        __ b(eq, &exit);
+        __ cmp(r0, Operand(Factory::undefined_value()));
+
+        // NOTE: it can be undetectable object.
+        __ b(eq, &exit);
+        __ tst(r0, Operand(kSmiTagMask));
+
+        __ b(ne, &undetectable);
+        __ b(false_target());
+
+        __ bind(&undetectable);
+        __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+        __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
+        __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
+        __ cmp(r2, Operand(1 << Map::kIsUndetectable));
+      }
+
+      __ bind(&exit);
+
+      cc_reg_ = eq;
+      return;
+    }
+  }
+
+
+  // NOTE: To make typeof testing for natives implemented in
+  // JavaScript really efficient, we generate special code for
+  // expressions of the form: 'typeof <expression> == <string>'.
+
+  UnaryOperation* operation = left->AsUnaryOperation();
+  if ((op == Token::EQ || op == Token::EQ_STRICT) &&
+      (operation != NULL && operation->op() == Token::TYPEOF) &&
+      (right->AsLiteral() != NULL &&
+       right->AsLiteral()->handle()->IsString())) {
+    Handle<String> check(String::cast(*right->AsLiteral()->handle()));
+
+    // Load the operand, move it to register r1.
+    LoadTypeofExpression(operation->expression());
+    __ pop(r1);
+
+    if (check->Equals(Heap::number_symbol())) {
+      __ tst(r1, Operand(kSmiTagMask));
+      __ b(eq, true_target());
+      __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
+      __ cmp(r1, Operand(Factory::heap_number_map()));
+      cc_reg_ = eq;
+
+    } else if (check->Equals(Heap::string_symbol())) {
+      __ tst(r1, Operand(kSmiTagMask));
+      __ b(eq, false_target());
+
+      __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
+
+      // NOTE: it might be an undetectable string object
+      __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
+      __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
+      __ cmp(r2, Operand(1 << Map::kIsUndetectable));
+      __ b(eq, false_target());
+
+      __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+      __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
+      cc_reg_ = lt;
+
+    } else if (check->Equals(Heap::boolean_symbol())) {
+      __ cmp(r1, Operand(Factory::true_value()));
+      __ b(eq, true_target());
+      __ cmp(r1, Operand(Factory::false_value()));
+      cc_reg_ = eq;
+
+    } else if (check->Equals(Heap::undefined_symbol())) {
+      __ cmp(r1, Operand(Factory::undefined_value()));
+      __ b(eq, true_target());
+
+      __ tst(r1, Operand(kSmiTagMask));
+      __ b(eq, false_target());
+
+      // NOTE: it can be undetectable object.
+      __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
+      __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
+      __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
+      __ cmp(r2, Operand(1 << Map::kIsUndetectable));
+
+      cc_reg_ = eq;
+
+    } else if (check->Equals(Heap::function_symbol())) {
+      __ tst(r1, Operand(kSmiTagMask));
+      __ b(eq, false_target());
+      __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
+      __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+      __ cmp(r1, Operand(JS_FUNCTION_TYPE));
+      cc_reg_ = eq;
+
+    } else if (check->Equals(Heap::object_symbol())) {
+      __ tst(r1, Operand(kSmiTagMask));
+      __ b(eq, false_target());
+
+      __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+      __ cmp(r1, Operand(Factory::null_value()));
+      __ b(eq, true_target());
+
+      // NOTE: it might be an undetectable object.
+      __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
+      __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
+      __ cmp(r1, Operand(1 << Map::kIsUndetectable));
+      __ b(eq, false_target());
+
+      __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+      __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
+      __ b(lt, false_target());
+      __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
+      cc_reg_ = le;
+
+    } else {
+      // Uncommon case: Typeof testing against a string literal that
+      // is never returned from the typeof operator.
+      __ b(false_target());
+    }
+    return;
+  }
+
+  Load(left);
+  Load(right);
+  switch (op) {
+    case Token::EQ:
+      Comparison(eq, false);
+      break;
+
+    case Token::LT:
+      Comparison(lt);
+      break;
+
+    case Token::GT:
+      Comparison(gt);
+      break;
+
+    case Token::LTE:
+      Comparison(le);
+      break;
+
+    case Token::GTE:
+      Comparison(ge);
+      break;
+
+    case Token::EQ_STRICT:
+      Comparison(eq, true);
+      break;
+
+    case Token::IN:
+      __ mov(r0, Operand(1));  // not counting receiver
+      __ InvokeBuiltin(Builtins::IN, CALL_JS);
+      __ push(r0);
+      break;
+
+    case Token::INSTANCEOF:
+      __ mov(r0, Operand(1));  // not counting receiver
+      __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS);
+      __ tst(r0, Operand(r0));
+      cc_reg_ = eq;
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void CodeGenerator::RecordStatementPosition(Node* node) {
+  if (FLAG_debug_info) {
+    int statement_pos = node->statement_pos();
+    if (statement_pos == RelocInfo::kNoPosition) return;
+    __ RecordStatementPosition(statement_pos);
+  }
+}
+
+
+void CodeGenerator::EnterJSFrame() {
+#if defined(DEBUG)
+  { Label done, fail;
+    __ tst(r1, Operand(kSmiTagMask));
+    __ b(eq, &fail);
+    __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+    __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+    __ cmp(r2, Operand(JS_FUNCTION_TYPE));
+    __ b(eq, &done);
+    __ bind(&fail);
+    __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
+    __ bind(&done);
+  }
+#endif  // DEBUG
+
+  __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+  __ add(fp, sp, Operand(2 * kPointerSize));  // Adjust FP to point to saved FP.
+}
+
+
+void CodeGenerator::ExitJSFrame() {
+  // Drop the execution stack down to the frame pointer and restore the caller
+  // frame pointer and return address.
+  __ mov(sp, fp);
+  __ ldm(ia_w, sp, fp.bit() | lr.bit());
+}
+
+
+#undef __
+#define __ masm->
+
+Handle<String> Reference::GetName() {
+  ASSERT(type_ == NAMED);
+  Property* property = expression_->AsProperty();
+  if (property == NULL) {
+    // Global variable reference treated as a named property reference.
+    VariableProxy* proxy = expression_->AsVariableProxy();
+    ASSERT(proxy->AsVariable() != NULL);
+    ASSERT(proxy->AsVariable()->is_global());
+    return proxy->name();
+  } else {
+    Literal* raw_name = property->key()->AsLiteral();
+    ASSERT(raw_name != NULL);
+    return Handle<String>(String::cast(*raw_name->handle()));
+  }
+}
+
+
+void Reference::GetValue(TypeofState typeof_state) {
+  ASSERT(!is_illegal());
+  ASSERT(!cgen_->has_cc());
+  MacroAssembler* masm = cgen_->masm();
+  Property* property = expression_->AsProperty();
+  if (property != NULL) {
+    __ RecordPosition(property->position());
+  }
+
+  switch (type_) {
+    case SLOT: {
+      Comment cmnt(masm, "[ Load from Slot");
+      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
+      ASSERT(slot != NULL);
+      cgen_->LoadFromSlot(slot, typeof_state);
+      break;
+    }
+
+    case NAMED: {
+      // TODO(1241834): Make sure that this it is safe to ignore the
+      // distinction between expressions in a typeof and not in a typeof. If
+      // there is a chance that reference errors can be thrown below, we
+      // must distinguish between the two kinds of loads (typeof expression
+      // loads must not throw a reference error).
+      Comment cmnt(masm, "[ Load from named Property");
+      // Setup the name register.
+      Handle<String> name(GetName());
+      __ mov(r2, Operand(name));
+      Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+
+      Variable* var = expression_->AsVariableProxy()->AsVariable();
+      if (var != NULL) {
+        ASSERT(var->is_global());
+        __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+      } else {
+        __ Call(ic, RelocInfo::CODE_TARGET);
+      }
+      __ push(r0);
+      break;
+    }
+
+    case KEYED: {
+      // TODO(1241834): Make sure that this it is safe to ignore the
+      // distinction between expressions in a typeof and not in a typeof.
+      Comment cmnt(masm, "[ Load from keyed Property");
+      ASSERT(property != NULL);
+      // TODO(1224671): Implement inline caching for keyed loads as on ia32.
+      GetPropertyStub stub;
+      __ CallStub(&stub);
+      __ push(r0);
+      break;
+    }
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Reference::SetValue(InitState init_state) {
+  ASSERT(!is_illegal());
+  ASSERT(!cgen_->has_cc());
+  MacroAssembler* masm = cgen_->masm();
+  Property* property = expression_->AsProperty();
+  if (property != NULL) {
+    __ RecordPosition(property->position());
+  }
+
+  switch (type_) {
+    case SLOT: {
+      Comment cmnt(masm, "[ Store to Slot");
+      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
+      ASSERT(slot != NULL);
+      if (slot->type() == Slot::LOOKUP) {
+        ASSERT(slot->var()->mode() == Variable::DYNAMIC);
+
+        // For now, just do a runtime call.
+        __ push(cp);
+        __ mov(r0, Operand(slot->var()->name()));
+        __ push(r0);
+
+        if (init_state == CONST_INIT) {
+          // Same as the case for a normal store, but ignores attribute
+          // (e.g. READ_ONLY) of context slot so that we can initialize
+          // const properties (introduced via eval("const foo = (some
+          // expr);")). Also, uses the current function context instead of
+          // the top context.
+          //
+          // Note that we must declare the foo upon entry of eval(), via a
+          // context slot declaration, but we cannot initialize it at the
+          // same time, because the const declaration may be at the end of
+          // the eval code (sigh...) and the const variable may have been
+          // used before (where its value is 'undefined'). Thus, we can only
+          // do the initialization when we actually encounter the expression
+          // and when the expression operands are defined and valid, and
+          // thus we need the split into 2 operations: declaration of the
+          // context slot followed by initialization.
+          __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+        } else {
+          __ CallRuntime(Runtime::kStoreContextSlot, 3);
+        }
+        // Storing a variable must keep the (new) value on the expression
+        // stack. This is necessary for compiling assignment expressions.
+        __ push(r0);
+
+      } else {
+        ASSERT(slot->var()->mode() != Variable::DYNAMIC);
+
+        Label exit;
+        if (init_state == CONST_INIT) {
+          ASSERT(slot->var()->mode() == Variable::CONST);
+          // Only the first const initialization must be executed (the slot
+          // still contains 'the hole' value). When the assignment is
+          // executed, the code is identical to a normal store (see below).
+          Comment cmnt(masm, "[ Init const");
+          __ ldr(r2, cgen_->SlotOperand(slot, r2));
+          __ cmp(r2, Operand(Factory::the_hole_value()));
+          __ b(ne, &exit);
+        }
+
+        // We must execute the store.  Storing a variable must keep the
+        // (new) value on the stack. This is necessary for compiling
+        // assignment expressions.
+        //
+        // Note: We will reach here even with slot->var()->mode() ==
+        // Variable::CONST because of const declarations which will
+        // initialize consts to 'the hole' value and by doing so, end up
+        // calling this code.  r2 may be loaded with context; used below in
+        // RecordWrite.
+        __ pop(r0);
+        __ str(r0, cgen_->SlotOperand(slot, r2));
+        __ push(r0);
+        if (slot->type() == Slot::CONTEXT) {
+          // Skip write barrier if the written value is a smi.
+          __ tst(r0, Operand(kSmiTagMask));
+          __ b(eq, &exit);
+          // r2 is loaded with context when calling SlotOperand above.
+          int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+          __ mov(r3, Operand(offset));
+          __ RecordWrite(r2, r3, r1);
+        }
+        // If we definitely did not jump over the assignment, we do not need
+        // to bind the exit label.  Doing so can defeat peephole
+        // optimization.
+        if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) {
+          __ bind(&exit);
+        }
+      }
+      break;
+    }
+
+    case NAMED: {
+      Comment cmnt(masm, "[ Store to named Property");
+      // Call the appropriate IC code.
+      __ pop(r0);  // value
+      // Setup the name register.
+      Handle<String> name(GetName());
+      __ mov(r2, Operand(name));
+      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+      __ Call(ic, RelocInfo::CODE_TARGET);
+      __ push(r0);
+      break;
+    }
+
+    case KEYED: {
+      Comment cmnt(masm, "[ Store to keyed Property");
+      Property* property = expression_->AsProperty();
+      ASSERT(property != NULL);
+      __ RecordPosition(property->position());
+      __ pop(r0);  // value
+      SetPropertyStub stub;
+      __ CallStub(&stub);
+      __ push(r0);
+      break;
+    }
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void GetPropertyStub::Generate(MacroAssembler* masm) {
+  // sp[0]: key
+  // sp[1]: receiver
+  Label slow, fast;
+  // Get the key and receiver object from the stack.
+  __ ldm(ia, sp, r0.bit() | r1.bit());
+  // Check that the key is a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(ne, &slow);
+  __ mov(r0, Operand(r0, ASR, kSmiTagSize));
+  // Check that the object isn't a smi.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &slow);
+
+  // Check that the object is some kind of JS object EXCEPT JS Value type.
+  // In the case that the object is a value-wrapper object,
+  // we enter the runtime system to make sure that indexing into string
+  // objects work as intended.
+  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
+  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+  __ cmp(r2, Operand(JS_OBJECT_TYPE));
+  __ b(lt, &slow);
+
+  // Get the elements array of the object.
+  __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
+  // Check that the object is in fast mode (not dictionary).
+  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ cmp(r3, Operand(Factory::hash_table_map()));
+  __ b(eq, &slow);
+  // Check that the key (index) is within bounds.
+  __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
+  __ cmp(r0, Operand(r3));
+  __ b(lo, &fast);
+
+  // Slow case: Push extra copies of the arguments (2).
+  __ bind(&slow);
+  __ ldm(ia, sp, r0.bit() | r1.bit());
+  __ stm(db_w, sp, r0.bit() | r1.bit());
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
+
+  // Fast case: Do the load.
+  __ bind(&fast);
+  __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
+  __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
+  __ cmp(r0, Operand(Factory::the_hole_value()));
+  // In case the loaded value is the_hole we have to consult GetProperty
+  // to ensure the prototype chain is searched.
+  __ b(eq, &slow);
+
+  __ StubReturn(1);
+}
+
+
+void SetPropertyStub::Generate(MacroAssembler* masm) {
+  // r0 : value
+  // sp[0] : key
+  // sp[1] : receiver
+
+  Label slow, fast, array, extra, exit;
+  // Get the key and the object from the stack.
+  __ ldm(ia, sp, r1.bit() | r3.bit());  // r1 = key, r3 = receiver
+  // Check that the key is a smi.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(ne, &slow);
+  // Check that the object isn't a smi.
+  __ tst(r3, Operand(kSmiTagMask));
+  __ b(eq, &slow);
+  // Get the type of the object from its map.
+  __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+  // Check if the object is a JS array or not.
+  __ cmp(r2, Operand(JS_ARRAY_TYPE));
+  __ b(eq, &array);
+  // Check that the object is some kind of JS object.
+  __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
+  __ b(lt, &slow);
+
+
+  // Object case: Check key against length in the elements array.
+  __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
+  // Check that the object is in fast mode (not dictionary).
+  __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ cmp(r2, Operand(Factory::hash_table_map()));
+  __ b(eq, &slow);
+  // Untag the key (for checking against untagged length in the fixed array).
+  __ mov(r1, Operand(r1, ASR, kSmiTagSize));
+  // Compute address to store into and check array bounds.
+  __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
+  __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
+  __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
+  __ cmp(r1, Operand(ip));
+  __ b(lo, &fast);
+
+
+  // Slow case: Push extra copies of the arguments (3).
+  __ bind(&slow);
+  __ ldm(ia, sp, r1.bit() | r3.bit());  // r0 == value, r1 == key, r3 == object
+  __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
+
+
+  // Extra capacity case: Check if there is extra capacity to
+  // perform the store and update the length. Used for adding one
+  // element to the array by writing to array[array.length].
+  // r0 == value, r1 == key, r2 == elements, r3 == object
+  __ bind(&extra);
+  __ b(ne, &slow);  // do not leave holes in the array
+  __ mov(r1, Operand(r1, ASR, kSmiTagSize));  // untag
+  __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset));
+  __ cmp(r1, Operand(ip));
+  __ b(hs, &slow);
+  __ mov(r1, Operand(r1, LSL, kSmiTagSize));  // restore tag
+  __ add(r1, r1, Operand(1 << kSmiTagSize));  // and increment
+  __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset));
+  __ mov(r3, Operand(r2));
+  // NOTE: Computing the address to store into must take the fact
+  // that the key has been incremented into account.
+  int displacement = Array::kHeaderSize - kHeapObjectTag -
+      ((1 << kSmiTagSize) * 2);
+  __ add(r2, r2, Operand(displacement));
+  __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
+  __ b(&fast);
+
+
+  // Array case: Get the length and the elements array from the JS
+  // array. Check that the array is in fast mode; if it is the
+  // length is always a smi.
+  // r0 == value, r3 == object
+  __ bind(&array);
+  __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
+  __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
+  __ cmp(r1, Operand(Factory::hash_table_map()));
+  __ b(eq, &slow);
+
+  // Check the key against the length in the array, compute the
+  // address to store into and fall through to fast case.
+  __ ldr(r1, MemOperand(sp));
+  // r0 == value, r1 == key, r2 == elements, r3 == object.
+  __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset));
+  __ cmp(r1, Operand(ip));
+  __ b(hs, &extra);
+  __ mov(r3, Operand(r2));
+  __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
+  __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
+
+
+  // Fast case: Do the store.
+  // r0 == value, r2 == address to store into, r3 == elements
+  __ bind(&fast);
+  __ str(r0, MemOperand(r2));
+  // Skip write barrier if the written value is a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &exit);
+  // Update write barrier for the elements array address.
+  __ sub(r1, r2, Operand(r3));
+  __ RecordWrite(r3, r1, r2);
+  __ bind(&exit);
+  __ StubReturn(1);
+}
+
+
+void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
+  // r1 : x
+  // r0 : y
+  // result : r0
+
+  switch (op_) {
+    case Token::ADD: {
+      Label slow, exit;
+      // fast path
+      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
+      __ add(r0, r1, Operand(r0), SetCC);  // add y optimistically
+      // go slow-path in case of overflow
+      __ b(vs, &slow);
+      // go slow-path in case of non-smi operands
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ tst(r2, Operand(kSmiTagMask));
+      __ b(eq, &exit);
+      // slow path
+      __ bind(&slow);
+      __ sub(r0, r0, Operand(r1));  // revert optimistic add
+      __ push(r1);
+      __ push(r0);
+      __ mov(r0, Operand(1));  // set number of arguments
+      __ InvokeBuiltin(Builtins::ADD, JUMP_JS);
+      // done
+      __ bind(&exit);
+      break;
+    }
+
+    case Token::SUB: {
+      Label slow, exit;
+      // fast path
+      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
+      __ sub(r3, r1, Operand(r0), SetCC);  // subtract y optimistically
+      // go slow-path in case of overflow
+      __ b(vs, &slow);
+      // go slow-path in case of non-smi operands
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ tst(r2, Operand(kSmiTagMask));
+      __ mov(r0, Operand(r3), LeaveCC, eq);  // conditionally set r0 to result
+      __ b(eq, &exit);
+      // slow path
+      __ bind(&slow);
+      __ push(r1);
+      __ push(r0);
+      __ mov(r0, Operand(1));  // set number of arguments
+      __ InvokeBuiltin(Builtins::SUB, JUMP_JS);
+      // done
+      __ bind(&exit);
+      break;
+    }
+
+    case Token::MUL: {
+      Label slow, exit;
+      // tag check
+      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ tst(r2, Operand(kSmiTagMask));
+      __ b(ne, &slow);
+      // remove tag from one operand (but keep sign), so that result is smi
+      __ mov(ip, Operand(r0, ASR, kSmiTagSize));
+      // do multiplication
+      __ smull(r3, r2, r1, ip);  // r3 = lower 32 bits of ip*r1
+      // go slow on overflows (overflow bit is not set)
+      __ mov(ip, Operand(r3, ASR, 31));
+      __ cmp(ip, Operand(r2));  // no overflow if higher 33 bits are identical
+      __ b(ne, &slow);
+      // go slow on zero result to handle -0
+      __ tst(r3, Operand(r3));
+      __ mov(r0, Operand(r3), LeaveCC, ne);
+      __ b(ne, &exit);
+      // slow case
+      __ bind(&slow);
+      __ push(r1);
+      __ push(r0);
+      __ mov(r0, Operand(1));  // set number of arguments
+      __ InvokeBuiltin(Builtins::MUL, JUMP_JS);
+      // done
+      __ bind(&exit);
+      break;
+    }
+
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR: {
+      Label slow, exit;
+      // tag check
+      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ tst(r2, Operand(kSmiTagMask));
+      __ b(ne, &slow);
+      switch (op_) {
+        case Token::BIT_OR:  __ orr(r0, r0, Operand(r1)); break;
+        case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
+        case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
+        default: UNREACHABLE();
+      }
+      __ b(&exit);
+      __ bind(&slow);
+      __ push(r1);  // restore stack
+      __ push(r0);
+      __ mov(r0, Operand(1));  // 1 argument (not counting receiver).
+      switch (op_) {
+        case Token::BIT_OR:
+          __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS);
+          break;
+        case Token::BIT_AND:
+          __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS);
+          break;
+        case Token::BIT_XOR:
+          __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS);
+          break;
+        default:
+          UNREACHABLE();
+      }
+      __ bind(&exit);
+      break;
+    }
+
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
+      Label slow, exit;
+      // tag check
+      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ tst(r2, Operand(kSmiTagMask));
+      __ b(ne, &slow);
+      // remove tags from operands (but keep sign)
+      __ mov(r3, Operand(r1, ASR, kSmiTagSize));  // x
+      __ mov(r2, Operand(r0, ASR, kSmiTagSize));  // y
+      // use only the 5 least significant bits of the shift count
+      __ and_(r2, r2, Operand(0x1f));
+      // perform operation
+      switch (op_) {
+        case Token::SAR:
+          __ mov(r3, Operand(r3, ASR, r2));
+          // no checks of result necessary
+          break;
+
+        case Token::SHR:
+          __ mov(r3, Operand(r3, LSR, r2));
+          // check that the *unsigned* result fits in a smi
+          // neither of the two high-order bits can be set:
+          // - 0x80000000: high bit would be lost when smi tagging
+          // - 0x40000000: this number would convert to negative when
+          // smi tagging these two cases can only happen with shifts
+          // by 0 or 1 when handed a valid smi
+          __ and_(r2, r3, Operand(0xc0000000), SetCC);
+          __ b(ne, &slow);
+          break;
+
+        case Token::SHL:
+          __ mov(r3, Operand(r3, LSL, r2));
+          // check that the *signed* result fits in a smi
+          __ add(r2, r3, Operand(0x40000000), SetCC);
+          __ b(mi, &slow);
+          break;
+
+        default: UNREACHABLE();
+      }
+      // tag result and store it in r0
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ mov(r0, Operand(r3, LSL, kSmiTagSize));
+      __ b(&exit);
+      // slow case
+      __ bind(&slow);
+      __ push(r1);  // restore stack
+      __ push(r0);
+      __ mov(r0, Operand(1));  // 1 argument (not counting receiver).
+      switch (op_) {
+        case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break;
+        case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break;
+        case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break;
+        default: UNREACHABLE();
+      }
+      __ bind(&exit);
+      break;
+    }
+
+    default: UNREACHABLE();
+  }
+  __ Ret();
+}
+
+
+void StackCheckStub::Generate(MacroAssembler* masm) {
+  Label within_limit;
+  __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
+  __ ldr(ip, MemOperand(ip));
+  __ cmp(sp, Operand(ip));
+  __ b(hs, &within_limit);
+  // Do tail-call to runtime routine.
+  __ push(r0);
+  __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
+  __ bind(&within_limit);
+
+  __ StubReturn(1);
+}
+
+
+void UnarySubStub::Generate(MacroAssembler* masm) {
+  Label undo;
+  Label slow;
+  Label done;
+
+  // Enter runtime system if the value is not a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(ne, &slow);
+
+  // Enter runtime system if the value of the expression is zero
+  // to make sure that we switch between 0 and -0.
+  __ cmp(r0, Operand(0));
+  __ b(eq, &slow);
+
+  // The value of the expression is a smi that is not zero.  Try
+  // optimistic subtraction '0 - value'.
+  __ rsb(r1, r0, Operand(0), SetCC);
+  __ b(vs, &slow);
+
+  // If result is a smi we are done.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ mov(r0, Operand(r1), LeaveCC, eq);  // conditionally set r0 to result
+  __ b(eq, &done);
+
+  // Enter runtime system.
+  __ bind(&slow);
+  __ push(r0);
+  __ mov(r0, Operand(0));  // set number of arguments
+  __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS);
+
+  __ bind(&done);
+  __ StubReturn(1);
+}
+
+
+void InvokeBuiltinStub::Generate(MacroAssembler* masm) {
+  __ push(r0);
+  __ mov(r0, Operand(0));  // set number of arguments
+  switch (kind_) {
+    case ToNumber: __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_JS); break;
+    case Inc:      __ InvokeBuiltin(Builtins::INC, JUMP_JS);       break;
+    case Dec:      __ InvokeBuiltin(Builtins::DEC, JUMP_JS);       break;
+    default: UNREACHABLE();
+  }
+  __ StubReturn(argc_);
+}
+
+
+void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
+  // r0 holds exception
+  ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize);  // adjust this code
+  __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+  __ ldr(sp, MemOperand(r3));
+  __ pop(r2);  // pop next in chain
+  __ str(r2, MemOperand(r3));
+  // restore parameter- and frame-pointer and pop state.
+  __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
+  // Before returning we restore the context from the frame pointer if not NULL.
+  // The frame pointer is NULL in the exception handler of a JS entry frame.
+  __ cmp(fp, Operand(0));
+  // Set cp to NULL if fp is NULL.
+  __ mov(cp, Operand(0), LeaveCC, eq);
+  // Restore cp otherwise.
+  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
+  if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
+  __ pop(pc);
+}
+
+
+void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
+  // Fetch top stack handler.
+  __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+  __ ldr(r3, MemOperand(r3));
+
+  // Unwind the handlers until the ENTRY handler is found.
+  Label loop, done;
+  __ bind(&loop);
+  // Load the type of the current stack handler.
+  const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
+      StackHandlerConstants::kStateOffset;
+  __ ldr(r2, MemOperand(r3, kStateOffset));
+  __ cmp(r2, Operand(StackHandler::ENTRY));
+  __ b(eq, &done);
+  // Fetch the next handler in the list.
+  const int kNextOffset =  StackHandlerConstants::kAddressDisplacement +
+      StackHandlerConstants::kNextOffset;
+  __ ldr(r3, MemOperand(r3, kNextOffset));
+  __ jmp(&loop);
+  __ bind(&done);
+
+  // Set the top handler address to next handler past the current ENTRY handler.
+  __ ldr(r0, MemOperand(r3, kNextOffset));
+  __ mov(r2, Operand(ExternalReference(Top::k_handler_address)));
+  __ str(r0, MemOperand(r2));
+
+  // Set external caught exception to false.
+  __ mov(r0, Operand(false));
+  ExternalReference external_caught(Top::k_external_caught_exception_address);
+  __ mov(r2, Operand(external_caught));
+  __ str(r0, MemOperand(r2));
+
+  // 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(Top::k_pending_exception_address)));
+  __ str(r0, MemOperand(r2));
+
+  // Restore the stack to the address of the ENTRY handler
+  __ mov(sp, Operand(r3));
+
+  // restore parameter- and frame-pointer and pop state.
+  __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
+  // Before returning we restore the context from the frame pointer if not NULL.
+  // The frame pointer is NULL in the exception handler of a JS entry frame.
+  __ cmp(fp, Operand(0));
+  // Set cp to NULL if fp is NULL.
+  __ mov(cp, Operand(0), LeaveCC, eq);
+  // Restore cp otherwise.
+  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
+  if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
+  __ pop(pc);
+}
+
+
+void CEntryStub::GenerateCore(MacroAssembler* masm,
+                              Label* throw_normal_exception,
+                              Label* throw_out_of_memory_exception,
+                              StackFrame::Type frame_type,
+                              bool do_gc) {
+  // r0: result parameter for PerformGC, if any
+  // r4: number of arguments including receiver  (C callee-saved)
+  // r5: pointer to builtin function  (C callee-saved)
+  // r6: pointer to the first argument (C callee-saved)
+
+  if (do_gc) {
+    // Passing r0.
+    __ Call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
+  }
+
+  // Call C built-in.
+  // r0 = argc, r1 = argv
+  __ mov(r0, Operand(r4));
+  __ mov(r1, Operand(r6));
+
+  // TODO(1242173): To let the GC traverse the return address of the exit
+  // frames, we need to know where the return address is. Right now,
+  // we push it on the stack to be able to find it again, but we never
+  // restore from it in case of changes, which makes it impossible to
+  // support moving the C entry code stub. This should be fixed, but currently
+  // this is OK because the CEntryStub gets generated so early in the V8 boot
+  // sequence that it is not moving ever.
+  __ add(lr, pc, Operand(4));  // compute return address: (pc + 8) + 4
+  __ push(lr);
+#if !defined(__arm__)
+  // Notify the simulator of the transition to C code.
+  __ swi(assembler::arm::call_rt_r5);
+#else /* !defined(__arm__) */
+  __ mov(pc, Operand(r5));
+#endif /* !defined(__arm__) */
+  // result is in r0 or r0:r1 - do not destroy these registers!
+
+  // check for failure result
+  Label failure_returned;
+  ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
+  // Lower 2 bits of r2 are 0 iff r0 has failure tag.
+  __ add(r2, r0, Operand(1));
+  __ tst(r2, Operand(kFailureTagMask));
+  __ b(eq, &failure_returned);
+
+  // Exit C frame and return.
+  // r0:r1: result
+  // sp: stack pointer
+  // fp: frame pointer
+  // pp: caller's parameter pointer pp  (restored as C callee-saved)
+  __ LeaveExitFrame(frame_type);
+
+  // check if we should retry or throw exception
+  Label retry;
+  __ bind(&failure_returned);
+  ASSERT(Failure::RETRY_AFTER_GC == 0);
+  __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
+  __ b(eq, &retry);
+
+  Label continue_exception;
+  // If the returned failure is EXCEPTION then promote Top::pending_exception().
+  __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
+  __ b(ne, &continue_exception);
+
+  // Retrieve the pending exception and clear the variable.
+  __ mov(ip, Operand(Factory::the_hole_value().location()));
+  __ ldr(r3, MemOperand(ip));
+  __ mov(ip, Operand(Top::pending_exception_address()));
+  __ ldr(r0, MemOperand(ip));
+  __ str(r3, MemOperand(ip));
+
+  __ bind(&continue_exception);
+  // Special handling of out of memory exception.
+  Failure* out_of_memory = Failure::OutOfMemoryException();
+  __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
+  __ b(eq, throw_out_of_memory_exception);
+
+  // Handle normal exception.
+  __ jmp(throw_normal_exception);
+
+  __ bind(&retry);  // pass last failure (r0) as parameter (r0) when retrying
+}
+
+
+void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
+  // Called from JavaScript; parameters are on stack as if calling JS function
+  // r0: number of arguments including receiver
+  // r1: pointer to builtin function
+  // fp: frame pointer  (restored after C call)
+  // sp: stack pointer  (restored as callee's pp after C call)
+  // cp: current context  (C callee-saved)
+  // pp: caller's parameter pointer pp  (C callee-saved)
+
+  // NOTE: Invocations of builtins may return failure objects
+  // instead of a proper result. The builtin entry handles
+  // this by performing a garbage collection and retrying the
+  // builtin once.
+
+  StackFrame::Type frame_type = is_debug_break
+      ? StackFrame::EXIT_DEBUG
+      : StackFrame::EXIT;
+
+  // Enter the exit frame that transitions from JavaScript to C++.
+  __ EnterExitFrame(frame_type);
+
+  // r4: number of arguments (C callee-saved)
+  // r5: pointer to builtin function (C callee-saved)
+  // r6: pointer to first argument (C callee-saved)
+
+  Label throw_out_of_memory_exception;
+  Label throw_normal_exception;
+
+#ifdef DEBUG
+  if (FLAG_gc_greedy) {
+    Failure* failure = Failure::RetryAfterGC(0);
+    __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure)));
+  }
+  GenerateCore(masm,
+               &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               FLAG_gc_greedy);
+#else
+  GenerateCore(masm,
+               &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               false);
+#endif
+  GenerateCore(masm,
+               &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               true);
+
+  __ bind(&throw_out_of_memory_exception);
+  GenerateThrowOutOfMemory(masm);
+  // control flow for generated will not return.
+
+  __ bind(&throw_normal_exception);
+  GenerateThrowTOS(masm);
+}
+
+
+void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
+  // r0: code entry
+  // r1: function
+  // r2: receiver
+  // r3: argc
+  // [sp+0]: argv
+
+  Label invoke, exit;
+
+  // Called from C, so do not pop argc and args on exit (preserve sp)
+  // No need to save register-passed args
+  // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr
+  __ stm(db_w, sp, kCalleeSaved | lr.bit());
+
+  // Get address of argv, see stm above.
+  // r0: code entry
+  // r1: function
+  // r2: receiver
+  // r3: argc
+  __ add(r4, sp, Operand((kNumCalleeSaved + 1)*kPointerSize));
+  __ ldr(r4, MemOperand(r4));  // argv
+
+  // Push a frame with special values setup to mark it as an entry frame.
+  // r0: code entry
+  // r1: function
+  // r2: receiver
+  // r3: argc
+  // r4: argv
+  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
+  __ mov(r8, Operand(-1));  // Push a bad frame pointer to fail if it is used.
+  __ mov(r7, Operand(~ArgumentsAdaptorFrame::SENTINEL));
+  __ mov(r6, Operand(Smi::FromInt(marker)));
+  __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+  __ ldr(r5, MemOperand(r5));
+  __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit());
+
+  // Setup frame pointer for the frame to be pushed.
+  __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
+
+  // Call a faked try-block that does the invoke.
+  __ bl(&invoke);
+
+  // Caught exception: Store result (exception) in the pending
+  // 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(Top::pending_exception_address()));
+  __ str(r0, MemOperand(ip));
+  __ mov(r0, Operand(Handle<Failure>(Failure::Exception())));
+  __ b(&exit);
+
+  // Invoke: Link this frame into the handler chain.
+  __ bind(&invoke);
+  // Must preserve r0-r4, r5-r7 are available.
+  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
+  // If an exception not caught by another handler occurs, this handler returns
+  // control to the code after the bl(&invoke) above, which restores all
+  // kCalleeSaved registers (including cp, pp and fp) to their saved values
+  // before returning a failure to C.
+
+  // Clear any pending exceptions.
+  __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
+  __ ldr(r5, MemOperand(ip));
+  __ mov(ip, Operand(Top::pending_exception_address()));
+  __ str(r5, MemOperand(ip));
+
+  // Invoke the function by calling through JS entry trampoline builtin.
+  // Notice that we cannot store a reference to the trampoline code directly in
+  // this stub, because runtime stubs are not traversed when doing GC.
+
+  // Expected registers by Builtins::JSEntryTrampoline
+  // r0: code entry
+  // r1: function
+  // r2: receiver
+  // r3: argc
+  // r4: argv
+  if (is_construct) {
+    ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
+    __ mov(ip, Operand(construct_entry));
+  } else {
+    ExternalReference entry(Builtins::JSEntryTrampoline);
+    __ mov(ip, Operand(entry));
+  }
+  __ ldr(ip, MemOperand(ip));  // deref address
+
+  // Branch and link to JSEntryTrampoline
+  __ mov(lr, Operand(pc));
+  __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // Unlink this frame from the handler chain. When reading the
+  // address of the next handler, there is no need to use the address
+  // displacement since the current stack pointer (sp) points directly
+  // to the stack handler.
+  __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset));
+  __ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
+  __ str(r3, MemOperand(ip));
+  // No need to restore registers
+  __ add(sp, sp, Operand(StackHandlerConstants::kSize));
+
+  __ bind(&exit);  // r0 holds result
+  // Restore the top frame descriptors from the stack.
+  __ pop(r3);
+  __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+  __ str(r3, MemOperand(ip));
+
+  // Reset the stack to the callee saved registers.
+  __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
+
+  // Restore callee-saved registers and return.
+#ifdef DEBUG
+  if (FLAG_debug_code) __ mov(lr, Operand(pc));
+#endif
+  __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
+}
+
+
+void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
+  // Check if the calling frame is an arguments adaptor frame.
+  Label adaptor;
+  __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
+  __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
+  __ b(eq, &adaptor);
+
+  // Nothing to do: The formal number of parameters has already been
+  // passed in register r0 by calling function. Just return it.
+  __ mov(pc, lr);
+
+  // Arguments adaptor case: Read the arguments length from the
+  // adaptor frame and return it.
+  __ bind(&adaptor);
+  __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ mov(pc, lr);
+}
+
+
+void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
+  // The displacement is the offset of the last parameter (if any)
+  // relative to the frame pointer.
+  static const int kDisplacement =
+      StandardFrameConstants::kCallerSPOffset - kPointerSize;
+
+  // Check that the key is a smi.
+  Label slow;
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(ne, &slow);
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label adaptor;
+  __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
+  __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
+  __ b(eq, &adaptor);
+
+  // Check index against formal parameters count limit passed in
+  // through register eax. Use unsigned comparison to get negative
+  // check for free.
+  __ cmp(r1, r0);
+  __ b(cs, &slow);
+
+  // Read the argument from the stack and return it.
+  __ sub(r3, r0, r1);
+  __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
+  __ ldr(r0, MemOperand(r3, kDisplacement));
+  __ mov(pc, lr);
+
+  // Arguments adaptor case: Check index against actual arguments
+  // limit found in the arguments adaptor frame. Use unsigned
+  // comparison to get negative check for free.
+  __ bind(&adaptor);
+  __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ cmp(r1, r0);
+  __ b(cs, &slow);
+
+  // Read the argument from the adaptor frame and return it.
+  __ sub(r3, r0, r1);
+  __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
+  __ ldr(r0, MemOperand(r3, kDisplacement));
+  __ mov(pc, lr);
+
+  // Slow-case: Handle non-smi or out-of-bounds access to arguments
+  // by calling the runtime system.
+  __ bind(&slow);
+  __ push(r1);
+  __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
+}
+
+
+void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
+  // Check if the calling frame is an arguments adaptor frame.
+  Label runtime;
+  __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
+  __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
+  __ b(ne, &runtime);
+
+  // Patch the arguments.length and the parameters pointer.
+  __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ str(r0, MemOperand(sp, 0 * kPointerSize));
+  __ add(r3, r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
+  __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
+  __ str(r3, MemOperand(sp, 1 * kPointerSize));
+
+  // Do the runtime call to allocate the arguments object.
+  __ bind(&runtime);
+  __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
+}
+
+
+void CallFunctionStub::Generate(MacroAssembler* masm) {
+  Label slow;
+  // Get the function to call from the stack.
+  // function, receiver [, arguments]
+  __ ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
+
+  // Check that the function is really a JavaScript function.
+  // r1: pushed function (to be verified)
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &slow);
+  // Get the map of the function object.
+  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+  __ cmp(r2, Operand(JS_FUNCTION_TYPE));
+  __ b(ne, &slow);
+
+  // Fast-case: Invoke the function now.
+  // r1: pushed function
+  ParameterCount actual(argc_);
+  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
+
+  // Slow-case: Non-function called.
+  __ bind(&slow);
+  __ mov(r0, Operand(argc_));  // Setup the number of arguments.
+  __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS);
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/codegen-arm.h b/regexp2000/src/codegen-arm.h
new file mode 100644 (file)
index 0000000..8058138
--- /dev/null
@@ -0,0 +1,376 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CODEGEN_ARM_H_
+#define V8_CODEGEN_ARM_H_
+
+#include "scopes.h"
+
+namespace v8 { namespace internal {
+
+// Forward declarations
+class DeferredCode;
+
+// Mode to overwrite BinaryExpression values.
+enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+
+
+// -----------------------------------------------------------------------------
+// Reference support
+
+// A reference is a C++ stack-allocated object that keeps an ECMA
+// reference on the execution stack while in scope. For variables
+// the reference is empty, indicating that it isn't necessary to
+// store state on the stack for keeping track of references to those.
+// For properties, we keep either one (named) or two (indexed) values
+// on the execution stack to represent the reference.
+
+enum InitState { CONST_INIT, NOT_CONST_INIT };
+enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
+
+class Reference BASE_EMBEDDED {
+ public:
+  // The values of the types is important, see size().
+  enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
+  Reference(CodeGenerator* cgen, Expression* expression);
+  ~Reference();
+
+  Expression* expression() const { return expression_; }
+  Type type() const { return type_; }
+  void set_type(Type value) {
+    ASSERT(type_ == ILLEGAL);
+    type_ = value;
+  }
+
+  // The size of the reference or -1 if the reference is illegal.
+  int size() const { return type_; }
+
+  bool is_illegal() const { return type_ == ILLEGAL; }
+  bool is_slot() const { return type_ == SLOT; }
+  bool is_property() const { return type_ == NAMED || type_ == KEYED; }
+
+  // Return the name.  Only valid for named property references.
+  Handle<String> GetName();
+
+  // Generate code to push the value of the reference on top of the
+  // expression stack.  The reference is expected to be already on top of
+  // the expression stack, and it is left in place with its value above it.
+  void GetValue(TypeofState typeof_state);
+
+  // Generate code to store the value on top of the expression stack in the
+  // reference.  The reference is expected to be immediately below the value
+  // on the expression stack.  The stored value is left in place (with the
+  // reference intact below it) to support chained assignments.
+  void SetValue(InitState init_state);
+
+ private:
+  CodeGenerator* cgen_;
+  Expression* expression_;
+  Type type_;
+};
+
+
+// -------------------------------------------------------------------------
+// Code generation state
+
+// The state is passed down the AST by the code generator (and back up, in
+// the form of the state of the label pair).  It is threaded through the
+// call stack.  Constructing a state implicitly pushes it on the owning code
+// generator's stack of states, and destroying one implicitly pops it.
+
+class CodeGenState BASE_EMBEDDED {
+ public:
+  // Create an initial code generator state.  Destroying the initial state
+  // leaves the code generator with a NULL state.
+  explicit CodeGenState(CodeGenerator* owner);
+
+  // Create a code generator state based on a code generator's current
+  // state.  The new state has its own typeof state and pair of branch
+  // labels.
+  CodeGenState(CodeGenerator* owner,
+               TypeofState typeof_state,
+               Label* true_target,
+               Label* false_target);
+
+  // Destroy a code generator state and restore the owning code generator's
+  // previous state.
+  ~CodeGenState();
+
+  TypeofState typeof_state() const { return typeof_state_; }
+  Label* true_target() const { return true_target_; }
+  Label* false_target() const { return false_target_; }
+
+ private:
+  CodeGenerator* owner_;
+  TypeofState typeof_state_;
+  Label* true_target_;
+  Label* false_target_;
+  CodeGenState* previous_;
+};
+
+
+// -----------------------------------------------------------------------------
+// CodeGenerator
+
+class CodeGenerator: public Visitor {
+ public:
+  // Takes a function literal, generates code for it. This function should only
+  // be called by compiler.cc.
+  static Handle<Code> MakeCode(FunctionLiteral* fun,
+                               Handle<Script> script,
+                               bool is_eval);
+
+  static void SetFunctionInfo(Handle<JSFunction> fun,
+                              int length,
+                              int function_token_position,
+                              int start_position,
+                              int end_position,
+                              bool is_expression,
+                              bool is_toplevel,
+                              Handle<Script> script);
+
+  // Accessors
+  MacroAssembler* masm() { return masm_; }
+
+  CodeGenState* state() { return state_; }
+  void set_state(CodeGenState* state) { state_ = state; }
+
+  void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
+
+ private:
+  // Construction/Destruction
+  CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
+  virtual ~CodeGenerator() { delete masm_; }
+
+  // Accessors
+  Scope* scope() const { return scope_; }
+
+  void ProcessDeferred();
+
+  bool is_eval() { return is_eval_; }
+
+  // State
+  bool has_cc() const  { return cc_reg_ != al; }
+  TypeofState typeof_state() const { return state_->typeof_state(); }
+  Label* true_target() const  { return state_->true_target(); }
+  Label* false_target() const  { return state_->false_target(); }
+
+
+  // Node visitors.
+#define DEF_VISIT(type) \
+  void Visit##type(type* node);
+  NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+  // Main code generation function
+  void GenCode(FunctionLiteral* fun);
+
+  // The following are used by class Reference.
+  void LoadReference(Reference* ref);
+  void UnloadReference(Reference* ref);
+
+  // Support functions for accessing parameters and other operands.
+  MemOperand ParameterOperand(int index) const {
+    int num_parameters = scope()->num_parameters();
+    // index -2 corresponds to the activated closure, -1 corresponds
+    // to the receiver
+    ASSERT(-2 <= index && index < num_parameters);
+    int offset = (1 + num_parameters - index) * kPointerSize;
+    return MemOperand(fp, offset);
+  }
+
+  MemOperand FunctionOperand() const {
+    return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset);
+  }
+
+  MemOperand ContextOperand(Register context, int index) const {
+    return MemOperand(context, Context::SlotOffset(index));
+  }
+
+  MemOperand SlotOperand(Slot* slot, Register tmp);
+
+  // Expressions
+  MemOperand GlobalObject() const  {
+    return ContextOperand(cp, Context::GLOBAL_INDEX);
+  }
+
+  void LoadCondition(Expression* x,
+                     TypeofState typeof_state,
+                     Label* true_target,
+                     Label* false_target,
+                     bool force_cc);
+  void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
+  void LoadGlobal();
+  void LoadGlobalReceiver(Register scratch);
+
+  // Read a value from a slot and leave it on top of the expression stack.
+  void LoadFromSlot(Slot* slot, TypeofState typeof_state);
+
+  // Special code for typeof expressions: Unfortunately, we must
+  // be careful when loading the expression in 'typeof'
+  // expressions. We are not allowed to throw reference errors for
+  // non-existing properties of the global object, so we must make it
+  // look like an explicit property access, instead of an access
+  // through the context chain.
+  void LoadTypeofExpression(Expression* x);
+
+  void ToBoolean(Label* true_target, Label* false_target);
+
+  void GenericBinaryOperation(Token::Value op);
+  void Comparison(Condition cc, bool strict = false);
+
+  void SmiOperation(Token::Value op, Handle<Object> value, bool reversed);
+
+  void CallWithArguments(ZoneList<Expression*>* arguments, int position);
+
+  // Control flow
+  void Branch(bool if_true, Label* L);
+  void CheckStack();
+  void CleanStack(int num_bytes);
+
+  bool CheckForInlineRuntimeCall(CallRuntime* node);
+  Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
+  void ProcessDeclarations(ZoneList<Declaration*>* declarations);
+
+  Handle<Code> ComputeCallInitialize(int argc);
+
+  // Declare global variables and functions in the given array of
+  // name/value pairs.
+  void DeclareGlobals(Handle<FixedArray> pairs);
+
+  // Instantiate the function boilerplate.
+  void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
+
+  // Support for type checks.
+  void GenerateIsSmi(ZoneList<Expression*>* args);
+  void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
+  void GenerateIsArray(ZoneList<Expression*>* args);
+
+  // Support for arguments.length and arguments[?].
+  void GenerateArgumentsLength(ZoneList<Expression*>* args);
+  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+
+  // Support for accessing the value field of an object (used by Date).
+  void GenerateValueOf(ZoneList<Expression*>* args);
+  void GenerateSetValueOf(ZoneList<Expression*>* args);
+
+  // Fast support for charCodeAt(n).
+  void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
+
+  // Fast support for object equality testing.
+  void GenerateObjectEquals(ZoneList<Expression*>* args);
+
+  // Methods and constants for fast case switch statement support.
+  //
+  // Only allow fast-case switch if the range of labels is at most
+  // this factor times the number of case labels.
+  // Value is derived from comparing the size of code generated by the normal
+  // switch code for Smi-labels to the size of a single pointer. If code
+  // quality increases this number should be decreased to match.
+  static const int kFastSwitchMaxOverheadFactor = 10;
+
+  // Minimal number of switch cases required before we allow jump-table
+  // optimization.
+  static const int kFastSwitchMinCaseCount = 5;
+
+  // The limit of the range of a fast-case switch, as a factor of the number
+  // of cases of the switch. Each platform should return a value that
+  // is optimal compared to the default code generated for a switch statement
+  // on that platform.
+  int FastCaseSwitchMaxOverheadFactor();
+
+  // The minimal number of cases in a switch before the fast-case switch
+  // optimization is enabled. Each platform should return a value that
+  // is optimal compared to the default code generated for a switch statement
+  // on that platform.
+  int FastCaseSwitchMinCaseCount();
+
+  // Allocate a jump table and create code to jump through it.
+  // Should call GenerateFastCaseSwitchCases to generate the code for
+  // all the cases at the appropriate point.
+  void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
+                                       int min_index,
+                                       int range,
+                                       Label* fail_label,
+                                       Vector<Label*> case_targets,
+                                       Vector<Label> case_labels);
+
+  // Generate the code for cases for the fast case switch.
+  // Called by GenerateFastCaseSwitchJumpTable.
+  void GenerateFastCaseSwitchCases(SwitchStatement* node,
+                                   Vector<Label> case_labels);
+
+  // Fast support for constant-Smi switches.
+  void GenerateFastCaseSwitchStatement(SwitchStatement* node,
+                                       int min_index,
+                                       int range,
+                                       int default_index);
+
+  // Fast support for constant-Smi switches. Tests whether switch statement
+  // permits optimization and calls GenerateFastCaseSwitch if it does.
+  // Returns true if the fast-case switch was generated, and false if not.
+  bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node);
+
+
+  // Bottle-neck interface to call the Assembler to generate the statement
+  // position. This allows us to easily control whether statement positions
+  // should be generated or not.
+  void RecordStatementPosition(Node* node);
+
+  // Activation frames.
+  void EnterJSFrame();
+  void ExitJSFrame();
+
+
+  bool is_eval_;  // Tells whether code is generated for eval.
+  Handle<Script> script_;
+  List<DeferredCode*> deferred_;
+
+  // Assembler
+  MacroAssembler* masm_;  // to generate code
+
+  // Code generation state
+  Scope* scope_;
+  Condition cc_reg_;
+  CodeGenState* state_;
+  bool is_inside_try_;
+  int break_stack_height_;
+
+  // Labels
+  Label function_return_;
+
+  friend class Reference;
+  friend class Property;
+  friend class VariableProxy;
+  friend class Slot;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_CODEGEN_ARM_H_
diff --git a/regexp2000/src/codegen-ia32.cc b/regexp2000/src/codegen-ia32.cc
new file mode 100644 (file)
index 0000000..e927c5c
--- /dev/null
@@ -0,0 +1,5122 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "codegen-inl.h"
+#include "debug.h"
+#include "scopes.h"
+#include "runtime.h"
+
+namespace v8 { namespace internal {
+
+#define __ masm_->
+
+// -------------------------------------------------------------------------
+// VirtualFrame implementation.
+
+VirtualFrame::VirtualFrame(CodeGenerator* cgen) {
+  ASSERT(cgen->scope() != NULL);
+
+  masm_ = cgen->masm();
+  frame_local_count_ = cgen->scope()->num_stack_slots();
+  parameter_count_ = cgen->scope()->num_parameters();
+}
+
+
+void VirtualFrame::Enter() {
+  Comment cmnt(masm_, "[ Enter JS frame");
+  __ push(ebp);
+  __ mov(ebp, Operand(esp));
+
+  // Store the context and the function in the frame.
+  __ push(esi);
+  __ push(edi);
+
+  // Clear the function slot when generating debug code.
+  if (FLAG_debug_code) {
+    __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue)));
+  }
+}
+
+
+void VirtualFrame::Exit() {
+  Comment cmnt(masm_, "[ Exit JS frame");
+  // Record the location of the JS exit code for patching when setting
+  // break point.
+  __ RecordJSReturn();
+
+  // Avoid using the leave instruction here, because it is too
+  // short. We need the return sequence to be a least the size of a
+  // call instruction to support patching the exit code in the
+  // debugger. See VisitReturnStatement for the full return sequence.
+  __ mov(esp, Operand(ebp));
+  __ pop(ebp);
+}
+
+
+void VirtualFrame::AllocateLocals() {
+  if (frame_local_count_ > 0) {
+    Comment cmnt(masm_, "[ Allocate space for locals");
+    __ Set(eax, Immediate(Factory::undefined_value()));
+    for (int i = 0; i < frame_local_count_; i++) {
+      __ push(eax);
+    }
+  }
+}
+
+
+void VirtualFrame::Drop(int count) {
+  ASSERT(count >= 0);
+  if (count > 0) {
+    __ add(Operand(esp), Immediate(count * kPointerSize));
+  }
+}
+
+
+void VirtualFrame::Pop() {
+  __ add(Operand(esp), Immediate(kPointerSize));
+}
+
+
+void VirtualFrame::Pop(Register reg) {
+  __ pop(reg);
+}
+
+
+void VirtualFrame::Pop(Operand operand) {
+  __ pop(operand);
+}
+
+
+void VirtualFrame::Push(Register reg) {
+  __ push(reg);
+}
+
+
+void VirtualFrame::Push(Operand operand) {
+  __ push(operand);
+}
+
+
+void VirtualFrame::Push(Immediate immediate) {
+  __ push(immediate);
+}
+
+
+// -------------------------------------------------------------------------
+// CodeGenState implementation.
+
+CodeGenState::CodeGenState(CodeGenerator* owner)
+    : owner_(owner),
+      typeof_state_(NOT_INSIDE_TYPEOF),
+      true_target_(NULL),
+      false_target_(NULL),
+      previous_(NULL) {
+  owner_->set_state(this);
+}
+
+
+CodeGenState::CodeGenState(CodeGenerator* owner,
+                           TypeofState typeof_state,
+                           Label* true_target,
+                           Label* false_target)
+    : owner_(owner),
+      typeof_state_(typeof_state),
+      true_target_(true_target),
+      false_target_(false_target),
+      previous_(owner->state()) {
+  owner_->set_state(this);
+}
+
+
+CodeGenState::~CodeGenState() {
+  ASSERT(owner_->state() == this);
+  owner_->set_state(previous_);
+}
+
+
+// -------------------------------------------------------------------------
+// CodeGenerator implementation
+
+CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
+                             bool is_eval)
+    : is_eval_(is_eval),
+      script_(script),
+      deferred_(8),
+      masm_(new MacroAssembler(NULL, buffer_size)),
+      scope_(NULL),
+      frame_(NULL),
+      cc_reg_(no_condition),
+      state_(NULL),
+      is_inside_try_(false),
+      break_stack_height_(0) {
+}
+
+
+// Calling conventions:
+// ebp: frame pointer
+// esp: stack pointer
+// edi: caller's parameter pointer
+// esi: callee's context
+
+void CodeGenerator::GenCode(FunctionLiteral* fun) {
+  // Record the position for debugging purposes.
+  __ RecordPosition(fun->start_position());
+
+  ZoneList<Statement*>* body = fun->body();
+
+  // Initialize state.
+  ASSERT(scope_ == NULL);
+  scope_ = fun->scope();
+  ASSERT(frame_ == NULL);
+  VirtualFrame virtual_frame(this);
+  frame_ = &virtual_frame;
+  cc_reg_ = no_condition;
+  {
+    CodeGenState state(this);
+
+    // Entry
+    // stack: function, receiver, arguments, return address
+    // esp: stack pointer
+    // ebp: frame pointer
+    // edi: caller's parameter pointer
+    // esi: callee's context
+
+    frame_->Enter();
+    // tos: code slot
+#ifdef DEBUG
+    if (strlen(FLAG_stop_at) > 0 &&
+        fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+      __ int3();
+    }
+#endif
+
+    // This section now only allocates and copies the formals into the
+    // arguments object. It saves the address in ecx, which is saved
+    // at any point before either garbage collection or ecx is
+    // overwritten.  The flag arguments_array_allocated communicates
+    // with the store into the arguments variable and guards the lazy
+    // pushes of ecx to TOS.  The flag arguments_array_saved notes
+    // when the push has happened.
+    bool arguments_object_allocated = false;
+    bool arguments_object_saved = false;
+
+    // Allocate arguments object.
+    // The arguments object pointer needs to be saved in ecx, since we need
+    // to store arguments into the context.
+    if (scope_->arguments() != NULL) {
+      ASSERT(scope_->arguments_shadow() != NULL);
+      Comment cmnt(masm_, "[ allocate arguments object");
+      ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+      __ lea(eax, frame_->Receiver());
+      frame_->Push(frame_->Function());
+      frame_->Push(eax);
+      frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters())));
+      __ CallStub(&stub);
+      __ mov(ecx, Operand(eax));
+      arguments_object_allocated = true;
+    }
+
+    // Allocate space for locals and initialize them.
+    frame_->AllocateLocals();
+
+    if (scope_->num_heap_slots() > 0) {
+      Comment cmnt(masm_, "[ allocate local context");
+      // Save the arguments object pointer, if any.
+      if (arguments_object_allocated && !arguments_object_saved) {
+        frame_->Push(ecx);
+        arguments_object_saved = true;
+      }
+      // Allocate local context.
+      // Get outer context and create a new context based on it.
+      frame_->Push(frame_->Function());
+      __ CallRuntime(Runtime::kNewContext, 1);  // eax holds the result
+
+      if (kDebug) {
+        Label verified_true;
+        // Verify eax and esi are the same in debug mode
+        __ cmp(eax, Operand(esi));
+        __ j(equal, &verified_true);
+        __ int3();
+        __ bind(&verified_true);
+      }
+
+      // Update context local.
+      __ mov(frame_->Context(), esi);
+      // Restore the arguments array pointer, if any.
+    }
+
+    // TODO(1241774): Improve this code:
+    // 1) only needed if we have a context
+    // 2) no need to recompute context ptr every single time
+    // 3) don't copy parameter operand code from SlotOperand!
+    {
+      Comment cmnt2(masm_, "[ copy context parameters into .context");
+
+      // Note that iteration order is relevant here! If we have the same
+      // parameter twice (e.g., function (x, y, x)), and that parameter
+      // needs to be copied into the context, it must be the last argument
+      // passed to the parameter that needs to be copied. This is a rare
+      // case so we don't check for it, instead we rely on the copying
+      // order: such a parameter is copied repeatedly into the same
+      // context location and thus the last value is what is seen inside
+      // the function.
+      for (int i = 0; i < scope_->num_parameters(); i++) {
+        Variable* par = scope_->parameter(i);
+        Slot* slot = par->slot();
+        if (slot != NULL && slot->type() == Slot::CONTEXT) {
+          // Save the arguments object pointer, if any.
+          if (arguments_object_allocated && !arguments_object_saved) {
+            frame_->Push(ecx);
+            arguments_object_saved = true;
+          }
+          ASSERT(!scope_->is_global_scope());  // no parameters in global scope
+          __ mov(eax, frame_->Parameter(i));
+          // Loads ecx with context; used below in RecordWrite.
+          __ mov(SlotOperand(slot, ecx), eax);
+          int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+          __ RecordWrite(ecx, offset, eax, ebx);
+        }
+      }
+    }
+
+    // This section stores the pointer to the arguments object that
+    // was allocated and copied into above. If the address was not
+    // saved to TOS, we push ecx onto the stack.
+
+    // Store the arguments object.
+    // This must happen after context initialization because
+    // the arguments object may be stored in the context
+    if (arguments_object_allocated) {
+      ASSERT(scope_->arguments() != NULL);
+      ASSERT(scope_->arguments_shadow() != NULL);
+      Comment cmnt(masm_, "[ store arguments object");
+      { Reference shadow_ref(this, scope_->arguments_shadow());
+        ASSERT(shadow_ref.is_slot());
+        { Reference arguments_ref(this, scope_->arguments());
+          ASSERT(arguments_ref.is_slot());
+          // If the newly-allocated arguments object is already on the
+          // stack, we make use of the convenient property that references
+          // representing slots take up no space on the expression stack
+          // (ie, it doesn't matter that the stored value is actually below
+          // the reference).
+          //
+          // If the newly-allocated argument object is not already on
+          // the stack, we rely on the property that loading a
+          // zero-sized reference will not clobber the ecx register.
+          if (!arguments_object_saved) {
+            frame_->Push(ecx);
+          }
+          arguments_ref.SetValue(NOT_CONST_INIT);
+        }
+        shadow_ref.SetValue(NOT_CONST_INIT);
+      }
+      frame_->Pop();  // Value is no longer needed.
+    }
+
+    // Generate code to 'execute' declarations and initialize
+    // functions (source elements). In case of an illegal
+    // redeclaration we need to handle that instead of processing the
+    // declarations.
+    if (scope_->HasIllegalRedeclaration()) {
+      Comment cmnt(masm_, "[ illegal redeclarations");
+      scope_->VisitIllegalRedeclaration(this);
+    } else {
+      Comment cmnt(masm_, "[ declarations");
+      ProcessDeclarations(scope_->declarations());
+      // Bail out if a stack-overflow exception occurred when
+      // processing declarations.
+      if (HasStackOverflow()) return;
+    }
+
+    if (FLAG_trace) {
+      __ CallRuntime(Runtime::kTraceEnter, 0);
+      // Ignore the return value.
+    }
+    CheckStack();
+
+    // Compile the body of the function in a vanilla state. Don't
+    // bother compiling all the code if the scope has an illegal
+    // redeclaration.
+    if (!scope_->HasIllegalRedeclaration()) {
+      Comment cmnt(masm_, "[ function body");
+#ifdef DEBUG
+      bool is_builtin = Bootstrapper::IsActive();
+      bool should_trace =
+          is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
+      if (should_trace) {
+        __ CallRuntime(Runtime::kDebugTrace, 0);
+        // Ignore the return value.
+      }
+#endif
+      VisitStatements(body);
+
+      // Generate a return statement if necessary.
+      if (body->is_empty() || body->last()->AsReturnStatement() == NULL) {
+        Literal undefined(Factory::undefined_value());
+        ReturnStatement statement(&undefined);
+        statement.set_statement_pos(fun->end_position());
+        VisitReturnStatement(&statement);
+      }
+    }
+  }
+
+  // Code generation state must be reset.
+  scope_ = NULL;
+  frame_ = NULL;
+  ASSERT(!has_cc());
+  ASSERT(state_ == NULL);
+}
+
+
+Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+  // Currently, this assertion will fail if we try to assign to
+  // a constant variable that is constant because it is read-only
+  // (such as the variable referring to a named function expression).
+  // We need to implement assignments to read-only variables.
+  // Ideally, we should do this during AST generation (by converting
+  // such assignments into expression statements); however, in general
+  // we may not be able to make the decision until past AST generation,
+  // that is when the entire program is known.
+  ASSERT(slot != NULL);
+  int index = slot->index();
+  switch (slot->type()) {
+    case Slot::PARAMETER:
+      return frame_->Parameter(index);
+
+    case Slot::LOCAL:
+      return frame_->Local(index);
+
+    case Slot::CONTEXT: {
+      // Follow the context chain if necessary.
+      ASSERT(!tmp.is(esi));  // do not overwrite context register
+      Register context = esi;
+      int chain_length = scope()->ContextChainLength(slot->var()->scope());
+      for (int i = chain_length; i-- > 0;) {
+        // Load the closure.
+        // (All contexts, even 'with' contexts, have a closure,
+        // and it is the same for all contexts inside a function.
+        // There is no need to go to the function context first.)
+        __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
+        // Load the function context (which is the incoming, outer context).
+        __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
+        context = tmp;
+      }
+      // We may have a 'with' context now. Get the function context.
+      // (In fact this mov may never be the needed, since the scope analysis
+      // may not permit a direct context access in this case and thus we are
+      // always at a function context. However it is safe to dereference be-
+      // cause the function context of a function context is itself. Before
+      // deleting this mov we should try to create a counter-example first,
+      // though...)
+      __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
+      return ContextOperand(tmp, index);
+    }
+
+    default:
+      UNREACHABLE();
+      return Operand(eax);
+  }
+}
+
+
+// Loads a value on TOS. If it is a boolean value, the result may have been
+// (partially) translated into branches, or it may have set the condition code
+// register. If force_cc is set, the value is forced to set the condition code
+// register and no value is pushed. If the condition code register was set,
+// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
+void CodeGenerator::LoadCondition(Expression* x,
+                                  TypeofState typeof_state,
+                                  Label* true_target,
+                                  Label* false_target,
+                                  bool force_cc) {
+  ASSERT(!has_cc());
+
+  { CodeGenState new_state(this, typeof_state, true_target, false_target);
+    Visit(x);
+  }
+  if (force_cc && !has_cc()) {
+    ToBoolean(true_target, false_target);
+  }
+  ASSERT(has_cc() || !force_cc);
+}
+
+
+void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
+  Label true_target;
+  Label false_target;
+  LoadCondition(x, typeof_state, &true_target, &false_target, false);
+
+  if (has_cc()) {
+    // convert cc_reg_ into a bool
+
+    Label loaded, materialize_true;
+    __ j(cc_reg_, &materialize_true);
+    frame_->Push(Immediate(Factory::false_value()));
+    __ jmp(&loaded);
+    __ bind(&materialize_true);
+    frame_->Push(Immediate(Factory::true_value()));
+    __ bind(&loaded);
+    cc_reg_ = no_condition;
+  }
+
+  if (true_target.is_linked() || false_target.is_linked()) {
+    // we have at least one condition value
+    // that has been "translated" into a branch,
+    // thus it needs to be loaded explicitly again
+    Label loaded;
+    __ jmp(&loaded);  // don't lose current TOS
+    bool both = true_target.is_linked() && false_target.is_linked();
+    // reincarnate "true", if necessary
+    if (true_target.is_linked()) {
+      __ bind(&true_target);
+      frame_->Push(Immediate(Factory::true_value()));
+    }
+    // if both "true" and "false" need to be reincarnated,
+    // jump across code for "false"
+    if (both)
+      __ jmp(&loaded);
+    // reincarnate "false", if necessary
+    if (false_target.is_linked()) {
+      __ bind(&false_target);
+      frame_->Push(Immediate(Factory::false_value()));
+    }
+    // everything is loaded at this point
+    __ bind(&loaded);
+  }
+  ASSERT(!has_cc());
+}
+
+
+void CodeGenerator::LoadGlobal() {
+  frame_->Push(GlobalObject());
+}
+
+
+void CodeGenerator::LoadGlobalReceiver(Register scratch) {
+  __ mov(scratch, GlobalObject());
+  frame_->Push(FieldOperand(scratch, GlobalObject::kGlobalReceiverOffset));
+}
+
+
+// TODO(1241834): Get rid of this function in favor of just using Load, now
+// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
+// variables w/o reference errors elsewhere.
+void CodeGenerator::LoadTypeofExpression(Expression* x) {
+  Variable* variable = x->AsVariableProxy()->AsVariable();
+  if (variable != NULL && !variable->is_this() && variable->is_global()) {
+    // NOTE: This is somewhat nasty. We force the compiler to load
+    // the variable as if through '<global>.<variable>' to make sure we
+    // do not get reference errors.
+    Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
+    Literal key(variable->name());
+    // TODO(1241834): Fetch the position from the variable instead of using
+    // no position.
+    Property property(&global, &key, RelocInfo::kNoPosition);
+    Load(&property);
+  } else {
+    Load(x, INSIDE_TYPEOF);
+  }
+}
+
+
+Reference::Reference(CodeGenerator* cgen, Expression* expression)
+    : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
+  cgen->LoadReference(this);
+}
+
+
+Reference::~Reference() {
+  cgen_->UnloadReference(this);
+}
+
+
+void CodeGenerator::LoadReference(Reference* ref) {
+  Comment cmnt(masm_, "[ LoadReference");
+  Expression* e = ref->expression();
+  Property* property = e->AsProperty();
+  Variable* var = e->AsVariableProxy()->AsVariable();
+
+  if (property != NULL) {
+    // The expression is either a property or a variable proxy that rewrites
+    // to a property.
+    Load(property->obj());
+    // We use a named reference if the key is a literal symbol, unless it is
+    // a string that can be legally parsed as an integer.  This is because
+    // otherwise we will not get into the slow case code that handles [] on
+    // String objects.
+    Literal* literal = property->key()->AsLiteral();
+    uint32_t dummy;
+    if (literal != NULL &&
+        literal->handle()->IsSymbol() &&
+        !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
+      ref->set_type(Reference::NAMED);
+    } else {
+      Load(property->key());
+      ref->set_type(Reference::KEYED);
+    }
+  } else if (var != NULL) {
+    // The expression is a variable proxy that does not rewrite to a
+    // property.  Global variables are treated as named property references.
+    if (var->is_global()) {
+      LoadGlobal();
+      ref->set_type(Reference::NAMED);
+    } else {
+      ASSERT(var->slot() != NULL);
+      ref->set_type(Reference::SLOT);
+    }
+  } else {
+    // Anything else is a runtime error.
+    Load(e);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+  }
+}
+
+
+void CodeGenerator::UnloadReference(Reference* ref) {
+  // Pop a reference from the stack while preserving TOS.
+  Comment cmnt(masm_, "[ UnloadReference");
+  int size = ref->size();
+  if (size <= 0) {
+    // Do nothing. No popping is necessary.
+  } else if (size == 1) {
+    frame_->Pop(eax);
+    __ mov(frame_->Top(), eax);
+  } else {
+    frame_->Pop(eax);
+    frame_->Drop(size);
+    frame_->Push(eax);
+  }
+}
+
+
+class ToBooleanStub: public CodeStub {
+ public:
+  ToBooleanStub() { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  Major MajorKey() { return ToBoolean; }
+  int MinorKey() { return 0; }
+};
+
+
+// ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and
+// convert it to a boolean in the condition code register or jump to
+// 'false_target'/'true_target' as appropriate.
+void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) {
+  Comment cmnt(masm_, "[ ToBoolean");
+
+  // The value to convert should be popped from the stack.
+  frame_->Pop(eax);
+
+  // Fast case checks.
+
+  // 'false' => false.
+  __ cmp(eax, Factory::false_value());
+  __ j(equal, false_target);
+
+  // 'true' => true.
+  __ cmp(eax, Factory::true_value());
+  __ j(equal, true_target);
+
+  // 'undefined' => false.
+  __ cmp(eax, Factory::undefined_value());
+  __ j(equal, false_target);
+
+  // Smi => false iff zero.
+  ASSERT(kSmiTag == 0);
+  __ test(eax, Operand(eax));
+  __ j(zero, false_target);
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, true_target);
+
+  // Call the stub for all other cases.
+  frame_->Push(eax);  // Undo the pop(eax) from above.
+  ToBooleanStub stub;
+  __ CallStub(&stub);
+  // Convert result (eax) to condition code.
+  __ test(eax, Operand(eax));
+
+  ASSERT(not_equal == not_zero);
+  cc_reg_ = not_equal;
+}
+
+
+class FloatingPointHelper : public AllStatic {
+ public:
+  // Code pattern for loading floating point values. Input values must
+  // be either smi or heap number objects (fp values). Requirements:
+  // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as
+  // floating point numbers on FPU stack.
+  static void LoadFloatOperands(MacroAssembler* masm, Register scratch);
+  // Test if operands are smi or number objects (fp). Requirements:
+  // operand_1 in eax, operand_2 in edx; falls through on float
+  // operands, jumps to the non_float label otherwise.
+  static void CheckFloatOperands(MacroAssembler* masm,
+                                 Label* non_float,
+                                 Register scratch);
+  // Allocate a heap number in new space with undefined value.
+  // Returns tagged pointer in eax, or jumps to need_gc if new space is full.
+  static void AllocateHeapNumber(MacroAssembler* masm,
+                                 Label* need_gc,
+                                 Register scratch1,
+                                 Register scratch2);
+};
+
+
+// Flag that indicates whether or not the code for dealing with smis
+// is inlined or should be dealt with in the stub.
+enum GenericBinaryFlags {
+  SMI_CODE_IN_STUB,
+  SMI_CODE_INLINED
+};
+
+
+class GenericBinaryOpStub: public CodeStub {
+ public:
+  GenericBinaryOpStub(Token::Value op,
+                      OverwriteMode mode,
+                      GenericBinaryFlags flags)
+      : op_(op), mode_(mode), flags_(flags) { }
+
+  void GenerateSmiCode(MacroAssembler* masm, Label* slow);
+
+ private:
+  Token::Value op_;
+  OverwriteMode mode_;
+  GenericBinaryFlags flags_;
+
+  const char* GetName();
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("GenericBinaryOpStub (op %s), (mode %d, flags %d)\n",
+           Token::String(op_),
+           static_cast<int>(mode_),
+           static_cast<int>(flags_));
+  }
+#endif
+
+  // Minor key encoding in 16 bits FOOOOOOOOOOOOOMM.
+  class ModeBits: public BitField<OverwriteMode, 0, 2> {};
+  class OpBits: public BitField<Token::Value, 2, 13> {};
+  class FlagBits: public BitField<GenericBinaryFlags, 15, 1> {};
+
+  Major MajorKey() { return GenericBinaryOp; }
+  int MinorKey() {
+    // Encode the parameters in a unique 16 bit value.
+    return OpBits::encode(op_) |
+        ModeBits::encode(mode_) |
+        FlagBits::encode(flags_);
+  }
+  void Generate(MacroAssembler* masm);
+};
+
+
+const char* GenericBinaryOpStub::GetName() {
+  switch (op_) {
+  case Token::ADD: return "GenericBinaryOpStub_ADD";
+  case Token::SUB: return "GenericBinaryOpStub_SUB";
+  case Token::MUL: return "GenericBinaryOpStub_MUL";
+  case Token::DIV: return "GenericBinaryOpStub_DIV";
+  case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
+  case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
+  case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
+  case Token::SAR: return "GenericBinaryOpStub_SAR";
+  case Token::SHL: return "GenericBinaryOpStub_SHL";
+  case Token::SHR: return "GenericBinaryOpStub_SHR";
+  default:         return "GenericBinaryOpStub";
+  }
+}
+
+
+class DeferredInlineBinaryOperation: public DeferredCode {
+ public:
+  DeferredInlineBinaryOperation(CodeGenerator* generator,
+                                Token::Value op,
+                                OverwriteMode mode,
+                                GenericBinaryFlags flags)
+      : DeferredCode(generator), stub_(op, mode, flags) { }
+
+  void GenerateInlineCode() {
+    stub_.GenerateSmiCode(masm(), enter());
+  }
+
+  virtual void Generate() {
+    __ push(ebx);
+    __ CallStub(&stub_);
+    // We must preserve the eax value here, because it will be written
+    // to the top-of-stack element when getting back to the fast case
+    // code. See comment in GenericBinaryOperation where
+    // deferred->exit() is bound.
+    __ push(eax);
+  }
+
+ private:
+  GenericBinaryOpStub stub_;
+};
+
+
+void CodeGenerator::GenericBinaryOperation(Token::Value op,
+                                           OverwriteMode overwrite_mode) {
+  Comment cmnt(masm_, "[ BinaryOperation");
+  Comment cmnt_token(masm_, Token::String(op));
+
+  if (op == Token::COMMA) {
+    // Simply discard left value.
+    frame_->Pop(eax);
+    frame_->Pop();
+    frame_->Push(eax);
+    return;
+  }
+
+  // For now, we keep the old behavior and only inline the smi code
+  // for the bitwise operations.
+  GenericBinaryFlags flags;
+  switch (op) {
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR:
+      flags = SMI_CODE_INLINED;
+      break;
+
+    default:
+      flags = SMI_CODE_IN_STUB;
+      break;
+  }
+
+  if (flags == SMI_CODE_INLINED) {
+    // Create a new deferred code for the slow-case part.
+    DeferredInlineBinaryOperation* deferred =
+        new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags);
+    // Fetch the operands from the stack.
+    frame_->Pop(ebx);  // get y
+    __ mov(eax, frame_->Top());  // get x
+    // Generate the inline part of the code.
+    deferred->GenerateInlineCode();
+    // Put result back on the stack. It seems somewhat weird to let
+    // the deferred code jump back before the assignment to the frame
+    // top, but this is just to let the peephole optimizer get rid of
+    // more code.
+    __ bind(deferred->exit());
+    __ mov(frame_->Top(), eax);
+  } else {
+    // Call the stub and push the result to the stack.
+    GenericBinaryOpStub stub(op, overwrite_mode, flags);
+    __ CallStub(&stub);
+    frame_->Push(eax);
+  }
+}
+
+
+class DeferredInlinedSmiOperation: public DeferredCode {
+ public:
+  DeferredInlinedSmiOperation(CodeGenerator* generator,
+                              Token::Value op, int value,
+                              OverwriteMode overwrite_mode) :
+      DeferredCode(generator), op_(op), value_(value),
+      overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlinedSmiOperation");
+  }
+  virtual void Generate() {
+    __ push(eax);
+    __ push(Immediate(Smi::FromInt(value_)));
+    GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  Token::Value op_;
+  int value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+class DeferredInlinedSmiOperationReversed: public DeferredCode {
+ public:
+  DeferredInlinedSmiOperationReversed(CodeGenerator* generator,
+                                      Token::Value op, int value,
+                                      OverwriteMode overwrite_mode) :
+      DeferredCode(generator), op_(op), value_(value),
+      overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlinedSmiOperationReversed");
+  }
+  virtual void Generate() {
+    __ push(Immediate(Smi::FromInt(value_)));
+    __ push(eax);
+    GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  Token::Value op_;
+  int value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+class DeferredInlinedSmiAdd: public DeferredCode {
+ public:
+  DeferredInlinedSmiAdd(CodeGenerator* generator, int value,
+                        OverwriteMode overwrite_mode) :
+      DeferredCode(generator), value_(value), overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlinedSmiAdd");
+  }
+
+  virtual void Generate() {
+    // Undo the optimistic add operation and call the shared stub.
+    Immediate immediate(Smi::FromInt(value_));
+    __ sub(Operand(eax), immediate);
+    __ push(eax);
+    __ push(immediate);
+    GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  int value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+class DeferredInlinedSmiAddReversed: public DeferredCode {
+ public:
+  DeferredInlinedSmiAddReversed(CodeGenerator* generator, int value,
+                        OverwriteMode overwrite_mode) :
+      DeferredCode(generator), value_(value), overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlinedSmiAddReversed");
+  }
+
+  virtual void Generate() {
+    // Undo the optimistic add operation and call the shared stub.
+    Immediate immediate(Smi::FromInt(value_));
+    __ sub(Operand(eax), immediate);
+    __ push(immediate);
+    __ push(eax);
+    GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, SMI_CODE_INLINED);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  int value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+class DeferredInlinedSmiSub: public DeferredCode {
+ public:
+  DeferredInlinedSmiSub(CodeGenerator* generator, int value,
+                        OverwriteMode overwrite_mode) :
+      DeferredCode(generator), value_(value), overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlinedSmiSub");
+  }
+
+  virtual void Generate() {
+    // Undo the optimistic sub operation and call the shared stub.
+    Immediate immediate(Smi::FromInt(value_));
+    __ add(Operand(eax), immediate);
+    __ push(eax);
+    __ push(immediate);
+    GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  int value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+class DeferredInlinedSmiSubReversed: public DeferredCode {
+ public:
+  // tos_reg is used to save the TOS value before reversing the operands
+  // eax will contain the immediate value after undoing the optimistic sub.
+  DeferredInlinedSmiSubReversed(CodeGenerator* generator, Register tos_reg,
+                                OverwriteMode overwrite_mode) :
+      DeferredCode(generator), tos_reg_(tos_reg),
+      overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlinedSmiSubReversed");
+  }
+
+  virtual void Generate() {
+    // Undo the optimistic sub operation and call the shared stub.
+    __ add(eax, Operand(tos_reg_));
+    __ push(eax);
+    __ push(tos_reg_);
+    GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, SMI_CODE_INLINED);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  Register tos_reg_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+void CodeGenerator::SmiOperation(Token::Value op,
+                                 Handle<Object> value,
+                                 bool reversed,
+                                 OverwriteMode overwrite_mode) {
+  // NOTE: This is an attempt to inline (a bit) more of the code for
+  // some possible smi operations (like + and -) when (at least) one
+  // of the operands is a literal smi. With this optimization, the
+  // performance of the system is increased by ~15%, and the generated
+  // code size is increased by ~1% (measured on a combination of
+  // different benchmarks).
+
+  // TODO(1217802): Optimize some special cases of operations
+  // involving a smi literal (multiply by 2, shift by 0, etc.).
+
+  // Get the literal value.
+  int int_value = Smi::cast(*value)->value();
+  ASSERT(is_intn(int_value, kMaxSmiInlinedBits));
+
+  switch (op) {
+    case Token::ADD: {
+      DeferredCode* deferred = NULL;
+      if (!reversed) {
+        deferred = new DeferredInlinedSmiAdd(this, int_value, overwrite_mode);
+      } else {
+        deferred = new DeferredInlinedSmiAddReversed(this, int_value,
+                                                     overwrite_mode);
+      }
+      frame_->Pop(eax);
+      __ add(Operand(eax), Immediate(value));
+      __ j(overflow, deferred->enter(), not_taken);
+      __ test(eax, Immediate(kSmiTagMask));
+      __ j(not_zero, deferred->enter(), not_taken);
+      __ bind(deferred->exit());
+      frame_->Push(eax);
+      break;
+    }
+
+    case Token::SUB: {
+      DeferredCode* deferred = NULL;
+      frame_->Pop(eax);
+      if (!reversed) {
+        deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode);
+        __ sub(Operand(eax), Immediate(value));
+      } else {
+        deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode);
+        __ mov(edx, Operand(eax));
+        __ mov(Operand(eax), Immediate(value));
+        __ sub(eax, Operand(edx));
+      }
+      __ j(overflow, deferred->enter(), not_taken);
+      __ test(eax, Immediate(kSmiTagMask));
+      __ j(not_zero, deferred->enter(), not_taken);
+      __ bind(deferred->exit());
+      frame_->Push(eax);
+      break;
+    }
+
+    case Token::SAR: {
+      if (reversed) {
+        frame_->Pop(eax);
+        frame_->Push(Immediate(value));
+        frame_->Push(eax);
+        GenericBinaryOperation(op, overwrite_mode);
+      } else {
+        int shift_value = int_value & 0x1f;  // only least significant 5 bits
+        DeferredCode* deferred =
+          new DeferredInlinedSmiOperation(this, Token::SAR, shift_value,
+                                          overwrite_mode);
+        frame_->Pop(eax);
+        __ test(eax, Immediate(kSmiTagMask));
+        __ j(not_zero, deferred->enter(), not_taken);
+        __ sar(eax, shift_value);
+        __ and_(eax, ~kSmiTagMask);
+        __ bind(deferred->exit());
+        frame_->Push(eax);
+      }
+      break;
+    }
+
+    case Token::SHR: {
+      if (reversed) {
+        frame_->Pop(eax);
+        frame_->Push(Immediate(value));
+        frame_->Push(eax);
+        GenericBinaryOperation(op, overwrite_mode);
+      } else {
+        int shift_value = int_value & 0x1f;  // only least significant 5 bits
+        DeferredCode* deferred =
+        new DeferredInlinedSmiOperation(this, Token::SHR, shift_value,
+                                        overwrite_mode);
+        frame_->Pop(eax);
+        __ test(eax, Immediate(kSmiTagMask));
+        __ mov(ebx, Operand(eax));
+        __ j(not_zero, deferred->enter(), not_taken);
+        __ sar(ebx, kSmiTagSize);
+        __ shr(ebx, shift_value);
+        __ test(ebx, Immediate(0xc0000000));
+        __ j(not_zero, deferred->enter(), not_taken);
+        // tag result and store it in TOS (eax)
+        ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+        __ lea(eax, Operand(ebx, times_2, kSmiTag));
+        __ bind(deferred->exit());
+        frame_->Push(eax);
+      }
+      break;
+    }
+
+    case Token::SHL: {
+      if (reversed) {
+        frame_->Pop(eax);
+        frame_->Push(Immediate(value));
+        frame_->Push(eax);
+        GenericBinaryOperation(op, overwrite_mode);
+      } else {
+        int shift_value = int_value & 0x1f;  // only least significant 5 bits
+        DeferredCode* deferred =
+        new DeferredInlinedSmiOperation(this, Token::SHL, shift_value,
+                                        overwrite_mode);
+        frame_->Pop(eax);
+        __ test(eax, Immediate(kSmiTagMask));
+        __ mov(ebx, Operand(eax));
+        __ j(not_zero, deferred->enter(), not_taken);
+        __ sar(ebx, kSmiTagSize);
+        __ shl(ebx, shift_value);
+        __ lea(ecx, Operand(ebx, 0x40000000));
+        __ test(ecx, Immediate(0x80000000));
+        __ j(not_zero, deferred->enter(), not_taken);
+        // tag result and store it in TOS (eax)
+        ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+        __ lea(eax, Operand(ebx, times_2, kSmiTag));
+        __ bind(deferred->exit());
+        frame_->Push(eax);
+      }
+      break;
+    }
+
+    case Token::BIT_OR:
+    case Token::BIT_XOR:
+    case Token::BIT_AND: {
+      DeferredCode* deferred = NULL;
+      if (!reversed) {
+        deferred =  new DeferredInlinedSmiOperation(this, op, int_value,
+                                                    overwrite_mode);
+      } else {
+        deferred = new DeferredInlinedSmiOperationReversed(this, op, int_value,
+                                                           overwrite_mode);
+      }
+      frame_->Pop(eax);
+      __ test(eax, Immediate(kSmiTagMask));
+      __ j(not_zero, deferred->enter(), not_taken);
+      if (op == Token::BIT_AND) {
+        __ and_(Operand(eax), Immediate(value));
+      } else if (op == Token::BIT_XOR) {
+        __ xor_(Operand(eax), Immediate(value));
+      } else {
+        ASSERT(op == Token::BIT_OR);
+        __ or_(Operand(eax), Immediate(value));
+      }
+      __ bind(deferred->exit());
+      frame_->Push(eax);
+      break;
+    }
+
+    default: {
+      if (!reversed) {
+        frame_->Push(Immediate(value));
+      } else {
+        frame_->Pop(eax);
+        frame_->Push(Immediate(value));
+        frame_->Push(eax);
+      }
+      GenericBinaryOperation(op, overwrite_mode);
+      break;
+    }
+  }
+}
+
+
+class CompareStub: public CodeStub {
+ public:
+  CompareStub(Condition cc, bool strict) : cc_(cc), strict_(strict) { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  Condition cc_;
+  bool strict_;
+
+  Major MajorKey() { return Compare; }
+
+  int MinorKey() {
+    // Encode the three parameters in a unique 16 bit value.
+    ASSERT(static_cast<int>(cc_) < (1 << 15));
+    return (static_cast<int>(cc_) << 1) | (strict_ ? 1 : 0);
+  }
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("CompareStub (cc %d), (strict %s)\n",
+           static_cast<int>(cc_),
+           strict_ ? "true" : "false");
+  }
+#endif
+};
+
+
+void CodeGenerator::Comparison(Condition cc, bool strict) {
+  // Strict only makes sense for equality comparisons.
+  ASSERT(!strict || cc == equal);
+
+  // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
+  if (cc == greater || cc == less_equal) {
+    cc = ReverseCondition(cc);
+    frame_->Pop(edx);
+    frame_->Pop(eax);
+  } else {
+    frame_->Pop(eax);
+    frame_->Pop(edx);
+  }
+
+  // Check for the smi case.
+  Label is_smi, done;
+  __ mov(ecx, Operand(eax));
+  __ or_(ecx, Operand(edx));
+  __ test(ecx, Immediate(kSmiTagMask));
+  __ j(zero, &is_smi, taken);
+
+  // When non-smi, call out to the compare stub.  "parameters" setup by
+  // calling code in edx and eax and "result" is returned in the flags.
+  CompareStub stub(cc, strict);
+  __ CallStub(&stub);
+  if (cc == equal) {
+    __ test(eax, Operand(eax));
+  } else {
+    __ cmp(eax, 0);
+  }
+  __ jmp(&done);
+
+  // Test smi equality by pointer comparison.
+  __ bind(&is_smi);
+  __ cmp(edx, Operand(eax));
+  // Fall through to |done|.
+
+  __ bind(&done);
+  cc_reg_ = cc;
+}
+
+
+class SmiComparisonDeferred: public DeferredCode {
+ public:
+  SmiComparisonDeferred(CodeGenerator* generator,
+                        Condition cc,
+                        bool strict,
+                        int value)
+      : DeferredCode(generator), cc_(cc), strict_(strict), value_(value) {
+    set_comment("[ ComparisonDeferred");
+  }
+  virtual void Generate();
+
+ private:
+  Condition cc_;
+  bool strict_;
+  int value_;
+};
+
+
+void SmiComparisonDeferred::Generate() {
+  CompareStub stub(cc_, strict_);
+  // Setup parameters and call stub.
+  __ mov(edx, Operand(eax));
+  __ mov(Operand(eax), Immediate(Smi::FromInt(value_)));
+  __ CallStub(&stub);
+  __ cmp(eax, 0);
+  // "result" is returned in the flags
+}
+
+
+void CodeGenerator::SmiComparison(Condition cc,
+                                      Handle<Object> value,
+                                      bool strict) {
+  // Strict only makes sense for equality comparisons.
+  ASSERT(!strict || cc == equal);
+
+  int int_value = Smi::cast(*value)->value();
+  ASSERT(is_intn(int_value, kMaxSmiInlinedBits));
+
+  SmiComparisonDeferred* deferred =
+      new SmiComparisonDeferred(this, cc, strict, int_value);
+  frame_->Pop(eax);
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(not_zero, deferred->enter(), not_taken);
+  // Test smi equality by pointer comparison.
+  __ cmp(Operand(eax), Immediate(value));
+  __ bind(deferred->exit());
+  cc_reg_ = cc;
+}
+
+
+class CallFunctionStub: public CodeStub {
+ public:
+  explicit CallFunctionStub(int argc) : argc_(argc) { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  int argc_;
+
+#ifdef DEBUG
+  void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
+#endif
+
+  Major MajorKey() { return CallFunction; }
+  int MinorKey() { return argc_; }
+};
+
+
+// Call the function just below TOS on the stack with the given
+// arguments. The receiver is the TOS.
+void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
+                                          int position) {
+  // Push the arguments ("left-to-right") on the stack.
+  for (int i = 0; i < args->length(); i++) {
+    Load(args->at(i));
+  }
+
+  // Record the position for debugging purposes.
+  __ RecordPosition(position);
+
+  // Use the shared code stub to call the function.
+  CallFunctionStub call_function(args->length());
+  __ CallStub(&call_function);
+
+  // Restore context and pop function from the stack.
+  __ mov(esi, frame_->Context());
+  __ mov(frame_->Top(), eax);
+}
+
+
+void CodeGenerator::Branch(bool if_true, Label* L) {
+  ASSERT(has_cc());
+  Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
+  __ j(cc, L);
+  cc_reg_ = no_condition;
+}
+
+
+void CodeGenerator::CheckStack() {
+  if (FLAG_check_stack) {
+    Label stack_is_ok;
+    StackCheckStub stub;
+    ExternalReference stack_guard_limit =
+        ExternalReference::address_of_stack_guard_limit();
+    __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+    __ j(above_equal, &stack_is_ok, taken);
+    __ CallStub(&stub);
+    __ bind(&stack_is_ok);
+  }
+}
+
+
+void CodeGenerator::VisitBlock(Block* node) {
+  Comment cmnt(masm_, "[ Block");
+  RecordStatementPosition(node);
+  node->set_break_stack_height(break_stack_height_);
+  VisitStatements(node->statements());
+  __ bind(node->break_target());
+}
+
+
+void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+  frame_->Push(Immediate(pairs));
+  frame_->Push(esi);
+  frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
+  __ CallRuntime(Runtime::kDeclareGlobals, 3);
+  // Return value is ignored.
+}
+
+
+void CodeGenerator::VisitDeclaration(Declaration* node) {
+  Comment cmnt(masm_, "[ Declaration");
+  Variable* var = node->proxy()->var();
+  ASSERT(var != NULL);  // must have been resolved
+  Slot* slot = var->slot();
+
+  // 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) {
+    // Variables with a "LOOKUP" slot were introduced as non-locals
+    // during variable resolution and must have mode DYNAMIC.
+    ASSERT(var->mode() == Variable::DYNAMIC);
+    // For now, just do a runtime call.
+    frame_->Push(esi);
+    frame_->Push(Immediate(var->name()));
+    // Declaration nodes are always introduced in one of two modes.
+    ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
+    PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
+    frame_->Push(Immediate(Smi::FromInt(attr)));
+    // Push initial value, if any.
+    // 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 (node->mode() == Variable::CONST) {
+      frame_->Push(Immediate(Factory::the_hole_value()));
+    } else if (node->fun() != NULL) {
+      Load(node->fun());
+    } else {
+      frame_->Push(Immediate(0));  // no initial value!
+    }
+    __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+    // Ignore the return value (declarations are statements).
+    return;
+  }
+
+  ASSERT(!var->is_global());
+
+  // If we have a function or a constant, we need to initialize the variable.
+  Expression* val = NULL;
+  if (node->mode() == Variable::CONST) {
+    val = new Literal(Factory::the_hole_value());
+  } else {
+    val = node->fun();  // NULL if we don't have a function
+  }
+
+  if (val != NULL) {
+    // Set initial value.
+    Reference target(this, node->proxy());
+    ASSERT(target.is_slot());
+    Load(val);
+    target.SetValue(NOT_CONST_INIT);
+    // Get rid of the assigned value (declarations are statements).  It's
+    // safe to pop the value lying on top of the reference before unloading
+    // the reference itself (which preserves the top of stack) because we
+    // know that it is a zero-sized reference.
+    frame_->Pop();
+  }
+}
+
+
+void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
+  Comment cmnt(masm_, "[ ExpressionStatement");
+  RecordStatementPosition(node);
+  Expression* expression = node->expression();
+  expression->MarkAsStatement();
+  Load(expression);
+  // Remove the lingering expression result from the top of stack.
+  frame_->Pop();
+}
+
+
+void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
+  Comment cmnt(masm_, "// EmptyStatement");
+  // nothing to do
+}
+
+
+void CodeGenerator::VisitIfStatement(IfStatement* node) {
+  Comment cmnt(masm_, "[ IfStatement");
+  // Generate different code depending on which
+  // parts of the if statement are present or not.
+  bool has_then_stm = node->HasThenStatement();
+  bool has_else_stm = node->HasElseStatement();
+
+  RecordStatementPosition(node);
+  Label exit;
+  if (has_then_stm && has_else_stm) {
+    Label then;
+    Label else_;
+    // if (cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
+    Branch(false, &else_);
+    // then
+    __ bind(&then);
+    Visit(node->then_statement());
+    __ jmp(&exit);
+    // else
+    __ bind(&else_);
+    Visit(node->else_statement());
+
+  } else if (has_then_stm) {
+    ASSERT(!has_else_stm);
+    Label then;
+    // if (cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
+    Branch(false, &exit);
+    // then
+    __ bind(&then);
+    Visit(node->then_statement());
+
+  } else if (has_else_stm) {
+    ASSERT(!has_then_stm);
+    Label else_;
+    // if (!cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
+    Branch(true, &exit);
+    // else
+    __ bind(&else_);
+    Visit(node->else_statement());
+
+  } else {
+    ASSERT(!has_then_stm && !has_else_stm);
+    // if (cond)
+    LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
+    if (has_cc()) {
+      cc_reg_ = no_condition;
+    } else {
+      // No cc value set up, that means the boolean was pushed.
+      // Pop it again, since it is not going to be used.
+      frame_->Pop();
+    }
+  }
+
+  // end
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::CleanStack(int num_bytes) {
+  ASSERT(num_bytes % kPointerSize == 0);
+  frame_->Drop(num_bytes / kPointerSize);
+}
+
+
+void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
+  Comment cmnt(masm_, "[ ContinueStatement");
+  RecordStatementPosition(node);
+  CleanStack(break_stack_height_ - node->target()->break_stack_height());
+  __ jmp(node->target()->continue_target());
+}
+
+
+void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
+  Comment cmnt(masm_, "[ BreakStatement");
+  RecordStatementPosition(node);
+  CleanStack(break_stack_height_ - node->target()->break_stack_height());
+  __ jmp(node->target()->break_target());
+}
+
+
+void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
+  Comment cmnt(masm_, "[ ReturnStatement");
+  RecordStatementPosition(node);
+  Load(node->expression());
+
+  // Move the function result into eax
+  frame_->Pop(eax);
+
+  // If we're inside a try statement or the return instruction
+  // sequence has been generated, we just jump to that
+  // point. Otherwise, we generate the return instruction sequence and
+  // bind the function return label.
+  if (is_inside_try_ || function_return_.is_bound()) {
+    __ jmp(&function_return_);
+  } else {
+    __ bind(&function_return_);
+    if (FLAG_trace) {
+      frame_->Push(eax);  // undo the pop(eax) from above
+      __ CallRuntime(Runtime::kTraceExit, 1);
+    }
+
+    // Add a label for checking the size of the code used for returning.
+    Label check_exit_codesize;
+    __ bind(&check_exit_codesize);
+
+    // Leave the frame and return popping the arguments and the
+    // receiver.
+    frame_->Exit();
+    __ ret((scope_->num_parameters() + 1) * kPointerSize);
+
+    // Check that the size of the code used for returning matches what is
+    // expected by the debugger.
+    ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
+              __ SizeOfCodeGeneratedSince(&check_exit_codesize));
+  }
+}
+
+
+void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
+  Comment cmnt(masm_, "[ WithEnterStatement");
+  RecordStatementPosition(node);
+  Load(node->expression());
+  __ CallRuntime(Runtime::kPushContext, 1);
+
+  if (kDebug) {
+    Label verified_true;
+    // Verify eax and esi are the same in debug mode
+    __ cmp(eax, Operand(esi));
+    __ j(equal, &verified_true);
+    __ int3();
+    __ bind(&verified_true);
+  }
+
+  // Update context local.
+  __ mov(frame_->Context(), esi);
+}
+
+
+void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
+  Comment cmnt(masm_, "[ WithExitStatement");
+  // Pop context.
+  __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
+  // Update context local.
+  __ mov(frame_->Context(), esi);
+}
+
+int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
+    return kFastSwitchMaxOverheadFactor;
+}
+
+int CodeGenerator::FastCaseSwitchMinCaseCount() {
+    return kFastSwitchMinCaseCount;
+}
+
+// Generate a computed jump to a switch case.
+void CodeGenerator::GenerateFastCaseSwitchJumpTable(
+    SwitchStatement* node,
+    int min_index,
+    int range,
+    Label* fail_label,
+    Vector<Label*> case_targets,
+    Vector<Label> case_labels) {
+  // Notice: Internal references, used by both the jmp instruction and
+  // the table entries, need to be relocated if the buffer grows. This
+  // prevents the forward use of Labels, since a displacement cannot
+  // survive relocation, and it also cannot safely be distinguished
+  // from a real address.  Instead we put in zero-values as
+  // placeholders, and fill in the addresses after the labels have been
+  // bound.
+
+  frame_->Pop(eax);  // supposed smi
+  // check range of value, if outside [0..length-1] jump to default/end label.
+  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+  if (min_index != 0) {
+    __ sub(Operand(eax), Immediate(min_index << kSmiTagSize));
+  }
+  __ test(eax, Immediate(0x80000000 | kSmiTagMask));  // negative or not Smi
+  __ j(not_equal, fail_label, not_taken);
+  __ cmp(eax, range << kSmiTagSize);
+  __ j(greater_equal, fail_label, not_taken);
+
+  // 0 is placeholder.
+  __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE));
+  // calculate address to overwrite later with actual address of table.
+  int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t);
+
+  __ Align(4);
+  Label table_start;
+  __ bind(&table_start);
+  __ WriteInternalReference(jump_table_ref, table_start);
+
+  for (int i = 0; i < range; i++) {
+    // table entry, 0 is placeholder for case address
+    __ dd(0x0, RelocInfo::INTERNAL_REFERENCE);
+  }
+
+  GenerateFastCaseSwitchCases(node, case_labels);
+
+  for (int i = 0, entry_pos = table_start.pos();
+       i < range; i++, entry_pos += sizeof(uint32_t)) {
+    __ WriteInternalReference(entry_pos, *case_targets[i]);
+  }
+}
+
+
+void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
+  Comment cmnt(masm_, "[ SwitchStatement");
+  RecordStatementPosition(node);
+  node->set_break_stack_height(break_stack_height_);
+
+  Load(node->tag());
+
+  if (TryGenerateFastCaseSwitchStatement(node)) {
+    return;
+  }
+
+  Label next, fall_through, default_case;
+  ZoneList<CaseClause*>* cases = node->cases();
+  int length = cases->length();
+
+  for (int i = 0; i < length; i++) {
+    CaseClause* clause = cases->at(i);
+    Comment cmnt(masm_, "[ case clause");
+
+    if (clause->is_default()) {
+      // Continue matching cases. The program will execute the default case's
+      // statements if it does not match any of the cases.
+      __ jmp(&next);
+
+      // Bind the default case label, so we can branch to it when we
+      // have compared against all other cases.
+      ASSERT(default_case.is_unused());  // at most one default clause
+      __ bind(&default_case);
+    } else {
+      __ bind(&next);
+      next.Unuse();
+      __ mov(eax, frame_->Top());
+      frame_->Push(eax);  // duplicate TOS
+      Load(clause->label());
+      Comparison(equal, true);
+      Branch(false, &next);
+    }
+
+    // Entering the case statement for the first time. Remove the switch value
+    // from the stack.
+    frame_->Pop(eax);
+
+    // Generate code for the body.
+    // This is also the target for the fall through from the previous case's
+    // statements which has to skip over the matching code and the popping of
+    // the switch value.
+    __ bind(&fall_through);
+    fall_through.Unuse();
+    VisitStatements(clause->statements());
+    __ jmp(&fall_through);
+  }
+
+  __ bind(&next);
+  // Reached the end of the case statements without matching any of the cases.
+  if (default_case.is_bound()) {
+    // A default case exists -> execute its statements.
+    __ jmp(&default_case);
+  } else {
+    // Remove the switch value from the stack.
+    frame_->Pop();
+  }
+
+  __ bind(&fall_through);
+  __ bind(node->break_target());
+}
+
+
+void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
+  Comment cmnt(masm_, "[ LoopStatement");
+  RecordStatementPosition(node);
+  node->set_break_stack_height(break_stack_height_);
+
+  // simple condition analysis
+  enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
+  if (node->cond() == NULL) {
+    ASSERT(node->type() == LoopStatement::FOR_LOOP);
+    info = ALWAYS_TRUE;
+  } else {
+    Literal* lit = node->cond()->AsLiteral();
+    if (lit != NULL) {
+      if (lit->IsTrue()) {
+        info = ALWAYS_TRUE;
+      } else if (lit->IsFalse()) {
+        info = ALWAYS_FALSE;
+      }
+    }
+  }
+
+  Label loop, entry;
+
+  // init
+  if (node->init() != NULL) {
+    ASSERT(node->type() == LoopStatement::FOR_LOOP);
+    Visit(node->init());
+  }
+  if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) {
+    __ jmp(&entry);
+  }
+
+  // body
+  __ bind(&loop);
+  CheckStack();  // TODO(1222600): ignore if body contains calls.
+  Visit(node->body());
+
+  // next
+  __ bind(node->continue_target());
+  if (node->next() != NULL) {
+    // Record source position of the statement as this code which is after the
+    // code for the body actually belongs to the loop statement and not the
+    // body.
+    RecordStatementPosition(node);
+    __ RecordPosition(node->statement_pos());
+    ASSERT(node->type() == LoopStatement::FOR_LOOP);
+    Visit(node->next());
+  }
+
+  // cond
+  __ bind(&entry);
+  switch (info) {
+    case ALWAYS_TRUE:
+      __ jmp(&loop);
+      break;
+    case ALWAYS_FALSE:
+      break;
+    case DONT_KNOW:
+      LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop,
+                    node->break_target(), true);
+      Branch(true, &loop);
+      break;
+  }
+
+  // exit
+  __ bind(node->break_target());
+}
+
+
+void CodeGenerator::VisitForInStatement(ForInStatement* node) {
+  Comment cmnt(masm_, "[ ForInStatement");
+  RecordStatementPosition(node);
+
+  // We keep stuff on the stack while the body is executing.
+  // Record it, so that a break/continue crossing this statement
+  // can restore the stack.
+  const int kForInStackSize = 5 * kPointerSize;
+  break_stack_height_ += kForInStackSize;
+  node->set_break_stack_height(break_stack_height_);
+
+  Label loop, next, entry, cleanup, exit, primitive, jsobject;
+  Label end_del_check, fixed_array;
+
+  // Get the object to enumerate over (converted to JSObject).
+  Load(node->enumerable());
+
+  // Both SpiderMonkey and kjs ignore null and undefined in contrast
+  // to the specification.  12.6.4 mandates a call to ToObject.
+  frame_->Pop(eax);
+
+  // eax: value to be iterated over
+  __ cmp(eax, Factory::undefined_value());
+  __ j(equal, &exit);
+  __ cmp(eax, Factory::null_value());
+  __ j(equal, &exit);
+
+  // Stack layout in body:
+  // [iteration counter (smi)] <- slot 0
+  // [length of array]         <- slot 1
+  // [FixedArray]              <- slot 2
+  // [Map or 0]                <- slot 3
+  // [Object]                  <- slot 4
+
+  // Check if enumerable is already a JSObject
+  // eax: value to be iterated over
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &primitive);
+  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(above_equal, &jsobject);
+
+  __ bind(&primitive);
+  frame_->Push(eax);
+  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+  // function call returns the value in eax, which is where we want it below
+
+
+  __ bind(&jsobject);
+
+  // Get the set of properties (as a FixedArray or Map).
+  // eax: value to be iterated over
+  frame_->Push(eax);  // push the object being iterated over (slot 4)
+
+  frame_->Push(eax);  // push the Object (slot 4) for the runtime call
+  __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+
+  // If we got a Map, we can do a fast modification check.
+  // Otherwise, we got a FixedArray, and we have to do a slow check.
+  // eax: map or fixed array (result from call to
+  // Runtime::kGetPropertyNamesFast)
+  __ mov(edx, Operand(eax));
+  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ cmp(ecx, Factory::meta_map());
+  __ j(not_equal, &fixed_array);
+
+  // Get enum cache
+  // eax: map (result from call to Runtime::kGetPropertyNamesFast)
+  __ mov(ecx, Operand(eax));
+  __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
+  // Get the bridge array held in the enumeration index field.
+  __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
+  // Get the cache from the bridge array.
+  __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
+
+  frame_->Push(eax);  // <- slot 3
+  frame_->Push(edx);  // <- slot 2
+  __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
+  __ shl(eax, kSmiTagSize);
+  frame_->Push(eax);  // <- slot 1
+  frame_->Push(Immediate(Smi::FromInt(0)));  // <- slot 0
+  __ jmp(&entry);
+
+
+  __ bind(&fixed_array);
+
+  // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast)
+  frame_->Push(Immediate(Smi::FromInt(0)));  // <- slot 3
+  frame_->Push(eax);  // <- slot 2
+
+  // Push the length of the array and the initial index onto the stack.
+  __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
+  __ shl(eax, kSmiTagSize);
+  frame_->Push(eax);  // <- slot 1
+  frame_->Push(Immediate(Smi::FromInt(0)));  // <- slot 0
+  __ jmp(&entry);
+
+  // Body.
+  __ bind(&loop);
+  Visit(node->body());
+
+  // Next.
+  __ bind(node->continue_target());
+  __ bind(&next);
+  frame_->Pop(eax);
+  __ add(Operand(eax), Immediate(Smi::FromInt(1)));
+  frame_->Push(eax);
+
+  // Condition.
+  __ bind(&entry);
+
+  __ mov(eax, frame_->Element(0));  // load the current count
+  __ cmp(eax, frame_->Element(1));  // compare to the array length
+  __ j(above_equal, &cleanup);
+
+  // Get the i'th entry of the array.
+  __ mov(edx, frame_->Element(2));
+  __ mov(ebx, Operand(edx, eax, times_2,
+                      FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // Get the expected map from the stack or a zero map in the
+  // permanent slow case eax: current iteration count ebx: i'th entry
+  // of the enum cache
+  __ mov(edx, frame_->Element(3));
+  // Check if the expected map still matches that of the enumerable.
+  // If not, we have to filter the key.
+  // eax: current iteration count
+  // ebx: i'th entry of the enum cache
+  // edx: expected map value
+  __ mov(ecx, frame_->Element(4));
+  __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
+  __ cmp(ecx, Operand(edx));
+  __ j(equal, &end_del_check);
+
+  // Convert the entry to a string (or null if it isn't a property anymore).
+  frame_->Push(frame_->Element(4));  // push enumerable
+  frame_->Push(ebx);  // push entry
+  __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
+  __ mov(ebx, Operand(eax));
+
+  // If the property has been removed while iterating, we just skip it.
+  __ cmp(ebx, Factory::null_value());
+  __ j(equal, &next);
+
+
+  __ bind(&end_del_check);
+
+  // Store the entry in the 'each' expression and take another spin in the loop.
+  // edx: i'th entry of the enum cache (or string there of)
+  frame_->Push(ebx);
+  { Reference each(this, node->each());
+    if (!each.is_illegal()) {
+      if (each.size() > 0) {
+        frame_->Push(frame_->Element(each.size()));
+      }
+      // If the reference was to a slot we rely on the convenient property
+      // that it doesn't matter whether a value (eg, ebx pushed above) is
+      // right on top of or right underneath a zero-sized reference.
+      each.SetValue(NOT_CONST_INIT);
+      if (each.size() > 0) {
+        // It's safe to pop the value lying on top of the reference before
+        // unloading the reference itself (which preserves the top of stack,
+        // ie, now the topmost value of the non-zero sized reference), since
+        // we will discard the top of stack after unloading the reference
+        // anyway.
+        frame_->Pop();
+      }
+    }
+  }
+  // Discard the i'th entry pushed above or else the remainder of the
+  // reference, whichever is currently on top of the stack.
+  frame_->Pop();
+  CheckStack();  // TODO(1222600): ignore if body contains calls.
+  __ jmp(&loop);
+
+  // Cleanup.
+  __ bind(&cleanup);
+  __ bind(node->break_target());
+  frame_->Drop(5);
+
+  // Exit.
+  __ bind(&exit);
+
+  break_stack_height_ -= kForInStackSize;
+}
+
+
+void CodeGenerator::VisitTryCatch(TryCatch* node) {
+  Comment cmnt(masm_, "[ TryCatch");
+
+  Label try_block, exit;
+
+  __ call(&try_block);
+  // --- Catch block ---
+  frame_->Push(eax);
+
+  // Store the caught exception in the catch variable.
+  { Reference ref(this, node->catch_var());
+    ASSERT(ref.is_slot());
+    // Load the exception to the top of the stack.  Here we make use of the
+    // convenient property that it doesn't matter whether a value is
+    // immediately on top of or underneath a zero-sized reference.
+    ref.SetValue(NOT_CONST_INIT);
+  }
+
+  // Remove the exception from the stack.
+  frame_->Pop();
+
+  VisitStatements(node->catch_block()->statements());
+  __ jmp(&exit);
+
+
+  // --- Try block ---
+  __ bind(&try_block);
+
+  __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
+  // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS
+  frame_->Push(eax);  //
+
+  // Shadow the labels for all escapes from the try block, including
+  // returns.  During shadowing, the original label is hidden as the
+  // LabelShadow and operations on the original actually affect the
+  // shadowing label.
+  //
+  // We should probably try to unify the escaping labels and the return
+  // label.
+  int nof_escapes = node->escaping_labels()->length();
+  List<LabelShadow*> shadows(1 + nof_escapes);
+  shadows.Add(new LabelShadow(&function_return_));
+  for (int i = 0; i < nof_escapes; i++) {
+    shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
+  }
+
+  // Generate code for the statements in the try block.
+  bool was_inside_try = is_inside_try_;
+  is_inside_try_ = true;
+  VisitStatements(node->try_block()->statements());
+  is_inside_try_ = was_inside_try;
+
+  // Stop the introduced shadowing and count the number of required unlinks.
+  // After shadowing stops, the original labels are unshadowed and the
+  // LabelShadows represent the formerly shadowing labels.
+  int nof_unlinks = 0;
+  for (int i = 0; i <= nof_escapes; i++) {
+    shadows[i]->StopShadowing();
+    if (shadows[i]->is_linked()) nof_unlinks++;
+  }
+
+  // Get an external reference to the handler address.
+  ExternalReference handler_address(Top::k_handler_address);
+
+  // Make sure that there's nothing left on the stack above the
+  // handler structure.
+  if (FLAG_debug_code) {
+    __ mov(eax, Operand::StaticVariable(handler_address));
+    __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement));
+    __ cmp(esp, Operand(eax));
+    __ Assert(equal, "stack pointer should point to top handler");
+  }
+
+  // Unlink from try chain.
+  frame_->Pop(eax);
+  __ mov(Operand::StaticVariable(handler_address), eax);  // TOS == next_sp
+  frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
+  // next_sp popped.
+  if (nof_unlinks > 0) __ jmp(&exit);
+
+  // Generate unlink code for the (formerly) shadowing labels that have been
+  // jumped to.
+  for (int i = 0; i <= nof_escapes; i++) {
+    if (shadows[i]->is_linked()) {
+      // Unlink from try chain; be careful not to destroy the TOS.
+      __ bind(shadows[i]);
+
+      // Reload sp from the top handler, because some statements that we
+      // break from (eg, for...in) may have left stuff on the stack.
+      __ mov(edx, Operand::StaticVariable(handler_address));
+      const int kNextOffset = StackHandlerConstants::kNextOffset +
+          StackHandlerConstants::kAddressDisplacement;
+      __ lea(esp, Operand(edx, kNextOffset));
+
+      frame_->Pop(Operand::StaticVariable(handler_address));
+      frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
+      // next_sp popped.
+      __ jmp(shadows[i]->original_label());
+    }
+  }
+
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::VisitTryFinally(TryFinally* node) {
+  Comment cmnt(masm_, "[ TryFinally");
+
+  // State: Used to keep track of reason for entering the finally
+  // block. Should probably be extended to hold information for
+  // break/continue from within the try block.
+  enum { FALLING, THROWING, JUMPING };
+
+  Label exit, unlink, try_block, finally_block;
+
+  __ call(&try_block);
+
+  frame_->Push(eax);
+  // In case of thrown exceptions, this is where we continue.
+  __ Set(ecx, Immediate(Smi::FromInt(THROWING)));
+  __ jmp(&finally_block);
+
+
+  // --- Try block ---
+  __ bind(&try_block);
+
+  __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
+  // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS
+  frame_->Push(eax);
+
+  // Shadow the labels for all escapes from the try block, including
+  // returns.  During shadowing, the original label is hidden as the
+  // LabelShadow and operations on the original actually affect the
+  // shadowing label.
+  //
+  // We should probably try to unify the escaping labels and the return
+  // label.
+  int nof_escapes = node->escaping_labels()->length();
+  List<LabelShadow*> shadows(1 + nof_escapes);
+  shadows.Add(new LabelShadow(&function_return_));
+  for (int i = 0; i < nof_escapes; i++) {
+    shadows.Add(new LabelShadow(node->escaping_labels()->at(i)));
+  }
+
+  // Generate code for the statements in the try block.
+  bool was_inside_try = is_inside_try_;
+  is_inside_try_ = true;
+  VisitStatements(node->try_block()->statements());
+  is_inside_try_ = was_inside_try;
+
+  // Stop the introduced shadowing and count the number of required unlinks.
+  // After shadowing stops, the original labels are unshadowed and the
+  // LabelShadows represent the formerly shadowing labels.
+  int nof_unlinks = 0;
+  for (int i = 0; i <= nof_escapes; i++) {
+    shadows[i]->StopShadowing();
+    if (shadows[i]->is_linked()) nof_unlinks++;
+  }
+
+  // Set the state on the stack to FALLING.
+  frame_->Push(Immediate(Factory::undefined_value()));  // fake TOS
+  __ Set(ecx, Immediate(Smi::FromInt(FALLING)));
+  if (nof_unlinks > 0) __ jmp(&unlink);
+
+  // Generate code to set the state for the (formerly) shadowing labels that
+  // have been jumped to.
+  for (int i = 0; i <= nof_escapes; i++) {
+    if (shadows[i]->is_linked()) {
+      __ bind(shadows[i]);
+      if (shadows[i]->original_label() == &function_return_) {
+        // If this label shadowed the function return, materialize the
+        // return value on the stack.
+        frame_->Push(eax);
+      } else {
+        // Fake TOS for labels that shadowed breaks and continues.
+        frame_->Push(Immediate(Factory::undefined_value()));
+      }
+      __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i)));
+      __ jmp(&unlink);
+    }
+  }
+
+  // Unlink from try chain; be careful not to destroy the TOS.
+  __ bind(&unlink);
+  // Reload sp from the top handler, because some statements that we
+  // break from (eg, for...in) may have left stuff on the stack.
+  // Preserve the TOS in a register across stack manipulation.
+  frame_->Pop(eax);
+  ExternalReference handler_address(Top::k_handler_address);
+  __ mov(edx, Operand::StaticVariable(handler_address));
+  const int kNextOffset = StackHandlerConstants::kNextOffset +
+      StackHandlerConstants::kAddressDisplacement;
+  __ lea(esp, Operand(edx, kNextOffset));
+
+  frame_->Pop(Operand::StaticVariable(handler_address));
+  frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
+  // Next_sp popped.
+  // Preserve the TOS in a register across stack manipulation.
+  frame_->Push(eax);
+
+  // --- Finally block ---
+  __ bind(&finally_block);
+
+  // Push the state on the stack.
+  frame_->Push(ecx);
+
+  // We keep two elements on the stack - the (possibly faked) result
+  // and the state - while evaluating the finally block. Record it, so
+  // that a break/continue crossing this statement can restore the
+  // stack.
+  const int kFinallyStackSize = 2 * kPointerSize;
+  break_stack_height_ += kFinallyStackSize;
+
+  // Generate code for the statements in the finally block.
+  VisitStatements(node->finally_block()->statements());
+
+  // Restore state and return value or faked TOS.
+  frame_->Pop(ecx);
+  frame_->Pop(eax);
+  break_stack_height_ -= kFinallyStackSize;
+
+  // Generate code to jump to the right destination for all used (formerly)
+  // shadowing labels.
+  for (int i = 0; i <= nof_escapes; i++) {
+    if (shadows[i]->is_bound()) {
+      __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
+      __ j(equal, shadows[i]->original_label());
+    }
+  }
+
+  // Check if we need to rethrow the exception.
+  __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING)));
+  __ j(not_equal, &exit);
+
+  // Rethrow exception.
+  frame_->Push(eax);  // undo pop from above
+  __ CallRuntime(Runtime::kReThrow, 1);
+
+  // Done.
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
+  Comment cmnt(masm_, "[ DebuggerStatement");
+  RecordStatementPosition(node);
+  __ CallRuntime(Runtime::kDebugBreak, 0);
+  // Ignore the return value.
+}
+
+
+void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
+  ASSERT(boilerplate->IsBoilerplate());
+
+  // Push the boilerplate on the stack.
+  frame_->Push(Immediate(boilerplate));
+
+  // Create a new closure.
+  frame_->Push(esi);
+  __ CallRuntime(Runtime::kNewClosure, 2);
+  frame_->Push(eax);
+}
+
+
+void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
+  Comment cmnt(masm_, "[ FunctionLiteral");
+
+  // Build the function boilerplate and instantiate it.
+  Handle<JSFunction> boilerplate = BuildBoilerplate(node);
+  // Check for stack-overflow exception.
+  if (HasStackOverflow()) return;
+  InstantiateBoilerplate(boilerplate);
+}
+
+
+void CodeGenerator::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* node) {
+  Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
+  InstantiateBoilerplate(node->boilerplate());
+}
+
+
+void CodeGenerator::VisitConditional(Conditional* node) {
+  Comment cmnt(masm_, "[ Conditional");
+  Label then, else_, exit;
+  LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
+  Branch(false, &else_);
+  __ bind(&then);
+  Load(node->then_expression(), typeof_state());
+  __ jmp(&exit);
+  __ bind(&else_);
+  Load(node->else_expression(), typeof_state());
+  __ bind(&exit);
+}
+
+
+void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
+  if (slot->type() == Slot::LOOKUP) {
+    ASSERT(slot->var()->mode() == Variable::DYNAMIC);
+
+    // For now, just do a runtime call.
+    frame_->Push(esi);
+    frame_->Push(Immediate(slot->var()->name()));
+
+    if (typeof_state == INSIDE_TYPEOF) {
+      __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
+    } else {
+      __ CallRuntime(Runtime::kLoadContextSlot, 2);
+    }
+    frame_->Push(eax);
+
+  } else {
+    // Note: We would like to keep the assert below, but it fires because of
+    // some nasty code in LoadTypeofExpression() which should be removed...
+    // ASSERT(slot->var()->mode() != Variable::DYNAMIC);
+    if (slot->var()->mode() == Variable::CONST) {
+      // Const slots may contain 'the hole' value (the constant hasn't been
+      // initialized yet) which needs to be converted into the 'undefined'
+      // value.
+      Comment cmnt(masm_, "[ Load const");
+      Label exit;
+      __ mov(eax, SlotOperand(slot, ecx));
+      __ cmp(eax, Factory::the_hole_value());
+      __ j(not_equal, &exit);
+      __ mov(eax, Factory::undefined_value());
+      __ bind(&exit);
+      frame_->Push(eax);
+    } else {
+      frame_->Push(SlotOperand(slot, ecx));
+    }
+  }
+}
+
+
+void CodeGenerator::VisitSlot(Slot* node) {
+  Comment cmnt(masm_, "[ Slot");
+  LoadFromSlot(node, typeof_state());
+}
+
+
+void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
+  Comment cmnt(masm_, "[ VariableProxy");
+  Variable* var = node->var();
+  Expression* expr = var->rewrite();
+  if (expr != NULL) {
+    Visit(expr);
+  } else {
+    ASSERT(var->is_global());
+    Reference ref(this, node);
+    ref.GetValue(typeof_state());
+  }
+}
+
+
+void CodeGenerator::VisitLiteral(Literal* node) {
+  Comment cmnt(masm_, "[ Literal");
+  if (node->handle()->IsSmi() && !IsInlineSmi(node)) {
+    // To prevent long attacker-controlled byte sequences in code, larger
+    // Smis are loaded in two steps.
+    int bits = reinterpret_cast<int>(*node->handle());
+    __ mov(eax, bits & 0x0000FFFF);
+    __ xor_(eax, bits & 0xFFFF0000);
+    frame_->Push(eax);
+  } else {
+    frame_->Push(Immediate(node->handle()));
+  }
+}
+
+
+class RegExpDeferred: public DeferredCode {
+ public:
+  RegExpDeferred(CodeGenerator* generator, RegExpLiteral* node)
+      : DeferredCode(generator), node_(node) {
+    set_comment("[ RegExpDeferred");
+  }
+  virtual void Generate();
+ private:
+  RegExpLiteral* node_;
+};
+
+
+void RegExpDeferred::Generate() {
+  // If the entry is undefined we call the runtime system to computed
+  // the literal.
+
+  // Literal array (0).
+  __ push(ecx);
+  // Literal index (1).
+  __ push(Immediate(Smi::FromInt(node_->literal_index())));
+  // RegExp pattern (2).
+  __ push(Immediate(node_->pattern()));
+  // RegExp flags (3).
+  __ push(Immediate(node_->flags()));
+  __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
+  __ mov(ebx, Operand(eax));  // "caller" expects result in ebx
+}
+
+
+void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
+  Comment cmnt(masm_, "[ RegExp Literal");
+  RegExpDeferred* deferred = new RegExpDeferred(this, node);
+
+  // Retrieve the literal array and check the allocated entry.
+
+  // Load the function of this activation.
+  __ mov(ecx, frame_->Function());
+
+  // Load the literals array of the function.
+  __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset));
+
+  // Load the literal at the ast saved index.
+  int literal_offset =
+      FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
+  __ mov(ebx, FieldOperand(ecx, literal_offset));
+
+  // Check whether we need to materialize the RegExp object.
+  // If so, jump to the deferred code.
+  __ cmp(ebx, Factory::undefined_value());
+  __ j(equal, deferred->enter(), not_taken);
+  __ bind(deferred->exit());
+
+  // Push the literal.
+  frame_->Push(ebx);
+}
+
+
+// This deferred code stub will be used for creating the boilerplate
+// by calling Runtime_CreateObjectLiteral.
+// Each created boilerplate is stored in the JSFunction and they are
+// therefore context dependent.
+class ObjectLiteralDeferred: public DeferredCode {
+ public:
+  ObjectLiteralDeferred(CodeGenerator* generator,
+                        ObjectLiteral* node)
+      : DeferredCode(generator), node_(node) {
+    set_comment("[ ObjectLiteralDeferred");
+  }
+  virtual void Generate();
+ private:
+  ObjectLiteral* node_;
+};
+
+
+void ObjectLiteralDeferred::Generate() {
+  // If the entry is undefined we call the runtime system to compute
+  // the literal.
+
+  // Literal array (0).
+  __ push(ecx);
+  // Literal index (1).
+  __ push(Immediate(Smi::FromInt(node_->literal_index())));
+  // Constant properties (2).
+  __ push(Immediate(node_->constant_properties()));
+  __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
+  __ mov(ebx, Operand(eax));
+}
+
+
+void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
+  Comment cmnt(masm_, "[ ObjectLiteral");
+  ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
+
+  // Retrieve the literal array and check the allocated entry.
+
+  // Load the function of this activation.
+  __ mov(ecx, frame_->Function());
+
+  // Load the literals array of the function.
+  __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset));
+
+  // Load the literal at the ast saved index.
+  int literal_offset =
+      FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
+  __ mov(ebx, FieldOperand(ecx, literal_offset));
+
+  // Check whether we need to materialize the object literal boilerplate.
+  // If so, jump to the deferred code.
+  __ cmp(ebx, Factory::undefined_value());
+  __ j(equal, deferred->enter(), not_taken);
+  __ bind(deferred->exit());
+
+  // Push the literal.
+  frame_->Push(ebx);
+  // Clone the boilerplate object.
+  __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
+  // Push the new cloned literal object as the result.
+  frame_->Push(eax);
+
+
+  for (int i = 0; i < node->properties()->length(); i++) {
+    ObjectLiteral::Property* property  = node->properties()->at(i);
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT: break;
+      case ObjectLiteral::Property::COMPUTED: {
+        Handle<Object> key(property->key()->handle());
+        Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+        if (key->IsSymbol()) {
+          __ mov(eax, frame_->Top());
+          frame_->Push(eax);
+          Load(property->value());
+          frame_->Pop(eax);
+          __ Set(ecx, Immediate(key));
+          __ call(ic, RelocInfo::CODE_TARGET);
+          frame_->Pop();
+          // Ignore result.
+          break;
+        }
+        // Fall through
+      }
+      case ObjectLiteral::Property::PROTOTYPE: {
+        __ mov(eax, frame_->Top());
+        frame_->Push(eax);
+        Load(property->key());
+        Load(property->value());
+        __ CallRuntime(Runtime::kSetProperty, 3);
+        // Ignore result.
+        break;
+      }
+      case ObjectLiteral::Property::SETTER: {
+        // Duplicate the resulting object on the stack. The runtime
+        // function will pop the three arguments passed in.
+        __ mov(eax, frame_->Top());
+        frame_->Push(eax);
+        Load(property->key());
+        frame_->Push(Immediate(Smi::FromInt(1)));
+        Load(property->value());
+        __ CallRuntime(Runtime::kDefineAccessor, 4);
+        // Ignore result.
+        break;
+      }
+      case ObjectLiteral::Property::GETTER: {
+        // Duplicate the resulting object on the stack. The runtime
+        // function will pop the three arguments passed in.
+        __ mov(eax, frame_->Top());
+        frame_->Push(eax);
+        Load(property->key());
+        frame_->Push(Immediate(Smi::FromInt(0)));
+        Load(property->value());
+        __ CallRuntime(Runtime::kDefineAccessor, 4);
+        // Ignore result.
+        break;
+      }
+      default: UNREACHABLE();
+    }
+  }
+}
+
+
+void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
+  Comment cmnt(masm_, "[ ArrayLiteral");
+
+  // Call runtime to create the array literal.
+  frame_->Push(Immediate(node->literals()));
+  // Load the function of this frame.
+  __ mov(ecx, frame_->Function());
+  // Load the literals array of the function.
+  __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset));
+  frame_->Push(ecx);
+  __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
+
+  // Push the resulting array literal on the stack.
+  frame_->Push(eax);
+
+  // Generate code to set the elements in the array that are not
+  // literals.
+  for (int i = 0; i < node->values()->length(); i++) {
+    Expression* value = node->values()->at(i);
+
+    // If value is literal the property value is already
+    // set in the boilerplate object.
+    if (value->AsLiteral() == NULL) {
+      // The property must be set by generated code.
+      Load(value);
+
+      // Get the value off the stack.
+      frame_->Pop(eax);
+      // Fetch the object literal while leaving on the stack.
+      __ mov(ecx, frame_->Top());
+      // Get the elements array.
+      __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
+
+      // Write to the indexed properties array.
+      int offset = i * kPointerSize + Array::kHeaderSize;
+      __ mov(FieldOperand(ecx, offset), eax);
+
+      // Update the write barrier for the array address.
+      __ RecordWrite(ecx, offset, eax, ebx);
+    }
+  }
+}
+
+
+bool CodeGenerator::IsInlineSmi(Literal* literal) {
+  if (literal == NULL || !literal->handle()->IsSmi()) return false;
+  int int_value = Smi::cast(*literal->handle())->value();
+  return is_intn(int_value, kMaxSmiInlinedBits);
+}
+
+
+void CodeGenerator::VisitAssignment(Assignment* node) {
+  Comment cmnt(masm_, "[ Assignment");
+
+  RecordStatementPosition(node);
+  Reference target(this, node->target());
+  if (target.is_illegal()) return;
+
+  if (node->op() == Token::ASSIGN ||
+      node->op() == Token::INIT_VAR ||
+      node->op() == Token::INIT_CONST) {
+    Load(node->value());
+
+  } else {
+    target.GetValue(NOT_INSIDE_TYPEOF);
+    Literal* literal = node->value()->AsLiteral();
+    if (IsInlineSmi(literal)) {
+      SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE);
+    } else {
+      Load(node->value());
+      GenericBinaryOperation(node->binary_op());
+    }
+  }
+
+  Variable* var = node->target()->AsVariableProxy()->AsVariable();
+  if (var != NULL &&
+      var->mode() == Variable::CONST &&
+      node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
+    // Assignment ignored - leave the value on the stack.
+  } else {
+    __ RecordPosition(node->position());
+    if (node->op() == Token::INIT_CONST) {
+      // Dynamic constant initializations must use the function context
+      // and initialize the actual constant declared. Dynamic variable
+      // initializations are simply assignments and use SetValue.
+      target.SetValue(CONST_INIT);
+    } else {
+      target.SetValue(NOT_CONST_INIT);
+    }
+  }
+}
+
+
+void CodeGenerator::VisitThrow(Throw* node) {
+  Comment cmnt(masm_, "[ Throw");
+
+  Load(node->exception());
+  __ RecordPosition(node->position());
+  __ CallRuntime(Runtime::kThrow, 1);
+  frame_->Push(eax);
+}
+
+
+void CodeGenerator::VisitProperty(Property* node) {
+  Comment cmnt(masm_, "[ Property");
+
+  Reference property(this, node);
+  property.GetValue(typeof_state());
+}
+
+
+void CodeGenerator::VisitCall(Call* node) {
+  Comment cmnt(masm_, "[ Call");
+
+  ZoneList<Expression*>* args = node->arguments();
+
+  RecordStatementPosition(node);
+
+  // Check if the function is a variable or a property.
+  Expression* function = node->expression();
+  Variable* var = function->AsVariableProxy()->AsVariable();
+  Property* property = function->AsProperty();
+
+  // ------------------------------------------------------------------------
+  // Fast-case: Use inline caching.
+  // ---
+  // According to ECMA-262, section 11.2.3, page 44, the function to call
+  // must be resolved after the arguments have been evaluated. The IC code
+  // automatically handles this by loading the arguments before the function
+  // is resolved in cache misses (this also holds for megamorphic calls).
+  // ------------------------------------------------------------------------
+
+  if (var != NULL && !var->is_this() && var->is_global()) {
+    // ----------------------------------
+    // JavaScript example: 'foo(1, 2, 3)'  // foo is global
+    // ----------------------------------
+
+    // Push the name of the function and the receiver onto the stack.
+    frame_->Push(Immediate(var->name()));
+
+    // TODO(120): Use global object for function lookup and inline
+    // cache, and use global proxy as 'this' for invocation.
+    LoadGlobalReceiver(eax);
+
+    // Load the arguments.
+    for (int i = 0; i < args->length(); i++) {
+      Load(args->at(i));
+    }
+
+    // Setup the receiver register and call the IC initialization code.
+    Handle<Code> stub = ComputeCallInitialize(args->length());
+    __ RecordPosition(node->position());
+    __ call(stub, RelocInfo::CODE_TARGET_CONTEXT);
+    __ mov(esi, frame_->Context());
+
+    // Overwrite the function on the stack with the result.
+    __ mov(frame_->Top(), eax);
+
+  } else if (var != NULL && var->slot() != NULL &&
+             var->slot()->type() == Slot::LOOKUP) {
+    // ----------------------------------
+    // JavaScript example: 'with (obj) foo(1, 2, 3)'  // foo is in obj
+    // ----------------------------------
+
+    // Load the function
+    frame_->Push(esi);
+    frame_->Push(Immediate(var->name()));
+    __ CallRuntime(Runtime::kLoadContextSlot, 2);
+    // eax: slot value; edx: receiver
+
+    // Load the receiver.
+    frame_->Push(eax);
+    frame_->Push(edx);
+
+    // Call the function.
+    CallWithArguments(args, node->position());
+
+  } else if (property != NULL) {
+    // Check if the key is a literal string.
+    Literal* literal = property->key()->AsLiteral();
+
+    if (literal != NULL && literal->handle()->IsSymbol()) {
+      // ------------------------------------------------------------------
+      // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
+      // ------------------------------------------------------------------
+
+      // Push the name of the function and the receiver onto the stack.
+      frame_->Push(Immediate(literal->handle()));
+      Load(property->obj());
+
+      // Load the arguments.
+      for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
+      // Call the IC initialization code.
+      Handle<Code> stub = ComputeCallInitialize(args->length());
+      __ RecordPosition(node->position());
+      __ call(stub, RelocInfo::CODE_TARGET);
+      __ mov(esi, frame_->Context());
+
+      // Overwrite the function on the stack with the result.
+      __ mov(frame_->Top(), eax);
+
+    } else {
+      // -------------------------------------------
+      // JavaScript example: 'array[index](1, 2, 3)'
+      // -------------------------------------------
+
+      // Load the function to call from the property through a reference.
+      Reference ref(this, property);
+      ref.GetValue(NOT_INSIDE_TYPEOF);
+
+      // Pass receiver to called function.
+      // The reference's size is non-negative.
+      frame_->Push(frame_->Element(ref.size()));
+
+      // Call the function.
+      CallWithArguments(args, node->position());
+    }
+
+  } else {
+    // ----------------------------------
+    // JavaScript example: 'foo(1, 2, 3)'  // foo is not global
+    // ----------------------------------
+
+    // Load the function.
+    Load(function);
+
+    // Pass the global proxy as the receiver.
+    LoadGlobalReceiver(eax);
+
+    // Call the function.
+    CallWithArguments(args, node->position());
+  }
+}
+
+
+void CodeGenerator::VisitCallNew(CallNew* node) {
+  Comment cmnt(masm_, "[ CallNew");
+
+  // According to ECMA-262, section 11.2.2, page 44, the function
+  // expression in new calls must be evaluated before the
+  // arguments. This is different from ordinary calls, where the
+  // actual function to call is resolved after the arguments have been
+  // evaluated.
+
+  // Compute function to call and use the global object as the
+  // receiver. There is no need to use the global proxy here because
+  // it will always be replaced with a newly allocated object.
+  Load(node->expression());
+  LoadGlobal();
+
+  // Push the arguments ("left-to-right") on the stack.
+  ZoneList<Expression*>* args = node->arguments();
+  for (int i = 0; i < args->length(); i++) Load(args->at(i));
+
+  // Constructors are called with the number of arguments in register
+  // eax for now. Another option would be to have separate construct
+  // call trampolines per different arguments counts encountered.
+  __ Set(eax, Immediate(args->length()));
+
+  // Load the function into temporary function slot as per calling
+  // convention.
+  __ mov(edi, frame_->Element(args->length() + 1));
+
+  // Call the construct call builtin that handles allocation and
+  // constructor invocation.
+  __ RecordPosition(node->position());
+  __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+          RelocInfo::CONSTRUCT_CALL);
+  // Discard the function and "push" the newly created object.
+  __ mov(frame_->Top(), eax);
+}
+
+
+void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  frame_->Pop(eax);
+  __ test(eax, Immediate(kSmiTagMask));
+  cc_reg_ = zero;
+}
+
+
+void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  frame_->Pop(eax);
+  __ test(eax, Immediate(kSmiTagMask | 0x80000000));
+  cc_reg_ = zero;
+}
+
+
+// This generates code that performs a charCodeAt() call or returns
+// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
+// It can handle flat and sliced strings, 8 and 16 bit characters and
+// cons strings where the answer is found in the left hand branch of the
+// cons.  The slow case will flatten the string, which will ensure that
+// the answer is in the left hand side the next time around.
+void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+
+  Label slow_case;
+  Label end;
+  Label not_a_flat_string;
+  Label not_a_cons_string_either;
+  Label try_again_with_new_string;
+  Label ascii_string;
+  Label got_char_code;
+
+  // Load the string into eax.
+  Load(args->at(0));
+  frame_->Pop(eax);
+  // If the receiver is a smi return undefined.
+  ASSERT(kSmiTag == 0);
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &slow_case, not_taken);
+
+  // Load the index into ebx.
+  Load(args->at(1));
+  frame_->Pop(ebx);
+
+  // Check for negative or non-smi index.
+  ASSERT(kSmiTag == 0);
+  __ test(ebx, Immediate(kSmiTagMask | 0x80000000));
+  __ j(not_zero, &slow_case, not_taken);
+  // Get rid of the smi tag on the index.
+  __ sar(ebx, kSmiTagSize);
+
+  __ bind(&try_again_with_new_string);
+  // Get the type of the heap object into ecx.
+  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
+  // We don't handle non-strings.
+  __ test(ecx, Immediate(kIsNotStringMask));
+  __ j(not_zero, &slow_case, not_taken);
+
+  // Get the length field.
+  __ mov(edx, FieldOperand(eax, String::kLengthOffset));
+  Label long_string;
+  Label medium_string;
+  Label string_length_shifted;
+  // The code assumes the tags are disjoint.
+  ASSERT((kLongStringTag & kMediumStringTag) == 0);
+  ASSERT(kShortStringTag == 0);
+  __ test(ecx, Immediate(kLongStringTag));
+  __ j(not_zero, &long_string, not_taken);
+  __ test(ecx, Immediate(kMediumStringTag));
+  __ j(not_zero, &medium_string, taken);
+  // Short string.
+  __ shr(edx, String::kShortLengthShift);
+  __ jmp(&string_length_shifted);
+
+  // Medium string.
+  __ bind(&medium_string);
+  __ shr(edx, String::kMediumLengthShift - String::kLongLengthShift);
+  // Fall through to long string.
+  __ bind(&long_string);
+  __ shr(edx, String::kLongLengthShift);
+
+  __ bind(&string_length_shifted);
+  ASSERT(kSmiTag == 0);
+  // edx is now the length of the string.
+
+  // Check for index out of range.
+  __ cmp(ebx, Operand(edx));
+  __ j(greater_equal, &slow_case, not_taken);
+
+  // We need special handling for non-flat strings.
+  ASSERT(kSeqStringTag == 0);
+  __ test(ecx, Immediate(kStringRepresentationMask));
+  __ j(not_zero, &not_a_flat_string, not_taken);
+
+  // Check for 1-byte or 2-byte string.
+  __ test(ecx, Immediate(kStringEncodingMask));
+  __ j(not_zero, &ascii_string, taken);
+
+  // 2-byte string.
+  // Load the 2-byte character code.
+  __ movzx_w(eax,
+             FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
+  __ jmp(&got_char_code);
+
+  // ASCII string.
+  __ bind(&ascii_string);
+  // Load the byte.
+  __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
+
+  __ bind(&got_char_code);
+  ASSERT(kSmiTag == 0);
+  __ shl(eax, kSmiTagSize);
+  frame_->Push(eax);
+  __ jmp(&end);
+
+
+  // Handle non-flat strings.
+  __ bind(&not_a_flat_string);
+  __ and_(ecx, kStringRepresentationMask);
+  __ cmp(ecx, kConsStringTag);
+  __ j(not_equal, &not_a_cons_string_either, not_taken);
+
+  // ConsString.
+  // Get the first of the two strings.
+  __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
+  __ jmp(&try_again_with_new_string);
+
+  __ bind(&not_a_cons_string_either);
+  __ cmp(ecx, kSlicedStringTag);
+  __ j(not_equal, &slow_case, not_taken);
+
+  // SlicedString.
+  // Add the offset to the index.
+  __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset));
+  __ j(overflow, &slow_case);
+  // Get the underlying string.
+  __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset));
+  __ jmp(&try_again_with_new_string);
+
+  __ bind(&slow_case);
+  frame_->Push(Immediate(Factory::undefined_value()));
+
+  __ bind(&end);
+}
+
+
+void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Load(args->at(0));
+  Label answer;
+  // We need the CC bits to come out as not_equal in the case where the
+  // object is a smi.  This can't be done with the usual test opcode so
+  // we copy the object to ecx and do some destructive ops on it that
+  // result in the right CC bits.
+  frame_->Pop(eax);
+  __ mov(ecx, Operand(eax));
+  __ and_(ecx, kSmiTagMask);
+  __ xor_(ecx, kSmiTagMask);
+  __ j(not_equal, &answer, not_taken);
+  // It is a heap object - get map.
+  __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
+  // Check if the object is a JS array or not.
+  __ cmp(eax, JS_ARRAY_TYPE);
+  __ bind(&answer);
+  cc_reg_ = equal;
+}
+
+
+void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 0);
+
+  // Seed the result with the formal parameters count, which will be
+  // used in case no arguments adaptor frame is found below the
+  // current frame.
+  __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters())));
+
+  // Call the shared stub to get to the arguments.length.
+  ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
+  __ CallStub(&stub);
+  frame_->Push(eax);
+}
+
+
+void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+  Label leave;
+  Load(args->at(0));  // Load the object.
+  __ mov(eax, frame_->Top());
+  // if (object->IsSmi()) return object.
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &leave, taken);
+  // It is a heap object - get map.
+  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  // if (!object->IsJSValue()) return object.
+  __ cmp(ecx, JS_VALUE_TYPE);
+  __ j(not_equal, &leave, not_taken);
+  __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
+  __ mov(frame_->Top(), eax);
+  __ bind(&leave);
+}
+
+
+void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+  Label leave;
+  Load(args->at(0));  // Load the object.
+  Load(args->at(1));  // Load the value.
+  __ mov(eax, frame_->Element(1));
+  __ mov(ecx, frame_->Top());
+  // if (object->IsSmi()) return object.
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &leave, taken);
+  // It is a heap object - get map.
+  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  // if (!object->IsJSValue()) return object.
+  __ cmp(ebx, JS_VALUE_TYPE);
+  __ j(not_equal, &leave, not_taken);
+  // Store the value.
+  __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx);
+  // Update the write barrier.
+  __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx);
+  // Leave.
+  __ bind(&leave);
+  __ mov(ecx, frame_->Top());
+  frame_->Pop();
+  __ mov(frame_->Top(), ecx);
+}
+
+
+void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 1);
+
+  // Load the key onto the stack and set register eax to the formal
+  // parameters count for the currently executing function.
+  Load(args->at(0));
+  __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters())));
+
+  // Call the shared stub to get to arguments[key].
+  ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
+  __ CallStub(&stub);
+  __ mov(frame_->Top(), eax);
+}
+
+
+void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 2);
+
+  // Load the two objects into registers and perform the comparison.
+  Load(args->at(0));
+  Load(args->at(1));
+  frame_->Pop(eax);
+  frame_->Pop(ecx);
+  __ cmp(eax, Operand(ecx));
+  cc_reg_ = equal;
+}
+
+
+void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
+  if (CheckForInlineRuntimeCall(node)) return;
+
+  ZoneList<Expression*>* args = node->arguments();
+  Comment cmnt(masm_, "[ CallRuntime");
+  Runtime::Function* function = node->function();
+
+  if (function == NULL) {
+    // Prepare stack for calling JS runtime function.
+    frame_->Push(Immediate(node->name()));
+    // Push the builtins object found in the current global object.
+    __ mov(edx, GlobalObject());
+    frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset));
+  }
+
+  // Push the arguments ("left-to-right").
+  for (int i = 0; i < args->length(); i++)
+    Load(args->at(i));
+
+  if (function != NULL) {
+    // Call the C runtime function.
+    __ CallRuntime(function, args->length());
+    frame_->Push(eax);
+  } else {
+    // Call the JS runtime function.
+    Handle<Code> stub = ComputeCallInitialize(args->length());
+    __ Set(eax, Immediate(args->length()));
+    __ call(stub, RelocInfo::CODE_TARGET);
+    __ mov(esi, frame_->Context());
+    __ mov(frame_->Top(), eax);
+  }
+}
+
+
+void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
+  Comment cmnt(masm_, "[ UnaryOperation");
+
+  Token::Value op = node->op();
+
+  if (op == Token::NOT) {
+    LoadCondition(node->expression(), NOT_INSIDE_TYPEOF,
+                  false_target(), true_target(), true);
+    cc_reg_ = NegateCondition(cc_reg_);
+
+  } else if (op == Token::DELETE) {
+    Property* property = node->expression()->AsProperty();
+    if (property != NULL) {
+      Load(property->obj());
+      Load(property->key());
+      __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+      frame_->Push(eax);
+      return;
+    }
+
+    Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
+    if (variable != NULL) {
+      Slot* slot = variable->slot();
+      if (variable->is_global()) {
+        LoadGlobal();
+        frame_->Push(Immediate(variable->name()));
+        __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+        frame_->Push(eax);
+        return;
+
+      } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
+        // lookup the context holding the named variable
+        frame_->Push(esi);
+        frame_->Push(Immediate(variable->name()));
+        __ CallRuntime(Runtime::kLookupContext, 2);
+        // eax: context
+        frame_->Push(eax);
+        frame_->Push(Immediate(variable->name()));
+        __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+        frame_->Push(eax);
+        return;
+      }
+
+      // Default: Result of deleting non-global, not dynamically
+      // introduced variables is false.
+      frame_->Push(Immediate(Factory::false_value()));
+
+    } else {
+      // Default: Result of deleting expressions is true.
+      Load(node->expression());  // may have side-effects
+      __ Set(frame_->Top(), Immediate(Factory::true_value()));
+    }
+
+  } else if (op == Token::TYPEOF) {
+    // Special case for loading the typeof expression; see comment on
+    // LoadTypeofExpression().
+    LoadTypeofExpression(node->expression());
+    __ CallRuntime(Runtime::kTypeof, 1);
+    frame_->Push(eax);
+
+  } else {
+    Load(node->expression());
+    switch (op) {
+      case Token::NOT:
+      case Token::DELETE:
+      case Token::TYPEOF:
+        UNREACHABLE();  // handled above
+        break;
+
+      case Token::SUB: {
+        UnarySubStub stub;
+        // TODO(1222589): remove dependency of TOS being cached inside stub
+        frame_->Pop(eax);
+        __ CallStub(&stub);
+        frame_->Push(eax);
+        break;
+      }
+
+      case Token::BIT_NOT: {
+        // Smi check.
+        Label smi_label;
+        Label continue_label;
+        frame_->Pop(eax);
+        __ test(eax, Immediate(kSmiTagMask));
+        __ j(zero, &smi_label, taken);
+
+        frame_->Push(eax);  // undo popping of TOS
+        __ InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION);
+
+        __ jmp(&continue_label);
+        __ bind(&smi_label);
+        __ not_(eax);
+        __ and_(eax, ~kSmiTagMask);  // Remove inverted smi-tag.
+        __ bind(&continue_label);
+        frame_->Push(eax);
+        break;
+      }
+
+      case Token::VOID:
+        __ mov(frame_->Top(), Factory::undefined_value());
+        break;
+
+      case Token::ADD: {
+        // Smi check.
+        Label continue_label;
+        frame_->Pop(eax);
+        __ test(eax, Immediate(kSmiTagMask));
+        __ j(zero, &continue_label);
+
+        frame_->Push(eax);
+        __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+
+        __ bind(&continue_label);
+        frame_->Push(eax);
+        break;
+      }
+
+      default:
+        UNREACHABLE();
+    }
+  }
+}
+
+
+class CountOperationDeferred: public DeferredCode {
+ public:
+  CountOperationDeferred(CodeGenerator* generator,
+                         bool is_postfix,
+                         bool is_increment,
+                         int result_offset)
+      : DeferredCode(generator),
+        is_postfix_(is_postfix),
+        is_increment_(is_increment),
+        result_offset_(result_offset) {
+    set_comment("[ CountOperationDeferred");
+  }
+
+  virtual void Generate();
+
+ private:
+  bool is_postfix_;
+  bool is_increment_;
+  int result_offset_;
+};
+
+
+class RevertToNumberStub: public CodeStub {
+ public:
+  explicit RevertToNumberStub(bool is_increment)
+     :  is_increment_(is_increment) { }
+
+ private:
+  bool is_increment_;
+
+  Major MajorKey() { return RevertToNumber; }
+  int MinorKey() { return is_increment_ ? 1 : 0; }
+  void Generate(MacroAssembler* masm);
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("RevertToNumberStub (is_increment %s)\n",
+           is_increment_ ? "true" : "false");
+  }
+#endif
+};
+
+
+class CounterOpStub: public CodeStub {
+ public:
+  CounterOpStub(int result_offset, bool is_postfix, bool is_increment)
+     :  result_offset_(result_offset),
+        is_postfix_(is_postfix),
+        is_increment_(is_increment) { }
+
+ private:
+  int result_offset_;
+  bool is_postfix_;
+  bool is_increment_;
+
+  Major MajorKey() { return CounterOp; }
+  int MinorKey() {
+    return ((result_offset_ << 2) |
+            (is_postfix_ ? 2 : 0) |
+            (is_increment_ ? 1 : 0));
+  }
+  void Generate(MacroAssembler* masm);
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("CounterOpStub (result_offset %d), (is_postfix %s),"
+           " (is_increment %s)\n",
+           result_offset_,
+           is_postfix_ ? "true" : "false",
+           is_increment_ ? "true" : "false");
+  }
+#endif
+};
+
+
+void CountOperationDeferred::Generate() {
+  if (is_postfix_) {
+    RevertToNumberStub to_number_stub(is_increment_);
+    __ CallStub(&to_number_stub);
+  }
+  CounterOpStub stub(result_offset_, is_postfix_, is_increment_);
+  __ CallStub(&stub);
+}
+
+
+void CodeGenerator::VisitCountOperation(CountOperation* node) {
+  Comment cmnt(masm_, "[ CountOperation");
+
+  bool is_postfix = node->is_postfix();
+  bool is_increment = node->op() == Token::INC;
+
+  Variable* var = node->expression()->AsVariableProxy()->AsVariable();
+  bool is_const = (var != NULL && var->mode() == Variable::CONST);
+
+  // Postfix: Make room for the result.
+  if (is_postfix) {
+    frame_->Push(Immediate(0));
+  }
+
+  { Reference target(this, node->expression());
+    if (target.is_illegal()) return;
+    target.GetValue(NOT_INSIDE_TYPEOF);
+
+    CountOperationDeferred* deferred =
+        new CountOperationDeferred(this, is_postfix, is_increment,
+                                   target.size() * kPointerSize);
+
+    frame_->Pop(eax);  // Load TOS into eax for calculations below
+
+    // Postfix: Store the old value as the result.
+    if (is_postfix) {
+      __ mov(frame_->Element(target.size()), eax);
+    }
+
+    // Perform optimistic increment/decrement.
+    if (is_increment) {
+      __ add(Operand(eax), Immediate(Smi::FromInt(1)));
+    } else {
+      __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
+    }
+
+    // If the count operation didn't overflow and the result is a
+    // valid smi, we're done. Otherwise, we jump to the deferred
+    // slow-case code.
+    __ j(overflow, deferred->enter(), not_taken);
+    __ test(eax, Immediate(kSmiTagMask));
+    __ j(not_zero, deferred->enter(), not_taken);
+
+    // Store the new value in the target if not const.
+    __ bind(deferred->exit());
+    frame_->Push(eax);  // Push the new value to TOS
+    if (!is_const) target.SetValue(NOT_CONST_INIT);
+  }
+
+  // Postfix: Discard the new value and use the old.
+  if (is_postfix) {
+    frame_->Pop();
+  }
+}
+
+
+void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+  Comment cmnt(masm_, "[ BinaryOperation");
+  Token::Value op = node->op();
+
+  // According to ECMA-262 section 11.11, page 58, the binary logical
+  // operators must yield the result of one of the two expressions
+  // before any ToBoolean() conversions. This means that the value
+  // produced by a && or || operator is not necessarily a boolean.
+
+  // NOTE: If the left hand side produces a materialized value (not in
+  // the CC register), we force the right hand side to do the
+  // same. This is necessary because we may have to branch to the exit
+  // after evaluating the left hand side (due to the shortcut
+  // semantics), but the compiler must (statically) know if the result
+  // of compiling the binary operation is materialized or not.
+
+  if (op == Token::AND) {
+    Label is_true;
+    LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true,
+                  false_target(), false);
+    if (has_cc()) {
+      Branch(false, false_target());
+
+      // Evaluate right side expression.
+      __ bind(&is_true);
+      LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
+                    false_target(), false);
+
+    } else {
+      Label pop_and_continue, exit;
+
+      // Avoid popping the result if it converts to 'false' using the
+      // standard ToBoolean() conversion as described in ECMA-262,
+      // section 9.2, page 30.
+       // Duplicate the TOS value. The duplicate will be popped by ToBoolean.
+      __ mov(eax, frame_->Top());
+      frame_->Push(eax);
+      ToBoolean(&pop_and_continue, &exit);
+      Branch(false, &exit);
+
+      // Pop the result of evaluating the first part.
+      __ bind(&pop_and_continue);
+      frame_->Pop();
+
+      // Evaluate right side expression.
+      __ bind(&is_true);
+      Load(node->right());
+
+      // Exit (always with a materialized value).
+      __ bind(&exit);
+    }
+
+  } else if (op == Token::OR) {
+    Label is_false;
+    LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(),
+                  &is_false, false);
+    if (has_cc()) {
+      Branch(true, true_target());
+
+      // Evaluate right side expression.
+      __ bind(&is_false);
+      LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
+                    false_target(), false);
+
+    } else {
+      Label pop_and_continue, exit;
+
+      // Avoid popping the result if it converts to 'true' using the
+      // standard ToBoolean() conversion as described in ECMA-262,
+      // section 9.2, page 30.
+      // Duplicate the TOS value. The duplicate will be popped by ToBoolean.
+      __ mov(eax, frame_->Top());
+      frame_->Push(eax);
+      ToBoolean(&exit, &pop_and_continue);
+      Branch(true, &exit);
+
+      // Pop the result of evaluating the first part.
+      __ bind(&pop_and_continue);
+      frame_->Pop();
+
+      // Evaluate right side expression.
+      __ bind(&is_false);
+      Load(node->right());
+
+      // Exit (always with a materialized value).
+      __ bind(&exit);
+    }
+
+  } else {
+    // NOTE: The code below assumes that the slow cases (calls to runtime)
+    // never return a constant/immutable object.
+    OverwriteMode overwrite_mode = NO_OVERWRITE;
+    if (node->left()->AsBinaryOperation() != NULL &&
+        node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) {
+      overwrite_mode = OVERWRITE_LEFT;
+    } else if (node->right()->AsBinaryOperation() != NULL &&
+               node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) {
+      overwrite_mode = OVERWRITE_RIGHT;
+    }
+
+    // Optimize for the case where (at least) one of the expressions
+    // is a literal small integer.
+    Literal* lliteral = node->left()->AsLiteral();
+    Literal* rliteral = node->right()->AsLiteral();
+
+    if (IsInlineSmi(rliteral)) {
+      Load(node->left());
+      SmiOperation(node->op(), rliteral->handle(), false, overwrite_mode);
+
+    } else if (IsInlineSmi(lliteral)) {
+      Load(node->right());
+      SmiOperation(node->op(), lliteral->handle(), true, overwrite_mode);
+
+    } else {
+      Load(node->left());
+      Load(node->right());
+      GenericBinaryOperation(node->op(), overwrite_mode);
+    }
+  }
+}
+
+
+void CodeGenerator::VisitThisFunction(ThisFunction* node) {
+  frame_->Push(frame_->Function());
+}
+
+
+class InstanceofStub: public CodeStub {
+ public:
+  InstanceofStub() { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  Major MajorKey() { return Instanceof; }
+  int MinorKey() { return 0; }
+};
+
+
+void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
+  Comment cmnt(masm_, "[ CompareOperation");
+
+  // Get the expressions from the node.
+  Expression* left = node->left();
+  Expression* right = node->right();
+  Token::Value op = node->op();
+
+  // NOTE: To make null checks efficient, we check if either left or
+  // right is the literal 'null'. If so, we optimize the code by
+  // inlining a null check instead of calling the (very) general
+  // runtime routine for checking equality.
+
+  if (op == Token::EQ || op == Token::EQ_STRICT) {
+    bool left_is_null =
+      left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
+    bool right_is_null =
+      right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
+    // The 'null' value is only equal to 'null' or 'undefined'.
+    if (left_is_null || right_is_null) {
+      Load(left_is_null ? right : left);
+      Label exit, undetectable;
+      frame_->Pop(eax);
+      __ cmp(eax, Factory::null_value());
+
+      // The 'null' value is only equal to 'undefined' if using
+      // non-strict comparisons.
+      if (op != Token::EQ_STRICT) {
+        __ j(equal, &exit);
+        __ cmp(eax, Factory::undefined_value());
+
+        // NOTE: it can be an undetectable object.
+        __ j(equal, &exit);
+        __ test(eax, Immediate(kSmiTagMask));
+
+        __ j(not_equal, &undetectable);
+        __ jmp(false_target());
+
+        __ bind(&undetectable);
+        __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
+        __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
+        __ and_(ecx, 1 << Map::kIsUndetectable);
+        __ cmp(ecx, 1 << Map::kIsUndetectable);
+      }
+
+      __ bind(&exit);
+
+      cc_reg_ = equal;
+      return;
+    }
+  }
+
+  // NOTE: To make typeof testing for natives implemented in
+  // JavaScript really efficient, we generate special code for
+  // expressions of the form: 'typeof <expression> == <string>'.
+
+  UnaryOperation* operation = left->AsUnaryOperation();
+  if ((op == Token::EQ || op == Token::EQ_STRICT) &&
+      (operation != NULL && operation->op() == Token::TYPEOF) &&
+      (right->AsLiteral() != NULL &&
+       right->AsLiteral()->handle()->IsString())) {
+    Handle<String> check(String::cast(*right->AsLiteral()->handle()));
+
+    // Load the operand, move it to register edx, and restore TOS.
+    LoadTypeofExpression(operation->expression());
+    frame_->Pop(edx);
+
+    if (check->Equals(Heap::number_symbol())) {
+      __ test(edx, Immediate(kSmiTagMask));
+      __ j(zero, true_target());
+      __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
+      __ cmp(edx, Factory::heap_number_map());
+      cc_reg_ = equal;
+
+    } else if (check->Equals(Heap::string_symbol())) {
+      __ test(edx, Immediate(kSmiTagMask));
+      __ j(zero, false_target());
+
+      __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
+
+      // NOTE: it might be an undetectable string object
+      __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
+      __ and_(ecx, 1 << Map::kIsUndetectable);
+      __ cmp(ecx, 1 << Map::kIsUndetectable);
+      __ j(equal, false_target());
+
+      __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
+      __ cmp(ecx, FIRST_NONSTRING_TYPE);
+      cc_reg_ = less;
+
+    } else if (check->Equals(Heap::boolean_symbol())) {
+      __ cmp(edx, Factory::true_value());
+      __ j(equal, true_target());
+      __ cmp(edx, Factory::false_value());
+      cc_reg_ = equal;
+
+    } else if (check->Equals(Heap::undefined_symbol())) {
+      __ cmp(edx, Factory::undefined_value());
+      __ j(equal, true_target());
+
+      __ test(edx, Immediate(kSmiTagMask));
+      __ j(zero, false_target());
+
+      // NOTE: it can be an undetectable object.
+      __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
+      __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
+      __ and_(ecx, 1 << Map::kIsUndetectable);
+      __ cmp(ecx, 1 << Map::kIsUndetectable);
+
+      cc_reg_ = equal;
+
+    } else if (check->Equals(Heap::function_symbol())) {
+      __ test(edx, Immediate(kSmiTagMask));
+      __ j(zero, false_target());
+      __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
+      __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
+      __ cmp(edx, JS_FUNCTION_TYPE);
+      cc_reg_ = equal;
+
+    } else if (check->Equals(Heap::object_symbol())) {
+      __ test(edx, Immediate(kSmiTagMask));
+      __ j(zero, false_target());
+
+      __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+      __ cmp(edx, Factory::null_value());
+      __ j(equal, true_target());
+
+      // NOTE: it might be an undetectable object
+      __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset));
+      __ and_(edx, 1 << Map::kIsUndetectable);
+      __ cmp(edx, 1 << Map::kIsUndetectable);
+      __ j(equal, false_target());
+
+      __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+      __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+      __ j(less, false_target());
+      __ cmp(ecx, LAST_JS_OBJECT_TYPE);
+      cc_reg_ = less_equal;
+
+    } else {
+      // Uncommon case: Typeof testing against a string literal that
+      // is never returned from the typeof operator.
+      __ jmp(false_target());
+    }
+    return;
+  }
+
+  Condition cc = no_condition;
+  bool strict = false;
+  switch (op) {
+    case Token::EQ_STRICT:
+      strict = true;
+      // Fall through
+    case Token::EQ:
+      cc = equal;
+      break;
+    case Token::LT:
+      cc = less;
+      break;
+    case Token::GT:
+      cc = greater;
+      break;
+    case Token::LTE:
+      cc = less_equal;
+      break;
+    case Token::GTE:
+      cc = greater_equal;
+      break;
+    case Token::IN: {
+      Load(left);
+      Load(right);
+      __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
+      frame_->Push(eax);  // push the result
+      return;
+    }
+    case Token::INSTANCEOF: {
+      Load(left);
+      Load(right);
+      InstanceofStub stub;
+      __ CallStub(&stub);
+      __ test(eax, Operand(eax));
+      cc_reg_ = zero;
+      return;
+    }
+    default:
+      UNREACHABLE();
+  }
+
+  // Optimize for the case where (at least) one of the expressions
+  // is a literal small integer.
+  if (IsInlineSmi(left->AsLiteral())) {
+    Load(right);
+    SmiComparison(ReverseCondition(cc), left->AsLiteral()->handle(), strict);
+    return;
+  }
+  if (IsInlineSmi(right->AsLiteral())) {
+    Load(left);
+    SmiComparison(cc, right->AsLiteral()->handle(), strict);
+    return;
+  }
+
+  Load(left);
+  Load(right);
+  Comparison(cc, strict);
+}
+
+
+void CodeGenerator::RecordStatementPosition(Node* node) {
+  if (FLAG_debug_info) {
+    int pos = node->statement_pos();
+    if (pos != RelocInfo::kNoPosition) {
+      __ RecordStatementPosition(pos);
+    }
+  }
+}
+
+
+#undef __
+#define __ masm->
+
+Handle<String> Reference::GetName() {
+  ASSERT(type_ == NAMED);
+  Property* property = expression_->AsProperty();
+  if (property == NULL) {
+    // Global variable reference treated as a named property reference.
+    VariableProxy* proxy = expression_->AsVariableProxy();
+    ASSERT(proxy->AsVariable() != NULL);
+    ASSERT(proxy->AsVariable()->is_global());
+    return proxy->name();
+  } else {
+    MacroAssembler* masm = cgen_->masm();
+    __ RecordPosition(property->position());
+    Literal* raw_name = property->key()->AsLiteral();
+    ASSERT(raw_name != NULL);
+    return Handle<String>(String::cast(*raw_name->handle()));
+  }
+}
+
+
+void Reference::GetValue(TypeofState typeof_state) {
+  ASSERT(!is_illegal());
+  ASSERT(!cgen_->has_cc());
+  MacroAssembler* masm = cgen_->masm();
+  VirtualFrame* frame = cgen_->frame();
+  switch (type_) {
+    case SLOT: {
+      Comment cmnt(masm, "[ Load from Slot");
+      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
+      ASSERT(slot != NULL);
+      cgen_->LoadFromSlot(slot, typeof_state);
+      break;
+    }
+
+    case NAMED: {
+      // TODO(1241834): Make sure that this it is safe to ignore the
+      // distinction between expressions in a typeof and not in a typeof. If
+      // there is a chance that reference errors can be thrown below, we
+      // must distinguish between the two kinds of loads (typeof expression
+      // loads must not throw a reference error).
+      Comment cmnt(masm, "[ Load from named Property");
+      Handle<String> name(GetName());
+      Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+      // Setup the name register.
+      __ mov(ecx, name);
+
+      Variable* var = expression_->AsVariableProxy()->AsVariable();
+      if (var != NULL) {
+        ASSERT(var->is_global());
+        __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+      } else {
+        __ call(ic, RelocInfo::CODE_TARGET);
+      }
+      frame->Push(eax);  // IC call leaves result in eax, push it out
+      break;
+    }
+
+    case KEYED: {
+      // TODO(1241834): Make sure that this it is safe to ignore the
+      // distinction between expressions in a typeof and not in a typeof.
+      Comment cmnt(masm, "[ Load from keyed Property");
+      Property* property = expression_->AsProperty();
+      ASSERT(property != NULL);
+      __ RecordPosition(property->position());
+      Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+
+      Variable* var = expression_->AsVariableProxy()->AsVariable();
+      if (var != NULL) {
+        ASSERT(var->is_global());
+        __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+      } else {
+        __ call(ic, RelocInfo::CODE_TARGET);
+      }
+      frame->Push(eax);  // IC call leaves result in eax, push it out
+      break;
+    }
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Reference::SetValue(InitState init_state) {
+  ASSERT(!is_illegal());
+  ASSERT(!cgen_->has_cc());
+  MacroAssembler* masm = cgen_->masm();
+  VirtualFrame* frame = cgen_->frame();
+  switch (type_) {
+    case SLOT: {
+      Comment cmnt(masm, "[ Store to Slot");
+      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
+      ASSERT(slot != NULL);
+      if (slot->type() == Slot::LOOKUP) {
+        ASSERT(slot->var()->mode() == Variable::DYNAMIC);
+
+        // For now, just do a runtime call.
+        frame->Push(esi);
+        frame->Push(Immediate(slot->var()->name()));
+
+        if (init_state == CONST_INIT) {
+          // Same as the case for a normal store, but ignores attribute
+          // (e.g. READ_ONLY) of context slot so that we can initialize
+          // const properties (introduced via eval("const foo = (some
+          // expr);")). Also, uses the current function context instead of
+          // the top context.
+          //
+          // Note that we must declare the foo upon entry of eval(), via a
+          // context slot declaration, but we cannot initialize it at the
+          // same time, because the const declaration may be at the end of
+          // the eval code (sigh...) and the const variable may have been
+          // used before (where its value is 'undefined'). Thus, we can only
+          // do the initialization when we actually encounter the expression
+          // and when the expression operands are defined and valid, and
+          // thus we need the split into 2 operations: declaration of the
+          // context slot followed by initialization.
+          __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+        } else {
+          __ CallRuntime(Runtime::kStoreContextSlot, 3);
+        }
+        // Storing a variable must keep the (new) value on the expression
+        // stack. This is necessary for compiling chained assignment
+        // expressions.
+        frame->Push(eax);
+
+      } else {
+        ASSERT(slot->var()->mode() != Variable::DYNAMIC);
+
+        Label exit;
+        if (init_state == CONST_INIT) {
+          ASSERT(slot->var()->mode() == Variable::CONST);
+          // Only the first const initialization must be executed (the slot
+          // still contains 'the hole' value). When the assignment is
+          // executed, the code is identical to a normal store (see below).
+          Comment cmnt(masm, "[ Init const");
+          __ mov(eax, cgen_->SlotOperand(slot, ecx));
+          __ cmp(eax, Factory::the_hole_value());
+          __ j(not_equal, &exit);
+        }
+
+        // We must execute the store.  Storing a variable must keep the
+        // (new) value on the stack. This is necessary for compiling
+        // assignment expressions.
+        //
+        // Note: We will reach here even with slot->var()->mode() ==
+        // Variable::CONST because of const declarations which will
+        // initialize consts to 'the hole' value and by doing so, end up
+        // calling this code.
+        frame->Pop(eax);
+        __ mov(cgen_->SlotOperand(slot, ecx), eax);
+        frame->Push(eax);  // RecordWrite may destroy the value in eax.
+        if (slot->type() == Slot::CONTEXT) {
+          // ecx is loaded with context when calling SlotOperand above.
+          int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+          __ RecordWrite(ecx, offset, eax, ebx);
+        }
+        // If we definitely did not jump over the assignment, we do not need
+        // to bind the exit label.  Doing so can defeat peephole
+        // optimization.
+        if (init_state == CONST_INIT) __ bind(&exit);
+      }
+      break;
+    }
+
+    case NAMED: {
+      Comment cmnt(masm, "[ Store to named Property");
+      // Call the appropriate IC code.
+      Handle<String> name(GetName());
+      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+      // TODO(1222589): Make the IC grab the values from the stack.
+      frame->Pop(eax);
+      // Setup the name register.
+      __ mov(ecx, name);
+      __ call(ic, RelocInfo::CODE_TARGET);
+      frame->Push(eax);  // IC call leaves result in eax, push it out
+      break;
+    }
+
+    case KEYED: {
+      Comment cmnt(masm, "[ Store to keyed Property");
+      Property* property = expression_->AsProperty();
+      ASSERT(property != NULL);
+      __ RecordPosition(property->position());
+      // Call IC code.
+      Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+      // TODO(1222589): Make the IC grab the values from the stack.
+      frame->Pop(eax);
+      __ call(ic, RelocInfo::CODE_TARGET);
+      frame->Push(eax);  // IC call leaves result in eax, push it out
+      break;
+    }
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+// NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined).
+void ToBooleanStub::Generate(MacroAssembler* masm) {
+  Label false_result, true_result, not_string;
+  __ mov(eax, Operand(esp, 1 * kPointerSize));
+
+  // 'null' => false.
+  __ cmp(eax, Factory::null_value());
+  __ j(equal, &false_result);
+
+  // Get the map and type of the heap object.
+  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
+
+  // Undetectable => false.
+  __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
+  __ and_(ebx, 1 << Map::kIsUndetectable);
+  __ j(not_zero, &false_result);
+
+  // JavaScript object => true.
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(above_equal, &true_result);
+
+  // String value => false iff empty.
+  __ cmp(ecx, FIRST_NONSTRING_TYPE);
+  __ j(above_equal, &not_string);
+  __ and_(ecx, kStringSizeMask);
+  __ cmp(ecx, kShortStringTag);
+  __ j(not_equal, &true_result);  // Empty string is always short.
+  __ mov(edx, FieldOperand(eax, String::kLengthOffset));
+  __ shr(edx, String::kShortLengthShift);
+  __ j(zero, &false_result);
+  __ jmp(&true_result);
+
+  __ bind(&not_string);
+  // HeapNumber => false iff +0, -0, or NaN.
+  __ cmp(edx, Factory::heap_number_map());
+  __ j(not_equal, &true_result);
+  __ fldz();
+  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+  __ fucompp();
+  __ push(eax);
+  __ fnstsw_ax();
+  __ sahf();
+  __ pop(eax);
+  __ j(zero, &false_result);
+  // Fall through to |true_result|.
+
+  // Return 1/0 for true/false in eax.
+  __ bind(&true_result);
+  __ mov(eax, 1);
+  __ ret(1 * kPointerSize);
+  __ bind(&false_result);
+  __ mov(eax, 0);
+  __ ret(1 * kPointerSize);
+}
+
+
+void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
+  // Perform fast-case smi code for the operation (eax <op> ebx) and
+  // leave result in register eax.
+
+  // Prepare the smi check of both operands by or'ing them together
+  // before checking against the smi mask.
+  __ mov(ecx, Operand(ebx));
+  __ or_(ecx, Operand(eax));
+
+  switch (op_) {
+    case Token::ADD:
+      __ add(eax, Operand(ebx));  // add optimistically
+      __ j(overflow, slow, not_taken);
+      break;
+
+    case Token::SUB:
+      __ sub(eax, Operand(ebx));  // subtract optimistically
+      __ j(overflow, slow, not_taken);
+      break;
+
+    case Token::DIV:
+    case Token::MOD:
+      // Sign extend eax into edx:eax.
+      __ cdq();
+      // Check for 0 divisor.
+      __ test(ebx, Operand(ebx));
+      __ j(zero, slow, not_taken);
+      break;
+
+    default:
+      // Fall-through to smi check.
+      break;
+  }
+
+  // Perform the actual smi check.
+  ASSERT(kSmiTag == 0);  // adjust zero check if not the case
+  __ test(ecx, Immediate(kSmiTagMask));
+  __ j(not_zero, slow, not_taken);
+
+  switch (op_) {
+    case Token::ADD:
+    case Token::SUB:
+      // Do nothing here.
+      break;
+
+    case Token::MUL:
+      // If the smi tag is 0 we can just leave the tag on one operand.
+      ASSERT(kSmiTag == 0);  // adjust code below if not the case
+      // Remove tag from one of the operands (but keep sign).
+      __ sar(eax, kSmiTagSize);
+      // Do multiplication.
+      __ imul(eax, Operand(ebx));  // multiplication of smis; result in eax
+      // Go slow on overflows.
+      __ j(overflow, slow, not_taken);
+      // Check for negative zero result.
+      __ NegativeZeroTest(eax, ecx, slow);  // use ecx = x | y
+      break;
+
+    case Token::DIV:
+      // Divide edx:eax by ebx.
+      __ idiv(ebx);
+      // Check for the corner case of dividing the most negative smi
+      // by -1. We cannot use the overflow flag, since it is not set
+      // by idiv instruction.
+      ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+      __ cmp(eax, 0x40000000);
+      __ j(equal, slow);
+      // Check for negative zero result.
+      __ NegativeZeroTest(eax, ecx, slow);  // use ecx = x | y
+      // Check that the remainder is zero.
+      __ test(edx, Operand(edx));
+      __ j(not_zero, slow);
+      // Tag the result and store it in register eax.
+      ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+      __ lea(eax, Operand(eax, times_2, kSmiTag));
+      break;
+
+    case Token::MOD:
+      // Divide edx:eax by ebx.
+      __ idiv(ebx);
+      // Check for negative zero result.
+      __ NegativeZeroTest(edx, ecx, slow);  // use ecx = x | y
+      // Move remainder to register eax.
+      __ mov(eax, Operand(edx));
+      break;
+
+    case Token::BIT_OR:
+      __ or_(eax, Operand(ebx));
+      break;
+
+    case Token::BIT_AND:
+      __ and_(eax, Operand(ebx));
+      break;
+
+    case Token::BIT_XOR:
+      __ xor_(eax, Operand(ebx));
+      break;
+
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR:
+      // Move the second operand into register ecx.
+      __ mov(ecx, Operand(ebx));
+      // Remove tags from operands (but keep sign).
+      __ sar(eax, kSmiTagSize);
+      __ sar(ecx, kSmiTagSize);
+      // Perform the operation.
+      switch (op_) {
+        case Token::SAR:
+          __ sar(eax);
+          // No checks of result necessary
+          break;
+        case Token::SHR:
+          __ shr(eax);
+          // Check that the *unsigned* result fits in a smi.
+          // Neither of the two high-order bits can be set:
+          // - 0x80000000: high bit would be lost when smi tagging.
+          // - 0x40000000: this number would convert to negative when
+          // Smi tagging these two cases can only happen with shifts
+          // by 0 or 1 when handed a valid smi.
+          __ test(eax, Immediate(0xc0000000));
+          __ j(not_zero, slow, not_taken);
+          break;
+        case Token::SHL:
+          __ shl(eax);
+          // Check that the *signed* result fits in a smi.
+          __ lea(ecx, Operand(eax, 0x40000000));
+          __ test(ecx, Immediate(0x80000000));
+          __ j(not_zero, slow, not_taken);
+          break;
+        default:
+          UNREACHABLE();
+      }
+      // Tag the result and store it in register eax.
+      ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+      __ lea(eax, Operand(eax, times_2, kSmiTag));
+      break;
+
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
+  Label call_runtime;
+
+  if (flags_ == SMI_CODE_IN_STUB) {
+    // The fast case smi code wasn't inlined in the stub caller
+    // code. Generate it here to speed up common operations.
+    Label slow;
+    __ mov(ebx, Operand(esp, 1 * kPointerSize));  // get y
+    __ mov(eax, Operand(esp, 2 * kPointerSize));  // get x
+    GenerateSmiCode(masm, &slow);
+    __ ret(2 * kPointerSize);  // remove both operands
+
+    // Too bad. The fast case smi code didn't succeed.
+    __ bind(&slow);
+  }
+
+  // Setup registers.
+  __ mov(eax, Operand(esp, 1 * kPointerSize));  // get y
+  __ mov(edx, Operand(esp, 2 * kPointerSize));  // get x
+
+  // Floating point case.
+  switch (op_) {
+    case Token::ADD:
+    case Token::SUB:
+    case Token::MUL:
+    case Token::DIV: {
+      // eax: y
+      // edx: x
+      FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
+      // Fast-case: Both operands are numbers.
+      // Allocate a heap number, if needed.
+      Label skip_allocation;
+      switch (mode_) {
+        case OVERWRITE_LEFT:
+          __ mov(eax, Operand(edx));
+          // Fall through!
+        case OVERWRITE_RIGHT:
+          // If the argument in eax is already an object, we skip the
+          // allocation of a heap number.
+          __ test(eax, Immediate(kSmiTagMask));
+          __ j(not_zero, &skip_allocation, not_taken);
+          // Fall through!
+        case NO_OVERWRITE:
+          FloatingPointHelper::AllocateHeapNumber(masm,
+                                                  &call_runtime,
+                                                  ecx,
+                                                  edx);
+          __ bind(&skip_allocation);
+          break;
+        default: UNREACHABLE();
+      }
+      FloatingPointHelper::LoadFloatOperands(masm, ecx);
+
+      switch (op_) {
+        case Token::ADD: __ faddp(1); break;
+        case Token::SUB: __ fsubp(1); break;
+        case Token::MUL: __ fmulp(1); break;
+        case Token::DIV: __ fdivp(1); break;
+        default: UNREACHABLE();
+      }
+      __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+      __ ret(2 * kPointerSize);
+    }
+    case Token::MOD: {
+      // For MOD we go directly to runtime in the non-smi case.
+      break;
+    }
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SAR:
+    case Token::SHL:
+    case Token::SHR: {
+      FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
+      FloatingPointHelper::LoadFloatOperands(masm, ecx);
+
+      Label non_int32_operands, non_smi_result, skip_allocation;
+      // Reserve space for converted numbers.
+      __ sub(Operand(esp), Immediate(2 * kPointerSize));
+
+      // Check if right operand is int32.
+      __ fist_s(Operand(esp, 1 * kPointerSize));
+      __ fild_s(Operand(esp, 1 * kPointerSize));
+      __ fucompp();
+      __ fnstsw_ax();
+      __ sahf();
+      __ j(not_zero, &non_int32_operands);
+      __ j(parity_even, &non_int32_operands);
+
+      // Check if left operand is int32.
+      __ fist_s(Operand(esp, 0 * kPointerSize));
+      __ fild_s(Operand(esp, 0 * kPointerSize));
+      __ fucompp();
+      __ fnstsw_ax();
+      __ sahf();
+      __ j(not_zero, &non_int32_operands);
+      __ j(parity_even, &non_int32_operands);
+
+      // Get int32 operands and perform bitop.
+      __ pop(eax);
+      __ pop(ecx);
+      switch (op_) {
+        case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
+        case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
+        case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
+        case Token::SAR: __ sar(eax); break;
+        case Token::SHL: __ shl(eax); break;
+        case Token::SHR: __ shr(eax); break;
+        default: UNREACHABLE();
+      }
+
+      // Check if result is non-negative and fits in a smi.
+      __ test(eax, Immediate(0xc0000000));
+      __ j(not_zero, &non_smi_result);
+
+      // Tag smi result and return.
+      ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+      __ lea(eax, Operand(eax, times_2, kSmiTag));
+      __ ret(2 * kPointerSize);
+
+      // All ops except SHR return a signed int32 that we load in a HeapNumber.
+      if (op_ != Token::SHR) {
+        __ bind(&non_smi_result);
+        // Allocate a heap number if needed.
+        __ mov(ebx, Operand(eax));  // ebx: result
+        switch (mode_) {
+          case OVERWRITE_LEFT:
+          case OVERWRITE_RIGHT:
+            // If the operand was an object, we skip the
+            // allocation of a heap number.
+            __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
+                                1 * kPointerSize : 2 * kPointerSize));
+            __ test(eax, Immediate(kSmiTagMask));
+            __ j(not_zero, &skip_allocation, not_taken);
+            // Fall through!
+          case NO_OVERWRITE:
+            FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime,
+                                                    ecx, edx);
+            __ bind(&skip_allocation);
+            break;
+          default: UNREACHABLE();
+        }
+        // Store the result in the HeapNumber and return.
+        __ mov(Operand(esp, 1 * kPointerSize), ebx);
+        __ fild_s(Operand(esp, 1 * kPointerSize));
+        __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+        __ ret(2 * kPointerSize);
+      }
+      __ bind(&non_int32_operands);
+      // Restore stacks and operands before calling runtime.
+      __ ffree(0);
+      __ add(Operand(esp), Immediate(2 * kPointerSize));
+
+      // SHR should return uint32 - go to runtime for non-smi/negative result.
+      if (op_ == Token::SHR) __ bind(&non_smi_result);
+      __ mov(eax, Operand(esp, 1 * kPointerSize));
+      __ mov(edx, Operand(esp, 2 * kPointerSize));
+      break;
+    }
+    default: UNREACHABLE(); break;
+  }
+
+  // If all else fails, use the runtime system to get the correct
+  // result.
+  __ bind(&call_runtime);
+  switch (op_) {
+    case Token::ADD:
+      __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
+      break;
+    case Token::SUB:
+      __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
+      break;
+    case Token::MUL:
+      __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
+        break;
+    case Token::DIV:
+      __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
+      break;
+    case Token::MOD:
+      __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
+      break;
+    case Token::BIT_OR:
+      __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
+      break;
+    case Token::BIT_AND:
+      __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
+      break;
+    case Token::BIT_XOR:
+      __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
+      break;
+    case Token::SAR:
+      __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
+      break;
+    case Token::SHL:
+      __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
+      break;
+    case Token::SHR:
+      __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FloatingPointHelper::AllocateHeapNumber(MacroAssembler* masm,
+                                             Label* need_gc,
+                                             Register scratch1,
+                                             Register scratch2) {
+  ExternalReference allocation_top =
+      ExternalReference::new_space_allocation_top_address();
+  ExternalReference allocation_limit =
+      ExternalReference::new_space_allocation_limit_address();
+  __ mov(Operand(scratch1), Immediate(allocation_top));
+  __ mov(eax, Operand(scratch1, 0));
+  __ lea(scratch2, Operand(eax, HeapNumber::kSize));  // scratch2: new top
+  __ cmp(scratch2, Operand::StaticVariable(allocation_limit));
+  __ j(above, need_gc, not_taken);
+
+  __ mov(Operand(scratch1, 0), scratch2);  // store new top
+  __ mov(Operand(eax, HeapObject::kMapOffset),
+         Immediate(Factory::heap_number_map()));
+  // Tag old top and use as result.
+  __ add(Operand(eax), Immediate(kHeapObjectTag));
+}
+
+
+void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
+                                            Register scratch) {
+  Label load_smi_1, load_smi_2, done_load_1, done;
+  __ mov(scratch, Operand(esp, 2 * kPointerSize));
+  __ test(scratch, Immediate(kSmiTagMask));
+  __ j(zero, &load_smi_1, not_taken);
+  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
+  __ bind(&done_load_1);
+
+  __ mov(scratch, Operand(esp, 1 * kPointerSize));
+  __ test(scratch, Immediate(kSmiTagMask));
+  __ j(zero, &load_smi_2, not_taken);
+  __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
+  __ jmp(&done);
+
+  __ bind(&load_smi_1);
+  __ sar(scratch, kSmiTagSize);
+  __ push(scratch);
+  __ fild_s(Operand(esp, 0));
+  __ pop(scratch);
+  __ jmp(&done_load_1);
+
+  __ bind(&load_smi_2);
+  __ sar(scratch, kSmiTagSize);
+  __ push(scratch);
+  __ fild_s(Operand(esp, 0));
+  __ pop(scratch);
+
+  __ bind(&done);
+}
+
+
+void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
+                                             Label* non_float,
+                                             Register scratch) {
+  Label test_other, done;
+  // Test if both operands are floats or smi -> scratch=k_is_float;
+  // Otherwise scratch = k_not_float.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &test_other, not_taken);  // argument in edx is OK
+  __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
+  __ cmp(scratch, Factory::heap_number_map());
+  __ j(not_equal, non_float);  // argument in edx is not a number -> NaN
+
+  __ bind(&test_other);
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &done);  // argument in eax is OK
+  __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
+  __ cmp(scratch, Factory::heap_number_map());
+  __ j(not_equal, non_float);  // argument in eax is not a number -> NaN
+
+  // Fall-through: Both operands are numbers.
+  __ bind(&done);
+}
+
+
+void UnarySubStub::Generate(MacroAssembler* masm) {
+  Label undo;
+  Label slow;
+  Label done;
+  Label try_float;
+
+  // Check whether the value is a smi.
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(not_zero, &try_float, not_taken);
+
+  // Enter runtime system if the value of the expression is zero
+  // to make sure that we switch between 0 and -0.
+  __ test(eax, Operand(eax));
+  __ j(zero, &slow, not_taken);
+
+  // The value of the expression is a smi that is not zero.  Try
+  // optimistic subtraction '0 - value'.
+  __ mov(edx, Operand(eax));
+  __ Set(eax, Immediate(0));
+  __ sub(eax, Operand(edx));
+  __ j(overflow, &undo, not_taken);
+
+  // If result is a smi we are done.
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &done, taken);
+
+  // Restore eax and enter runtime system.
+  __ bind(&undo);
+  __ mov(eax, Operand(edx));
+
+  // Enter runtime system.
+  __ bind(&slow);
+  __ pop(ecx);  // pop return address
+  __ push(eax);
+  __ push(ecx);  // push return address
+  __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
+
+  // Try floating point case.
+  __ bind(&try_float);
+  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ cmp(edx, Factory::heap_number_map());
+  __ j(not_equal, &slow);
+  __ mov(edx, Operand(eax));
+  // edx: operand
+  FloatingPointHelper::AllocateHeapNumber(masm, &undo, ebx, ecx);
+  // eax: allocated 'empty' number
+  __ fld_d(FieldOperand(edx, HeapNumber::kValueOffset));
+  __ fchs();
+  __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
+
+  __ bind(&done);
+
+  __ StubReturn(1);
+}
+
+
+void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
+  // Check if the calling frame is an arguments adaptor frame.
+  Label adaptor;
+  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
+  __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
+  __ j(equal, &adaptor);
+
+  // Nothing to do: The formal number of parameters has already been
+  // passed in register eax by calling function. Just return it.
+  __ ret(0);
+
+  // Arguments adaptor case: Read the arguments length from the
+  // adaptor frame and return it.
+  __ bind(&adaptor);
+  __ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ ret(0);
+}
+
+
+void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
+  // The displacement is used for skipping the frame pointer on the
+  // stack. It is the offset of the last parameter (if any) relative
+  // to the frame pointer.
+  static const int kDisplacement = 1 * kPointerSize;
+
+  // Check that the key is a smi.
+  Label slow;
+  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // skip return address
+  __ test(ebx, Immediate(kSmiTagMask));
+  __ j(not_zero, &slow, not_taken);
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label adaptor;
+  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
+  __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
+  __ j(equal, &adaptor);
+
+  // Check index against formal parameters count limit passed in
+  // through register eax. Use unsigned comparison to get negative
+  // check for free.
+  __ cmp(ebx, Operand(eax));
+  __ j(above_equal, &slow, not_taken);
+
+  // Read the argument from the stack and return it.
+  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);  // shifting code depends on this
+  __ lea(edx, Operand(ebp, eax, times_2, 0));
+  __ neg(ebx);
+  __ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
+  __ ret(0);
+
+  // Arguments adaptor case: Check index against actual arguments
+  // limit found in the arguments adaptor frame. Use unsigned
+  // comparison to get negative check for free.
+  __ bind(&adaptor);
+  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ cmp(ebx, Operand(ecx));
+  __ j(above_equal, &slow, not_taken);
+
+  // Read the argument from the stack and return it.
+  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);  // shifting code depends on this
+  __ lea(edx, Operand(edx, ecx, times_2, 0));
+  __ neg(ebx);
+  __ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
+  __ ret(0);
+
+  // Slow-case: Handle non-smi or out-of-bounds access to arguments
+  // by calling the runtime system.
+  __ bind(&slow);
+  __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
+}
+
+
+void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
+  // The displacement is used for skipping the return address and the
+  // frame pointer on the stack. It is the offset of the last
+  // parameter (if any) relative to the frame pointer.
+  static const int kDisplacement = 2 * kPointerSize;
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label runtime;
+  __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+  __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
+  __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
+  __ j(not_equal, &runtime);
+
+  // Patch the arguments.length and the parameters pointer.
+  __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ mov(Operand(esp, 1 * kPointerSize), ecx);
+  __ lea(edx, Operand(edx, ecx, times_2, kDisplacement));
+  __ mov(Operand(esp, 2 * kPointerSize), edx);
+
+  // Do the runtime call to allocate the arguments object.
+  __ bind(&runtime);
+  __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
+}
+
+
+void CompareStub::Generate(MacroAssembler* masm) {
+  Label call_builtin, done;
+
+  // If we're doing a strict equality comparison, we generate code
+  // to do fast comparison for objects and oddballs. Numbers and
+  // strings still go through the usual slow-case code.
+  if (strict_) {
+    Label slow;
+    __ test(eax, Immediate(kSmiTagMask));
+    __ j(zero, &slow);
+
+    // Get the type of the first operand.
+    __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
+    __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+
+    // If the first object is an object, we do pointer comparison.
+    ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+    Label non_object;
+    __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+    __ j(less, &non_object);
+    __ sub(eax, Operand(edx));
+    __ ret(0);
+
+    // Check for oddballs: true, false, null, undefined.
+    __ bind(&non_object);
+    __ cmp(ecx, ODDBALL_TYPE);
+    __ j(not_equal, &slow);
+
+    // If the oddball isn't undefined, we do pointer comparison. For
+    // the undefined value, we have to be careful and check for
+    // 'undetectable' objects too.
+    Label undefined;
+    __ cmp(Operand(eax), Immediate(Factory::undefined_value()));
+    __ j(equal, &undefined);
+    __ sub(eax, Operand(edx));
+    __ ret(0);
+
+    // Undefined case: If the other operand isn't undefined too, we
+    // have to check if it's 'undetectable'.
+    Label check_undetectable;
+    __ bind(&undefined);
+    __ cmp(Operand(edx), Immediate(Factory::undefined_value()));
+    __ j(not_equal, &check_undetectable);
+    __ Set(eax, Immediate(0));
+    __ ret(0);
+
+    // Check for undetectability of the other operand.
+    Label not_strictly_equal;
+    __ bind(&check_undetectable);
+    __ test(edx, Immediate(kSmiTagMask));
+    __ j(zero, &not_strictly_equal);
+    __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+    __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
+    __ and_(ecx, 1 << Map::kIsUndetectable);
+    __ cmp(ecx, 1 << Map::kIsUndetectable);
+    __ j(not_equal, &not_strictly_equal);
+    __ Set(eax, Immediate(0));
+    __ ret(0);
+
+    // No cigar: Objects aren't strictly equal. Register eax contains
+    // a non-smi value so it can't be 0. Just return.
+    ASSERT(kHeapObjectTag != 0);
+    __ bind(&not_strictly_equal);
+    __ ret(0);
+
+    // Fall through to the general case.
+    __ bind(&slow);
+  }
+
+  // Save the return address (and get it off the stack).
+  __ pop(ecx);
+
+  // Push arguments.
+  __ push(eax);
+  __ push(edx);
+  __ push(ecx);
+
+  // Inlined floating point compare.
+  // Call builtin if operands are not floating point or smi.
+  FloatingPointHelper::CheckFloatOperands(masm, &call_builtin, ebx);
+  FloatingPointHelper::LoadFloatOperands(masm, ecx);
+  __ FCmp();
+
+  // Jump to builtin for NaN.
+  __ j(parity_even, &call_builtin, not_taken);
+
+  // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up.
+  Label below_lbl, above_lbl;
+  // use edx, eax to convert unsigned to signed comparison
+  __ j(below, &below_lbl, not_taken);
+  __ j(above, &above_lbl, not_taken);
+
+  __ xor_(eax, Operand(eax));  // equal
+  __ ret(2 * kPointerSize);
+
+  __ bind(&below_lbl);
+  __ mov(eax, -1);
+  __ ret(2 * kPointerSize);
+
+  __ bind(&above_lbl);
+  __ mov(eax, 1);
+  __ ret(2 * kPointerSize);  // eax, edx were pushed
+
+  __ bind(&call_builtin);
+  // must swap argument order
+  __ pop(ecx);
+  __ pop(edx);
+  __ pop(eax);
+  __ push(edx);
+  __ push(eax);
+
+  // Figure out which native to call and setup the arguments.
+  Builtins::JavaScript builtin;
+  if (cc_ == equal) {
+    builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  } else {
+    builtin = Builtins::COMPARE;
+    int ncr;  // NaN compare result
+    if (cc_ == less || cc_ == less_equal) {
+      ncr = GREATER;
+    } else {
+      ASSERT(cc_ == greater || cc_ == greater_equal);  // remaining cases
+      ncr = LESS;
+    }
+    __ push(Immediate(Smi::FromInt(ncr)));
+  }
+
+  // Restore return address on the stack.
+  __ push(ecx);
+
+  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+  // tagged as a small integer.
+  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+}
+
+
+void StackCheckStub::Generate(MacroAssembler* masm) {
+  // Because builtins always remove the receiver from the stack, we
+  // have to fake one to avoid underflowing the stack. The receiver
+  // must be inserted below the return address on the stack so we
+  // temporarily store that in a register.
+  __ pop(eax);
+  __ push(Immediate(Smi::FromInt(0)));
+  __ push(eax);
+
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
+}
+
+
+void CallFunctionStub::Generate(MacroAssembler* masm) {
+  Label slow;
+
+  // Get the function to call from the stack.
+  // +2 ~ receiver, return address
+  __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
+
+  // Check that the function really is a JavaScript function.
+  __ test(edi, Immediate(kSmiTagMask));
+  __ j(zero, &slow, not_taken);
+  // Get the map.
+  __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ cmp(ecx, JS_FUNCTION_TYPE);
+  __ j(not_equal, &slow, not_taken);
+
+  // Fast-case: Just invoke the function.
+  ParameterCount actual(argc_);
+  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
+
+  // Slow-case: Non-function called.
+  __ bind(&slow);
+  __ Set(eax, Immediate(argc_));
+  __ Set(ebx, Immediate(0));
+  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
+  Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+  __ jmp(adaptor, RelocInfo::CODE_TARGET);
+}
+
+
+void RevertToNumberStub::Generate(MacroAssembler* masm) {
+  // Revert optimistic increment/decrement.
+  if (is_increment_) {
+    __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
+  } else {
+    __ add(Operand(eax), Immediate(Smi::FromInt(1)));
+  }
+
+  __ pop(ecx);
+  __ push(eax);
+  __ push(ecx);
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+  // Code never returns due to JUMP_FUNCTION.
+}
+
+
+void CounterOpStub::Generate(MacroAssembler* masm) {
+  // Store to the result on the stack (skip return address) before
+  // performing the count operation.
+  if (is_postfix_) {
+    __ mov(Operand(esp, result_offset_ + kPointerSize), eax);
+  }
+
+  // Revert optimistic increment/decrement but only for prefix
+  // counts. For postfix counts it has already been reverted before
+  // the conversion to numbers.
+  if (!is_postfix_) {
+    if (is_increment_) {
+      __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
+    } else {
+      __ add(Operand(eax), Immediate(Smi::FromInt(1)));
+    }
+  }
+
+  // Compute the new value by calling the right JavaScript native.
+  __ pop(ecx);
+  __ push(eax);
+  __ push(ecx);
+  Builtins::JavaScript builtin = is_increment_ ? Builtins::INC : Builtins::DEC;
+  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+  // Code never returns due to JUMP_FUNCTION.
+}
+
+
+void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
+  ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize);  // adjust this code
+  ExternalReference handler_address(Top::k_handler_address);
+  __ mov(edx, Operand::StaticVariable(handler_address));
+  __ mov(ecx, Operand(edx, -1 * kPointerSize));  // get next in chain
+  __ mov(Operand::StaticVariable(handler_address), ecx);
+  __ mov(esp, Operand(edx));
+  __ pop(edi);
+  __ pop(ebp);
+  __ pop(edx);  // remove code pointer
+  __ pop(edx);  // remove state
+
+  // Before returning we restore the context from the frame pointer if not NULL.
+  // The frame pointer is NULL in the exception handler of a JS entry frame.
+  __ xor_(esi, Operand(esi));  // tentatively set context pointer to NULL
+  Label skip;
+  __ cmp(ebp, 0);
+  __ j(equal, &skip, not_taken);
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ bind(&skip);
+
+  __ ret(0);
+}
+
+
+void CEntryStub::GenerateCore(MacroAssembler* masm,
+                              Label* throw_normal_exception,
+                              Label* throw_out_of_memory_exception,
+                              StackFrame::Type frame_type,
+                              bool do_gc) {
+  // eax: result parameter for PerformGC, if any
+  // ebx: pointer to C function  (C callee-saved)
+  // ebp: frame pointer  (restored after C call)
+  // esp: stack pointer  (restored after C call)
+  // edi: number of arguments including receiver  (C callee-saved)
+  // esi: pointer to the first argument (C callee-saved)
+
+  if (do_gc) {
+    __ mov(Operand(esp, 0 * kPointerSize), eax);  // Result.
+    __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
+  }
+
+  // Call C function.
+  __ mov(Operand(esp, 0 * kPointerSize), edi);  // argc.
+  __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv.
+  __ call(Operand(ebx));
+  // Result is in eax or edx:eax - do not destroy these registers!
+
+  // Check for failure result.
+  Label failure_returned;
+  ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
+  __ lea(ecx, Operand(eax, 1));
+  // Lower 2 bits of ecx are 0 iff eax has failure tag.
+  __ test(ecx, Immediate(kFailureTagMask));
+  __ j(zero, &failure_returned, not_taken);
+
+  // Exit the JavaScript to C++ exit frame.
+  __ LeaveExitFrame(frame_type);
+  __ ret(0);
+
+  // Handling of failure.
+  __ bind(&failure_returned);
+
+  Label retry;
+  // If the returned exception is RETRY_AFTER_GC continue at retry label
+  ASSERT(Failure::RETRY_AFTER_GC == 0);
+  __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
+  __ j(zero, &retry, taken);
+
+  Label continue_exception;
+  // If the returned failure is EXCEPTION then promote Top::pending_exception().
+  __ cmp(eax, reinterpret_cast<int32_t>(Failure::Exception()));
+  __ j(not_equal, &continue_exception);
+
+  // Retrieve the pending exception and clear the variable.
+  ExternalReference pending_exception_address(Top::k_pending_exception_address);
+  __ mov(eax, Operand::StaticVariable(pending_exception_address));
+  __ mov(edx,
+         Operand::StaticVariable(ExternalReference::the_hole_value_location()));
+  __ mov(Operand::StaticVariable(pending_exception_address), edx);
+
+  __ bind(&continue_exception);
+  // Special handling of out of memory exception.
+  __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
+  __ j(equal, throw_out_of_memory_exception);
+
+  // Handle normal exception.
+  __ jmp(throw_normal_exception);
+
+  // Retry.
+  __ bind(&retry);
+}
+
+
+void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
+  // Fetch top stack handler.
+  ExternalReference handler_address(Top::k_handler_address);
+  __ mov(edx, Operand::StaticVariable(handler_address));
+
+  // Unwind the handlers until the ENTRY handler is found.
+  Label loop, done;
+  __ bind(&loop);
+  // Load the type of the current stack handler.
+  const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
+      StackHandlerConstants::kStateOffset;
+  __ cmp(Operand(edx, kStateOffset), Immediate(StackHandler::ENTRY));
+  __ j(equal, &done);
+  // Fetch the next handler in the list.
+  const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
+      StackHandlerConstants::kNextOffset;
+  __ mov(edx, Operand(edx, kNextOffset));
+  __ jmp(&loop);
+  __ bind(&done);
+
+  // Set the top handler address to next handler past the current ENTRY handler.
+  __ mov(eax, Operand(edx, kNextOffset));
+  __ mov(Operand::StaticVariable(handler_address), eax);
+
+  // Set external caught exception to false.
+  __ mov(eax, false);
+  ExternalReference external_caught(Top::k_external_caught_exception_address);
+  __ mov(Operand::StaticVariable(external_caught), eax);
+
+  // Set pending exception and eax to out of memory exception.
+  __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
+  ExternalReference pending_exception(Top::k_pending_exception_address);
+  __ mov(Operand::StaticVariable(pending_exception), eax);
+
+  // Restore the stack to the address of the ENTRY handler
+  __ mov(esp, Operand(edx));
+
+  // Clear the context pointer;
+  __ xor_(esi, Operand(esi));
+
+  // Restore registers from handler.
+  __ pop(edi);  // PP
+  __ pop(ebp);  // FP
+  __ pop(edx);  // Code
+  __ pop(edx);  // State
+
+  __ ret(0);
+}
+
+
+void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
+  // eax: number of arguments including receiver
+  // ebx: pointer to C function  (C callee-saved)
+  // ebp: frame pointer  (restored after C call)
+  // esp: stack pointer  (restored after C call)
+  // esi: current context (C callee-saved)
+  // edi: caller's parameter pointer pp  (C callee-saved)
+
+  // NOTE: Invocations of builtins may return failure objects
+  // instead of a proper result. The builtin entry handles
+  // this by performing a garbage collection and retrying the
+  // builtin once.
+
+  StackFrame::Type frame_type = is_debug_break ?
+      StackFrame::EXIT_DEBUG :
+      StackFrame::EXIT;
+
+  // Enter the exit frame that transitions from JavaScript to C++.
+  __ EnterExitFrame(frame_type);
+
+  // eax: result parameter for PerformGC, if any (setup below)
+  // ebx: pointer to builtin function  (C callee-saved)
+  // ebp: frame pointer  (restored after C call)
+  // esp: stack pointer  (restored after C call)
+  // edi: number of arguments including receiver (C callee-saved)
+  // esi: argv pointer (C callee-saved)
+
+  Label throw_out_of_memory_exception;
+  Label throw_normal_exception;
+
+#ifdef DEBUG
+  if (FLAG_gc_greedy) {
+    Failure* failure = Failure::RetryAfterGC(0);
+    __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
+  }
+  GenerateCore(masm, &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               FLAG_gc_greedy);
+#else
+  GenerateCore(masm,
+               &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               false);
+#endif
+
+  GenerateCore(masm,
+               &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               true);
+
+  __ bind(&throw_out_of_memory_exception);
+  GenerateThrowOutOfMemory(masm);
+  // control flow for generated will not return.
+
+  __ bind(&throw_normal_exception);
+  GenerateThrowTOS(masm);
+}
+
+
+void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
+  Label invoke, exit;
+
+  // Setup frame.
+  __ push(ebp);
+  __ mov(ebp, Operand(esp));
+
+  // Save callee-saved registers (C calling conventions).
+  int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
+  // Push something that is not an arguments adaptor.
+  __ push(Immediate(~ArgumentsAdaptorFrame::SENTINEL));
+  __ push(Immediate(Smi::FromInt(marker)));  // @ function offset
+  __ push(edi);
+  __ push(esi);
+  __ push(ebx);
+
+  // Save copies of the top frame descriptor on the stack.
+  ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
+  __ push(Operand::StaticVariable(c_entry_fp));
+
+  // Call a faked try-block that does the invoke.
+  __ call(&invoke);
+
+  // Caught exception: Store result (exception) in the pending
+  // exception field in the JSEnv and return a failure sentinel.
+  ExternalReference pending_exception(Top::k_pending_exception_address);
+  __ mov(Operand::StaticVariable(pending_exception), eax);
+  __ mov(eax, Handle<Failure>(Failure::Exception()));
+  __ jmp(&exit);
+
+  // Invoke: Link this frame into the handler chain.
+  __ bind(&invoke);
+  __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
+  __ push(eax);  // flush TOS
+
+  // Clear any pending exceptions.
+  __ mov(edx,
+         Operand::StaticVariable(ExternalReference::the_hole_value_location()));
+  __ mov(Operand::StaticVariable(pending_exception), edx);
+
+  // Fake a receiver (NULL).
+  __ push(Immediate(0));  // receiver
+
+  // Invoke the function by calling through JS entry trampoline
+  // builtin and pop the faked function when we return. Notice that we
+  // cannot store a reference to the trampoline code directly in this
+  // stub, because the builtin stubs may not have been generated yet.
+  if (is_construct) {
+    ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
+    __ mov(Operand(edx), Immediate(construct_entry));
+  } else {
+    ExternalReference entry(Builtins::JSEntryTrampoline);
+    __ mov(Operand(edx), Immediate(entry));
+  }
+  __ mov(edx, Operand(edx, 0));  // deref address
+  __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
+  __ call(Operand(edx));
+
+  // Unlink this frame from the handler chain.
+  __ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
+  // Pop next_sp.
+  __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
+
+  // Restore the top frame descriptor from the stack.
+  __ bind(&exit);
+  __ pop(Operand::StaticVariable(ExternalReference(Top::k_c_entry_fp_address)));
+
+  // Restore callee-saved registers (C calling conventions).
+  __ pop(ebx);
+  __ pop(esi);
+  __ pop(edi);
+  __ add(Operand(esp), Immediate(2 * kPointerSize));  // remove markers
+
+  // Restore frame pointer and return.
+  __ pop(ebp);
+  __ ret(0);
+}
+
+
+void InstanceofStub::Generate(MacroAssembler* masm) {
+  // Get the object - go slow case if it's a smi.
+  Label slow;
+  __ mov(eax, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, function
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &slow, not_taken);
+
+  // Check that the left hand is a JS object.
+  __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));  // ebx - object map
+  __ movzx_b(ecx, FieldOperand(eax, Map::kInstanceTypeOffset));  // ecx - type
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(less, &slow, not_taken);
+  __ cmp(ecx, LAST_JS_OBJECT_TYPE);
+  __ j(greater, &slow, not_taken);
+
+  // Get the prototype of the function.
+  __ mov(edx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
+  __ TryGetFunctionPrototype(edx, ebx, ecx, &slow);
+
+  // Check that the function prototype is a JS object.
+  __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(less, &slow, not_taken);
+  __ cmp(ecx, LAST_JS_OBJECT_TYPE);
+  __ j(greater, &slow, not_taken);
+
+  // Register mapping: eax is object map and ebx is function prototype.
+  __ mov(ecx, FieldOperand(eax, Map::kPrototypeOffset));
+
+  // Loop through the prototype chain looking for the function prototype.
+  Label loop, is_instance, is_not_instance;
+  __ bind(&loop);
+  __ cmp(ecx, Operand(ebx));
+  __ j(equal, &is_instance);
+  __ cmp(Operand(ecx), Immediate(Factory::null_value()));
+  __ j(equal, &is_not_instance);
+  __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
+  __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset));
+  __ jmp(&loop);
+
+  __ bind(&is_instance);
+  __ Set(eax, Immediate(0));
+  __ ret(2 * kPointerSize);
+
+  __ bind(&is_not_instance);
+  __ Set(eax, Immediate(Smi::FromInt(1)));
+  __ ret(2 * kPointerSize);
+
+  // Slow-case: Go through the JavaScript implementation.
+  __ bind(&slow);
+  __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/codegen-ia32.h b/regexp2000/src/codegen-ia32.h
new file mode 100644 (file)
index 0000000..3f1bf22
--- /dev/null
@@ -0,0 +1,428 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CODEGEN_IA32_H_
+#define V8_CODEGEN_IA32_H_
+
+#include "scopes.h"
+
+namespace v8 { namespace internal {
+
+// Forward declarations
+class DeferredCode;
+
+// Mode to overwrite BinaryExpression values.
+enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+
+enum InitState { CONST_INIT, NOT_CONST_INIT };
+enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
+
+
+// -------------------------------------------------------------------------
+// Virtual frame
+
+class VirtualFrame BASE_EMBEDDED {
+ public:
+  explicit VirtualFrame(CodeGenerator* cgen);
+
+  void Enter();
+  void Exit();
+
+  void AllocateLocals();
+
+  Operand Top() const { return Operand(esp, 0); }
+
+  Operand Element(int index) const {
+    return Operand(esp, index * kPointerSize);
+  }
+
+  Operand Local(int index) const {
+    ASSERT(0 <= index && index < frame_local_count_);
+    return Operand(ebp, kLocal0Offset - index * kPointerSize);
+  }
+
+  Operand Function() const { return Operand(ebp, kFunctionOffset); }
+
+  Operand Context() const { return Operand(ebp, kContextOffset); }
+
+  Operand Parameter(int index) const {
+    ASSERT(-1 <= index && index < parameter_count_);
+    return Operand(ebp, (1 + parameter_count_ - index) * kPointerSize);
+  }
+
+  Operand Receiver() const { return Parameter(-1); }
+
+  inline void Drop(int count);
+
+  inline void Pop();
+  inline void Pop(Register reg);
+  inline void Pop(Operand operand);
+
+  inline void Push(Register reg);
+  inline void Push(Operand operand);
+  inline void Push(Immediate immediate);
+
+ private:
+  static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
+  static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
+  static const int kContextOffset = StandardFrameConstants::kContextOffset;
+
+  MacroAssembler* masm_;
+  int frame_local_count_;
+  int parameter_count_;
+};
+
+
+// -------------------------------------------------------------------------
+// Reference support
+
+// A reference is a C++ stack-allocated object that keeps an ECMA
+// reference on the execution stack while in scope. For variables
+// the reference is empty, indicating that it isn't necessary to
+// store state on the stack for keeping track of references to those.
+// For properties, we keep either one (named) or two (indexed) values
+// on the execution stack to represent the reference.
+
+class Reference BASE_EMBEDDED {
+ public:
+  // The values of the types is important, see size().
+  enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
+  Reference(CodeGenerator* cgen, Expression* expression);
+  ~Reference();
+
+  Expression* expression() const { return expression_; }
+  Type type() const { return type_; }
+  void set_type(Type value) {
+    ASSERT(type_ == ILLEGAL);
+    type_ = value;
+  }
+
+  // The size of the reference or -1 if the reference is illegal.
+  int size() const { return type_; }
+
+  bool is_illegal() const { return type_ == ILLEGAL; }
+  bool is_slot() const { return type_ == SLOT; }
+  bool is_property() const { return type_ == NAMED || type_ == KEYED; }
+
+  // Return the name.  Only valid for named property references.
+  Handle<String> GetName();
+
+  // Generate code to push the value of the reference on top of the
+  // expression stack.  The reference is expected to be already on top of
+  // the expression stack, and it is left in place with its value above it.
+  void GetValue(TypeofState typeof_state);
+
+  // Generate code to store the value on top of the expression stack in the
+  // reference.  The reference is expected to be immediately below the value
+  // on the expression stack.  The stored value is left in place (with the
+  // reference intact below it) to support chained assignments.
+  void SetValue(InitState init_state);
+
+ private:
+  CodeGenerator* cgen_;
+  Expression* expression_;
+  Type type_;
+};
+
+
+// -------------------------------------------------------------------------
+// Code generation state
+
+// The state is passed down the AST by the code generator (and back up, in
+// the form of the state of the label pair).  It is threaded through the
+// call stack.  Constructing a state implicitly pushes it on the owning code
+// generator's stack of states, and destroying one implicitly pops it.
+
+class CodeGenState BASE_EMBEDDED {
+ public:
+  // Create an initial code generator state.  Destroying the initial state
+  // leaves the code generator with a NULL state.
+  explicit CodeGenState(CodeGenerator* owner);
+
+  // Create a code generator state based on a code generator's current
+  // state.  The new state has its own access type and pair of branch
+  // labels, and no reference.
+  CodeGenState(CodeGenerator* owner,
+               TypeofState typeof_state,
+               Label* true_target,
+               Label* false_target);
+
+  // Destroy a code generator state and restore the owning code generator's
+  // previous state.
+  ~CodeGenState();
+
+  TypeofState typeof_state() const { return typeof_state_; }
+  Label* true_target() const { return true_target_; }
+  Label* false_target() const { return false_target_; }
+
+ private:
+  CodeGenerator* owner_;
+  TypeofState typeof_state_;
+  Label* true_target_;
+  Label* false_target_;
+  CodeGenState* previous_;
+};
+
+
+
+
+// -------------------------------------------------------------------------
+// CodeGenerator
+
+class CodeGenerator: public Visitor {
+ public:
+  // Takes a function literal, generates code for it. This function should only
+  // be called by compiler.cc.
+  static Handle<Code> MakeCode(FunctionLiteral* fun,
+                               Handle<Script> script,
+                               bool is_eval);
+
+  static void SetFunctionInfo(Handle<JSFunction> fun,
+                              int length,
+                              int function_token_position,
+                              int start_position,
+                              int end_position,
+                              bool is_expression,
+                              bool is_toplevel,
+                              Handle<Script> script);
+
+  // Accessors
+  MacroAssembler* masm() { return masm_; }
+
+  VirtualFrame* frame() const { return frame_; }
+
+  CodeGenState* state() { return state_; }
+  void set_state(CodeGenState* state) { state_ = state; }
+
+  void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
+
+ private:
+  // Construction/Destruction
+  CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
+  virtual ~CodeGenerator() { delete masm_; }
+
+  // Accessors
+  Scope* scope() const { return scope_; }
+
+  void ProcessDeferred();
+
+  bool is_eval() { return is_eval_; }
+
+  // State
+  bool has_cc() const  { return cc_reg_ >= 0; }
+  TypeofState typeof_state() const { return state_->typeof_state(); }
+  Label* true_target() const  { return state_->true_target(); }
+  Label* false_target() const  { return state_->false_target(); }
+
+
+  // Node visitors.
+#define DEF_VISIT(type) \
+  void Visit##type(type* node);
+  NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+  // Main code generation function
+  void GenCode(FunctionLiteral* fun);
+
+  // The following are used by class Reference.
+  void LoadReference(Reference* ref);
+  void UnloadReference(Reference* ref);
+
+  Operand ContextOperand(Register context, int index) const {
+    return Operand(context, Context::SlotOffset(index));
+  }
+
+  Operand SlotOperand(Slot* slot, Register tmp);
+
+
+  // Expressions
+  Operand GlobalObject() const {
+    return ContextOperand(esi, Context::GLOBAL_INDEX);
+  }
+
+  void LoadCondition(Expression* x,
+                     TypeofState typeof_state,
+                     Label* true_target,
+                     Label* false_target,
+                     bool force_cc);
+  void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
+  void LoadGlobal();
+  void LoadGlobalReceiver(Register scratch);
+
+  // Read a value from a slot and leave it on top of the expression stack.
+  void LoadFromSlot(Slot* slot, TypeofState typeof_state);
+
+  // Special code for typeof expressions: Unfortunately, we must
+  // be careful when loading the expression in 'typeof'
+  // expressions. We are not allowed to throw reference errors for
+  // non-existing properties of the global object, so we must make it
+  // look like an explicit property access, instead of an access
+  // through the context chain.
+  void LoadTypeofExpression(Expression* x);
+
+  void ToBoolean(Label* true_target, Label* false_target);
+
+  void GenericBinaryOperation(Token::Value op,
+      const OverwriteMode overwrite_mode = NO_OVERWRITE);
+
+  void Comparison(Condition cc, bool strict = false);
+
+  // Inline small integer literals. To prevent long attacker-controlled byte
+  // sequences, we only inline small Smis.
+  static const int kMaxSmiInlinedBits = 16;
+  bool IsInlineSmi(Literal* literal);
+  void SmiComparison(Condition cc,  Handle<Object> value, bool strict = false);
+  void SmiOperation(Token::Value op,
+                    Handle<Object> value,
+                    bool reversed,
+                    OverwriteMode overwrite_mode);
+
+  void CallWithArguments(ZoneList<Expression*>* arguments, int position);
+
+  // Control flow
+  void Branch(bool if_true, Label* L);
+  void CheckStack();
+  void CleanStack(int num_bytes);
+
+  bool CheckForInlineRuntimeCall(CallRuntime* node);
+  Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
+  void ProcessDeclarations(ZoneList<Declaration*>* declarations);
+
+  Handle<Code> ComputeCallInitialize(int argc);
+
+  // Declare global variables and functions in the given array of
+  // name/value pairs.
+  void DeclareGlobals(Handle<FixedArray> pairs);
+
+  // Instantiate the function boilerplate.
+  void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
+
+  // Support for type checks.
+  void GenerateIsSmi(ZoneList<Expression*>* args);
+  void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
+  void GenerateIsArray(ZoneList<Expression*>* args);
+
+  // Support for arguments.length and arguments[?].
+  void GenerateArgumentsLength(ZoneList<Expression*>* args);
+  void GenerateArgumentsAccess(ZoneList<Expression*>* args);
+
+  // Support for accessing the value field of an object (used by Date).
+  void GenerateValueOf(ZoneList<Expression*>* args);
+  void GenerateSetValueOf(ZoneList<Expression*>* args);
+
+  // Fast support for charCodeAt(n).
+  void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
+
+  // Fast support for object equality testing.
+  void GenerateObjectEquals(ZoneList<Expression*>* args);
+
+
+  // Methods and constants for fast case switch statement support.
+  //
+  // Only allow fast-case switch if the range of labels is at most
+  // this factor times the number of case labels.
+  // Value is derived from comparing the size of code generated by the normal
+  // switch code for Smi-labels to the size of a single pointer. If code
+  // quality increases this number should be decreased to match.
+  static const int kFastSwitchMaxOverheadFactor = 5;
+
+  // Minimal number of switch cases required before we allow jump-table
+  // optimization.
+  static const int kFastSwitchMinCaseCount = 5;
+
+  // The limit of the range of a fast-case switch, as a factor of the number
+  // of cases of the switch. Each platform should return a value that
+  // is optimal compared to the default code generated for a switch statement
+  // on that platform.
+  int FastCaseSwitchMaxOverheadFactor();
+
+  // The minimal number of cases in a switch before the fast-case switch
+  // optimization is enabled. Each platform should return a value that
+  // is optimal compared to the default code generated for a switch statement
+  // on that platform.
+  int FastCaseSwitchMinCaseCount();
+
+  // Allocate a jump table and create code to jump through it.
+  // Should call GenerateFastCaseSwitchCases to generate the code for
+  // all the cases at the appropriate point.
+  void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
+                                       int min_index,
+                                       int range,
+                                       Label* fail_label,
+                                       Vector<Label*> case_targets,
+                                       Vector<Label> case_labels);
+
+  // Generate the code for cases for the fast case switch.
+  // Called by GenerateFastCaseSwitchJumpTable.
+  void GenerateFastCaseSwitchCases(SwitchStatement* node,
+                                   Vector<Label> case_labels);
+
+  // Fast support for constant-Smi switches.
+  void GenerateFastCaseSwitchStatement(SwitchStatement* node,
+                                       int min_index,
+                                       int range,
+                                       int default_index);
+
+  // Fast support for constant-Smi switches. Tests whether switch statement
+  // permits optimization and calls GenerateFastCaseSwitch if it does.
+  // Returns true if the fast-case switch was generated, and false if not.
+  bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node);
+
+
+  // Bottle-neck interface to call the Assembler to generate the statement
+  // position. This allows us to easily control whether statement positions
+  // should be generated or not.
+  void RecordStatementPosition(Node* node);
+
+  bool is_eval_;  // Tells whether code is generated for eval.
+  Handle<Script> script_;
+  List<DeferredCode*> deferred_;
+
+  // Assembler
+  MacroAssembler* masm_;  // to generate code
+
+  // Code generation state
+  Scope* scope_;
+  VirtualFrame* frame_;
+  Condition cc_reg_;
+  CodeGenState* state_;
+  bool is_inside_try_;
+  int break_stack_height_;
+
+  // Labels
+  Label function_return_;
+
+  friend class VirtualFrame;
+  friend class Reference;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_CODEGEN_IA32_H_
diff --git a/regexp2000/src/codegen-inl.h b/regexp2000/src/codegen-inl.h
new file mode 100644 (file)
index 0000000..c6abbec
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef V8_CODEGEN_INL_H_
+#define V8_CODEGEN_INL_H_
+
+#include "codegen.h"
+
+
+namespace v8 { namespace internal {
+
+
+// -----------------------------------------------------------------------------
+// Support for "structured" code comments.
+//
+// By selecting matching brackets in disassembler output,
+// code segments can be identified more easily.
+
+#ifdef DEBUG
+
+class Comment BASE_EMBEDDED {
+ public:
+  Comment(MacroAssembler* masm, const char* msg)
+    : masm_(masm),
+      msg_(msg) {
+    masm_->RecordComment(msg);
+  }
+
+  ~Comment() {
+    if (msg_[0] == '[')
+      masm_->RecordComment("]");
+  }
+
+ private:
+  MacroAssembler* masm_;
+  const char* msg_;
+};
+
+#else
+
+class Comment BASE_EMBEDDED {
+ public:
+  Comment(MacroAssembler*, const char*)  {}
+};
+
+#endif  // DEBUG
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_CODEGEN_INL_H_
diff --git a/regexp2000/src/codegen.cc b/regexp2000/src/codegen.cc
new file mode 100644 (file)
index 0000000..47f7842
--- /dev/null
@@ -0,0 +1,474 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "codegen-inl.h"
+#include "debug.h"
+#include "prettyprinter.h"
+#include "scopeinfo.h"
+#include "runtime.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+DeferredCode::DeferredCode(CodeGenerator* generator)
+  : masm_(generator->masm()),
+    generator_(generator),
+    statement_position_(masm_->last_statement_position()),
+    position_(masm_->last_position()) {
+  generator->AddDeferred(this);
+#ifdef DEBUG
+  comment_ = "";
+#endif
+}
+
+
+void CodeGenerator::ProcessDeferred() {
+  while (!deferred_.is_empty()) {
+    DeferredCode* code = deferred_.RemoveLast();
+    MacroAssembler* masm = code->masm();
+    // Record position of deferred code stub.
+    if (code->statement_position() != RelocInfo::kNoPosition) {
+      masm->RecordStatementPosition(code->statement_position());
+    }
+    if (code->position() != RelocInfo::kNoPosition) {
+      masm->RecordPosition(code->position());
+    }
+    // Bind labels and generate the code.
+    masm->bind(code->enter());
+    Comment cmnt(masm, code->comment());
+    code->Generate();
+    if (code->exit()->is_bound()) {
+      masm->jmp(code->exit());  // platform independent?
+    }
+  }
+}
+
+
+// Generate the code. Takes a function literal, generates code for it, assemble
+// all the pieces into a Code object. This function is only to be called by
+// the compiler.cc code.
+Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
+                                     Handle<Script> script,
+                                     bool is_eval) {
+#ifdef ENABLE_DISASSEMBLER
+  bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
+#endif
+
+#ifdef DEBUG
+  bool print_source = false;
+  bool print_ast = false;
+  const char* ftype;
+
+  if (Bootstrapper::IsActive()) {
+    print_source = FLAG_print_builtin_source;
+    print_ast = FLAG_print_builtin_ast;
+    print_code = FLAG_print_builtin_code;
+    ftype = "builtin";
+  } else {
+    print_source = FLAG_print_source;
+    print_ast = FLAG_print_ast;
+    ftype = "user-defined";
+  }
+
+  if (FLAG_trace_codegen || print_source || print_ast) {
+    PrintF("*** Generate code for %s function: ", ftype);
+    flit->name()->ShortPrint();
+    PrintF(" ***\n");
+  }
+
+  if (print_source) {
+    PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
+  }
+
+  if (print_ast) {
+    PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
+  }
+#endif  // DEBUG
+
+  // Generate code.
+  const int initial_buffer_size = 4 * KB;
+  CodeGenerator cgen(initial_buffer_size, script, is_eval);
+  cgen.GenCode(flit);
+  if (cgen.HasStackOverflow()) {
+    ASSERT(!Top::has_pending_exception());
+    return Handle<Code>::null();
+  }
+
+  // Process any deferred code.
+  cgen.ProcessDeferred();
+
+  // Allocate and install the code.
+  CodeDesc desc;
+  cgen.masm()->GetCode(&desc);
+  ScopeInfo<> sinfo(flit->scope());
+  Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
+  Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
+
+  // Add unresolved entries in the code to the fixup list.
+  Bootstrapper::AddFixup(*code, cgen.masm());
+
+#ifdef ENABLE_DISASSEMBLER
+  if (print_code) {
+    // Print the source code if available.
+    if (!script->IsUndefined() && !script->source()->IsUndefined()) {
+      PrintF("--- Raw source ---\n");
+      StringInputBuffer stream(String::cast(script->source()));
+      stream.Seek(flit->start_position());
+      // flit->end_position() points to the last character in the stream. We
+      // need to compensate by adding one to calculate the length.
+      int source_len = flit->end_position() - flit->start_position() + 1;
+      for (int i = 0; i < source_len; i++) {
+        if (stream.has_more()) PrintF("%c", stream.GetNext());
+      }
+      PrintF("\n\n");
+    }
+    PrintF("--- Code ---\n");
+    code->Disassemble();
+  }
+#endif  // ENABLE_DISASSEMBLER
+
+  if (!code.is_null()) {
+    Counters::total_compiled_code_size.Increment(code->instruction_size());
+  }
+
+  return code;
+}
+
+
+// Sets the function info on a function.
+// The start_position points to the first '(' character after the function name
+// in the full script source. When counting characters in the script source the
+// the first character is number 0 (not 1).
+void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
+                                    int length,
+                                    int function_token_position,
+                                    int start_position,
+                                    int end_position,
+                                    bool is_expression,
+                                    bool is_toplevel,
+                                    Handle<Script> script) {
+  fun->shared()->set_length(length);
+  fun->shared()->set_formal_parameter_count(length);
+  fun->shared()->set_script(*script);
+  fun->shared()->set_function_token_position(function_token_position);
+  fun->shared()->set_start_position(start_position);
+  fun->shared()->set_end_position(end_position);
+  fun->shared()->set_is_expression(is_expression);
+  fun->shared()->set_is_toplevel(is_toplevel);
+}
+
+
+static Handle<Code> ComputeLazyCompile(int argc) {
+  CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code);
+}
+
+
+Handle<JSFunction> CodeGenerator::BuildBoilerplate(FunctionLiteral* node) {
+  // Determine if the function can be lazily compiled. This is
+  // necessary to allow some of our builtin JS files to be lazily
+  // compiled. These builtins cannot be handled lazily by the parser,
+  // since we have to know if a function uses the special natives
+  // syntax, which is something the parser records.
+  bool allow_lazy = node->AllowsLazyCompilation();
+
+  // Generate code
+  Handle<Code> code;
+  if (FLAG_lazy && allow_lazy) {
+    code = ComputeLazyCompile(node->num_parameters());
+  } else {
+    code = MakeCode(node, script_, false);
+
+    // Check for stack-overflow exception.
+    if (code.is_null()) {
+      SetStackOverflow();
+      return Handle<JSFunction>::null();
+    }
+
+    // Function compilation complete.
+    LOG(CodeCreateEvent("Function", *code, *node->name()));
+  }
+
+  // Create a boilerplate function.
+  Handle<JSFunction> function =
+      Factory::NewFunctionBoilerplate(node->name(),
+                                      node->materialized_literal_count(),
+                                      node->contains_array_literal(),
+                                      code);
+  CodeGenerator::SetFunctionInfo(function, node->num_parameters(),
+                                 node->function_token_position(),
+                                 node->start_position(), node->end_position(),
+                                 node->is_expression(), false, script_);
+
+  // Notify debugger that a new function has been added.
+  Debugger::OnNewFunction(function);
+
+  // Set the expected number of properties for instances and return
+  // the resulting function.
+  SetExpectedNofPropertiesFromEstimate(function,
+                                       node->expected_property_count());
+  return function;
+}
+
+
+Handle<Code> CodeGenerator::ComputeCallInitialize(int argc) {
+  CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc), Code);
+}
+
+
+void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
+  int length = declarations->length();
+  int globals = 0;
+  for (int i = 0; i < length; i++) {
+    Declaration* node = declarations->at(i);
+    Variable* var = node->proxy()->var();
+    Slot* slot = var->slot();
+
+    // 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(node);
+    } else {
+      // Count global variables and functions for later processing
+      globals++;
+    }
+  }
+
+  // Return in case of no declared global functions or variables.
+  if (globals == 0) return;
+
+  // Compute array of global variable and function declarations.
+  Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
+  for (int j = 0, i = 0; i < length; i++) {
+    Declaration* node = declarations->at(i);
+    Variable* var = node->proxy()->var();
+    Slot* slot = var->slot();
+
+    if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
+      // Skip - already processed.
+    } else {
+      array->set(j++, *(var->name()));
+      if (node->fun() == NULL) {
+        if (var->mode() == Variable::CONST) {
+          // In case this is const property use the hole.
+          array->set_the_hole(j++);
+        } else {
+          array->set_undefined(j++);
+        }
+      } else {
+        Handle<JSFunction> function = BuildBoilerplate(node->fun());
+        // Check for stack-overflow exception.
+        if (HasStackOverflow()) return;
+        array->set(j++, *function);
+      }
+    }
+  }
+
+  // Invoke the platform-dependent code generator to do the actual
+  // declaration the global variables and functions.
+  DeclareGlobals(array);
+}
+
+
+struct InlineRuntimeLUT {
+  void (CodeGenerator::*method)(ZoneList<Expression*>*);
+  const char* name;
+};
+
+
+bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
+  ZoneList<Expression*>* args = node->arguments();
+  // Special cases: These 'runtime calls' manipulate the current
+  // frame and are only used 1 or two places, so we generate them
+  // inline instead of generating calls to them.  They are used
+  // for implementing Function.prototype.call() and
+  // Function.prototype.apply().
+  static const InlineRuntimeLUT kInlineRuntimeLUT[] = {
+    {&v8::internal::CodeGenerator::GenerateIsSmi,
+     "_IsSmi"},
+    {&v8::internal::CodeGenerator::GenerateIsNonNegativeSmi,
+     "_IsNonNegativeSmi"},
+    {&v8::internal::CodeGenerator::GenerateIsArray,
+     "_IsArray"},
+    {&v8::internal::CodeGenerator::GenerateArgumentsLength,
+     "_ArgumentsLength"},
+    {&v8::internal::CodeGenerator::GenerateArgumentsAccess,
+     "_Arguments"},
+    {&v8::internal::CodeGenerator::GenerateValueOf,
+     "_ValueOf"},
+    {&v8::internal::CodeGenerator::GenerateSetValueOf,
+     "_SetValueOf"},
+    {&v8::internal::CodeGenerator::GenerateFastCharCodeAt,
+     "_FastCharCodeAt"},
+    {&v8::internal::CodeGenerator::GenerateObjectEquals,
+     "_ObjectEquals"}
+  };
+  if (node->name()->length() > 0 && node->name()->Get(0) == '_') {
+    for (unsigned i = 0;
+         i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
+         i++) {
+      const InlineRuntimeLUT* entry = kInlineRuntimeLUT + i;
+      if (node->name()->IsEqualTo(CStrVector(entry->name))) {
+        ((*this).*(entry->method))(args);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+void CodeGenerator::GenerateFastCaseSwitchStatement(SwitchStatement* node,
+                                                    int min_index,
+                                                    int range,
+                                                    int default_index) {
+  ZoneList<CaseClause*>* cases = node->cases();
+  int length = cases->length();
+
+  // Label pointer per number in range
+  SmartPointer<Label*> case_targets(NewArray<Label*>(range));
+
+  // Label per switch case
+  SmartPointer<Label> case_labels(NewArray<Label>(length));
+
+  Label* fail_label = default_index >= 0 ? &(case_labels[default_index])
+                                         : node->break_target();
+
+  // Populate array of label pointers for each number in the range.
+  // Initally put the failure label everywhere.
+  for (int i = 0; i < range; i++) {
+    case_targets[i] = fail_label;
+  }
+
+  // Overwrite with label of a case for the number value of that case.
+  // (In reverse order, so that if the same label occurs twice, the
+  // first one wins).
+  for (int i = length-1; i >= 0 ; i--) {
+    CaseClause* clause = cases->at(i);
+    if (!clause->is_default()) {
+      Object* label_value = *(clause->label()->AsLiteral()->handle());
+      int case_value = Smi::cast(label_value)->value();
+      case_targets[case_value - min_index] = &(case_labels[i]);
+    }
+  }
+
+  GenerateFastCaseSwitchJumpTable(node,
+                                  min_index,
+                                  range,
+                                  fail_label,
+                                  Vector<Label*>(*case_targets, range),
+                                  Vector<Label>(*case_labels, length));
+}
+
+
+void CodeGenerator::GenerateFastCaseSwitchCases(
+    SwitchStatement* node,
+    Vector<Label> case_labels) {
+  ZoneList<CaseClause*>* cases = node->cases();
+  int length = cases->length();
+
+  for (int i = 0; i < length; i++) {
+    Comment cmnt(masm(), "[ Case clause");
+    masm()->bind(&(case_labels[i]));
+    VisitStatements(cases->at(i)->statements());
+  }
+
+  masm()->bind(node->break_target());
+}
+
+
+bool CodeGenerator::TryGenerateFastCaseSwitchStatement(SwitchStatement* node) {
+  ZoneList<CaseClause*>* cases = node->cases();
+  int length = cases->length();
+
+  if (length < FastCaseSwitchMinCaseCount()) {
+    return false;
+  }
+
+  // Test whether fast-case should be used.
+  int default_index = -1;
+  int min_index = Smi::kMaxValue;
+  int max_index = Smi::kMinValue;
+  for (int i = 0; i < length; i++) {
+    CaseClause* clause = cases->at(i);
+    if (clause->is_default()) {
+      if (default_index >= 0) {
+        return false;  // More than one default label:
+                       // Defer to normal case for error.
+    }
+      default_index = i;
+    } else {
+      Expression* label = clause->label();
+      Literal* literal = label->AsLiteral();
+      if (literal == NULL) {
+        return false;  // fail fast case
+      }
+      Object* value = *(literal->handle());
+      if (!value->IsSmi()) {
+        return false;
+      }
+      int smi = Smi::cast(value)->value();
+      if (smi < min_index) { min_index = smi; }
+      if (smi > max_index) { max_index = smi; }
+    }
+  }
+
+  // All labels are known to be Smis.
+  int range = max_index - min_index + 1;  // |min..max| inclusive
+  if (range / FastCaseSwitchMaxOverheadFactor() > length) {
+    return false;  // range of labels is too sparse
+  }
+
+  // Optimization accepted, generate code.
+  GenerateFastCaseSwitchStatement(node, min_index, range, default_index);
+  return true;
+}
+
+
+const char* RuntimeStub::GetName() {
+  return Runtime::FunctionForId(id_)->stub_name;
+}
+
+
+void RuntimeStub::Generate(MacroAssembler* masm) {
+  masm->TailCallRuntime(ExternalReference(id_), num_arguments_);
+}
+
+
+void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
+  switch (type_) {
+    case READ_LENGTH: GenerateReadLength(masm); break;
+    case READ_ELEMENT: GenerateReadElement(masm); break;
+    case NEW_OBJECT: GenerateNewObject(masm); break;
+  }
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/codegen.h b/regexp2000/src/codegen.h
new file mode 100644 (file)
index 0000000..f2ac05c
--- /dev/null
@@ -0,0 +1,288 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CODEGEN_H_
+#define V8_CODEGEN_H_
+
+#include "ast.h"
+#include "code-stubs.h"
+#include "runtime.h"
+
+// Include the declaration of the architecture defined class CodeGenerator.
+// The contract  to the shared code is that the the CodeGenerator is a subclass
+// of Visitor and that the following methods are available publicly:
+// CodeGenerator::MakeCode
+// CodeGenerator::SetFunctionInfo
+// CodeGenerator::AddDeferred
+// CodeGenerator::masm
+//
+// These methods are either used privately by the shared code or implemented as
+// shared code:
+// CodeGenerator::CodeGenerator
+// CodeGenerator::~CodeGenerator
+// CodeGenerator::ProcessDeferred
+// CodeGenerator::GenCode
+// CodeGenerator::BuildBoilerplate
+// CodeGenerator::ComputeCallInitialize
+// CodeGenerator::ProcessDeclarations
+// CodeGenerator::DeclareGlobals
+// CodeGenerator::CheckForInlineRuntimeCall
+// CodeGenerator::GenerateFastCaseSwitchStatement
+// CodeGenerator::GenerateFastCaseSwitchCases
+// CodeGenerator::TryGenerateFastCaseSwitchStatement
+// CodeGenerator::GenerateFastCaseSwitchJumpTable
+// CodeGenerator::FastCaseSwitchMinCaseCount
+// CodeGenerator::FastCaseSwitchMaxOverheadFactor
+
+#if defined(ARM)
+#include "codegen-arm.h"
+#else
+#include "codegen-ia32.h"
+#endif
+
+namespace v8 { namespace internal {
+
+
+// Use lazy compilation; defaults to true.
+// NOTE: Do not remove non-lazy compilation until we can properly
+//       install extensions with lazy compilation enabled. At the
+//       moment, this doesn't work for the extensions in Google3,
+//       and we can only run the tests with --nolazy.
+
+
+// Deferred code objects are small pieces of code that are compiled
+// out of line. They are used to defer the compilation of uncommon
+// paths thereby avoiding expensive jumps around uncommon code parts.
+class DeferredCode: public ZoneObject {
+ public:
+  explicit DeferredCode(CodeGenerator* generator);
+  virtual ~DeferredCode() { }
+
+  virtual void Generate() = 0;
+
+  MacroAssembler* masm() const { return masm_; }
+  CodeGenerator* generator() const { return generator_; }
+
+  Label* enter() { return &enter_; }
+  Label* exit() { return &exit_; }
+
+  int statement_position() const { return statement_position_; }
+  int position() const { return position_; }
+
+#ifdef DEBUG
+  void set_comment(const char* comment) { comment_ = comment; }
+  const char* comment() const { return comment_; }
+#else
+  inline void set_comment(const char* comment) { }
+  const char* comment() const { return ""; }
+#endif
+
+ protected:
+  // The masm_ field is manipulated when compiling stubs with the
+  // BEGIN_STUB and END_STUB macros. For that reason, it cannot be
+  // constant.
+  MacroAssembler* masm_;
+
+ private:
+  CodeGenerator* const generator_;
+  Label enter_;
+  Label exit_;
+  int statement_position_;
+  int position_;
+#ifdef DEBUG
+  const char* comment_;
+#endif
+  DISALLOW_COPY_AND_ASSIGN(DeferredCode);
+};
+
+
+// RuntimeStub models code stubs calling entry points in the Runtime class.
+class RuntimeStub : public CodeStub {
+ public:
+  explicit RuntimeStub(Runtime::FunctionId id, int num_arguments)
+      : id_(id), num_arguments_(num_arguments) { }
+
+  void Generate(MacroAssembler* masm);
+
+  // Disassembler support.  It is useful to be able to print the name
+  // of the runtime function called through this stub.
+  static const char* GetNameFromMinorKey(int minor_key) {
+    return Runtime::FunctionForId(IdField::decode(minor_key))->stub_name;
+  }
+
+ private:
+  Runtime::FunctionId id_;
+  int num_arguments_;
+
+  class ArgumentField: public BitField<int,  0, 16> {};
+  class IdField: public BitField<Runtime::FunctionId, 16, kMinorBits - 16> {};
+
+  Major MajorKey() { return Runtime; }
+  int MinorKey() {
+    return IdField::encode(id_) | ArgumentField::encode(num_arguments_);
+  }
+
+  const char* GetName();
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("RuntimeStub (id %s)\n", Runtime::FunctionForId(id_)->name);
+  }
+#endif
+};
+
+
+class StackCheckStub : public CodeStub {
+ public:
+  StackCheckStub() { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+
+  const char* GetName() { return "StackCheckStub"; }
+
+  Major MajorKey() { return StackCheck; }
+  int MinorKey() { return 0; }
+};
+
+
+class UnarySubStub : public CodeStub {
+ public:
+  UnarySubStub() { }
+
+ private:
+  Major MajorKey() { return UnarySub; }
+  int MinorKey() { return 0; }
+  void Generate(MacroAssembler* masm);
+
+  const char* GetName() { return "UnarySubStub"; }
+};
+
+
+class CEntryStub : public CodeStub {
+ public:
+  CEntryStub() { }
+
+  void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
+
+ protected:
+  void GenerateBody(MacroAssembler* masm, bool is_debug_break);
+  void GenerateCore(MacroAssembler* masm,
+                    Label* throw_normal_exception,
+                    Label* throw_out_of_memory_exception,
+                    StackFrame::Type frame_type,
+                    bool do_gc);
+  void GenerateThrowTOS(MacroAssembler* masm);
+  void GenerateThrowOutOfMemory(MacroAssembler* masm);
+
+ private:
+  Major MajorKey() { return CEntry; }
+  int MinorKey() { return 0; }
+
+  const char* GetName() { return "CEntryStub"; }
+};
+
+
+class CEntryDebugBreakStub : public CEntryStub {
+ public:
+  CEntryDebugBreakStub() { }
+
+  void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
+
+ private:
+  int MinorKey() { return 1; }
+
+  const char* GetName() { return "CEntryDebugBreakStub"; }
+};
+
+
+class JSEntryStub : public CodeStub {
+ public:
+  JSEntryStub() { }
+
+  void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
+
+ protected:
+  void GenerateBody(MacroAssembler* masm, bool is_construct);
+
+ private:
+  Major MajorKey() { return JSEntry; }
+  int MinorKey() { return 0; }
+
+  const char* GetName() { return "JSEntryStub"; }
+};
+
+
+class JSConstructEntryStub : public JSEntryStub {
+ public:
+  JSConstructEntryStub() { }
+
+  void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
+
+ private:
+  int MinorKey() { return 1; }
+
+  const char* GetName() { return "JSConstructEntryStub"; }
+};
+
+
+class ArgumentsAccessStub: public CodeStub {
+ public:
+  enum Type {
+    READ_LENGTH,
+    READ_ELEMENT,
+    NEW_OBJECT
+  };
+
+  explicit ArgumentsAccessStub(Type type) : type_(type) { }
+
+ private:
+  Type type_;
+
+  Major MajorKey() { return ArgumentsAccess; }
+  int MinorKey() { return type_; }
+
+  void Generate(MacroAssembler* masm);
+  void GenerateReadLength(MacroAssembler* masm);
+  void GenerateReadElement(MacroAssembler* masm);
+  void GenerateNewObject(MacroAssembler* masm);
+
+  const char* GetName() { return "ArgumentsAccessStub"; }
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("ArgumentsAccessStub (type %d)\n", type_);
+  }
+#endif
+};
+
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_CODEGEN_H_
diff --git a/regexp2000/src/compilation-cache.cc b/regexp2000/src/compilation-cache.cc
new file mode 100644 (file)
index 0000000..bf32621
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "compilation-cache.h"
+
+namespace v8 { namespace internal {
+
+enum {
+  NUMBER_OF_ENTRY_KINDS = CompilationCache::LAST_ENTRY + 1
+};
+
+
+// Keep separate tables for the different entry kinds.
+static Object* tables[NUMBER_OF_ENTRY_KINDS] = { 0, };
+
+
+static Handle<CompilationCacheTable> AllocateTable(int size) {
+  CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size),
+                     CompilationCacheTable);
+}
+
+
+static Handle<CompilationCacheTable> GetTable(CompilationCache::Entry entry) {
+  Handle<CompilationCacheTable> result;
+  if (tables[entry]->IsUndefined()) {
+    static const int kInitialCacheSize = 64;
+    result = AllocateTable(kInitialCacheSize);
+    tables[entry] = *result;
+  } else {
+    CompilationCacheTable* table = CompilationCacheTable::cast(tables[entry]);
+    result = Handle<CompilationCacheTable>(table);
+  }
+  return result;
+}
+
+
+// We only re-use a cached function for some script source code if the
+// script originates from the same places. This is to avoid issues
+// when reporting errors, etc.
+static bool HasOrigin(Handle<JSFunction> boilerplate,
+                      Handle<Object> name,
+                      int line_offset,
+                      int column_offset) {
+  Handle<Script> script =
+      Handle<Script>(Script::cast(boilerplate->shared()->script()));
+  // If the script name isn't set, the boilerplate script should have
+  // an undefined name to have the same origin.
+  if (name.is_null()) {
+    return script->name()->IsUndefined();
+  }
+  // Do the fast bailout checks first.
+  if (line_offset != script->line_offset()->value()) return false;
+  if (column_offset != script->column_offset()->value()) return false;
+  // Check that both names are strings. If not, no match.
+  if (!name->IsString() || !script->name()->IsString()) return false;
+  // Compare the two name strings for equality.
+  return String::cast(*name)->Equals(String::cast(script->name()));
+}
+
+
+static Handle<JSFunction> Lookup(Handle<String> source,
+                                 CompilationCache::Entry entry) {
+  // Make sure not to leak the table into the surrounding handle
+  // scope. Otherwise, we risk keeping old tables around even after
+  // having cleared the cache.
+  Object* result;
+  { HandleScope scope;
+    Handle<CompilationCacheTable> table = GetTable(entry);
+    result = table->Lookup(*source);
+  }
+  if (result->IsJSFunction()) {
+    return Handle<JSFunction>(JSFunction::cast(result));
+  } else {
+    return Handle<JSFunction>::null();
+  }
+}
+
+
+Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source,
+                                                  Handle<Object> name,
+                                                  int line_offset,
+                                                  int column_offset) {
+  Handle<JSFunction> result = Lookup(source, SCRIPT);
+  if (result.is_null()) {
+    Counters::compilation_cache_misses.Increment();
+  } else if (HasOrigin(result, name, line_offset, column_offset)) {
+    Counters::compilation_cache_hits.Increment();
+  } else {
+    result = Handle<JSFunction>::null();
+    Counters::compilation_cache_misses.Increment();
+  }
+  return result;
+}
+
+
+Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source,
+                                                Entry entry) {
+  ASSERT(entry == EVAL_GLOBAL || entry == EVAL_CONTEXTUAL);
+  Handle<JSFunction> result = Lookup(source, entry);
+  if (result.is_null()) {
+    Counters::compilation_cache_misses.Increment();
+  } else {
+    Counters::compilation_cache_hits.Increment();
+  }
+  return result;
+}
+
+
+void CompilationCache::PutFunction(Handle<String> source,
+                                   Entry entry,
+                                   Handle<JSFunction> boilerplate) {
+  HandleScope scope;
+  ASSERT(boilerplate->IsBoilerplate());
+  Handle<CompilationCacheTable> table = GetTable(entry);
+  CALL_HEAP_FUNCTION_VOID(table->Put(*source, *boilerplate));
+}
+
+
+Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
+                                                  JSRegExp::Flags flags) {
+  Handle<CompilationCacheTable> table = GetTable(REGEXP);
+  Object* result = table->LookupRegExp(*source, flags);
+  if (result->IsFixedArray()) {
+    Counters::regexp_cache_hits.Increment();
+    return Handle<FixedArray>(FixedArray::cast(result));
+  } else {
+    Counters::regexp_cache_misses.Increment();
+    return Handle<FixedArray>();
+  }
+}
+
+
+void CompilationCache::PutRegExp(Handle<String> source,
+                                 JSRegExp::Flags flags,
+                                 Handle<FixedArray> data) {
+  HandleScope scope;
+  Handle<CompilationCacheTable> table = GetTable(REGEXP);
+  CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data));
+}
+
+
+void CompilationCache::Clear() {
+  for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) {
+    tables[i] = Heap::undefined_value();
+  }
+}
+
+
+void CompilationCache::Iterate(ObjectVisitor* v) {
+  v->VisitPointers(&tables[0], &tables[NUMBER_OF_ENTRY_KINDS]);
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/compilation-cache.h b/regexp2000/src/compilation-cache.h
new file mode 100644 (file)
index 0000000..abe6110
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_COMPILATION_CACHE_H_
+#define V8_COMPILATION_CACHE_H_
+
+namespace v8 { namespace internal {
+
+
+// The compilation cache keeps function boilerplates for compiled
+// scripts and evals. The boilerplates are looked up using the source
+// string as the key.
+class CompilationCache {
+ public:
+  // The same source code string has different compiled code for
+  // scripts and evals. Internally, we use separate caches to avoid
+  // getting the wrong kind of entry when looking up.
+  enum Entry {
+    SCRIPT,
+    EVAL_GLOBAL,
+    EVAL_CONTEXTUAL,
+    REGEXP,
+    LAST_ENTRY = REGEXP
+  };
+
+  // Finds the script function boilerplate for a source
+  // string. Returns an empty handle if the cache doesn't contain a
+  // script for the given source string with the right origin.
+  static Handle<JSFunction> LookupScript(Handle<String> source,
+                                         Handle<Object> name,
+                                         int line_offset,
+                                         int column_offset);
+
+  // Finds the function boilerplate for a source string for
+  // eval. Returns an empty handle if the cache doesn't contain a
+  // script for the given source string.
+  static Handle<JSFunction> LookupEval(Handle<String> source,
+                                       Entry entry);
+
+  // Returns the regexp data associated with the given regexp if it
+  // is in cache, otherwise an empty handle.
+  static Handle<FixedArray> LookupRegExp(Handle<String> source,
+                                         JSRegExp::Flags flags);
+
+  // Associate the (source, flags) pair to the given regexp data.
+  // This may overwrite an existing mapping.
+  static void PutRegExp(Handle<String> source,
+                        JSRegExp::Flags flags,
+                        Handle<FixedArray> data);
+
+  // Associate the (source, kind) pair to the boilerplate. This may
+  // overwrite an existing mapping.
+  static void PutFunction(Handle<String> source,
+                          Entry entry,
+                          Handle<JSFunction> boilerplate);
+
+  // Clear the cache - also used to initialize the cache at startup.
+  static void Clear();
+
+  // GC support.
+  static void Iterate(ObjectVisitor* v);
+
+  // Notify the cache that a mark-sweep garbage collection is about to
+  // take place. This is used to retire entries from the cache to
+  // avoid keeping them alive too long without using them. For now, we
+  // just clear the cache but we should consider are more
+  // sophisticated LRU scheme.
+  static void MarkCompactPrologue() { Clear(); }
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_COMPILATION_CACHE_H_
diff --git a/regexp2000/src/compiler.cc b/regexp2000/src/compiler.cc
new file mode 100644 (file)
index 0000000..11ac145
--- /dev/null
@@ -0,0 +1,294 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "codegen-inl.h"
+#include "compilation-cache.h"
+#include "compiler.h"
+#include "debug.h"
+#include "scopes.h"
+#include "rewriter.h"
+#include "usage-analyzer.h"
+
+namespace v8 { namespace internal {
+
+static Handle<Code> MakeCode(FunctionLiteral* literal,
+                             Handle<Script> script,
+                             bool is_eval) {
+  ASSERT(literal != NULL);
+
+  // Rewrite the AST by introducing .result assignments where needed.
+  if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) {
+    // Signal a stack overflow by returning a null handle.  The stack
+    // overflow exception will be thrown by the caller.
+    return Handle<Code>::null();
+  }
+
+  // Compute top scope and allocate variables. For lazy compilation
+  // the top scope only contains the single lazily compiled function,
+  // so this doesn't re-allocate variables repeatedly.
+  Scope* top = literal->scope();
+  while (top->outer_scope() != NULL) top = top->outer_scope();
+  top->AllocateVariables();
+
+#ifdef DEBUG
+  if (Bootstrapper::IsActive() ?
+      FLAG_print_builtin_scopes :
+      FLAG_print_scopes) {
+    literal->scope()->Print();
+  }
+#endif
+
+  // Generate code and return it.
+  Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
+  return result;
+}
+
+
+static Handle<JSFunction> MakeFunction(bool is_global,
+                                       bool is_eval,
+                                       Handle<Script> script,
+                                       v8::Extension* extension,
+                                       ScriptDataImpl* pre_data) {
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+
+  // Make sure we have an initial stack limit.
+  StackGuard guard;
+  PostponeInterruptsScope postpone;
+
+  // Notify debugger
+  Debugger::OnBeforeCompile(script);
+
+  // Only allow non-global compiles for eval.
+  ASSERT(is_eval || is_global);
+
+  // Build AST.
+  FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
+
+  // Check for parse errors.
+  if (lit == NULL) {
+    ASSERT(Top::has_pending_exception());
+    return Handle<JSFunction>::null();
+  }
+
+  // Measure how long it takes to do the compilation; only take the
+  // rest of the function into account to avoid overlap with the
+  // parsing statistics.
+  StatsRate* rate = is_eval
+      ? &Counters::compile_eval
+      : &Counters::compile;
+  StatsRateScope timer(rate);
+
+  // Compile the code.
+  Handle<Code> code = MakeCode(lit, script, is_eval);
+
+  // Check for stack-overflow exceptions.
+  if (code.is_null()) {
+    Top::StackOverflow();
+    return Handle<JSFunction>::null();
+  }
+
+  if (script->name()->IsString()) {
+    SmartPointer<char> data =
+        String::cast(script->name())->ToCString(DISALLOW_NULLS);
+    LOG(CodeCreateEvent(is_eval ? "Eval" : "Script", *code, *data));
+  } else {
+    LOG(CodeCreateEvent(is_eval ? "Eval" : "Script", *code, ""));
+  }
+
+  // Allocate function.
+  Handle<JSFunction> fun =
+      Factory::NewFunctionBoilerplate(lit->name(),
+                                      lit->materialized_literal_count(),
+                                      lit->contains_array_literal(),
+                                      code);
+
+  CodeGenerator::SetFunctionInfo(fun, lit->scope()->num_parameters(),
+                                 RelocInfo::kNoPosition,
+                                 lit->start_position(), lit->end_position(),
+                                 lit->is_expression(), true, script);
+
+  // Hint to the runtime system used when allocating space for initial
+  // property space by setting the expected number of properties for
+  // the instances of the function.
+  SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
+
+  // Notify debugger
+  Debugger::OnAfterCompile(script, fun);
+
+  return fun;
+}
+
+
+static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
+
+
+Handle<JSFunction> Compiler::Compile(Handle<String> source,
+                                     Handle<Object> script_name,
+                                     int line_offset, int column_offset,
+                                     v8::Extension* extension,
+                                     ScriptDataImpl* input_pre_data) {
+  Counters::total_load_size.Increment(source->length());
+  Counters::total_compile_size.Increment(source->length());
+
+  // The VM is in the COMPILER state until exiting this function.
+  VMState state(COMPILER);
+
+  // Do a lookup in the compilation cache but not for extensions.
+  Handle<JSFunction> result;
+  if (extension == NULL) {
+    result = CompilationCache::LookupScript(source,
+                                            script_name,
+                                            line_offset,
+                                            column_offset);
+  }
+
+  if (result.is_null()) {
+    // No cache entry found. Do pre-parsing and compile the script.
+    ScriptDataImpl* pre_data = input_pre_data;
+    if (pre_data == NULL && source->length() >= FLAG_min_preparse_length) {
+      Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
+      buf->Reset(source.location());
+      pre_data = PreParse(buf.value(), extension);
+    }
+
+    // Create a script object describing the script to be compiled.
+    Handle<Script> script = Factory::NewScript(source);
+    if (!script_name.is_null()) {
+      script->set_name(*script_name);
+      script->set_line_offset(Smi::FromInt(line_offset));
+      script->set_column_offset(Smi::FromInt(column_offset));
+    }
+
+    // Compile the function and add it to the cache.
+    result = MakeFunction(true, false, script, extension, pre_data);
+    if (extension == NULL && !result.is_null()) {
+      CompilationCache::PutFunction(source, CompilationCache::SCRIPT, result);
+    }
+
+    // Get rid of the pre-parsing data (if necessary).
+    if (input_pre_data == NULL && pre_data != NULL) {
+      delete pre_data;
+    }
+  }
+
+  return result;
+}
+
+
+Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
+                                         int line_offset,
+                                         bool is_global) {
+  Counters::total_eval_size.Increment(source->length());
+  Counters::total_compile_size.Increment(source->length());
+
+  // The VM is in the COMPILER state until exiting this function.
+  VMState state(COMPILER);
+  CompilationCache::Entry entry = is_global
+      ? CompilationCache::EVAL_GLOBAL
+      : CompilationCache::EVAL_CONTEXTUAL;
+
+  // Do a lookup in the compilation cache; if the entry is not there,
+  // invoke the compiler and add the result to the cache.
+  Handle<JSFunction> result = CompilationCache::LookupEval(source, entry);
+  if (result.is_null()) {
+    // Create a script object describing the script to be compiled.
+    Handle<Script> script = Factory::NewScript(source);
+    script->set_line_offset(Smi::FromInt(line_offset));
+    result = MakeFunction(is_global, true, script, NULL, NULL);
+    if (!result.is_null()) {
+      CompilationCache::PutFunction(source, entry, result);
+    }
+  }
+  return result;
+}
+
+
+bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared) {
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+
+  // The VM is in the COMPILER state until exiting this function.
+  VMState state(COMPILER);
+
+  // Make sure we have an initial stack limit.
+  StackGuard guard;
+  PostponeInterruptsScope postpone;
+
+  // Compute name, source code and script data.
+  Handle<String> name(String::cast(shared->name()));
+  Handle<Script> script(Script::cast(shared->script()));
+
+  int start_position = shared->start_position();
+  int end_position = shared->end_position();
+  bool is_expression = shared->is_expression();
+  Counters::total_compile_size.Increment(end_position - start_position);
+
+  // Generate the AST for the lazily compiled function. The AST may be
+  // NULL in case of parser stack overflow.
+  FunctionLiteral* lit = MakeLazyAST(script, name,
+                                     start_position,
+                                     end_position,
+                                     is_expression);
+
+  // Check for parse errors.
+  if (lit == NULL) {
+    ASSERT(Top::has_pending_exception());
+    return false;
+  }
+
+  // Measure how long it takes to do the lazy compilation; only take
+  // the rest of the function into account to avoid overlap with the
+  // lazy parsing statistics.
+  StatsRateScope timer(&Counters::compile_lazy);
+
+  // Compile the code.
+  Handle<Code> code = MakeCode(lit, script, false);
+
+  // Check for stack-overflow exception.
+  if (code.is_null()) {
+    Top::StackOverflow();
+    return false;
+  }
+
+  // Generate the code, update the function info, and return the code.
+  LOG(CodeCreateEvent("LazyCompile", *code, *lit->name()));
+
+  // Update the shared function info with the compiled code.
+  shared->set_code(*code);
+
+  // Set the expected number of properties for instances.
+  SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
+
+  // Check the function has compiled code.
+  ASSERT(shared->is_compiled());
+  return true;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/compiler.h b/regexp2000/src/compiler.h
new file mode 100644 (file)
index 0000000..3bbc9aa
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_COMPILER_H_
+#define V8_COMPILER_H_
+
+#include "parser.h"
+
+namespace v8 { namespace internal {
+
+// The V8 compiler
+//
+// General strategy: Source code is translated into an anonymous function w/o
+// parameters which then can be executed. If the source code contains other
+// functions, they will be compiled and allocated as part of the compilation
+// of the source code.
+
+// Please note this interface returns function boilerplates.
+// This means you need to call Factory::NewFunctionFromBoilerplate
+// before you have a real function with context.
+
+class Compiler : public AllStatic {
+ public:
+  // All routines return a JSFunction.
+  // If an error occurs an exception is raised and
+  // the return handle contains NULL.
+
+  // Compile a String source within a context.
+  static Handle<JSFunction> Compile(Handle<String> source,
+                                    Handle<Object> script_name,
+                                    int line_offset, int column_offset,
+                                    v8::Extension* extension,
+                                    ScriptDataImpl* script_Data);
+
+  // Compile a String source within a context for Eval.
+  static Handle<JSFunction> CompileEval(Handle<String> source,
+                                        int line_offset,
+                                        bool is_global);
+
+  // Compile from function info (used for lazy compilation). Returns
+  // true on success and false if the compilation resulted in a stack
+  // overflow.
+  static bool CompileLazy(Handle<SharedFunctionInfo> shared);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_COMPILER_H_
diff --git a/regexp2000/src/constants-arm.h b/regexp2000/src/constants-arm.h
new file mode 100644 (file)
index 0000000..a388009
--- /dev/null
@@ -0,0 +1,208 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CONSTANTS_ARM_H_
+#define V8_CONSTANTS_ARM_H_
+
+namespace assembler { namespace arm {
+
+// Defines constants and accessor classes to assemble, disassemble and
+// simulate ARM instructions.
+//
+// Constants for specific fields are defined in their respective named enums.
+// General constants are in an anonymous enum in class Instr.
+
+typedef unsigned char byte;
+
+enum Condition {
+  no_condition = -1,
+  EQ =  0,
+  NE =  1,
+  CS =  2,
+  CC =  3,
+  MI =  4,
+  PL =  5,
+  VS =  6,
+  VC =  7,
+  HI =  8,
+  LS =  9,
+  GE = 10,
+  LT = 11,
+  GT = 12,
+  LE = 13,
+  AL = 14,
+  special_condition = 15
+};
+
+
+enum Opcode {
+  no_operand = -1,
+  AND =  0,
+  EOR =  1,
+  SUB =  2,
+  RSB =  3,
+  ADD =  4,
+  ADC =  5,
+  SBC =  6,
+  RSC =  7,
+  TST =  8,
+  TEQ =  9,
+  CMP = 10,
+  CMN = 11,
+  ORR = 12,
+  MOV = 13,
+  BIC = 14,
+  MVN = 15
+};
+
+
+enum Shift {
+  no_shift = -1,
+  LSL = 0,
+  LSR = 1,
+  ASR = 2,
+  ROR = 3
+};
+
+
+enum SoftwareInterruptCodes {
+  // transition to C code
+  call_rt_r5 = 0x10,
+  call_rt_r2 = 0x11,
+  // break point
+  break_point = 0x20
+};
+
+
+typedef int32_t instr_t;
+
+
+// The class Instr enables access to individual fields defined in the ARM
+// architecture.
+class Instr {
+ public:
+  enum {
+    kInstrSize = 4,
+    kPCReadOffset = 8
+  };
+
+  // Get the raw instruction bits
+  inline instr_t InstructionBits() const {
+    return *reinterpret_cast<const instr_t*>(this);
+  }
+
+  inline void SetInstructionBits(instr_t value) {
+    *reinterpret_cast<instr_t*>(this) = value;
+  }
+
+  inline int Bit(int nr) const {
+    return (InstructionBits() >> nr) & 1;
+  }
+
+  inline int Bits(int hi, int lo) const {
+    return (InstructionBits() >> lo) & ((2 << (hi - lo)) - 1);
+  }
+
+
+  // Accessors for the different named fields used in the ARM encoding.
+  // Generally applicable fields
+  inline Condition ConditionField() const {
+    return static_cast<Condition>(Bits(31, 28));
+  }
+  inline int TypeField() const { return Bits(27, 25); }
+
+  inline int RnField() const { return Bits(19, 16); }
+  inline int RdField() const { return Bits(15, 12); }
+
+  // Fields used in Data processing instructions
+  inline Opcode OpcodeField() const {
+    return static_cast<Opcode>(Bits(24, 21));
+  }
+  inline int SField() const { return Bit(20); }
+    // with register
+  inline int RmField() const { return Bits(3, 0); }
+  inline Shift ShiftField() const { return static_cast<Shift>(Bits(6, 5)); }
+  inline int RegShiftField() const { return Bit(4); }
+  inline int RsField() const { return Bits(11, 8); }
+  inline int ShiftAmountField() const { return Bits(11, 7); }
+    // with immediate
+  inline int RotateField() const { return Bits(11, 8); }
+  inline int Immed8Field() const { return Bits(7, 0); }
+
+  // Fields used in Load/Store instructions
+  inline int PUField() const { return Bits(24, 23); }
+  inline int  BField() const { return Bit(22); }
+  inline int  WField() const { return Bit(21); }
+  inline int  LField() const { return Bit(20); }
+    // with register uses same fields as Data processing instructions above
+    // with immediate
+  inline int Offset12Field() const { return Bits(11, 0); }
+    // multiple
+  inline int RlistField() const { return Bits(15, 0); }
+    // extra loads and stores
+  inline int SignField() const { return Bit(6); }
+  inline int HField() const { return Bit(5); }
+  inline int ImmedHField() const { return Bits(11, 8); }
+  inline int ImmedLField() const { return Bits(3, 0); }
+
+  // Fields used in Branch instructions
+  inline int LinkField() const { return Bit(24); }
+  inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); }
+
+  // Fields used in Software interrupt instructions
+  inline SoftwareInterruptCodes SwiField() const {
+    return static_cast<SoftwareInterruptCodes>(Bits(23, 0));
+  }
+
+  // Test for special encodings of type 0 instructions (extra loads and stores,
+  // as well as multiplications).
+  inline bool IsSpecialType0() const { return (Bit(7) == 1) && (Bit(4) == 1); }
+
+  // Special accessors that test for existence of a value.
+  inline bool HasS()    const { return SField() == 1; }
+  inline bool HasB()    const { return BField() == 1; }
+  inline bool HasW()    const { return WField() == 1; }
+  inline bool HasL()    const { return LField() == 1; }
+  inline bool HasSign() const { return SignField() == 1; }
+  inline bool HasH()    const { return HField() == 1; }
+  inline bool HasLink() const { return LinkField() == 1; }
+
+  // Instructions are read of out a code stream. The only way to get a
+  // reference to an instruction is to convert a pointer. There is no way
+  // to allocate or create instances of class Instr.
+  // Use the At(pc) function to create references to Instr.
+  static Instr* At(byte* pc) { return reinterpret_cast<Instr*>(pc); }
+
+ private:
+  // We need to prevent the creation of instances of class Instr.
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
+};
+
+
+} }  // namespace assembler::arm
+
+#endif  // V8_CONSTANTS_ARM_H_
diff --git a/regexp2000/src/contexts.cc b/regexp2000/src/contexts.cc
new file mode 100644 (file)
index 0000000..6aaa4cc
--- /dev/null
@@ -0,0 +1,218 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "debug.h"
+#include "scopeinfo.h"
+
+namespace v8 { namespace internal {
+
+JSBuiltinsObject* Context::builtins() {
+  GlobalObject* object = global();
+  if (object->IsJSGlobalObject()) {
+    return JSGlobalObject::cast(object)->builtins();
+  } else {
+    ASSERT(object->IsJSBuiltinsObject());
+    return JSBuiltinsObject::cast(object);
+  }
+}
+
+
+Context* Context::global_context() {
+  // Fast case: the global object for this context has been set.  In
+  // that case, the global object has a direct pointer to the global
+  // context.
+  if (global()->IsGlobalObject()) {
+    return global()->global_context();
+  }
+  // During bootstrapping, the global object might not be set and we
+  // have to search the context chain to find the global context.
+  Context* current = this;
+  while (!current->IsGlobalContext()) {
+    current = Context::cast(JSFunction::cast(current->closure())->context());
+  }
+  return current;
+}
+
+
+JSObject* Context::global_proxy() {
+  return global_context()->global_proxy_object();
+}
+
+void Context::set_global_proxy(JSObject* object) {
+  global_context()->set_global_proxy_object(object);
+}
+
+
+Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
+                               int* index_, PropertyAttributes* attributes) {
+  Handle<Context> context(this);
+
+  // The context must be in frame slot 0 (if not debugging).
+  if (kDebug && !Debug::InDebugger()) {
+    StackFrameLocator locator;
+    ASSERT(context->fcontext() ==
+           Context::cast(
+               locator.FindJavaScriptFrame(0)->context())->fcontext());
+  }
+
+  bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
+  *index_ = -1;
+  *attributes = ABSENT;
+
+  if (FLAG_trace_contexts) {
+    PrintF("Context::Lookup(");
+    name->ShortPrint();
+    PrintF(")\n");
+  }
+
+  do {
+    if (FLAG_trace_contexts) {
+      PrintF(" - looking in context %p", *context);
+      if (context->IsGlobalContext()) PrintF(" (global context)");
+      PrintF("\n");
+    }
+
+    // check extension/with object
+    if (context->has_extension()) {
+      Handle<JSObject> extension = Handle<JSObject>(context->extension());
+      if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) {
+        *attributes = extension->GetLocalPropertyAttribute(*name);
+      } else {
+        *attributes = extension->GetPropertyAttribute(*name);
+      }
+      if (*attributes != ABSENT) {
+        // property found
+        if (FLAG_trace_contexts) {
+          PrintF("=> found property in context object %p\n", *extension);
+        }
+        return extension;
+      }
+    }
+
+    if (context->is_function_context()) {
+      // we have context-local slots
+
+      // check non-parameter locals in context
+      Handle<Code> code(context->closure()->code());
+      Variable::Mode mode;
+      int index = ScopeInfo<>::ContextSlotIndex(*code, *name, &mode);
+      ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
+      if (index >= 0) {
+        // slot found
+        if (FLAG_trace_contexts) {
+          PrintF("=> found local in context slot %d (mode = %d)\n",
+                 index, mode);
+        }
+        *index_ = index;
+        // Note: Fixed context slots are statically allocated by the compiler.
+        // Statically allocated variables always have a statically known mode,
+        // which is the mode with which they were declared when added to the
+        // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
+        // declared variables that were introduced through declaration nodes)
+        // must not appear here.
+        switch (mode) {
+          case Variable::INTERNAL :  // fall through
+          case Variable::VAR      : *attributes = NONE; break;
+          case Variable::CONST    : *attributes = READ_ONLY; break;
+          case Variable::DYNAMIC  : UNREACHABLE(); break;
+          case Variable::TEMPORARY: UNREACHABLE(); break;
+        }
+        return context;
+      }
+
+      // check parameter locals in context
+      int param_index = ScopeInfo<>::ParameterIndex(*code, *name);
+      if (param_index >= 0) {
+        // slot found
+        int index =
+            ScopeInfo<>::ContextSlotIndex(*code,
+                                          Heap::arguments_shadow_symbol(),
+                                          NULL);
+        ASSERT(index >= 0);  // arguments must exist and be in the heap context
+        Handle<JSObject> arguments(JSObject::cast(context->get(index)));
+        ASSERT(arguments->HasLocalProperty(Heap::length_symbol()));
+        if (FLAG_trace_contexts) {
+          PrintF("=> found parameter %d in arguments object\n", param_index);
+        }
+        *index_ = param_index;
+        *attributes = NONE;
+        return arguments;
+      }
+
+      // check intermediate context (holding only the function name variable)
+      if (follow_context_chain) {
+        int index = ScopeInfo<>::FunctionContextSlotIndex(*code, *name);
+        if (index >= 0) {
+          // slot found
+          if (FLAG_trace_contexts) {
+            PrintF("=> found intermediate function in context slot %d\n",
+                   index);
+          }
+          *index_ = index;
+          *attributes = READ_ONLY;
+          return context;
+        }
+      }
+    }
+
+    // proceed with enclosing context
+    if (context->IsGlobalContext()) {
+      follow_context_chain = false;
+    } else if (context->is_function_context()) {
+      context = Handle<Context>(Context::cast(context->closure()->context()));
+    } else {
+      context = Handle<Context>(context->previous());
+    }
+  } while (follow_context_chain);
+
+  // slot not found
+  if (FLAG_trace_contexts) {
+    PrintF("=> no property/slot found\n");
+  }
+  return Handle<Object>::null();
+}
+
+
+#ifdef DEBUG
+bool Context::IsBootstrappingOrContext(Object* object) {
+  // During bootstrapping we allow all objects to pass as
+  // contexts. This is necessary to fix circular dependencies.
+  return Bootstrapper::IsActive() || object->IsContext();
+}
+
+
+bool Context::IsBootstrappingOrGlobalObject(Object* object) {
+  // During bootstrapping we allow all objects to pass as global
+  // objects. This is necessary to fix circular dependencies.
+  return Bootstrapper::IsActive() || object->IsGlobalObject();
+}
+#endif
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/contexts.h b/regexp2000/src/contexts.h
new file mode 100644 (file)
index 0000000..30aa5bb
--- /dev/null
@@ -0,0 +1,322 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CONTEXTS_H_
+#define V8_CONTEXTS_H_
+
+namespace v8 { namespace internal {
+
+
+enum ContextLookupFlags {
+  FOLLOW_CONTEXT_CHAIN = 1,
+  FOLLOW_PROTOTYPE_CHAIN = 2,
+
+  DONT_FOLLOW_CHAINS = 0,
+  FOLLOW_CHAINS = FOLLOW_CONTEXT_CHAIN | FOLLOW_PROTOTYPE_CHAIN
+};
+
+
+// Heap-allocated activation contexts.
+//
+// Contexts are implemented as FixedArray objects; the Context
+// class is a convenience interface casted on a FixedArray object.
+//
+// Note: Context must have no virtual functions and Context objects
+// must always be allocated via Heap::AllocateContext() or
+// Factory::NewContext.
+
+// Comment for special_function_table:
+// Table for providing optimized/specialized functions.
+// The array contains triplets [object, general_function, optimized_function].
+// Primarily added to support built-in optimized variants of
+// Array.prototype.{push,pop}.
+
+#define GLOBAL_CONTEXT_FIELDS(V) \
+  V(GLOBAL_PROXY_INDEX, JSObject, global_proxy_object) \
+  V(SECURITY_TOKEN_INDEX, Object, security_token) \
+  V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \
+  V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
+  V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
+  V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
+  V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
+  V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
+  V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
+  V(INITIAL_OBJECT_PROTOTYPE_INDEX, JSObject, initial_object_prototype) \
+  V(CREATE_DATE_FUN_INDEX, JSFunction,  create_date_fun) \
+  V(TO_NUMBER_FUN_INDEX, JSFunction, to_number_fun) \
+  V(TO_STRING_FUN_INDEX, JSFunction, to_string_fun) \
+  V(TO_DETAIL_STRING_FUN_INDEX, JSFunction, to_detail_string_fun) \
+  V(TO_OBJECT_FUN_INDEX, JSFunction, to_object_fun) \
+  V(TO_INTEGER_FUN_INDEX, JSFunction, to_integer_fun) \
+  V(TO_UINT32_FUN_INDEX, JSFunction, to_uint32_fun) \
+  V(TO_INT32_FUN_INDEX, JSFunction, to_int32_fun) \
+  V(TO_BOOLEAN_FUN_INDEX, JSFunction, to_boolean_fun) \
+  V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
+  V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
+  V(FUNCTION_MAP_INDEX, Map, function_map) \
+  V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
+  V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
+  V(SPECIAL_FUNCTION_TABLE_INDEX, FixedArray, special_function_table) \
+  V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
+  V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
+  V(DEBUG_EVENT_LISTENERS_INDEX, JSObject, debug_event_listeners) \
+  V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
+  V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
+  V(CONFIGURE_GLOBAL_INDEX, JSFunction, configure_global_fun) \
+  V(FUNCTION_CACHE_INDEX, JSObject, function_cache) \
+  V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \
+  V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
+  V(EMPTY_SCRIPT_INDEX, Script, empty_script) \
+  V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
+  V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
+  V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
+  V(MAP_CACHE_INDEX, Object, map_cache)
+
+// JSFunctions are pairs (context, function code), sometimes also called
+// closures. A Context object is used to represent function contexts and
+// dynamically pushed 'with' contexts (or 'scopes' in ECMA-262 speak).
+//
+// At runtime, the contexts build a stack in parallel to the execution
+// stack, with the top-most context being the current context. All contexts
+// have the following slots:
+//
+// [ closure   ]  This is the current function. It is the same for all
+//                contexts inside a function. It provides access to the
+//                incoming context (i.e., the outer context, which may
+//                or may not become the current function's context), and
+//                it provides access to the functions code and thus it's
+//                scope information, which in turn contains the names of
+//                statically allocated context slots. The names are needed
+//                for dynamic lookups in the presence of 'with' or 'eval'.
+//
+// [ fcontext  ]  A pointer to the innermost enclosing function context.
+//                It is the same for all contexts *allocated* inside a
+//                function, and the function context's fcontext points
+//                to itself. It is only needed for fast access of the
+//                function context (used for declarations, and static
+//                context slot access).
+//
+// [ previous  ]  A pointer to the previous context. It is NULL for
+//                function contexts, and non-NULL for 'with' contexts.
+//                Used to implement the 'with' statement.
+//
+// [ extension ]  A pointer to an extension JSObject, or NULL. Used to
+//                implement 'with' statements and dynamic declarations
+//                (through 'eval'). The object in a 'with' statement is
+//                stored in the extension slot of a 'with' context.
+//                Dynamically declared variables/functions are also added
+//                to lazily allocated extension object. Context::Lookup
+//                searches the extension object for properties.
+//
+// [ global    ]  A pointer to the global object. Provided for quick
+//                access to the global object from inside the code (since
+//                we always have a context pointer).
+//
+// In addition, function contexts may have statically allocated context slots
+// to store local variables/functions that are accessed from inner functions
+// (via static context addresses) or through 'eval' (dynamic context lookups).
+// Finally, the global context contains additional slots for fast access to
+// global properties.
+//
+// We may be able to simplify the implementation:
+//
+// - We may be able to get rid of 'fcontext': We can always use the fact that
+//   previous == NULL for function contexts and so we can search for them. They
+//   are only needed when doing dynamic declarations, and the context chains
+//   tend to be very very short (depth of nesting of 'with' statements). At
+//   the moment we also use it in generated code for context slot accesses -
+//   and there we don't want a loop because of code bloat - but we may not
+//   need it there after all (see comment in codegen_*.cc).
+//
+// - If we cannot get rid of fcontext, consider making 'previous' never NULL
+//   except for the global context. This could simplify Context::Lookup.
+
+class Context: public FixedArray {
+ public:
+  // Conversions.
+  static Context* cast(Object* context) {
+    ASSERT(context->IsContext());
+    return reinterpret_cast<Context*>(context);
+  }
+
+  // The default context slot layout; indices are FixedArray slot indices.
+  enum {
+    // These slots are in all contexts.
+    CLOSURE_INDEX,
+    FCONTEXT_INDEX,
+    PREVIOUS_INDEX,
+    EXTENSION_INDEX,
+    GLOBAL_INDEX,
+    MIN_CONTEXT_SLOTS,
+
+    // These slots are only in global contexts.
+    GLOBAL_PROXY_INDEX = MIN_CONTEXT_SLOTS,
+    SECURITY_TOKEN_INDEX,
+    ARGUMENTS_BOILERPLATE_INDEX,
+    JS_ARRAY_MAP_INDEX,
+    FUNCTION_MAP_INDEX,
+    FUNCTION_INSTANCE_MAP_INDEX,
+    INITIAL_OBJECT_PROTOTYPE_INDEX,
+    BOOLEAN_FUNCTION_INDEX,
+    NUMBER_FUNCTION_INDEX,
+    STRING_FUNCTION_INDEX,
+    OBJECT_FUNCTION_INDEX,
+    ARRAY_FUNCTION_INDEX,
+    DATE_FUNCTION_INDEX,
+    REGEXP_FUNCTION_INDEX,
+    CREATE_DATE_FUN_INDEX,
+    TO_NUMBER_FUN_INDEX,
+    TO_STRING_FUN_INDEX,
+    TO_DETAIL_STRING_FUN_INDEX,
+    TO_OBJECT_FUN_INDEX,
+    TO_INTEGER_FUN_INDEX,
+    TO_UINT32_FUN_INDEX,
+    TO_INT32_FUN_INDEX,
+    TO_BOOLEAN_FUN_INDEX,
+    INSTANTIATE_FUN_INDEX,
+    CONFIGURE_INSTANCE_FUN_INDEX,
+    SPECIAL_FUNCTION_TABLE_INDEX,
+    MESSAGE_LISTENERS_INDEX,
+    DEBUG_EVENT_LISTENERS_INDEX,
+    MAKE_MESSAGE_FUN_INDEX,
+    GET_STACK_TRACE_LINE_INDEX,
+    CONFIGURE_GLOBAL_INDEX,
+    FUNCTION_CACHE_INDEX,
+    RUNTIME_CONTEXT_INDEX,
+    CALL_AS_FUNCTION_DELEGATE_INDEX,
+    EMPTY_SCRIPT_INDEX,
+    SCRIPT_FUNCTION_INDEX,
+    CONTEXT_EXTENSION_FUNCTION_INDEX,
+    OUT_OF_MEMORY_INDEX,
+    MAP_CACHE_INDEX,
+    GLOBAL_CONTEXT_SLOTS
+  };
+
+  // Direct slot access.
+  JSFunction* closure() { return JSFunction::cast(get(CLOSURE_INDEX)); }
+  void set_closure(JSFunction* closure) { set(CLOSURE_INDEX, closure); }
+
+  Context* fcontext() { return Context::cast(get(FCONTEXT_INDEX)); }
+  void set_fcontext(Context* context) { set(FCONTEXT_INDEX, context); }
+
+  Context* previous() {
+    Object* result = unchecked_previous();
+    ASSERT(IsBootstrappingOrContext(result));
+    return reinterpret_cast<Context*>(result);
+  }
+  void set_previous(Context* context) { set(PREVIOUS_INDEX, context); }
+
+  bool has_extension() { return unchecked_extension() != NULL; }
+  JSObject* extension() { return JSObject::cast(unchecked_extension()); }
+  void set_extension(JSObject* object) { set(EXTENSION_INDEX, object); }
+
+  GlobalObject* global() {
+    Object* result = get(GLOBAL_INDEX);
+    ASSERT(IsBootstrappingOrGlobalObject(result));
+    return reinterpret_cast<GlobalObject*>(result);
+  }
+  void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); }
+
+  // Returns a JSGlobalProxy object or null.
+  JSObject* global_proxy();
+  void set_global_proxy(JSObject* global);
+
+  // The builtins object.
+  JSBuiltinsObject* builtins();
+
+  // Compute the global context by traversing the context chain.
+  Context* global_context();
+
+  // Tells if this is a function context (as opposed to a 'with' context).
+  bool is_function_context() { return unchecked_previous() == NULL; }
+
+  // Tells whether the global context is marked with out of memory.
+  bool has_out_of_memory() {
+    return global_context()->out_of_memory() == Heap::true_value();
+  }
+
+  // Mark the global context with out of memory.
+  void mark_out_of_memory() {
+    global_context()->set_out_of_memory(Heap::true_value());
+  }
+
+#define GLOBAL_CONTEXT_FIELD_ACCESSORS(index, type, name) \
+  void  set_##name(type* value) {                         \
+    ASSERT(IsGlobalContext());                            \
+    set(index, value);                                    \
+  }                                                       \
+  type* name() {                                          \
+    ASSERT(IsGlobalContext());                            \
+    return type::cast(get(index));                        \
+  }
+  GLOBAL_CONTEXT_FIELDS(GLOBAL_CONTEXT_FIELD_ACCESSORS)
+#undef GLOBAL_CONTEXT_FIELD_ACCESSORS
+
+  // Lookup the the slot called name, starting with the current context.
+  // There are 4 possible outcomes:
+  //
+  // 1) index_ >= 0 && result->IsContext():
+  //    most common case, the result is a Context, and index is the
+  //    context slot index, and the slot exists.
+  //    attributes == READ_ONLY for the function name variable, NONE otherwise.
+  //
+  // 2) index_ >= 0 && result->IsJSObject():
+  //    the result is the JSObject arguments object, the index is the parameter
+  //    index, i.e., key into the arguments object, and the property exists.
+  //    attributes != ABSENT.
+  //
+  // 3) index_ < 0 && result->IsJSObject():
+  //    the result is the JSObject extension context or the global object,
+  //    and the name is the property name, and the property exists.
+  //    attributes != ABSENT.
+  //
+  // 4) index_ < 0 && result.is_null():
+  //    there was no context found with the corresponding property.
+  //    attributes == ABSENT.
+  Handle<Object> Lookup(Handle<String> name, ContextLookupFlags flags,
+                        int* index_, PropertyAttributes* attributes);
+
+  // Code generation support.
+  static int SlotOffset(int index) {
+    return kHeaderSize + index * kPointerSize - kHeapObjectTag;
+  }
+
+ private:
+  // Unchecked access to the slots.
+  Object* unchecked_previous() { return get(PREVIOUS_INDEX); }
+  Object* unchecked_extension() { return get(EXTENSION_INDEX); }
+
+#ifdef DEBUG
+  // Bootstrapping-aware type checks.
+  static bool IsBootstrappingOrContext(Object* object);
+  static bool IsBootstrappingOrGlobalObject(Object* object);
+#endif
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_CONTEXTS_H_
diff --git a/regexp2000/src/conversions-inl.h b/regexp2000/src/conversions-inl.h
new file mode 100644 (file)
index 0000000..e3db4e9
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CONVERSIONS_INL_H_
+#define V8_CONVERSIONS_INL_H_
+
+#include <math.h>
+#include <float.h>         // required for DBL_MAX and on Win32 for finite()
+
+// ----------------------------------------------------------------------------
+// Extra POSIX/ANSI functions for Win32/MSVC.
+
+#include "conversions.h"
+#include "platform.h"
+
+namespace v8 { namespace internal {
+
+// The fast double-to-int conversion routine does not guarantee
+// rounding towards zero.
+static inline int FastD2I(double x) {
+#ifdef __USE_ISOC99
+  // The ISO C99 standard defines the lrint() function which rounds a
+  // double to an integer according to the current rounding direction.
+  return lrint(x);
+#else
+  // This is incredibly slow on Intel x86. The reason is that rounding
+  // towards zero is implied by the C standard. This means that the
+  // status register of the FPU has to be changed with the 'fldcw'
+  // instruction. This completely stalls the pipeline and takes many
+  // hundreds of clock cycles.
+  return static_cast<int>(x);
+#endif
+}
+
+
+static inline double DoubleToInteger(double x) {
+  if (isnan(x)) return 0;
+  if (!isfinite(x) || x == 0) return x;
+  return (x >= 0) ? floor(x) : ceil(x);
+}
+
+
+int32_t NumberToInt32(Object* number) {
+  if (number->IsSmi()) return Smi::cast(number)->value();
+  return DoubleToInt32(number->Number());
+}
+
+
+uint32_t NumberToUint32(Object* number) {
+  if (number->IsSmi()) return Smi::cast(number)->value();
+  return DoubleToUint32(number->Number());
+}
+
+
+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 = fmod(x, two32);
+  x = (x >= 0) ? floor(x) : ceil(x) + two32;
+  return (int32_t) ((x >= two31) ? x - two32 : x);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_CONVERSIONS_INL_H_
diff --git a/regexp2000/src/conversions.cc b/regexp2000/src/conversions.cc
new file mode 100644 (file)
index 0000000..a1adb22
--- /dev/null
@@ -0,0 +1,702 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdarg.h>
+
+#include "v8.h"
+
+#include "conversions-inl.h"
+#include "factory.h"
+#include "scanner.h"
+
+namespace v8 { namespace internal {
+
+int HexValue(uc32 c) {
+  if ('0' <= c && c <= '9')
+    return c - '0';
+  if ('a' <= c && c <= 'f')
+    return c - 'a' + 10;
+  if ('A' <= c && c <= 'F')
+    return c - 'A' + 10;
+  return -1;
+}
+
+
+// Provide a common interface to getting a character at a certain
+// index from a char* or a String object.
+static inline int GetChar(const char* str, int index) {
+  ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
+  return str[index];
+}
+
+
+static inline int GetChar(String* str, int index) {
+  return str->Get(index);
+}
+
+
+static inline int GetLength(const char* str) {
+  return strlen(str);
+}
+
+
+static inline int GetLength(String* str) {
+  return str->length();
+}
+
+
+static inline const char* GetCString(const char* str, int index) {
+  return str + index;
+}
+
+
+static inline const char* GetCString(String* str, int index) {
+  char* result = NewArray<char>(str->length() + 1);
+  for (int i = index; i < str->length(); i++) {
+    if (str->Get(i) <= 127) {
+      result[i - index] = static_cast<char>(str->Get(i));
+    } else {
+      result[i - index] = 127;  // Force number parsing to fail.
+    }
+  }
+  result[str->length() - index] = '\0';
+  return result;
+}
+
+
+static inline void ReleaseCString(const char* original, const char* str) {
+}
+
+
+static inline void ReleaseCString(String* original, const char* str) {
+  DeleteArray(const_cast<char *>(str));
+}
+
+
+static inline bool IsSpace(const char* str, int index) {
+  ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
+  return Scanner::kIsWhiteSpace.get(str[index]);
+}
+
+
+static inline bool IsSpace(String* str, int index) {
+  return Scanner::kIsWhiteSpace.get(str->Get(index));
+}
+
+
+static inline bool SubStringEquals(const char* str,
+                                   int index,
+                                   const char* other) {
+  return strncmp(str + index, other, strlen(other)) != 0;
+}
+
+
+static inline bool SubStringEquals(String* str, int index, const char* other) {
+  HandleScope scope;
+  int len = strlen(other);
+  int end = index + len < str->length() ? index + len : str->length();
+  Handle<String> slice =
+      Factory::NewStringSlice(Handle<String>(str), index, end);
+  return slice->IsEqualTo(Vector<const char>(other, len));
+}
+
+
+// Check if a string should be parsed as an octal number.  The string
+// can be either a char* or a String*.
+template<class S>
+static bool ShouldParseOctal(S* s, int i) {
+  int index = i;
+  int len = GetLength(s);
+  if (index < len && GetChar(s, index) != '0') return false;
+
+  // If the first real character (following '0') is not an octal
+  // digit, bail out early. This also takes care of numbers of the
+  // forms 0.xxx and 0exxx by not allowing the first 0 to be
+  // interpreted as an octal.
+  index++;
+  if (index < len) {
+    int d = GetChar(s, index) - '0';
+    if (d < 0 || d > 7) return false;
+  } else {
+    return false;
+  }
+
+  // Traverse all digits (including the first). If there is an octal
+  // prefix which is not a part of a longer decimal prefix, we return
+  // true. Otherwise, false is returned.
+  while (index < len) {
+    int d = GetChar(s, index++) - '0';
+    if (d == 8 || d == 9) return false;
+    if (d <  0 || d >  7) return true;
+  }
+  return true;
+}
+
+
+extern "C" double gay_strtod(const char* s00, const char** se);
+
+
+// Parse an int from a string starting a given index and in a given
+// radix.  The string can be either a char* or a String*.
+template <class S>
+static int InternalStringToInt(S* s, int i, int radix, double* value) {
+  int len = GetLength(s);
+
+  // Setup limits for computing the value.
+  ASSERT(2 <= radix && radix <= 36);
+  int lim_0 = '0' + (radix < 10 ? radix : 10);
+  int lim_a = 'a' + (radix - 10);
+  int lim_A = 'A' + (radix - 10);
+
+  // NOTE: The code for computing the value may seem a bit complex at
+  // first glance. It is structured to use 32-bit multiply-and-add
+  // loops as long as possible to avoid loosing precision.
+
+  double v = 0.0;
+  int j;
+  for (j = i; j < len;) {
+    // Parse the longest part of the string starting at index j
+    // possible while keeping the multiplier, and thus the part
+    // itself, within 32 bits.
+    uint32_t part = 0, multiplier = 1;
+    int k;
+    for (k = j; k < len; k++) {
+      int c = GetChar(s, k);
+      if (c >= '0' && c < lim_0) {
+        c = c - '0';
+      } else if (c >= 'a' && c < lim_a) {
+        c = c - 'a' + 10;
+      } else if (c >= 'A' && c < lim_A) {
+        c = c - 'A' + 10;
+      } else {
+        break;
+      }
+
+      // Update the value of the part as long as the multiplier fits
+      // in 32 bits. When we can't guarantee that the next iteration
+      // will not overflow the multiplier, we stop parsing the part
+      // by leaving the loop.
+      static const uint32_t kMaximumMultiplier = 0xffffffffU / 36;
+      uint32_t m = multiplier * radix;
+      if (m > kMaximumMultiplier) break;
+      part = part * radix + c;
+      multiplier = m;
+      ASSERT(multiplier > part);
+    }
+
+    // Compute the number of part digits. If no digits were parsed;
+    // we're done parsing the entire string.
+    int digits = k - j;
+    if (digits == 0) break;
+
+    // Update the value and skip the part in the string.
+    ASSERT(multiplier ==
+           pow(static_cast<double>(radix), static_cast<double>(digits)));
+    v = v * multiplier + part;
+    j = k;
+  }
+
+  // If the resulting value is larger than 2^53 the value does not fit
+  // in the mantissa of the double and there is a loss of precision.
+  // When the value is larger than 2^53 the rounding depends on the
+  // code generation.  If the code generator spills the double value
+  // it uses 64 bits and if it does not it uses 80 bits.
+  //
+  // If there is a potential for overflow we resort to strtod for
+  // radix 10 numbers to get higher precision.  For numbers in another
+  // radix we live with the loss of precision.
+  static const double kPreciseConversionLimit = 9007199254740992.0;
+  if (radix == 10 && v > kPreciseConversionLimit) {
+    const char* cstr = GetCString(s, i);
+    const char* end;
+    v = gay_strtod(cstr, &end);
+    ReleaseCString(s, cstr);
+  }
+
+  *value = v;
+  return j;
+}
+
+
+int StringToInt(String* str, int index, int radix, double* value) {
+  return InternalStringToInt(str, index, radix, value);
+}
+
+
+int StringToInt(const char* str, int index, int radix, double* value) {
+  return InternalStringToInt(const_cast<char*>(str), index, radix, value);
+}
+
+
+static const double JUNK_STRING_VALUE = OS::nan_value();
+
+
+// Convert a string to a double value.  The string can be either a
+// char* or a String*.
+template<class S>
+static double InternalStringToDouble(S* str,
+                                     int flags,
+                                     double empty_string_val) {
+  double result = 0.0;
+  int index = 0;
+
+  int len = GetLength(str);
+
+  // Skip leading spaces.
+  while ((index < len) && IsSpace(str, index)) index++;
+
+  // Is the string empty?
+  if (index >= len) return empty_string_val;
+
+  // Get the first character.
+  uint16_t first = GetChar(str, index);
+
+  // Numbers can only start with '-', '+', '.', 'I' (Infinity), or a digit.
+  if (first != '-' && first != '+' && first != '.' && first != 'I' &&
+      (first > '9' || first < '0')) {
+    return JUNK_STRING_VALUE;
+  }
+
+  // Compute sign of result based on first character.
+  int sign = 1;
+  if (first == '-') {
+    sign = -1;
+    index++;
+    // String only containing a '-' are junk chars.
+    if (index == len) return JUNK_STRING_VALUE;
+  }
+
+  // do we have a hex number?
+  // (since the string is 0-terminated, it's ok to look one char beyond the end)
+  if ((flags & ALLOW_HEX) != 0 &&
+      (index + 1) < len &&
+      GetChar(str, index) == '0' &&
+      (GetChar(str, index + 1) == 'x' || GetChar(str, index + 1) == 'X')) {
+    index += 2;
+    index = StringToInt(str, index, 16, &result);
+  } else if ((flags & ALLOW_OCTALS) != 0 && ShouldParseOctal(str, index)) {
+    // NOTE: We optimistically try to parse the number as an octal (if
+    // we're allowed to), even though this is not as dictated by
+    // ECMA-262. The reason for doing this is compatibility with IE and
+    // Firefox.
+    index = StringToInt(str, index, 8, &result);
+  } else {
+    const char* cstr = GetCString(str, index);
+    const char* end;
+    // Optimistically parse the number and then, if that fails,
+    // check if it might have been {+,-,}Infinity.
+    result = gay_strtod(cstr, &end);
+    ReleaseCString(str, cstr);
+    if (result != 0.0 || end != cstr) {
+      // It appears that strtod worked
+      index += end - cstr;
+    } else {
+      // Check for {+,-,}Infinity
+      bool is_negative = (GetChar(str, index) == '-');
+      if (GetChar(str, index) == '+' || GetChar(str, index) == '-')
+        index++;
+      if (!SubStringEquals(str, index, "Infinity"))
+        return JUNK_STRING_VALUE;
+      result = is_negative ? -INFINITY : INFINITY;
+      index += 8;
+    }
+  }
+
+  if ((flags & ALLOW_TRAILING_JUNK) == 0) {
+    // skip trailing spaces
+    while ((index < len) && IsSpace(str, index)) index++;
+    // string ending with junk?
+    if (index < len) return JUNK_STRING_VALUE;
+  }
+
+  return sign * result;
+}
+
+
+double StringToDouble(String* str, int flags, double empty_string_val) {
+  return InternalStringToDouble(str, flags, empty_string_val);
+}
+
+
+double StringToDouble(const char* str, int flags, double empty_string_val) {
+  return InternalStringToDouble(str, flags, empty_string_val);
+}
+
+
+extern "C" char* dtoa(double d, int mode, int ndigits,
+                      int* decpt, int* sign, char** rve);
+
+extern "C" void freedtoa(char* s);
+
+const char* DoubleToCString(double v, Vector<char> buffer) {
+  StringBuilder builder(buffer.start(), buffer.length());
+
+  switch (fpclassify(v)) {
+    case FP_NAN:
+      builder.AddString("NaN");
+      break;
+
+    case FP_INFINITE:
+      if (v < 0.0) {
+        builder.AddString("-Infinity");
+      } else {
+        builder.AddString("Infinity");
+      }
+      break;
+
+    case FP_ZERO:
+      builder.AddCharacter('0');
+      break;
+
+    default: {
+      int decimal_point;
+      int sign;
+
+      char* decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
+      int length = strlen(decimal_rep);
+
+      if (sign) builder.AddCharacter('-');
+
+      if (length <= decimal_point && decimal_point <= 21) {
+        // ECMA-262 section 9.8.1 step 6.
+        builder.AddString(decimal_rep);
+        builder.AddPadding('0', decimal_point - length);
+
+      } else if (0 < decimal_point && decimal_point <= 21) {
+        // ECMA-262 section 9.8.1 step 7.
+        builder.AddSubstring(decimal_rep, decimal_point);
+        builder.AddCharacter('.');
+        builder.AddString(decimal_rep + decimal_point);
+
+      } else if (decimal_point <= 0 && decimal_point > -6) {
+        // ECMA-262 section 9.8.1 step 8.
+        builder.AddString("0.");
+        builder.AddPadding('0', -decimal_point);
+        builder.AddString(decimal_rep);
+
+      } else {
+        // ECMA-262 section 9.8.1 step 9 and 10 combined.
+        builder.AddCharacter(decimal_rep[0]);
+        if (length != 1) {
+          builder.AddCharacter('.');
+          builder.AddString(decimal_rep + 1);
+        }
+        builder.AddCharacter('e');
+        builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
+        int exponent = decimal_point - 1;
+        if (exponent < 0) exponent = -exponent;
+        builder.AddFormatted("%d", exponent);
+      }
+
+      freedtoa(decimal_rep);
+    }
+  }
+  return builder.Finalize();
+}
+
+
+const char* IntToCString(int n, Vector<char> buffer) {
+  bool negative = false;
+  if (n < 0) {
+    // We must not negate the most negative int.
+    if (n == kMinInt) return DoubleToCString(n, buffer);
+    negative = true;
+    n = -n;
+  }
+  // Build the string backwards from the least significant digit.
+  int i = buffer.length();
+  buffer[--i] = '\0';
+  do {
+    buffer[--i] = '0' + (n % 10);
+    n /= 10;
+  } while (n);
+  if (negative) buffer[--i] = '-';
+  return buffer.start() + i;
+}
+
+
+char* DoubleToFixedCString(double value, int f) {
+  ASSERT(f >= 0);
+
+  bool negative = false;
+  double abs_value = value;
+  if (value < 0) {
+    abs_value = -value;
+    negative = true;
+  }
+
+  if (abs_value >= 1e21) {
+    char arr[100];
+    Vector<char> buffer(arr, ARRAY_SIZE(arr));
+    return StrDup(DoubleToCString(value, buffer));
+  }
+
+  // Find a sufficiently precise decimal representation of n.
+  int decimal_point;
+  int sign;
+  char* decimal_rep = dtoa(abs_value, 3, f, &decimal_point, &sign, NULL);
+  int decimal_rep_length = strlen(decimal_rep);
+
+  // Create a representation that is padded with zeros if needed.
+  int zero_prefix_length = 0;
+  int zero_postfix_length = 0;
+
+  if (decimal_point <= 0) {
+    zero_prefix_length = -decimal_point + 1;
+    decimal_point = 1;
+  }
+
+  if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
+    zero_postfix_length = decimal_point + f - decimal_rep_length -
+                          zero_prefix_length;
+  }
+
+  unsigned rep_length =
+      zero_prefix_length + decimal_rep_length + zero_postfix_length;
+  StringBuilder rep_builder(rep_length + 1);
+  rep_builder.AddPadding('0', zero_prefix_length);
+  rep_builder.AddString(decimal_rep);
+  rep_builder.AddPadding('0', zero_postfix_length);
+  char* rep = rep_builder.Finalize();
+  freedtoa(decimal_rep);
+
+  // Create the result string by appending a minus and putting in a
+  // decimal point if needed.
+  unsigned result_size = decimal_point + f + 2;
+  StringBuilder builder(result_size + 1);
+  if (negative) builder.AddCharacter('-');
+  builder.AddSubstring(rep, decimal_point);
+  if (f > 0) {
+    builder.AddCharacter('.');
+    builder.AddSubstring(rep + decimal_point, f);
+  }
+  DeleteArray(rep);
+  return builder.Finalize();
+}
+
+
+static char* CreateExponentialRepresentation(char* decimal_rep,
+                                             int exponent,
+                                             bool negative,
+                                             int significant_digits) {
+  bool negative_exponent = false;
+  if (exponent < 0) {
+    negative_exponent = true;
+    exponent = -exponent;
+  }
+
+  // Leave room in the result for appending a minus, for a period, the
+  // letter 'e', a minus or a plus depending on the exponent, and a
+  // three digit exponent.
+  unsigned result_size = significant_digits + 7;
+  StringBuilder builder(result_size + 1);
+
+  if (negative) builder.AddCharacter('-');
+  builder.AddCharacter(decimal_rep[0]);
+  if (significant_digits != 1) {
+    builder.AddCharacter('.');
+    builder.AddString(decimal_rep + 1);
+    builder.AddPadding('0', significant_digits - strlen(decimal_rep));
+  }
+
+  builder.AddCharacter('e');
+  builder.AddCharacter(negative_exponent ? '-' : '+');
+  builder.AddFormatted("%d", exponent);
+  return builder.Finalize();
+}
+
+
+
+char* DoubleToExponentialCString(double value, int f) {
+  // f might be -1 to signal that f was undefined in JavaScript.
+  ASSERT(f >= -1 && f <= 20);
+
+  bool negative = false;
+  if (value < 0) {
+    value = -value;
+    negative = true;
+  }
+
+  // Find a sufficiently precise decimal representation of n.
+  int decimal_point;
+  int sign;
+  char* decimal_rep = NULL;
+  if (f == -1) {
+    decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL);
+    f = strlen(decimal_rep) - 1;
+  } else {
+    decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL);
+  }
+  int decimal_rep_length = strlen(decimal_rep);
+  ASSERT(decimal_rep_length > 0);
+  ASSERT(decimal_rep_length <= f + 1);
+  USE(decimal_rep_length);
+
+  int exponent = decimal_point - 1;
+  char* result =
+      CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
+
+  freedtoa(decimal_rep);
+
+  return result;
+}
+
+
+char* DoubleToPrecisionCString(double value, int p) {
+  ASSERT(p >= 1 && p <= 21);
+
+  bool negative = false;
+  if (value < 0) {
+    value = -value;
+    negative = true;
+  }
+
+  // Find a sufficiently precise decimal representation of n.
+  int decimal_point;
+  int sign;
+  char* decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL);
+  int decimal_rep_length = strlen(decimal_rep);
+  ASSERT(decimal_rep_length <= p);
+
+  int exponent = decimal_point - 1;
+
+  char* result = NULL;
+
+  if (exponent < -6 || exponent >= p) {
+    result =
+        CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
+  } else {
+    // Use fixed notation.
+    //
+    // Leave room in the result for appending a minus, a period and in
+    // the case where decimal_point is not positive for a zero in
+    // front of the period.
+    unsigned result_size = (decimal_point <= 0)
+        ? -decimal_point + p + 3
+        : p + 2;
+    StringBuilder builder(result_size + 1);
+    if (negative) builder.AddCharacter('-');
+    if (decimal_point <= 0) {
+      builder.AddString("0.");
+      builder.AddPadding('0', -decimal_point);
+      builder.AddString(decimal_rep);
+      builder.AddPadding('0', p - decimal_rep_length);
+    } else {
+      const int m = Min(decimal_rep_length, decimal_point);
+      builder.AddSubstring(decimal_rep, m);
+      builder.AddPadding('0', decimal_point - decimal_rep_length);
+      if (decimal_point < p) {
+        builder.AddCharacter('.');
+        const int extra = negative ? 2 : 1;
+        if (decimal_rep_length > decimal_point) {
+          const int len = strlen(decimal_rep + decimal_point);
+          const int n = Min(len, p - (builder.position() - extra));
+          builder.AddSubstring(decimal_rep + decimal_point, n);
+        }
+        builder.AddPadding('0', extra + (p - builder.position()));
+      }
+    }
+    result = builder.Finalize();
+  }
+
+  freedtoa(decimal_rep);
+  return result;
+}
+
+
+char* DoubleToRadixCString(double value, int radix) {
+  ASSERT(radix >= 2 && radix <= 36);
+
+  // Character array used for conversion.
+  static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+  // Buffer for the integer part of the result. 1024 chars is enough
+  // for max integer value in radix 2.  We need room for a sign too.
+  static const int kBufferSize = 1100;
+  char integer_buffer[kBufferSize];
+  integer_buffer[kBufferSize - 1] = '\0';
+
+  // Buffer for the decimal part of the result.  We only generate up
+  // to kBufferSize - 1 chars for the decimal part.
+  char decimal_buffer[kBufferSize];
+  decimal_buffer[kBufferSize - 1] = '\0';
+
+  // Make sure the value is positive.
+  bool is_negative = value < 0.0;
+  if (is_negative) value = -value;
+
+  // Get the integer part and the decimal part.
+  double integer_part = floor(value);
+  double decimal_part = value - integer_part;
+
+  // Convert the integer part starting from the back.  Always generate
+  // at least one digit.
+  int integer_pos = kBufferSize - 2;
+  do {
+    integer_buffer[integer_pos--] =
+        chars[static_cast<int>(fmod(integer_part, radix))];
+    integer_part /= radix;
+  } while (integer_part >= 1.0);
+  // Sanity check.
+  ASSERT(integer_pos > 0);
+  // Add sign if needed.
+  if (is_negative) integer_buffer[integer_pos--] = '-';
+
+  // Convert the decimal part.  Repeatedly multiply by the radix to
+  // generate the next char.  Never generate more than kBufferSize - 1
+  // chars.
+  //
+  // TODO(1093998): We will often generate a full decimal_buffer of
+  // chars because hitting zero will often not happen.  The right
+  // solution would be to continue until the string representation can
+  // be read back and yield the original value.  To implement this
+  // efficiently, we probably have to modify dtoa.
+  int decimal_pos = 0;
+  while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
+    decimal_part *= radix;
+    decimal_buffer[decimal_pos++] =
+        chars[static_cast<int>(floor(decimal_part))];
+    decimal_part -= floor(decimal_part);
+  }
+  decimal_buffer[decimal_pos] = '\0';
+
+  // Compute the result size.
+  int integer_part_size = kBufferSize - 2 - integer_pos;
+  // Make room for zero termination.
+  unsigned result_size = integer_part_size + decimal_pos;
+  // If the number has a decimal part, leave room for the period.
+  if (decimal_pos > 0) result_size++;
+  // Allocate result and fill in the parts.
+  StringBuilder builder(result_size + 1);
+  builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
+  if (decimal_pos > 0) builder.AddCharacter('.');
+  builder.AddSubstring(decimal_buffer, decimal_pos);
+  return builder.Finalize();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/conversions.h b/regexp2000/src/conversions.h
new file mode 100644 (file)
index 0000000..605327d
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_CONVERSIONS_H_
+#define V8_CONVERSIONS_H_
+
+namespace v8 { namespace internal {
+
+// The fast double-to-int conversion routine does not guarantee
+// rounding towards zero.
+// The result is unspecified if x is infinite or NaN, or if the rounded
+// integer value is outside the range of type int.
+static inline int FastD2I(double x);
+
+
+static inline double FastI2D(int x) {
+  // There is no rounding involved in converting an integer to a
+  // double, so this code should compile to a few instructions without
+  // any FPU pipeline stalls.
+  return static_cast<double>(x);
+}
+
+
+static inline double FastUI2D(unsigned x) {
+  // There is no rounding involved in converting an unsigned integer to a
+  // double, so this code should compile to a few instructions without
+  // any FPU pipeline stalls.
+  return static_cast<double>(x);
+}
+
+
+// This function should match the exact semantics of ECMA-262 9.4.
+static inline double DoubleToInteger(double x);
+
+
+// This function should match the exact semantics of ECMA-262 9.5.
+static inline int32_t DoubleToInt32(double x);
+
+
+// This function should match the exact semantics of ECMA-262 9.6.
+static inline uint32_t DoubleToUint32(double x) {
+  return static_cast<uint32_t>(DoubleToInt32(x));
+}
+
+
+// Returns the value (0 .. 15) of a hexadecimal character c.
+// If c is not a legal hexadecimal character, returns a value < 0.
+int HexValue(uc32 c);
+
+
+// Enumeration for allowing octals and ignoring junk when converting
+// strings to numbers.
+enum ConversionFlags {
+  NO_FLAGS = 0,
+  ALLOW_HEX = 1,
+  ALLOW_OCTALS = 2,
+  ALLOW_TRAILING_JUNK = 4
+};
+
+
+// Convert from Number object to C integer.
+static inline int32_t NumberToInt32(Object* number);
+static inline uint32_t NumberToUint32(Object* number);
+
+
+// Converts a string into a double value according to ECMA-262 9.3.1
+double StringToDouble(const char* str, int flags, double empty_string_val = 0);
+double StringToDouble(String* str, int flags, double empty_string_val = 0);
+
+// Converts a string into an integer.
+int StringToInt(String* str, int index, int radix, double* value);
+int StringToInt(const char* str, int index, int radix, double* value);
+
+// 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.
+const char* DoubleToCString(double value, Vector<char> buffer);
+
+// Convert an int to a null-terminated string. The returned string is
+// located inside the buffer, but not necessarily at the start.
+const char* IntToCString(int n, Vector<char> buffer);
+
+// Additional number to string conversions for the number type.
+// The caller is responsible for calling free on the returned pointer.
+char* DoubleToFixedCString(double value, int f);
+char* DoubleToExponentialCString(double value, int f);
+char* DoubleToPrecisionCString(double value, int f);
+char* DoubleToRadixCString(double value, int radix);
+
+} }  // namespace v8::internal
+
+#endif  // V8_CONVERSIONS_H_
diff --git a/regexp2000/src/counters.cc b/regexp2000/src/counters.cc
new file mode 100644 (file)
index 0000000..8878ec5
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "counters.h"
+#include "platform.h"
+
+namespace v8 { namespace internal {
+
+CounterLookupCallback StatsTable::lookup_function_ = NULL;
+
+// Start the timer.
+void StatsCounterTimer::Start() {
+  if (!counter_.Enabled())
+    return;
+  stop_time_ = 0;
+  start_time_ = OS::Ticks();
+}
+
+// Stop the timer and record the results.
+void StatsCounterTimer::Stop() {
+  if (!counter_.Enabled())
+    return;
+  stop_time_ = OS::Ticks();
+
+  // Compute the delta between start and stop, in milliseconds.
+  int milliseconds = static_cast<int>(stop_time_ - start_time_) / 1000;
+  counter_.Increment(milliseconds);
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/counters.h b/regexp2000/src/counters.h
new file mode 100644 (file)
index 0000000..270c091
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_COUNTERS_H_
+#define V8_COUNTERS_H_
+
+#include <wchar.h>
+
+namespace v8 { namespace internal {
+
+// StatsCounters is an interface for plugging into external
+// counters for monitoring.  Counters can be looked up and
+// manipulated by name.
+
+class StatsTable : public AllStatic {
+ public:
+  // Register an application-defined function where
+  // counters can be looked up.
+  static void SetCounterFunction(CounterLookupCallback f) {
+    lookup_function_ = f;
+  }
+
+  static bool HasCounterFunction() {
+    return lookup_function_ != NULL;
+  }
+
+  // Lookup the location of a counter by name.  If the lookup
+  // is successful, returns a non-NULL pointer for writing the
+  // value of the counter.  Each thread calling this function
+  // may receive a different location to store it's counter.
+  // The return value must not be cached and re-used across
+  // threads, although a single thread is free to cache it.
+  static int *FindLocation(const wchar_t* name) {
+    if (!lookup_function_) return NULL;
+    return lookup_function_(name);
+  }
+
+ private:
+  static CounterLookupCallback lookup_function_;
+};
+
+// StatsCounters are dynamically created values which can be tracked in
+// the StatsTable.  They are designed to be lightweight to create and
+// easy to use.
+//
+// Internally, a counter represents a value in a row of a StatsTable.
+// The row has a 32bit value for each process/thread in the table and also
+// a name (stored in the table metadata).  Since the storage location can be
+// thread-specific, this class cannot be shared across threads.
+//
+// This class is designed to be POD initialized.  It will be registered with
+// the counter system on first use.  For example:
+//   StatsCounter c = { L"c:myctr", NULL, false };
+struct StatsCounter {
+  const wchar_t* name_;
+  int* ptr_;
+  bool lookup_done_;
+
+  // Sets the counter to a specific value.
+  void Set(int value) {
+    int* loc = GetPtr();
+    if (loc) *loc = value;
+  }
+
+  // Increments the counter.
+  void Increment() {
+    int* loc = GetPtr();
+    if (loc) (*loc)++;
+  }
+
+  void Increment(int value) {
+    int* loc = GetPtr();
+    if (loc)
+      (*loc) += value;
+  }
+
+  // Decrements the counter.
+  void Decrement() {
+    int* loc = GetPtr();
+    if (loc) (*loc)--;
+  }
+
+  void Decrement(int value) {
+    int* loc = GetPtr();
+    if (loc) (*loc) -= value;
+  }
+
+  // Is this counter enabled?
+  // Returns false if table is full.
+  bool Enabled() {
+    return GetPtr() != NULL;
+  }
+
+  // Get the internal pointer to the counter. This is used
+  // by the code generator to emit code that manipulates a
+  // given counter without calling the runtime system.
+  int* GetInternalPointer() {
+    int* loc = GetPtr();
+    ASSERT(loc != NULL);
+    return loc;
+  }
+
+ protected:
+  // Returns the cached address of this counter location.
+  int* GetPtr() {
+    if (lookup_done_)
+      return ptr_;
+    lookup_done_ = true;
+    ptr_ = StatsTable::FindLocation(name_);
+    return ptr_;
+  }
+};
+
+// StatsCounterTimer t = { { L"t:foo", NULL, false }, 0, 0 };
+struct StatsCounterTimer {
+  StatsCounter counter_;
+
+  int64_t start_time_;
+  int64_t stop_time_;
+
+  // Start the timer.
+  void Start();
+
+  // Stop the timer and record the results.
+  void Stop();
+
+  // Returns true if the timer is running.
+  bool Running() {
+    return counter_.Enabled() && start_time_ != 0 && stop_time_ == 0;
+  }
+};
+
+// A StatsRate is a combination of both a timer and a counter so that
+// several statistics can be produced:
+//    min, max, avg, count, total
+//
+// For example:
+//   StatsCounter c = { { { L"t:myrate", NULL, false }, 0, 0 },
+//                      { L"c:myrate", NULL, false } };
+struct StatsRate {
+  StatsCounterTimer timer_;
+  StatsCounter counter_;
+
+  // Starts the rate timer.
+  void Start() {
+    timer_.Start();
+  }
+
+  // Stops the rate and records the time.
+  void Stop() {
+    if (timer_.Running()) {
+      timer_.Stop();
+      counter_.Increment();
+    }
+  }
+};
+
+
+// Helper class for scoping a rate.
+class StatsRateScope BASE_EMBEDDED {
+ public:
+  explicit StatsRateScope(StatsRate* rate) :
+      rate_(rate) {
+    rate_->Start();
+  }
+  ~StatsRateScope() {
+    rate_->Stop();
+  }
+ private:
+  StatsRate* rate_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_COUNTERS_H_
diff --git a/regexp2000/src/cpu-arm.cc b/regexp2000/src/cpu-arm.cc
new file mode 100644 (file)
index 0000000..7369661
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// CPU specific code for arm independent of OS goes here.
+#if defined(__arm__)
+#include <sys/syscall.h>  // for cache flushing.
+#endif
+
+#include "v8.h"
+
+#include "cpu.h"
+
+namespace v8 { namespace internal {
+
+void CPU::Setup() {
+  // Nothing to do.
+}
+
+
+void CPU::FlushICache(void* start, size_t size) {
+#if !defined (__arm__)
+  // Not generating ARM instructions for C-code. This means that we are
+  // building an ARM emulator based target. No I$ flushes are necessary.
+#else
+  // Ideally, we would call
+  //   syscall(__ARM_NR_cacheflush, start,
+  //           reinterpret_cast<intptr_t>(start) + size, 0);
+  // however, syscall(int, ...) is not supported on all platforms, especially
+  // not when using EABI, so we call the __ARM_NR_cacheflush syscall directly.
+
+  register uint32_t beg asm("a1") = reinterpret_cast<uint32_t>(start);
+  register uint32_t end asm("a2") =
+      reinterpret_cast<uint32_t>(start) + size;
+  register uint32_t flg asm("a3") = 0;
+  #ifdef __ARM_EABI__
+    register uint32_t scno asm("r7") = __ARM_NR_cacheflush;
+    #if defined (__arm__) && !defined(__thumb__)
+      // __arm__ may be defined in thumb mode.
+      asm volatile(
+          "swi 0x0"
+          : "=r" (beg)
+          : "0" (beg), "r" (end), "r" (flg), "r" (scno));
+    #else
+      asm volatile(
+      "@   Enter ARM Mode  \n\t"
+          "adr r3, 1f      \n\t"
+          "bx  r3          \n\t"
+          ".ALIGN 4        \n\t"
+          ".ARM            \n"
+      "1:  swi 0x0         \n\t"
+      "@   Enter THUMB Mode\n\t"
+          "adr r3, 2f+1    \n\t"
+          "bx  r3          \n\t"
+          ".THUMB          \n"
+      "2:                  \n\t"
+          : "=r" (beg)
+          : "0" (beg), "r" (end), "r" (flg), "r" (scno)
+          : "r3");
+    #endif
+  #else
+    #if defined (__arm__) && !defined(__thumb__)
+      // __arm__ may be defined in thumb mode.
+      asm volatile(
+          "swi %1"
+          : "=r" (beg)
+          : "i" (__ARM_NR_cacheflush), "0" (beg), "r" (end), "r" (flg));
+    #else
+      // Do not use the value of __ARM_NR_cacheflush in the inline assembly
+      // below, because the thumb mode value would be used, which would be
+      // wrong, since we switch to ARM mode before executing the swi instruction
+      asm volatile(
+      "@   Enter ARM Mode  \n\t"
+          "adr r3, 1f      \n\t"
+          "bx  r3          \n\t"
+          ".ALIGN 4        \n\t"
+          ".ARM            \n"
+      "1:  swi 0x9f0002    \n"
+      "@   Enter THUMB Mode\n\t"
+          "adr r3, 2f+1    \n\t"
+          "bx  r3          \n\t"
+          ".THUMB          \n"
+      "2:                  \n\t"
+          : "=r" (beg)
+          : "0" (beg), "r" (end), "r" (flg)
+          : "r3");
+    #endif
+  #endif
+#endif
+}
+
+
+void CPU::DebugBreak() {
+#if !defined (__arm__)
+  UNIMPLEMENTED();  // when building ARM emulator target
+#else
+  asm volatile("bkpt 0");
+#endif
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/cpu-ia32.cc b/regexp2000/src/cpu-ia32.cc
new file mode 100644 (file)
index 0000000..d61a548
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// CPU specific code for ia32 independent of OS goes here.
+
+#include "v8.h"
+
+#include "cpu.h"
+
+namespace v8 { namespace internal {
+
+void CPU::Setup() {
+  // Nothing to do.
+}
+
+
+void CPU::FlushICache(void* start, size_t size) {
+  // No need to flush the instruction cache on Intel. On Intel instruction
+  // cache flushing is only necessary when multiple cores running the same
+  // code simultaneously. V8 (and JavaScript) is single threaded and when code
+  // is patched on an intel CPU the core performing the patching will have its
+  // own instruction cache updated automatically.
+
+  // If flushing of the instruction cache becomes necessary Windows have the
+  // API function FlushInstructionCache.
+}
+
+
+void CPU::DebugBreak() {
+#ifdef WIN32
+  // To avoid Visual Studio runtime support the following code can be used
+  // instead
+  // __asm { int 3 }
+  __debugbreak();
+#else
+  asm("int $3");
+#endif
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/cpu.h b/regexp2000/src/cpu.h
new file mode 100644 (file)
index 0000000..d12c30c
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This module contains the architecture-specific code. This make the rest of
+// the code less dependent on differences between different processor
+// architecture.
+// The classes have the same definition for all architectures. The
+// implementation for a particular architecture is put in cpu_<arch>.cc.
+// The build system then uses the implementation for the target architecture.
+//
+
+#ifndef V8_CPU_H_
+#define V8_CPU_H_
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// CPU
+//
+// This class has static methods for the architecture specific functions. Add
+// methods here to cope with differences between the supported architectures.
+//
+// For each architecture the file cpu_<arch>.cc contains the implementation of
+// these functions.
+
+class CPU : public AllStatic {
+ public:
+  // Initializes the cpu architecture support. Called once at VM startup.
+  static void Setup();
+
+  // Flush instruction cache.
+  static void FlushICache(void* start, size_t size);
+
+  // Try to activate a system level debugger.
+  static void DebugBreak();
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_CPU_H_
diff --git a/regexp2000/src/d8-readline.cc b/regexp2000/src/d8-readline.cc
new file mode 100644 (file)
index 0000000..4cfee8b
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+
+#include "d8.h"
+
+
+namespace v8 {
+
+
+class ReadLineEditor: public LineEditor {
+ public:
+  ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
+  virtual i::SmartPointer<char> Prompt(const char* prompt);
+  virtual bool Open();
+  virtual bool Close();
+  virtual void AddHistory(const char* str);
+ private:
+  static char** AttemptedCompletion(const char* text, int start, int end);
+  static char* CompletionGenerator(const char* text, int state);
+  static char kWordBreakCharacters[];
+};
+
+
+static ReadLineEditor read_line_editor;
+char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
+    '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
+    '\0'};
+
+
+bool ReadLineEditor::Open() {
+  rl_initialize();
+  rl_attempted_completion_function = AttemptedCompletion;
+  rl_completer_word_break_characters = kWordBreakCharacters;
+  rl_bind_key('\t', rl_complete);
+  using_history();
+  return read_history(Shell::kHistoryFileName) == 0;
+}
+
+
+bool ReadLineEditor::Close() {
+  return write_history(Shell::kHistoryFileName) == 0;
+}
+
+
+i::SmartPointer<char> ReadLineEditor::Prompt(const char* prompt) {
+  char* result = readline(prompt);
+  return i::SmartPointer<char>(result);
+}
+
+
+void ReadLineEditor::AddHistory(const char* str) {
+  add_history(str);
+}
+
+
+char** ReadLineEditor::AttemptedCompletion(const char* text,
+                                           int start,
+                                           int end) {
+  char** result = rl_completion_matches(text, CompletionGenerator);
+  rl_attempted_completion_over = true;
+  return result;
+}
+
+
+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(strndup(rl_line_buffer, rl_point));
+    HandleScope scope;
+    Handle<Array> completions =
+      Shell::GetCompletions(String::New(text), String::New(*full_text));
+    current_completions = Persistent<Array>::New(completions);
+    current_index = 0;
+  }
+  if (current_index < current_completions->Length()) {
+    HandleScope scope;
+    Handle<Integer> index = Integer::New(current_index);
+    Handle<Value> str_obj = current_completions->Get(index);
+    current_index++;
+    String::Utf8Value str(str_obj);
+    return strdup(*str);
+  } else {
+    current_completions.Dispose();
+    current_completions.Clear();
+    return NULL;
+  }
+}
+
+
+}  // namespace v8
diff --git a/regexp2000/src/d8.cc b/regexp2000/src/d8.cc
new file mode 100644 (file)
index 0000000..af6eb4c
--- /dev/null
@@ -0,0 +1,348 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#include "d8.h"
+#include "debug.h"
+#include "api.h"
+#include "natives.h"
+
+
+namespace v8 {
+
+
+const char* Shell::kHistoryFileName = ".d8_history";
+const char* Shell::kPrompt = "d8> ";
+
+
+LineEditor *LineEditor::first_ = NULL;
+
+
+LineEditor::LineEditor(Type type, const char* name)
+    : type_(type),
+      name_(name),
+      next_(first_) {
+  first_ = this;
+}
+
+
+LineEditor* LineEditor::Get() {
+  LineEditor* current = first_;
+  LineEditor* best = current;
+  while (current != NULL) {
+    if (current->type_ > best->type_)
+      best = current;
+    current = current->next_;
+  }
+  return best;
+}
+
+
+class DumbLineEditor: public LineEditor {
+ public:
+  DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
+  virtual i::SmartPointer<char> Prompt(const char* prompt);
+};
+
+
+static DumbLineEditor dumb_line_editor;
+
+
+i::SmartPointer<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::OS::StrDup(str) : str);
+}
+
+
+Shell::CounterMap Shell::counter_map_;
+Persistent<Context> Shell::utility_context_;
+Persistent<Context> Shell::evaluation_context_;
+
+
+// Executes a string within the current v8 context.
+bool Shell::ExecuteString(Handle<String> source,
+                          Handle<Value> name,
+                          bool print_result,
+                          bool report_exceptions) {
+  HandleScope handle_scope;
+  TryCatch try_catch;
+  Handle<Script> script = Script::Compile(source, name);
+  if (script.IsEmpty()) {
+    // Print errors that happened during compilation.
+    if (report_exceptions)
+      ReportException(&try_catch);
+    return false;
+  } else {
+    Handle<Value> result = script->Run();
+    if (result.IsEmpty()) {
+      // Print errors that happened during execution.
+      if (report_exceptions)
+        ReportException(&try_catch);
+      return false;
+    } else {
+      if (print_result && !result->IsUndefined()) {
+        // If all went well and the result wasn't undefined then print
+        // the returned value.
+        String::Utf8Value str(result);
+        printf("%s\n", *str);
+      }
+      return true;
+    }
+  }
+}
+
+
+Handle<Value> Shell::Print(const Arguments& args) {
+  bool first = true;
+  for (int i = 0; i < args.Length(); i++) {
+    HandleScope handle_scope;
+    if (first) {
+      first = false;
+    } else {
+      printf(" ");
+    }
+    String::Utf8Value str(args[i]);
+    printf("%s", *str);
+  }
+  printf("\n");
+  return Undefined();
+}
+
+
+Handle<Value> Shell::Load(const Arguments& args) {
+  for (int i = 0; i < args.Length(); i++) {
+    HandleScope handle_scope;
+    String::Utf8Value file(args[i]);
+    Handle<String> source = ReadFile(*file);
+    if (source.IsEmpty()) {
+      return ThrowException(String::New("Error loading file"));
+    }
+    if (!ExecuteString(source, String::New(*file), false, false)) {
+      return ThrowException(String::New("Error executing  file"));
+    }
+  }
+  return Undefined();
+}
+
+
+Handle<Value> Shell::Quit(const Arguments& args) {
+  int exit_code = args[0]->Int32Value();
+  OnExit();
+  exit(exit_code);
+  return Undefined();
+}
+
+
+Handle<Value> Shell::Version(const Arguments& args) {
+  return String::New(V8::GetVersion());
+}
+
+
+void Shell::ReportException(v8::TryCatch* try_catch) {
+  HandleScope handle_scope;
+  String::Utf8Value exception(try_catch->Exception());
+  Handle<Message> message = try_catch->Message();
+  if (message.IsEmpty()) {
+    // V8 didn't provide any extra information about this error; just
+    // print the exception.
+    printf("%s\n", *exception);
+  } else {
+    // Print (filename):(line number): (message).
+    String::Utf8Value filename(message->GetScriptResourceName());
+    int linenum = message->GetLineNumber();
+    printf("%s:%i: %s\n", *filename, linenum, *exception);
+    // Print line of source code.
+    String::Utf8Value sourceline(message->GetSourceLine());
+    printf("%s\n", *sourceline);
+    // Print wavy underline (GetUnderline is deprecated).
+    int start = message->GetStartColumn();
+    for (int i = 0; i < start; i++) {
+      printf(" ");
+    }
+    int end = message->GetEndColumn();
+    for (int i = start; i < end; i++) {
+      printf("^");
+    }
+    printf("\n");
+  }
+}
+
+
+Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
+  HandleScope handle_scope;
+  Context::Scope context_scope(utility_context_);
+  Handle<Object> global = utility_context_->Global();
+  Handle<Value> fun = global->Get(String::New("GetCompletions"));
+  static const int kArgc = 3;
+  Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
+  Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
+  return handle_scope.Close(Handle<Array>::Cast(val));
+}
+
+
+int* Shell::LookupCounter(const wchar_t* name) {
+  CounterMap::iterator item = counter_map_.find(name);
+  if (item != counter_map_.end()) {
+    Counter* result = (*item).second;
+    return result->GetValuePtr();
+  }
+  Counter* result = new Counter(name);
+  counter_map_[name] = result;
+  return result->GetValuePtr();
+}
+
+
+void Shell::Initialize() {
+  // Set up counters
+  if (i::FLAG_dump_counters)
+    V8::SetCounterFunction(LookupCounter);
+  // Initialize the global objects
+  HandleScope scope;
+  Handle<ObjectTemplate> global_template = ObjectTemplate::New();
+  global_template->Set(String::New("print"), FunctionTemplate::New(Print));
+  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));
+
+  utility_context_ = Context::New(NULL, global_template);
+  utility_context_->SetSecurityToken(Undefined());
+  Context::Scope utility_scope(utility_context_);
+
+  // Install the debugger object in the utility scope
+  i::Debug::Load();
+  i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
+  i::JSObject* debug = i::Debug::debug_context()->global();
+  utility_context_->Global()->Set(String::New("$debug"),
+                                  Utils::ToLocal(&debug));
+
+  // Run the d8 shell utility script in the utility context
+  int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
+  i::Vector<const char> shell_source
+      = i::NativesCollection<i::D8>::GetScriptSource(source_index);
+  i::Vector<const char> shell_source_name
+      = i::NativesCollection<i::D8>::GetScriptName(source_index);
+  Handle<String> source = String::New(shell_source.start(),
+                                      shell_source.length());
+  Handle<String> name = String::New(shell_source_name.start(),
+                                    shell_source_name.length());
+  Script::Compile(source, name)->Run();
+
+  // Create the evaluation context
+  evaluation_context_ = Context::New(NULL, global_template);
+  evaluation_context_->SetSecurityToken(Undefined());
+}
+
+
+void Shell::OnExit() {
+  if (i::FLAG_dump_counters) {
+    ::printf("+----------------------------------------+----------+\n");
+    ::printf("| Name                                   | Value    |\n");
+    ::printf("+----------------------------------------+----------+\n");
+    for (CounterMap::iterator i = counter_map_.begin();
+         i != counter_map_.end();
+         i++) {
+      Counter* counter = (*i).second;
+      ::printf("| %-38ls | %8i |\n", counter->name(), counter->value());
+    }
+    ::printf("+----------------------------------------+----------+\n");
+  }
+}
+
+
+// Reads a file into a v8 string.
+Handle<String> Shell::ReadFile(const char* name) {
+  FILE* file = i::OS::FOpen(name, "rb");
+  if (file == NULL) return Handle<String>();
+
+  fseek(file, 0, SEEK_END);
+  int size = ftell(file);
+  rewind(file);
+
+  char* chars = new char[size + 1];
+  chars[size] = '\0';
+  for (int i = 0; i < size;) {
+    int read = fread(&chars[i], 1, size - i, file);
+    i += read;
+  }
+  fclose(file);
+  Handle<String> result = String::New(chars, size);
+  delete[] chars;
+  return result;
+}
+
+
+void Shell::RunShell() {
+  LineEditor* editor = LineEditor::Get();
+  printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
+  editor->Open();
+  while (true) {
+    HandleScope handle_scope;
+    i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
+    if (input.is_empty())
+      break;
+    editor->AddHistory(*input);
+    Handle<String> name = String::New("(d8)");
+    ExecuteString(String::New(*input), name, true, true);
+  }
+  editor->Close();
+  printf("\n");
+}
+
+
+int Shell::Main(int argc, char* argv[]) {
+  i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
+  Initialize();
+  bool run_shell = (argc == 1);
+  Context::Scope context_scope(evaluation_context_);
+  for (int i = 1; i < argc; i++) {
+    char* str = argv[i];
+    HandleScope handle_scope;
+    Handle<String> file_name = v8::String::New(str);
+    Handle<String> source = ReadFile(str);
+    if (source.IsEmpty()) {
+      printf("Error reading '%s'\n", str);
+      return 1;
+    }
+    if (!ExecuteString(source, file_name, false, true))
+      return 1;
+  }
+  if (run_shell)
+    RunShell();
+  OnExit();
+  return 0;
+}
+
+
+}  // namespace v8
+
+
+int main(int argc, char* argv[]) {
+  return v8::Shell::Main(argc, argv);
+}
diff --git a/regexp2000/src/d8.h b/regexp2000/src/d8.h
new file mode 100644 (file)
index 0000000..7e988c4
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_D8_H_
+#define V8_D8_H_
+
+
+// Disable exceptions on windows to not generate warnings from <map>.
+#define _HAS_EXCEPTIONS 0
+#include <map>
+
+#include "v8.h"
+
+
+namespace v8 {
+
+
+namespace i = v8::internal;
+
+
+class Counter {
+ public:
+  explicit Counter(const wchar_t* name)
+    : name_(name), value_(0) { }
+  int* GetValuePtr() { return &value_; }
+  const wchar_t* name() { return name_; }
+  int value() { return value_; }
+ private:
+  const wchar_t* name_;
+  int value_;
+};
+
+
+class Shell: public i::AllStatic {
+ public:
+  static bool ExecuteString(Handle<String> source,
+                            Handle<Value> name,
+                            bool print_result,
+                            bool report_exceptions);
+  static void ReportException(TryCatch* try_catch);
+  static void Initialize();
+  static void OnExit();
+  static int* LookupCounter(const wchar_t* name);
+  static Handle<String> ReadFile(const char* name);
+  static void RunShell();
+  static int Main(int argc, char* argv[]);
+  static Handle<Array> GetCompletions(Handle<String> text,
+                                      Handle<String> full);
+
+  static Handle<Value> Print(const Arguments& args);
+  static Handle<Value> Quit(const Arguments& args);
+  static Handle<Value> Version(const Arguments& args);
+  static Handle<Value> Load(const Arguments& args);
+
+  static const char* kHistoryFileName;
+  static const char* kPrompt;
+ private:
+  static Persistent<Context> utility_context_;
+  static Persistent<Context> evaluation_context_;
+  typedef std::map<const wchar_t*, Counter*> CounterMap;
+  static CounterMap counter_map_;
+};
+
+
+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_;
+};
+
+
+}  // namespace v8
+
+
+#endif  // V8_D8_H_
diff --git a/regexp2000/src/d8.js b/regexp2000/src/d8.js
new file mode 100644 (file)
index 0000000..cf8b60c
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// How crappy is it that I have to implement completely basic stuff
+// like this myself?  Answer: very.
+String.prototype.startsWith = function (str) {
+  if (str.length > this.length)
+    return false;
+  return this.substr(0, str.length) == str;
+};
+
+function ToInspectableObject(obj) {
+  if (!obj && typeof obj === 'object') {
+    return void 0;
+  } else {
+    return Object(obj);
+  }
+}
+
+function GetCompletions(global, last, full) {
+  var full_tokens = full.split();
+  full = full_tokens.pop();
+  var parts = full.split('.');
+  parts.pop();
+  var current = global;
+  for (var i = 0; i < parts.length; i++) {
+    var part = parts[i];
+    var next = current[part];
+    if (!next)
+      return [];
+    current = next;
+  }
+  var result = [];
+  current = ToInspectableObject(current);
+  while (typeof current !== 'undefined') {
+    var mirror = new $debug.ObjectMirror(current);
+    var properties = mirror.properties();
+    for (var i = 0; i < properties.length; i++) {
+      var name = properties[i].name();
+      if (typeof name === 'string' && name.startsWith(last))
+        result.push(name);
+    }
+    current = ToInspectableObject(current.__proto__);
+  }
+  return result;
+}
diff --git a/regexp2000/src/date-delay.js b/regexp2000/src/date-delay.js
new file mode 100644 (file)
index 0000000..da7aebd
--- /dev/null
@@ -0,0 +1,1020 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// This file relies on the fact that the following declarations have been made
+// in v8natives.js:
+// const $isNaN = GlobalIsNaN;
+// const $isFinite = GlobalIsFinite;
+
+// -------------------------------------------------------------------
+
+// This file contains date support implemented in JavaScript.
+
+
+// Keep reference to original values of some global properties.  This
+// has the added benefit that the code in this file is isolated from
+// changes to these properties.
+const $Date = global.Date;
+
+// ECMA 262 - 15.9.1.2
+function Day(time) {
+  return FLOOR(time/msPerDay);
+}
+
+
+// ECMA 262 - 5.2
+function Modulo(value, remainder) {
+  var mod = value % remainder;
+  return mod >= 0 ? mod : mod + remainder;
+}
+
+
+function TimeWithinDay(time) {
+  return Modulo(time, msPerDay);
+}
+
+
+// ECMA 262 - 15.9.1.3
+function DaysInYear(year) {
+  if (year % 4 != 0) return 365;
+  if ((year % 100 == 0) && (year % 400 != 0)) return 365;
+  return 366;
+}
+
+
+function DayFromYear(year) {
+  return 365 * (year-1970)
+      + FLOOR((year-1969)/4)
+      - FLOOR((year-1901)/100)
+      + FLOOR((year-1601)/400);
+}
+
+
+function TimeFromYear(year) {
+  return msPerDay * DayFromYear(year);
+}
+
+
+function YearFromTime(time) {
+  return FromJulianDay(Day(time) + kDayZeroInJulianDay).year;
+}
+
+
+function InLeapYear(time) {
+  return DaysInYear(YearFromTime(time)) == 366 ? 1 : 0;
+}
+
+
+// ECMA 262 - 15.9.1.4
+function MonthFromTime(time) {
+  return FromJulianDay(Day(time) + kDayZeroInJulianDay).month;
+}
+
+
+function DayWithinYear(time) {
+  return Day(time) - DayFromYear(YearFromTime(time));
+}
+
+
+// ECMA 262 - 15.9.1.5
+function DateFromTime(time) {
+  return FromJulianDay(Day(time) + kDayZeroInJulianDay).date;
+}
+
+
+// ECMA 262 - 15.9.1.9
+function EquivalentYear(year) {
+  // Returns an equivalent year in the range [1956-2000] matching
+  // - leap year.
+  // - week day of first day.
+  var time = TimeFromYear(year);
+  return (InLeapYear(time) == 0 ? 1967 : 1956) + (WeekDay(time) * 12) % 28;
+}
+
+
+function EquivalentTime(t) {
+  // The issue here is that some library calls don't work right for dates
+  // that cannot be represented using a signed 32 bit integer (measured in
+  // whole seconds based on the 1970 epoch).
+  // We solve this by mapping the time to a year with same leap-year-ness
+  // and same starting day for the year.
+  // As an optimization we avoid finding an equivalent year in the common
+  // case.  We are measuring in ms here so the 32 bit signed integer range
+  // is +-(1<<30)*1000 ie approximately +-2.1e20.
+  if (t >= -2.1e12 && t <= 2.1e12) return t;
+  var day = MakeDay(EquivalentYear(YearFromTime(t)), MonthFromTime(t), DateFromTime(t));
+  return TimeClip(MakeDate(day, TimeWithinDay(t)));
+}
+
+var daylight_cache_time = $NaN;
+var daylight_cache_offset;
+
+function DaylightSavingsOffset(t) {
+  if (t == daylight_cache_time) {
+    return daylight_cache_offset;
+  }
+  var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
+  daylight_cache_time = t;
+  daylight_cache_offset = offset;
+  return offset;
+}
+
+
+var timezone_cache_time = $NaN;
+var timezone_cache_timezone;
+
+function LocalTimezone(t) {
+  if(t == timezone_cache_time) {
+    return timezone_cache_timezone;
+  }
+  var timezone = %DateLocalTimezone(EquivalentTime(t));
+  timezone_cache_time = t;
+  timezone_cache_timezone = timezone;
+  return timezone;
+}
+
+
+function WeekDay(time) {
+  return Modulo(Day(time) + 4, 7);
+}
+
+var local_time_offset = %DateLocalTimeOffset();
+
+function LocalTime(time) {
+  if ($isNaN(time)) return time;
+  return time + local_time_offset + DaylightSavingsOffset(time);
+}
+
+function LocalTimeNoCheck(time) {
+  return time + local_time_offset + DaylightSavingsOffset(time);
+}
+
+
+function UTC(time) {
+  if ($isNaN(time)) return time;
+  var tmp = time - local_time_offset;
+  return tmp - DaylightSavingsOffset(tmp);
+}
+
+
+// ECMA 262 - 15.9.1.10
+function HourFromTime(time) {
+  return Modulo(FLOOR(time / msPerHour), HoursPerDay);
+}
+
+
+function MinFromTime(time) {
+  return Modulo(FLOOR(time / msPerMinute), MinutesPerHour);
+}
+
+
+function SecFromTime(time) {
+  return Modulo(FLOOR(time / msPerSecond), SecondsPerMinute);
+}
+
+
+function msFromTime(time) {
+  return Modulo(time, msPerSecond);
+}
+
+
+// ECMA 262 - 15.9.1.11
+function MakeTime(hour, min, sec, ms) {
+  if (!$isFinite(hour)) return $NaN;
+  if (!$isFinite(min)) return $NaN;
+  if (!$isFinite(sec)) return $NaN;
+  if (!$isFinite(ms)) return $NaN;
+  return TO_INTEGER(hour) * msPerHour
+      + TO_INTEGER(min) * msPerMinute
+      + TO_INTEGER(sec) * msPerSecond
+      + TO_INTEGER(ms);
+}
+
+
+// ECMA 262 - 15.9.1.12
+function TimeInYear(year) {
+  return DaysInYear(year) * msPerDay;
+}
+
+
+// Compute modified Julian day from year, month, date.
+// The missing days in 1582 are ignored for JavaScript compatibility.
+function ToJulianDay(year, month, date) {
+  var jy = (month > 1) ? year : year - 1;
+  var jm = (month > 1) ? month + 2 : month + 14;
+  var ja = FLOOR(0.01*jy);
+  return FLOOR(FLOOR(365.25*jy) + FLOOR(30.6001*jm) + date + 1720995) + 2 - ja + FLOOR(0.25*ja);
+}
+
+var four_year_cycle_table = CalculateDateTable();
+
+
+function CalculateDateTable() {
+  var month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+  var four_year_cycle_table = new $Array(1461);
+
+  var cumulative = 0;
+  var position = 0;
+  var leap_position = 0;
+  for (var month = 0; month < 12; month++) {
+    var length = month_lengths[month];
+    for (var day = 1; day <= length; day++) {
+      four_year_cycle_table[leap_position] =
+        (month << kMonthShift) + day;
+      four_year_cycle_table[366 + position] =
+        (1 << kYearShift) + (month << kMonthShift) + day;
+      four_year_cycle_table[731 + position] =
+        (2 << kYearShift) + (month << kMonthShift) + day;
+      four_year_cycle_table[1096 + position] =
+        (3 << kYearShift) + (month << kMonthShift) + day;
+      leap_position++;
+      position++;
+    }
+    if (month == 1) {
+      four_year_cycle_table[leap_position++] =
+        (month << kMonthShift) + 29;
+    }
+  }
+  return four_year_cycle_table;
+}
+
+
+// Constructor for creating objects holding year, month, and date.
+// Introduced to ensure the two return points in FromJulianDay match same map.
+function DayTriplet(year, month, date) {
+  this.year = year;
+  this.month = month;
+  this.date = date;
+}
+
+
+// Compute year, month, and day from modified Julian day.
+// The missing days in 1582 are ignored for JavaScript compatibility.
+function FromJulianDay(julian) {
+  // Avoid floating point and non-Smi maths in common case.  This is also a period of
+  // time where leap years are very regular.  The range is not too large to avoid overflow
+  // when doing the multiply-to-divide trick.
+  if (julian > kDayZeroInJulianDay &&
+      (julian - kDayZeroInJulianDay) < 40177) { // 1970 - 2080
+    var jsimple = (julian - kDayZeroInJulianDay) + 731; // Day 0 is 1st January 1968
+    var y = 1968;
+    // Divide by 1461 by multiplying with 22967 and shifting down by 25!
+    var after_1968 = (jsimple * 22967) >> 25;
+    y += after_1968 << 2;
+    jsimple -= 1461 * after_1968;
+    var four_year_cycle = four_year_cycle_table[jsimple];
+    return new DayTriplet(y + (four_year_cycle >> kYearShift),
+                           (four_year_cycle & kMonthMask) >> kMonthShift,
+                           four_year_cycle & kDayMask);
+  }
+  var jalpha = FLOOR((julian - 1867216.25) / 36524.25);
+  var jb = julian + 1 + jalpha - FLOOR(0.25 * jalpha) + 1524;
+  var jc = FLOOR(6680.0 + ((jb-2439870) - 122.1)/365.25);
+  var jd = FLOOR(365 * jc + (0.25 * jc));
+  var je = FLOOR((jb - jd)/30.6001);
+  var m = je - 1;
+  if (m > 12) m -= 13;
+  var y = jc - 4715;
+  if (m > 2) { --y; --m; }
+  var d = jb - jd - FLOOR(30.6001 * je);
+  return new DayTriplet(y, m, d);
+}
+
+
+// Compute number of days given a year, month, date.
+// Note that month and date can lie outside the normal range.
+//   For example:
+//     MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
+//     MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
+//     MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
+function MakeDay(year, month, date) {
+  if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN;
+
+  // Conversion to integers.
+  year = TO_INTEGER(year);
+  month = TO_INTEGER(month);
+  date = TO_INTEGER(date);
+
+  // Overflow months into year.
+  year = year + FLOOR(month/12);
+  month = month % 12;
+  if (month < 0) {
+    month += 12;
+  }
+
+  // Return days relative to Jan 1 1970.
+  return ToJulianDay(year, month, date) - kDayZeroInJulianDay;
+}
+
+
+// ECMA 262 - 15.9.1.13
+function MakeDate(day, time) {
+  if (!$isFinite(day)) return $NaN;
+  if (!$isFinite(time)) return $NaN;
+  return day * msPerDay + time;
+}
+
+
+// ECMA 262 - 15.9.1.14
+function TimeClip(time) {
+  if (!$isFinite(time)) return $NaN;
+  if ($abs(time) > 8.64E15) return $NaN;
+  return TO_INTEGER(time);
+}
+
+
+%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
+  if (%IsConstructCall()) {
+    // ECMA 262 - 15.9.3
+    var argc = %_ArgumentsLength();
+    if (argc == 0) {
+      %_SetValueOf(this, %DateCurrentTime());
+      return;
+    }
+    if (argc == 1) {
+      // According to ECMA 262, no hint should be given for this
+      // conversion.  However, ToPrimitive defaults to String Hint
+      // for Date objects which will lose precision when the Date
+      // constructor is called with another Date object as its
+      // argument.  We therefore use Number Hint for the conversion
+      // (which is the default for everything else than Date
+      // objects).  This makes us behave like KJS and SpiderMonkey.
+      var time = ToPrimitive(year, NUMBER_HINT);
+      if (IS_STRING(time)) {
+        %_SetValueOf(this, DateParse(time));
+      } else {
+        %_SetValueOf(this, TimeClip(ToNumber(time)));
+      }
+      return;
+    }
+    year = ToNumber(year);
+    month = ToNumber(month);
+    date = argc > 2 ? ToNumber(date) : 1;
+    hours = argc > 3 ? ToNumber(hours) : 0;
+    minutes = argc > 4 ? ToNumber(minutes) : 0;
+    seconds = argc > 5 ? ToNumber(seconds) : 0;
+    ms = argc > 6 ? ToNumber(ms) : 0;
+    year = (!$isNaN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
+        ? 1900 + TO_INTEGER(year) : year;
+    var day = MakeDay(year, month, date);
+    var time = MakeTime(hours, minutes, seconds, ms);
+    %_SetValueOf(this, TimeClip(UTC(MakeDate(day, time))));
+  } else {
+    // ECMA 262 - 15.9.2
+    return (new $Date()).toString();
+  }
+});
+
+
+// Helper functions.
+function GetTimeFrom(aDate) {
+  if (IS_DATE(aDate)) return %_ValueOf(aDate);
+  throw new $TypeError('this is not a Date object.');
+}
+
+
+function GetMillisecondsFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return msFromTime(LocalTimeNoCheck(t));
+}
+
+
+function GetUTCMillisecondsFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return msFromTime(t);
+}
+
+
+function GetSecondsFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return SecFromTime(LocalTimeNoCheck(t));
+}
+
+
+function GetUTCSecondsFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return SecFromTime(t);
+}
+
+
+function GetMinutesFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return MinFromTime(LocalTimeNoCheck(t));
+}
+
+
+function GetUTCMinutesFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return MinFromTime(t);
+}
+
+
+function GetHoursFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return HourFromTime(LocalTimeNoCheck(t));
+}
+
+
+function GetUTCHoursFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return HourFromTime(t);
+}
+
+
+function GetFullYearFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return YearFromTime(LocalTimeNoCheck(t));
+}
+
+
+function GetUTCFullYearFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return YearFromTime(t);
+}
+
+
+function GetMonthFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return MonthFromTime(LocalTimeNoCheck(t));
+}
+
+
+function GetUTCMonthFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return MonthFromTime(t);
+}
+
+
+function GetDateFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return DateFromTime(LocalTimeNoCheck(t));
+}
+
+
+function GetUTCDateFrom(aDate) {
+  var t = GetTimeFrom(aDate);
+  if ($isNaN(t)) return t;
+  return DateFromTime(t);
+}
+
+
+%FunctionSetPrototype($Date, new $Date($NaN));
+
+
+var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+
+
+function TwoDigitString(value) {
+  return value < 10 ? "0" + value : "" + value;
+}
+
+
+function DateString(time) {
+  var YMD = FromJulianDay(Day(time) + kDayZeroInJulianDay);
+  return WeekDays[WeekDay(time)] + ' '
+      + Months[YMD.month] + ' '
+      + TwoDigitString(YMD.date) + ' '
+      + YMD.year;
+}
+
+
+function TimeString(time) {
+  return TwoDigitString(HourFromTime(time)) + ':'
+      + TwoDigitString(MinFromTime(time)) + ':'
+      + TwoDigitString(SecFromTime(time));
+}
+
+
+function LocalTimezoneString(time) {
+  var timezoneOffset = (local_time_offset + DaylightSavingsOffset(time)) / msPerMinute;
+  var sign = (timezoneOffset >= 0) ? 1 : -1;
+  var hours = FLOOR((sign * timezoneOffset)/60);
+  var min   = FLOOR((sign * timezoneOffset)%60);
+  var gmt = ' GMT' + ((sign == 1) ? '+' : '-') + TwoDigitString(hours) + TwoDigitString(min);
+  return gmt + ' (' +  LocalTimezone(time) + ')';
+}
+
+
+function DatePrintString(time) {
+  return DateString(time) + ' ' + TimeString(time);
+}
+
+// -------------------------------------------------------------------
+
+
+// ECMA 262 - 15.9.4.2
+function DateParse(string) {
+  var arr = %DateParseString(ToString(string));
+  if (IS_NULL(arr)) return $NaN;
+
+  var day = MakeDay(arr[0], arr[1], arr[2]);
+  var time = MakeTime(arr[3], arr[4], arr[5], 0);
+  var date = MakeDate(day, time);
+
+  if (IS_NULL(arr[6])) {
+    return TimeClip(UTC(date));
+  } else {
+    return TimeClip(date - arr[6] * 1000);
+  }
+}
+
+
+// ECMA 262 - 15.9.4.3
+function DateUTC(year, month, date, hours, minutes, seconds, ms) {
+  year = ToNumber(year);
+  month = ToNumber(month);
+  var argc = %_ArgumentsLength();
+  date = argc > 2 ? ToNumber(date) : 1;
+  hours = argc > 3 ? ToNumber(hours) : 0;
+  minutes = argc > 4 ? ToNumber(minutes) : 0;
+  seconds = argc > 5 ? ToNumber(seconds) : 0;
+  ms = argc > 6 ? ToNumber(ms) : 0;
+  year = (!$isNaN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
+      ? 1900 + TO_INTEGER(year) : year;
+  var day = MakeDay(year, month, date);
+  var time = MakeTime(hours, minutes, seconds, ms);
+  return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
+}
+
+
+// Mozilla-specific extension. Returns the number of milliseconds
+// elapsed since 1 January 1970 00:00:00 UTC.
+function DateNow() {
+  return %DateCurrentTime();
+}
+
+
+// ECMA 262 - 15.9.5.2
+function DateToString() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return kInvalidDate;
+  return DatePrintString(LocalTimeNoCheck(t)) + LocalTimezoneString(t);
+}
+
+
+// ECMA 262 - 15.9.5.3
+function DateToDateString() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return kInvalidDate;
+  return DateString(LocalTimeNoCheck(t));
+}
+
+
+// ECMA 262 - 15.9.5.4
+function DateToTimeString() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return kInvalidDate;
+  var lt = LocalTimeNoCheck(t);
+  return TimeString(lt) + LocalTimezoneString(lt);
+}
+
+
+// ECMA 262 - 15.9.5.5
+function DateToLocaleString() {
+  return DateToString.call(this);
+}
+
+
+// ECMA 262 - 15.9.5.6
+function DateToLocaleDateString() {
+  return DateToDateString.call(this);
+}
+
+
+// ECMA 262 - 15.9.5.7
+function DateToLocaleTimeString() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return kInvalidDate;
+  var lt = LocalTimeNoCheck(t);
+  return TimeString(lt);
+}
+
+
+// ECMA 262 - 15.9.5.8
+function DateValueOf() {
+  return GetTimeFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.9
+function DateGetTime() {
+  return GetTimeFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.10
+function DateGetFullYear() {
+  return GetFullYearFrom(this)
+}
+
+
+// ECMA 262 - 15.9.5.11
+function DateGetUTCFullYear() {
+  return GetUTCFullYearFrom(this)
+}
+
+
+// ECMA 262 - 15.9.5.12
+function DateGetMonth() {
+  return GetMonthFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.13
+function DateGetUTCMonth() {
+  return GetUTCMonthFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.14
+function DateGetDate() {
+  return GetDateFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.15
+function DateGetUTCDate() {
+  return GetUTCDateFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.16
+function DateGetDay() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return t;
+  return WeekDay(LocalTimeNoCheck(t));
+}
+
+
+// ECMA 262 - 15.9.5.17
+function DateGetUTCDay() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return t;
+  return WeekDay(t);
+}
+
+
+// ECMA 262 - 15.9.5.18
+function DateGetHours() {
+  return GetHoursFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.19
+function DateGetUTCHours() {
+  return GetUTCHoursFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.20
+function DateGetMinutes() {
+  return GetMinutesFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.21
+function DateGetUTCMinutes() {
+  return GetUTCMinutesFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.22
+function DateGetSeconds() {
+  return GetSecondsFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.23
+function DateGetUTCSeconds() {
+  return GetUTCSecondsFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.24
+function DateGetMilliseconds() {
+  return GetMillisecondsFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.25
+function DateGetUTCMilliseconds() {
+  return GetUTCMillisecondsFrom(this);
+}
+
+
+// ECMA 262 - 15.9.5.26
+function DateGetTimezoneOffset() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return t;
+  return (t - LocalTimeNoCheck(t)) / msPerMinute;
+}
+
+
+// ECMA 262 - 15.9.5.27
+function DateSetTime(ms) {
+  if (!IS_DATE(this)) throw new $TypeError('this is not a Date object.');
+  return %_SetValueOf(this, TimeClip(ToNumber(ms)));
+}
+
+
+// ECMA 262 - 15.9.5.28
+function DateSetMilliseconds(ms) {
+  var t = LocalTime(GetTimeFrom(this));
+  ms = ToNumber(ms);
+  var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms);
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(Day(t), time))));
+}
+
+
+// ECMA 262 - 15.9.5.29
+function DateSetUTCMilliseconds(ms) {
+  var t = GetTimeFrom(this);
+  ms = ToNumber(ms);
+  var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms);
+  return %_SetValueOf(this, TimeClip(MakeDate(Day(t), time)));
+}
+
+
+// ECMA 262 - 15.9.5.30
+function DateSetSeconds(sec, ms) {
+  var t = LocalTime(GetTimeFrom(this));
+  sec = ToNumber(sec);
+  ms = %_ArgumentsLength() < 2 ? GetMillisecondsFrom(this) : ToNumber(ms);
+  var time = MakeTime(HourFromTime(t), MinFromTime(t), sec, ms);
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(Day(t), time))));
+}
+
+
+// ECMA 262 - 15.9.5.31
+function DateSetUTCSeconds(sec, ms) {
+  var t = GetTimeFrom(this);
+  sec = ToNumber(sec);
+  ms = %_ArgumentsLength() < 2 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+  var time = MakeTime(HourFromTime(t), MinFromTime(t), sec, ms);
+  return %_SetValueOf(this, TimeClip(MakeDate(Day(t), time)));
+}
+
+
+// ECMA 262 - 15.9.5.33
+function DateSetMinutes(min, sec, ms) {
+  var t = LocalTime(GetTimeFrom(this));
+  min = ToNumber(min);
+  var argc = %_ArgumentsLength();
+  sec = argc < 2 ? GetSecondsFrom(this) : ToNumber(sec);
+  ms = argc < 3 ? GetMillisecondsFrom(this) : ToNumber(ms);
+  var time = MakeTime(HourFromTime(t), min, sec, ms);
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(Day(t), time))));
+}
+
+
+// ECMA 262 - 15.9.5.34
+function DateSetUTCMinutes(min, sec, ms) {
+  var t = GetTimeFrom(this);
+  min = ToNumber(min);
+  var argc = %_ArgumentsLength();
+  sec = argc < 2 ? GetUTCSecondsFrom(this) : ToNumber(sec);
+  ms = argc < 3 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+  var time = MakeTime(HourFromTime(t), min, sec, ms);
+  return %_SetValueOf(this, TimeClip(MakeDate(Day(t), time)));
+}
+
+
+// ECMA 262 - 15.9.5.35
+function DateSetHours(hour, min, sec, ms) {
+  var t = LocalTime(GetTimeFrom(this));
+  hour = ToNumber(hour);
+  var argc = %_ArgumentsLength();
+  min = argc < 2 ? GetMinutesFrom(this) : ToNumber(min);
+  sec = argc < 3 ? GetSecondsFrom(this) : ToNumber(sec);
+  ms = argc < 4 ? GetMillisecondsFrom(this) : ToNumber(ms);
+  var time = MakeTime(hour, min, sec, ms);
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(Day(t), time))));
+}
+
+
+// ECMA 262 - 15.9.5.34
+function DateSetUTCHours(hour, min, sec, ms) {
+  var t = GetTimeFrom(this);
+  hour = ToNumber(hour);
+  var argc = %_ArgumentsLength();
+  min = argc < 2 ? GetUTCMinutesFrom(this) : ToNumber(min);
+  sec = argc < 3 ? GetUTCSecondsFrom(this) : ToNumber(sec);
+  ms = argc < 4 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+  var time = MakeTime(hour, min, sec, ms);
+  return %_SetValueOf(this, TimeClip(MakeDate(Day(t), time)));
+}
+
+
+// ECMA 262 - 15.9.5.36
+function DateSetDate(date) {
+  var t = LocalTime(GetTimeFrom(this));
+  date = ToNumber(date);
+  var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
+}
+
+
+// ECMA 262 - 15.9.5.37
+function DateSetUTCDate(date) {
+  var t = GetTimeFrom(this);
+  date = ToNumber(date);
+  var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
+  return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
+}
+
+
+// ECMA 262 - 15.9.5.38
+function DateSetMonth(month, date) {
+  var t = LocalTime(GetTimeFrom(this));
+  month = ToNumber(month);
+  date = %_ArgumentsLength() < 2 ? GetDateFrom(this) : ToNumber(date);
+  var day = MakeDay(YearFromTime(t), month, date);
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
+}
+
+
+// ECMA 262 - 15.9.5.39
+function DateSetUTCMonth(month, date) {
+  var t = GetTimeFrom(this);
+  month = ToNumber(month);
+  date = %_ArgumentsLength() < 2 ? GetUTCDateFrom(this) : ToNumber(date);
+  var day = MakeDay(YearFromTime(t), month, date);
+  return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
+}
+
+
+// ECMA 262 - 15.9.5.40
+function DateSetFullYear(year, month, date) {
+  var t = GetTimeFrom(this);
+  t = $isNaN(t) ? 0 : LocalTimeNoCheck(t);
+  year = ToNumber(year);
+  var argc = %_ArgumentsLength();
+  month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
+  date = argc < 3 ? DateFromTime(t) : ToNumber(date);
+  var day = MakeDay(year, month, date);
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
+}
+
+
+// ECMA 262 - 15.9.5.41
+function DateSetUTCFullYear(year, month, date) {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) t = 0;
+  var argc = %_ArgumentsLength();
+  year = ToNumber(year);
+  month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
+  date = argc < 3 ? DateFromTime(t) : ToNumber(date);
+  var day = MakeDay(year, month, date);
+  return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
+}
+
+
+// ECMA 262 - 15.9.5.42
+function DateToUTCString() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return kInvalidDate;
+  // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
+  return WeekDays[WeekDay(t)] + ', '
+      + TwoDigitString(DateFromTime(t)) + ' '
+      + Months[MonthFromTime(t)] + ' '
+      + YearFromTime(t) + ' '
+      + TimeString(t) + ' GMT';
+}
+
+
+// ECMA 262 - B.2.4
+function DateGetYear() {
+  var t = GetTimeFrom(this);
+  if ($isNaN(t)) return $NaN;
+  return YearFromTime(LocalTimeNoCheck(t)) - 1900;
+}
+
+
+// ECMA 262 - B.2.5
+function DateSetYear(year) {
+  var t = LocalTime(GetTimeFrom(this));
+  if ($isNaN(t)) t = 0;
+  year = ToNumber(year);
+  if ($isNaN(year)) return %_SetValueOf(this, $NaN);
+  year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
+      ? 1900 + TO_INTEGER(year) : year;
+  var day = MakeDay(year, GetMonthFrom(this), GetDateFrom(this));
+  return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
+}
+
+
+// ECMA 262 - B.2.6
+//
+// Notice that this does not follow ECMA 262 completely.  ECMA 262
+// says that toGMTString should be the same Function object as
+// toUTCString.  JSC does not do this, so for compatibility we do not
+// do that either.  Instead, we create a new function whose name
+// property will return toGMTString.
+function DateToGMTString() {
+  return DateToUTCString.call(this);
+}
+
+
+// -------------------------------------------------------------------
+
+function SetupDate() {
+  // Setup 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.
+  %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
+
+  // Setup non-enumerable functions of the Date prototype object and
+  // set their names.
+  InstallFunctions($Date.prototype, DONT_ENUM, $Array(
+    "toString", DateToString,
+    "toDateString", DateToDateString,
+    "toTimeString", DateToTimeString,
+    "toLocaleString", DateToLocaleString,
+    "toLocaleDateString", DateToLocaleDateString,
+    "toLocaleTimeString", DateToLocaleTimeString,
+    "valueOf", DateValueOf,
+    "getTime", DateGetTime,
+    "getFullYear", DateGetFullYear,
+    "getUTCFullYear", DateGetUTCFullYear,
+    "getMonth", DateGetMonth,
+    "getUTCMonth", DateGetUTCMonth,
+    "getDate", DateGetDate,
+    "getUTCDate", DateGetUTCDate,
+    "getDay", DateGetDay,
+    "getUTCDay", DateGetUTCDay,
+    "getHours", DateGetHours,
+    "getUTCHours", DateGetUTCHours,
+    "getMinutes", DateGetMinutes,
+    "getUTCMinutes", DateGetUTCMinutes,
+    "getSeconds", DateGetSeconds,
+    "getUTCSeconds", DateGetUTCSeconds,
+    "getMilliseconds", DateGetMilliseconds,
+    "getUTCMilliseconds", DateGetUTCMilliseconds,
+    "getTimezoneOffset", DateGetTimezoneOffset,
+    "setTime", DateSetTime,
+    "setMilliseconds", DateSetMilliseconds,
+    "setUTCMilliseconds", DateSetUTCMilliseconds,
+    "setSeconds", DateSetSeconds,
+    "setUTCSeconds", DateSetUTCSeconds,
+    "setMinutes", DateSetMinutes,
+    "setUTCMinutes", DateSetUTCMinutes,
+    "setHours", DateSetHours,
+    "setUTCHours", DateSetUTCHours,
+    "setDate", DateSetDate,
+    "setUTCDate", DateSetUTCDate,
+    "setMonth", DateSetMonth,
+    "setUTCMonth", DateSetUTCMonth,
+    "setFullYear", DateSetFullYear,
+    "setUTCFullYear", DateSetUTCFullYear,
+    "toGMTString", DateToGMTString,
+    "toUTCString", DateToUTCString,
+    "getYear", DateGetYear,
+    "setYear", DateSetYear
+  ));
+}
+
+SetupDate();
diff --git a/regexp2000/src/dateparser.cc b/regexp2000/src/dateparser.cc
new file mode 100644 (file)
index 0000000..4b64785
--- /dev/null
@@ -0,0 +1,265 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "dateparser.h"
+
+namespace v8 { namespace internal {
+
+
+bool DateParser::Parse(String* str, FixedArray* out) {
+  ASSERT(out->length() == OUTPUT_SIZE);
+
+  InputReader in(str);
+  TimeZoneComposer tz;
+  TimeComposer time;
+  DayComposer day;
+
+  while (!in.IsEnd()) {
+    if (in.IsAsciiDigit()) {
+      // Parse a number (possibly with 1 or 2 trailing colons).
+      int n = in.ReadUnsignedNumber();
+      if (in.Skip(':')) {
+        if (in.Skip(':')) {
+          // n + "::"
+          if (!time.IsEmpty()) return false;
+          time.Add(n);
+          time.Add(0);
+        } else {
+          // n + ":"
+          if (!time.Add(n)) return false;
+        }
+      } else if (tz.IsExpecting(n)) {
+        tz.SetAbsoluteMinute(n);
+      } else if (time.IsExpecting(n)) {
+        time.AddFinal(n);
+        // Require end or white space immediately after finalizing time.
+        if (!in.IsEnd() && !in.SkipWhiteSpace()) return false;
+      } else {
+        if (!day.Add(n)) return false;
+        in.Skip('-');  // Ignore suffix '-' for year, month, or day.
+      }
+    } else if (in.IsAsciiAlphaOrAbove()) {
+      // Parse a "word" (sequence of chars. >= 'A').
+      uint32_t pre[KeywordTable::kPrefixLength];
+      int len = in.ReadWord(pre, KeywordTable::kPrefixLength);
+      int index = KeywordTable::Lookup(pre, len);
+      KeywordType type = KeywordTable::GetType(index);
+
+      if (type == AM_PM && !time.IsEmpty()) {
+        time.SetHourOffset(KeywordTable::GetValue(index));
+      } else if (type == MONTH_NAME) {
+        day.SetNamedMonth(KeywordTable::GetValue(index));
+        in.Skip('-');  // Ignore suffix '-' for month names
+      } else if (type == TIME_ZONE_NAME && in.HasReadNumber()) {
+        tz.Set(KeywordTable::GetValue(index));
+      } else {
+        // Garbage words are illegal if no number read yet.
+        if (in.HasReadNumber()) return false;
+      }
+    } else if (in.IsAsciiSign() && (tz.IsUTC() || !time.IsEmpty())) {
+      // Parse UTC offset (only after UTC or time).
+      tz.SetSign(in.GetAsciiSignValue());
+      in.Next();
+      int n = in.ReadUnsignedNumber();
+      if (in.Skip(':')) {
+        tz.SetAbsoluteHour(n);
+        tz.SetAbsoluteMinute(kNone);
+      } else {
+        tz.SetAbsoluteHour(n / 100);
+        tz.SetAbsoluteMinute(n % 100);
+      }
+    } else if (in.Is('(')) {
+      // Ignore anything from '(' to a matching ')' or end of string.
+      in.SkipParentheses();
+    } else if ((in.IsAsciiSign() || in.Is(')')) && in.HasReadNumber()) {
+      // Extra sign or ')' is illegal if no number read yet.
+      return false;
+    } else {
+      // Ignore other characters.
+      in.Next();
+    }
+  }
+  return day.Write(out) && time.Write(out) && tz.Write(out);
+}
+
+
+bool DateParser::DayComposer::Write(FixedArray* output) {
+  int year = 0;  // Default year is 0 (=> 2000) for KJS compatibility.
+  int month = kNone;
+  int day = kNone;
+
+  if (named_month_ == kNone) {
+    if (index_ < 2) return false;
+    if (index_ == 3 && !IsDay(comp_[0])) {
+      // YMD
+      year = comp_[0];
+      month = comp_[1];
+      day = comp_[2];
+    } else {
+      // MD(Y)
+      month = comp_[0];
+      day = comp_[1];
+      if (index_ == 3) year = comp_[2];
+    }
+  } else {
+    month = named_month_;
+    if (index_ < 1) return false;
+    if (index_ == 1) {
+      // MD or DM
+      day = comp_[0];
+    } else if (!IsDay(comp_[0])) {
+      // YMD, MYD, or YDM
+      year = comp_[0];
+      day = comp_[1];
+    } else {
+      // DMY, MDY, or DYM
+      day = comp_[0];
+      year = comp_[1];
+    }
+  }
+
+  if (Between(year, 0, 49)) year += 2000;
+  else if (Between(year, 50, 99)) year += 1900;
+
+  if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
+
+  output->set(YEAR,
+              Smi::FromInt(year),
+              SKIP_WRITE_BARRIER);
+  output->set(MONTH,
+              Smi::FromInt(month - 1),
+              SKIP_WRITE_BARRIER);  // 0-based
+  output->set(DAY,
+              Smi::FromInt(day),
+              SKIP_WRITE_BARRIER);
+  return true;
+}
+
+
+bool DateParser::TimeComposer::Write(FixedArray* output) {
+  // All time slots default to 0
+  while (index_ < kSize) {
+    comp_[index_++] = 0;
+  }
+
+  int& hour = comp_[0];
+  int& minute = comp_[1];
+  int& second = comp_[2];
+
+  if (hour_offset_ != kNone) {
+    if (!IsHour12(hour)) return false;
+    hour %= 12;
+    hour += hour_offset_;
+  }
+
+  if (!IsHour(hour) || !IsMinute(minute) || !IsSecond(second)) return false;
+
+  output->set(HOUR,
+              Smi::FromInt(hour),
+              SKIP_WRITE_BARRIER);
+  output->set(MINUTE,
+              Smi::FromInt(minute),
+              SKIP_WRITE_BARRIER);
+  output->set(SECOND,
+              Smi::FromInt(second),
+              SKIP_WRITE_BARRIER);
+  return true;
+}
+
+
+bool DateParser::TimeZoneComposer::Write(FixedArray* output) {
+  if (sign_ != kNone) {
+    if (hour_ == kNone) hour_ = 0;
+    if (minute_ == kNone) minute_ = 0;
+    int total_seconds = sign_ * (hour_ * 3600 + minute_ * 60);
+    if (!Smi::IsValid(total_seconds)) return false;
+    output->set(UTC_OFFSET,
+                Smi::FromInt(total_seconds),
+                SKIP_WRITE_BARRIER);
+  } else {
+    output->set(UTC_OFFSET,
+                Heap::null_value(),
+                SKIP_WRITE_BARRIER);
+  }
+  return true;
+}
+
+
+const int8_t
+DateParser::KeywordTable::array[][DateParser::KeywordTable::kEntrySize] = {
+  {'j', 'a', 'n', DateParser::MONTH_NAME, 1},
+  {'f', 'e', 'b', DateParser::MONTH_NAME, 2},
+  {'m', 'a', 'r', DateParser::MONTH_NAME, 3},
+  {'a', 'p', 'r', DateParser::MONTH_NAME, 4},
+  {'m', 'a', 'y', DateParser::MONTH_NAME, 5},
+  {'j', 'u', 'n', DateParser::MONTH_NAME, 6},
+  {'j', 'u', 'l', DateParser::MONTH_NAME, 7},
+  {'a', 'u', 'g', DateParser::MONTH_NAME, 8},
+  {'s', 'e', 'p', DateParser::MONTH_NAME, 9},
+  {'o', 'c', 't', DateParser::MONTH_NAME, 10},
+  {'n', 'o', 'v', DateParser::MONTH_NAME, 11},
+  {'d', 'e', 'c', DateParser::MONTH_NAME, 12},
+  {'a', 'm', '\0', DateParser::AM_PM, 0},
+  {'p', 'm', '\0', DateParser::AM_PM, 12},
+  {'u', 't', '\0', DateParser::TIME_ZONE_NAME, 0},
+  {'u', 't', 'c', DateParser::TIME_ZONE_NAME, 0},
+  {'g', 'm', 't', DateParser::TIME_ZONE_NAME, 0},
+  {'c', 'd', 't', DateParser::TIME_ZONE_NAME, -5},
+  {'c', 's', 't', DateParser::TIME_ZONE_NAME, -6},
+  {'e', 'd', 't', DateParser::TIME_ZONE_NAME, -4},
+  {'e', 's', 't', DateParser::TIME_ZONE_NAME, -5},
+  {'m', 'd', 't', DateParser::TIME_ZONE_NAME, -6},
+  {'m', 's', 't', DateParser::TIME_ZONE_NAME, -7},
+  {'p', 'd', 't', DateParser::TIME_ZONE_NAME, -7},
+  {'p', 's', 't', DateParser::TIME_ZONE_NAME, -8},
+  {'\0', '\0', '\0', DateParser::INVALID, 0},
+};
+
+
+// We could use perfect hashing here, but this is not a bottleneck.
+int DateParser::KeywordTable::Lookup(const uint32_t* pre, int len) {
+  int i;
+  for (i = 0; array[i][kTypeOffset] != INVALID; i++) {
+    int j = 0;
+    while (j < kPrefixLength &&
+           pre[j] == static_cast<uint32_t>(array[i][j])) {
+      j++;
+    }
+    // Check if we have a match and the length is legal.
+    // Word longer than keyword is only allowed for month names.
+    if (j == kPrefixLength &&
+        (len <= kPrefixLength || array[i][kTypeOffset] == MONTH_NAME)) {
+      return i;
+    }
+  }
+  return i;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/dateparser.h b/regexp2000/src/dateparser.h
new file mode 100644 (file)
index 0000000..bf96852
--- /dev/null
@@ -0,0 +1,230 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_DATEPARSER_H_
+#define V8_DATEPARSER_H_
+
+#include "scanner.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
+  // [1]: month (0 = Jan, 1 = Feb, ...)
+  // [2]: day
+  // [3]: hour
+  // [4]: minute
+  // [5]: second
+  // [6]: UTC offset in seconds, or null value if no timezone specified
+  // If parsing fails, return false (content of output array is not defined).
+  static bool Parse(String* str, FixedArray* output);
+
+  enum {YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, UTC_OFFSET, OUTPUT_SIZE};
+
+ private:
+  // Range testing
+  static bool Between(int x, int lo, int hi) { return x >= lo && x <= hi; }
+  // Indicates a missing value.
+  static const int kNone = kMaxInt;
+
+  // InputReader provides basic string parsing and character classification.
+  class InputReader BASE_EMBEDDED {
+   public:
+    explicit InputReader(String* s) : buffer_(s), has_read_number_(false) {
+      Next();
+    }
+
+    // Advance to the next character of the string.
+    void Next() { ch_ = buffer_.has_more() ? buffer_.GetNext() : 0; }
+
+    // Read a string of digits as an unsigned number (cap just below kMaxInt).
+    int ReadUnsignedNumber() {
+      has_read_number_ = true;
+      int n;
+      for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) {
+        n = n * 10 + ch_ - '0';
+      }
+      return n;
+    }
+
+    // Read a word (sequence of chars. >= 'A'), fill the given buffer with a
+    // lower-case prefix, and pad any remainder of the buffer with zeroes.
+    // Return word length.
+    int ReadWord(uint32_t* prefix, int prefix_size) {
+      int len;
+      for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) {
+        if (len < prefix_size) prefix[len] = GetAsciiAlphaLower();
+      }
+      for (int i = len; i < prefix_size; i++) prefix[i] = 0;
+      return len;
+    }
+
+    // The skip methods return whether they actually skipped something.
+    bool Skip(uint32_t c) { return ch_ == c ?  (Next(), true) : false; }
+
+    bool SkipWhiteSpace() {
+      return Scanner::kIsWhiteSpace.get(ch_) ? (Next(), true) : false;
+    }
+
+    bool SkipParentheses() {
+      if (ch_ != '(') return false;
+      int balance = 0;
+      do {
+        if (ch_ == ')') --balance;
+        else if (ch_ == '(') ++balance;
+        Next();
+      } while (balance > 0 && ch_);
+      return true;
+    }
+
+    // Character testing/classification. Non-ASCII digits are not supported.
+    bool Is(uint32_t c) const { return ch_ == c; }
+    bool IsEnd() const { return ch_ == 0; }
+    bool IsAsciiDigit() const { return IsDecimalDigit(ch_); }
+    bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; }
+    bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; }
+
+    // Return 1 for '+' and -1 for '-'.
+    int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
+
+    // Indicates whether any (possibly empty!) numbers have been read.
+    bool HasReadNumber() const { return has_read_number_; }
+
+   private:
+    // If current character is in 'A'-'Z' or 'a'-'z', return its lower-case.
+    // Else, return something outside of 'A'-'Z' and 'a'-'z'.
+    uint32_t GetAsciiAlphaLower() const { return ch_ | 32; }
+
+    StringInputBuffer buffer_;
+    bool has_read_number_;
+    uint32_t ch_;
+  };
+
+  enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM };
+
+  // KeywordTable maps names of months, time zones, am/pm to numbers.
+  class KeywordTable : public AllStatic {
+   public:
+    // Look up a word in the keyword table and return an index.
+    // 'pre' contains a prefix of the word, zero-padded to size kPrefixLength
+    // and 'len' is the word length.
+    static int Lookup(const uint32_t* pre, int len);
+    // Get the type of the keyword at index i.
+    static KeywordType GetType(int i) {
+      return static_cast<KeywordType>(array[i][kTypeOffset]);
+    }
+    // Get the value of the keyword at index i.
+    static int GetValue(int i) { return array[i][kValueOffset]; }
+
+    static const int kPrefixLength = 3;
+    static const int kTypeOffset = kPrefixLength;
+    static const int kValueOffset = kTypeOffset + 1;
+    static const int kEntrySize = kValueOffset + 1;
+    static const int8_t array[][kEntrySize];
+  };
+
+  class TimeZoneComposer BASE_EMBEDDED {
+   public:
+    TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {}
+    void Set(int offset_in_hours) {
+      sign_ = offset_in_hours < 0 ? -1 : 1;
+      hour_ = offset_in_hours * sign_;
+      minute_ = 0;
+    }
+    void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; }
+    void SetAbsoluteHour(int hour) { hour_ = hour; }
+    void SetAbsoluteMinute(int minute) { minute_ = minute; }
+    bool IsExpecting(int n) const {
+      return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
+    }
+    bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
+    bool Write(FixedArray* output);
+   private:
+    int sign_;
+    int hour_;
+    int minute_;
+  };
+
+  class TimeComposer BASE_EMBEDDED {
+   public:
+    TimeComposer() : index_(0), hour_offset_(kNone) {}
+    bool IsEmpty() const { return index_ == 0; }
+    bool IsExpecting(int n) const {
+      return (index_ == 1 && IsMinute(n)) || (index_ == 2 && IsSecond(n));
+    }
+    bool Add(int n) {
+      return index_ < kSize ? (comp_[index_++] = n, true) : false;
+    }
+    bool AddFinal(int n) {
+      if (!Add(n)) return false;
+      while (index_ < kSize) comp_[index_++] = 0;
+      return true;
+    }
+    void SetHourOffset(int n) { hour_offset_ = n; }
+    bool Write(FixedArray* output);
+
+    static bool IsMinute(int x) { return Between(x, 0, 59); }
+   private:
+    static bool IsHour(int x) { return Between(x, 0, 23); }
+    static bool IsHour12(int x) { return Between(x, 0, 12); }
+    static bool IsSecond(int x) { return Between(x, 0, 59); }
+
+    static const int kSize = 3;
+    int comp_[kSize];
+    int index_;
+    int hour_offset_;
+  };
+
+  class DayComposer BASE_EMBEDDED {
+   public:
+    DayComposer() : index_(0), named_month_(kNone) {}
+    bool IsEmpty() const { return index_ == 0; }
+    bool Add(int n) {
+      return index_ < kSize ? (comp_[index_++] = n, true) : false;
+    }
+    void SetNamedMonth(int n) { named_month_ = n; }
+    bool Write(FixedArray* output);
+   private:
+    static bool IsMonth(int x) { return Between(x, 1, 12); }
+    static bool IsDay(int x) { return Between(x, 1, 31); }
+
+    static const int kSize = 3;
+    int comp_[kSize];
+    int index_;
+    int named_month_;
+  };
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_DATEPARSER_H_
diff --git a/regexp2000/src/debug-delay.js b/regexp2000/src/debug-delay.js
new file mode 100644 (file)
index 0000000..783e4b7
--- /dev/null
@@ -0,0 +1,2030 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Default number of frames to include in the response to backtrace request.
+const kDefaultBacktraceLength = 10;
+
+const Debug = {};
+
+// Regular expression to skip "crud" at the beginning of a source line which is
+// not really code. Currently the regular expression matches whitespace and
+// comments.
+const sourceLineBeginningSkip = /^(?:[ \v\h]*(?:\/\*.*?\*\/)*)*/;
+
+// Debug events which can occour in the V8 JavaScript engine. These originate
+// from the API include file debug.h.
+Debug.DebugEvent = { Break: 1,
+                     Exception: 2,
+                     NewFunction: 3,
+                     BeforeCompile: 4,
+                     AfterCompile: 5 };
+
+// Types of exceptions that can be broken upon.
+Debug.ExceptionBreak = { All : 0,
+                         Uncaught: 1 };
+
+// The different types of steps.
+Debug.StepAction = { StepOut: 0,
+                     StepNext: 1,
+                     StepIn: 2,
+                     StepMin: 3,
+                     StepInMin: 4 };
+
+// The different types of scripts matching enum ScriptType in objects.h.
+Debug.ScriptType = { Native: 0,
+                     Extension: 1,
+                     Normal: 2 };
+
+function ScriptTypeFlag(type) {
+  return (1 << type);
+}
+
+// Globals.
+var next_response_seq = 0;
+var next_break_point_number = 1;
+var break_points = [];
+var script_break_points = [];
+
+
+// Create a new break point object and add it to the list of break points.
+function MakeBreakPoint(source_position, opt_line, opt_column, opt_script_break_point) {
+  var break_point = new BreakPoint(source_position, opt_line, opt_column, opt_script_break_point);
+  break_points.push(break_point);
+  return break_point;
+}
+
+
+// Object representing a break point.
+// NOTE: This object does not have a reference to the function having break
+// point as this would cause function not to be garbage collected when it is
+// not used any more. We do not want break points to keep functions alive.
+function BreakPoint(source_position, opt_line, opt_column, opt_script_break_point) {
+  this.source_position_ = source_position;
+  this.source_line_ = opt_line;
+  this.source_column_ = opt_column;
+  if (opt_script_break_point) {
+    this.script_break_point_ = opt_script_break_point;
+  } else {
+    this.number_ = next_break_point_number++;
+  }
+  this.hit_count_ = 0;
+  this.active_ = true;
+  this.condition_ = null;
+  this.ignoreCount_ = 0;
+}
+
+
+BreakPoint.prototype.number = function() {
+  return this.number_;
+};
+
+
+BreakPoint.prototype.func = function() {
+  return this.func_;
+};
+
+
+BreakPoint.prototype.source_position = function() {
+  return this.source_position_;
+};
+
+
+BreakPoint.prototype.hit_count = function() {
+  return this.hit_count_;
+};
+
+
+BreakPoint.prototype.active = function() {
+  if (this.script_break_point()) {
+    return this.script_break_point().active();
+  }
+  return this.active_;
+};
+
+
+BreakPoint.prototype.condition = function() {
+  if (this.script_break_point() && this.script_break_point().condition()) {
+    return this.script_break_point().condition();
+  }
+  return this.condition_;
+};
+
+
+BreakPoint.prototype.ignoreCount = function() {
+  return this.ignoreCount_;
+};
+
+
+BreakPoint.prototype.script_break_point = function() {
+  return this.script_break_point_;
+};
+
+
+BreakPoint.prototype.enable = function() {
+  this.active_ = true;
+};
+
+
+BreakPoint.prototype.disable = function() {
+  this.active_ = false;
+};
+
+
+BreakPoint.prototype.setCondition = function(condition) {
+  this.condition_ = condition;
+};
+
+
+BreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
+  this.ignoreCount_ = ignoreCount;
+};
+
+
+BreakPoint.prototype.isTriggered = function(exec_state) {
+  // Break point not active - not triggered.
+  if (!this.active()) return false;
+
+  // Check for conditional break point.
+  if (this.condition()) {
+    // If break point has condition try to evaluate it in the top frame.
+    try {
+      var mirror = exec_state.frame(0).evaluate(this.condition());
+      // If no sensible mirror or non true value break point not triggered.
+      if (!(mirror instanceof ValueMirror) || !%ToBoolean(mirror.value_)) {
+        return false;
+      }
+    } catch (e) {
+      // Exception evaluating condition counts as not triggered.
+      return false;
+    }
+  }
+
+  // Update the hit count.
+  this.hit_count_++;
+  if (this.script_break_point_) {
+    this.script_break_point_.hit_count_++;
+  }
+
+  // If the break point has an ignore count it is not triggered.
+  if (this.ignoreCount_ > 0) {
+    this.ignoreCount_--;
+    return false;
+  }
+
+  // Break point triggered.
+  return true;
+};
+
+
+// Function called from the runtime when a break point is hit. Returns true if
+// the break point is triggered and supposed to break execution.
+function IsBreakPointTriggered(break_id, break_point) {
+  return break_point.isTriggered(MakeExecutionState(break_id));
+}
+
+
+// Object representing a script break point. The script is referenced by its
+// script name and the break point is represented as line and column.
+function ScriptBreakPoint(script_name, opt_line, opt_column) {
+  this.script_name_ = script_name;
+  this.line_ = opt_line || 0;
+  this.column_ = opt_column;
+  this.hit_count_ = 0;
+  this.active_ = true;
+  this.condition_ = null;
+  this.ignoreCount_ = 0;
+}
+
+
+ScriptBreakPoint.prototype.number = function() {
+  return this.number_;
+};
+
+
+ScriptBreakPoint.prototype.script_name = function() {
+  return this.script_name_;
+};
+
+
+ScriptBreakPoint.prototype.line = function() {
+  return this.line_;
+};
+
+
+ScriptBreakPoint.prototype.column = function() {
+  return this.column_;
+};
+
+
+ScriptBreakPoint.prototype.hit_count = function() {
+  return this.hit_count_;
+};
+
+
+ScriptBreakPoint.prototype.active = function() {
+  return this.active_;
+};
+
+
+ScriptBreakPoint.prototype.condition = function() {
+  return this.condition_;
+};
+
+
+ScriptBreakPoint.prototype.ignoreCount = function() {
+  return this.ignoreCount_;
+};
+
+
+ScriptBreakPoint.prototype.enable = function() {
+  this.active_ = true;
+};
+
+
+ScriptBreakPoint.prototype.disable = function() {
+  this.active_ = false;
+};
+
+
+ScriptBreakPoint.prototype.setCondition = function(condition) {
+  this.condition_ = condition;
+};
+
+
+ScriptBreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
+  this.ignoreCount_ = ignoreCount;
+
+  // Set ignore count on all break points created from this script break point.
+  for (var i = 0; i < break_points.length; i++) {
+    if (break_points[i].script_break_point() === this) {
+      break_points[i].setIgnoreCount(ignoreCount);
+    }
+  }
+};
+
+
+// Check whether a script matches this script break point. Currently this is
+// only based on script name.
+ScriptBreakPoint.prototype.matchesScript = function(script) {
+  return this.script_name_ == script.name &&
+         script.line_offset <= this.line_  &&
+         this.line_ < script.line_offset + script.lineCount();
+};
+
+
+// Set the script break point in a script.
+ScriptBreakPoint.prototype.set = function (script) {
+  var column = this.column();
+  var line = this.line();
+  // If the column is undefined the break is on the line. To help locate the
+  // first piece of breakable code on the line try to find the column on the
+  // line which contains some source.
+  if (IS_UNDEFINED(column)) {
+    var source_line = script.sourceLine(this.line());
+
+    // Allocate array for caching the columns where the actual source starts.
+    if (!script.sourceColumnStart_) {
+      script.sourceColumnStart_ = new Array(script.lineCount());
+    }
+    
+    // Fill cache if needed and get column where the actual source starts.
+    if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
+      script.sourceColumnStart_[line] =
+          source_line.match(sourceLineBeginningSkip)[0].length;
+    }
+    column = script.sourceColumnStart_[line];
+  }
+
+  // Convert the line and column into an absolute position within the script.
+  var pos = Debug.findScriptSourcePosition(script, this.line(), column);
+  
+  // Create a break point object and set the break point.
+  break_point = MakeBreakPoint(pos, this.line(), this.column(), this);
+  break_point.setIgnoreCount(this.ignoreCount());
+  %SetScriptBreakPoint(script, pos, break_point);
+
+  return break_point;
+};
+
+
+// Clear all the break points created from this script break point
+ScriptBreakPoint.prototype.clear = function () {
+  var remaining_break_points = [];
+  for (var i = 0; i < break_points.length; i++) {
+    if (break_points[i].script_break_point() &&
+        break_points[i].script_break_point() === this) {
+      %ClearBreakPoint(break_points[i]);
+    } else {
+      remaining_break_points.push(break_points[i]);
+    }
+  }
+  break_points = remaining_break_points;
+};
+
+
+// Function called from runtime when a new script is compiled to set any script
+// break points set in this script.
+function UpdateScriptBreakPoints(script) {
+  for (var i = 0; i < script_break_points.length; i++) {
+    if (script_break_points[i].script_name() == script.name) {
+      script_break_points[i].set(script);
+    }
+  }
+}
+
+
+// Function called from the runtime to handle a debug request receiced from the
+// debugger. When this function is called the debugger is in the broken state
+// reflected by the exec_state parameter. When pending requests are handled the
+// parameter stopping indicate the expected running state.
+function ProcessDebugRequest(exec_state, request, stopping) {
+  return exec_state.debugCommandProcessor().processDebugJSONRequest(request, stopping);
+}
+
+
+Debug.addListener = function(listener, opt_data) {
+  if (!IS_FUNCTION(listener)) throw new Error('Parameters have wrong types.');
+  %AddDebugEventListener(listener, opt_data);
+};
+
+Debug.removeListener = function(listener) {
+  if (!IS_FUNCTION(listener)) throw new Error('Parameters have wrong types.');
+  %RemoveDebugEventListener(listener);
+};
+
+Debug.breakExecution = function(f) {
+  %Break();
+};
+
+Debug.breakLocations = function(f) {
+  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
+  return %GetBreakLocations(f);
+};
+
+// Returns a Script object. If the parameter is a function the return value
+// is the script in which the function is defined. If the parameter is a string
+// the return value is the script for which the script name has that string
+// value.  If it is a regexp and there is a unique script whose name matches
+// we return that, otherwise undefined.
+Debug.findScript = function(func_or_script_name) {
+  if (IS_FUNCTION(func_or_script_name)) {
+    return %FunctionGetScript(func_or_script_name);
+  } else if (IS_REGEXP(func_or_script_name)) {
+    var scripts = Debug.scripts();
+    var last_result = null;
+    var result_count = 0;
+    for (var i in scripts) {
+      var script = scripts[i];
+      if (func_or_script_name.test(script.name)) {
+        last_result = script;
+        result_count++;
+      }
+    }
+    // Return the unique script matching the regexp.  If there are more
+    // than one we don't return a value since there is no good way to
+    // decide which one to return.  Returning a "random" one, say the
+    // first, would introduce nondeterminism (or something close to it)
+    // because the order is the heap iteration order.
+    if (result_count == 1) {
+      return last_result;
+    } else {
+      return undefined;
+    }
+  } else {
+    return %GetScript(func_or_script_name);
+  }
+};
+
+// Returns the script source. If the parameter is a function the return value
+// is the script source for the script in which the function is defined. If the
+// parameter is a string the return value is the script for which the script
+// name has that string value.
+Debug.scriptSource = function(func_or_script_name) {
+  return this.findScript(func_or_script_name).source;
+};
+
+Debug.source = function(f) {
+  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
+  return %FunctionGetSourceCode(f);
+};
+
+Debug.assembler = function(f) {
+  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
+  return %FunctionGetAssemblerCode(f);
+};
+
+Debug.sourcePosition = function(f) {
+  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
+  return %FunctionGetScriptSourcePosition(f);
+};
+
+Debug.findFunctionSourcePosition = function(func, opt_line, opt_column) {
+  var script = %FunctionGetScript(func);
+  var script_offset = %FunctionGetScriptSourcePosition(func);
+  return script.locationFromLine(opt_line, opt_column, script_offset).position;
+}
+
+
+// Returns the character position in a script based on a line number and an
+// optional position within that line.
+Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
+  return script.locationFromLine(opt_line, opt_column).position;
+}
+
+
+Debug.findBreakPoint = function(break_point_number, remove) {
+  var break_point;
+  for (var i = 0; i < break_points.length; i++) {
+    if (break_points[i].number() == break_point_number) {
+      break_point = break_points[i];
+      // Remove the break point from the list if requested.
+      if (remove) {
+        break_points.splice(i, 1);
+      }
+      break;
+    }
+  }
+  if (break_point) {
+    return break_point;
+  } else {
+    return this.findScriptBreakPoint(break_point_number, remove);
+  }
+};
+
+
+Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
+  if (!IS_FUNCTION(func)) throw new Error('Parameters have wrong types.');
+  var source_position = this.findFunctionSourcePosition(func, opt_line, opt_column) -
+                        this.sourcePosition(func);
+  // Find the script for the function.
+  var script = %FunctionGetScript(func);
+  // If the script for the function has a name convert this to a script break
+  // point.
+  if (script && script.name) {
+    // Adjust the source position to be script relative.
+    source_position += %FunctionGetScriptSourcePosition(func);
+    // Find line and column for the position in the script and set a script
+    // break point from that.
+    var location = script.locationFromPosition(source_position);
+    return this.setScriptBreakPoint(script.name,
+                                    location.line, location.column,
+                                    opt_condition);
+  } else {
+    // Set a break point directly on the function.
+    var break_point = MakeBreakPoint(source_position, opt_line, opt_column);
+    %SetFunctionBreakPoint(func, source_position, break_point);
+    break_point.setCondition(opt_condition);
+    return break_point.number();
+  }
+};
+
+
+Debug.enableBreakPoint = function(break_point_number) {
+  var break_point = this.findBreakPoint(break_point_number, false);
+  break_point.enable();
+};
+
+
+Debug.disableBreakPoint = function(break_point_number) {
+  var break_point = this.findBreakPoint(break_point_number, false);
+  break_point.disable();
+};
+
+
+Debug.changeBreakPointCondition = function(break_point_number, condition) {
+  var break_point = this.findBreakPoint(break_point_number, false);
+  break_point.setCondition(condition);
+};
+
+
+Debug.changeBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
+  if (ignoreCount < 0) {
+    throw new Error('Invalid argument');
+  }
+  var break_point = this.findBreakPoint(break_point_number, false);
+  break_point.setIgnoreCount(ignoreCount);
+};
+
+
+Debug.clearBreakPoint = function(break_point_number) {
+  var break_point = this.findBreakPoint(break_point_number, true);
+  if (break_point) {
+    return %ClearBreakPoint(break_point);
+  } else {
+    break_point = this.findScriptBreakPoint(break_point_number, true);
+    if (!break_point) {
+      throw new Error('Invalid breakpoint');
+    }
+  }
+};
+
+
+Debug.clearAllBreakPoints = function() {
+  for (var i = 0; i < break_points.length; i++) {
+    break_point = break_points[i];
+    %ClearBreakPoint(break_point);
+  }
+  break_points = [];
+};
+
+
+Debug.findScriptBreakPoint = function(break_point_number, remove) {
+  var script_break_point;
+  for (var i = 0; i < script_break_points.length; i++) {
+    if (script_break_points[i].number() == break_point_number) {
+      script_break_point = script_break_points[i];
+      // Remove the break point from the list if requested.
+      if (remove) {
+        script_break_point.clear();
+        script_break_points.splice(i,1);
+      }
+      break;
+    }
+  }
+  return script_break_point;
+}
+
+
+// Sets a breakpoint in a script identified through script name at the
+// specified source line and column within that line.
+Debug.setScriptBreakPoint = function(script_name, opt_line, opt_column, opt_condition) {
+  // Create script break point object.
+  var script_break_point = new ScriptBreakPoint(script_name, opt_line, opt_column);
+
+  // Assign number to the new script break point and add it.
+  script_break_point.number_ = next_break_point_number++;
+  script_break_point.setCondition(opt_condition);
+  script_break_points.push(script_break_point);
+
+  // Run through all scripts to see it this script break point matches any
+  // loaded scripts.
+  var scripts = this.scripts();
+  for (var i = 0; i < scripts.length; i++) {
+    if (script_break_point.matchesScript(scripts[i])) {
+      script_break_point.set(scripts[i]);
+    }
+  }
+
+  return script_break_point.number();
+}
+
+
+Debug.enableScriptBreakPoint = function(break_point_number) {
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.enable();
+};
+
+
+Debug.disableScriptBreakPoint = function(break_point_number) {
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.disable();
+};
+
+
+Debug.changeScriptBreakPointCondition = function(break_point_number, condition) {
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.setCondition(condition);
+};
+
+
+Debug.changeScriptBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
+  if (ignoreCount < 0) {
+    throw new Error('Invalid argument');
+  }
+  var script_break_point = this.findScriptBreakPoint(break_point_number, false);
+  script_break_point.setIgnoreCount(ignoreCount);
+};
+
+
+Debug.scriptBreakPoints = function() {
+  return script_break_points;
+}
+
+
+Debug.clearStepping = function() {
+  %ClearStepping();
+}
+
+Debug.setBreakOnException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.All, true);
+};
+
+Debug.clearBreakOnException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.All, false);
+};
+
+Debug.setBreakOnUncaughtException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, true);
+};
+
+Debug.clearBreakOnUncaughtException = function() {
+  return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
+};
+
+Debug.showBreakPoints = function(f, full) {
+  if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
+  var source = full ? this.scriptSource(f) : this.source(f);
+  var offset = full ? this.sourcePosition(f) : 0;
+  var locations = this.breakLocations(f);
+  if (!locations) return source;
+  locations.sort(function(x, y) { return x - y; });
+  var result = "";
+  var prev_pos = 0;
+  var pos;
+  for (var i = 0; i < locations.length; i++) {
+    pos = locations[i] - offset;
+    result += source.slice(prev_pos, pos);
+    result += "[B" + i + "]";
+    prev_pos = pos;
+  }
+  pos = source.length;
+  result += source.substring(prev_pos, pos);
+  return result;
+};
+
+
+// Get all the scripts currently loaded. Locating all the scripts is based on
+// scanning the heap.
+Debug.scripts = function() {
+  // Collect all scripts in the heap.
+  return %DebugGetLoadedScripts();
+}
+
+function MakeExecutionState(break_id) {
+  return new ExecutionState(break_id);
+}
+
+function ExecutionState(break_id) {
+  this.break_id = break_id;
+  this.selected_frame = 0;
+}
+
+ExecutionState.prototype.prepareStep = function(opt_action, opt_count) {
+  var action = Debug.StepAction.StepIn;
+  if (!IS_UNDEFINED(opt_action)) action = %ToNumber(opt_action);
+  var count = opt_count ? %ToNumber(opt_count) : 1;
+
+  return %PrepareStep(this.break_id, action, count);
+}
+
+ExecutionState.prototype.evaluateGlobal = function(source, disable_break) {
+  return MakeMirror(
+      %DebugEvaluateGlobal(this.break_id, source, Boolean(disable_break)));
+};
+
+ExecutionState.prototype.frameCount = function() {
+  return %GetFrameCount(this.break_id);
+};
+
+ExecutionState.prototype.frame = function(opt_index) {
+  // If no index supplied return the selected frame.
+  if (opt_index == null) opt_index = this.selected_frame;
+  return new FrameMirror(this.break_id, opt_index);
+};
+
+ExecutionState.prototype.cframesValue = function(opt_from_index, opt_to_index) {
+  return %GetCFrames(this.break_id);
+};
+
+ExecutionState.prototype.setSelectedFrame = function(index) {
+  var i = %ToNumber(index);
+  if (i < 0 || i >= this.frameCount()) throw new Error('Illegal frame index.');
+  this.selected_frame = i;
+};
+
+ExecutionState.prototype.selectedFrame = function() {
+  return this.selected_frame;
+};
+
+ExecutionState.prototype.debugCommandProcessor = function(protocol) {
+  return new DebugCommandProcessor(this, protocol);
+};
+
+
+function MakeBreakEvent(exec_state, break_points_hit) {
+  return new BreakEvent(exec_state, break_points_hit);
+}
+
+
+function BreakEvent(exec_state, break_points_hit) {
+  this.exec_state_ = exec_state;
+  this.break_points_hit_ = break_points_hit;
+}
+
+
+BreakEvent.prototype.func = function() {
+  return this.exec_state_.frame(0).func();
+};
+
+
+BreakEvent.prototype.sourceLine = function() {
+  return this.exec_state_.frame(0).sourceLine();
+};
+
+
+BreakEvent.prototype.sourceColumn = function() {
+  return this.exec_state_.frame(0).sourceColumn();
+};
+
+
+BreakEvent.prototype.sourceLineText = function() {
+  return this.exec_state_.frame(0).sourceLineText();
+};
+
+
+BreakEvent.prototype.breakPointsHit = function() {
+  return this.break_points_hit_;
+};
+
+
+BreakEvent.prototype.details = function() {
+  // Build the break details.
+  var details = '';
+  if (this.breakPointsHit()) {
+    details += 'breakpoint';
+    if (this.breakPointsHit().length > 1) {
+      details += 's';
+    }
+    details += ' ';
+    for (var i = 0; i < this.breakPointsHit().length; i++) {
+      if (i > 0) {
+        details += ',';
+      }
+      details += this.breakPointsHit()[i].number();
+    }
+  } else {
+    details += 'break';
+  }
+  details += ' in ';
+  details += this.exec_state_.frame(0).invocationText();
+  details += ' at ';
+  details += this.exec_state_.frame(0).sourceAndPositionText();
+  details += '\n'
+  if (this.func().script()) {
+    details += FrameSourceUnderline(this.exec_state_.frame(0));
+  }
+  return details;
+};
+
+
+BreakEvent.prototype.debugPrompt = function() {
+  // Build the debug break prompt.
+  if (this.breakPointsHit()) {
+    return 'breakpoint';
+  } else {
+    return 'break';
+  }
+};
+
+
+BreakEvent.prototype.toJSONProtocol = function() {
+  var o = { seq: next_response_seq++,
+            type: "event",
+            event: "break",
+            body: { invocationText: this.exec_state_.frame(0).invocationText(),
+                  }
+          }
+
+  // Add script related information to the event if available.
+  var script = this.func().script();
+  if (script) {
+    o.body.sourceLine = this.sourceLine(),
+    o.body.sourceColumn = this.sourceColumn(),
+    o.body.sourceLineText = this.sourceLineText(),
+    o.body.script = { name: script.name(),
+                      lineOffset: script.lineOffset(),
+                      columnOffset: script.columnOffset(),
+                      lineCount: script.lineCount()
+                    };
+  }
+
+  // Add an Array of break points hit if any.
+  if (this.breakPointsHit()) {
+    o.body.breakpoints = [];
+    for (var i = 0; i < this.breakPointsHit().length; i++) {
+      // Find the break point number. For break points originating from a
+      // script break point supply the script break point number.
+      var breakpoint = this.breakPointsHit()[i];
+      var script_break_point = breakpoint.script_break_point();
+      var number;
+      if (script_break_point) {
+        number = script_break_point.number();
+      } else {
+        number = breakpoint.number();
+      }
+      o.body.breakpoints.push(number);
+    }
+  }
+
+  return SimpleObjectToJSON_(o);
+};
+
+
+function MakeExceptionEvent(exec_state, exception, uncaught) {
+  return new ExceptionEvent(exec_state, exception, uncaught);
+}
+
+function ExceptionEvent(exec_state, exception, uncaught) {
+  this.exec_state_ = exec_state;
+  this.exception_ = exception;
+  this.uncaught_ = uncaught;
+}
+
+ExceptionEvent.prototype.uncaught = function() {
+  return this.uncaught_;
+}
+
+ExceptionEvent.prototype.func = function() {
+  return this.exec_state_.frame(0).func();
+};
+
+
+ExceptionEvent.prototype.sourceLine = function() {
+  return this.exec_state_.frame(0).sourceLine();
+};
+
+
+ExceptionEvent.prototype.sourceColumn = function() {
+  return this.exec_state_.frame(0).sourceColumn();
+};
+
+
+ExceptionEvent.prototype.sourceLineText = function() {
+  return this.exec_state_.frame(0).sourceLineText();
+};
+
+
+ExceptionEvent.prototype.details = function() {
+  var details = "";
+  if (this.uncaught_) {
+    details += "Uncaught: ";
+  } else {
+    details += "Exception: ";
+  }
+
+  details += '"';
+  details += MakeMirror(this.exception_).toText();
+  details += '" at ';
+  details += this.exec_state_.frame(0).sourceAndPositionText();
+  details += '\n';
+  details += FrameSourceUnderline(this.exec_state_.frame(0));
+
+  return details;
+};
+
+ExceptionEvent.prototype.debugPrompt = function() {
+  if (this.uncaught_) {
+    return "uncaught exception";
+  } else {
+    return "exception";
+  }
+};
+
+ExceptionEvent.prototype.toJSONProtocol = function() {
+  var o = { seq: next_response_seq++,
+            type: "event",
+            event: "exception",
+            body: { uncaught: this.uncaught_,
+                    exception: MakeMirror(this.exception_),
+                    sourceLine: this.sourceLine(),
+                    sourceColumn: this.sourceColumn(),
+                    sourceLineText: this.sourceLineText(),
+                  }
+          }
+
+  // Add script information to the event if available.
+  var script = this.func().script();
+  if (script) {
+    o.body.script = { name: script.name(),
+                      lineOffset: script.lineOffset(),
+                      columnOffset: script.columnOffset(),
+                      lineCount: script.lineCount()
+                    };
+  }
+
+  return SimpleObjectToJSON_(o);
+};
+
+function MakeCompileEvent(script_source, script_name, script_function) {
+  return new CompileEvent(script_source, script_name, script_function);
+}
+
+function CompileEvent(script_source, script_name, script_function) {
+  this.scriptSource = script_source;
+  this.scriptName = script_name;
+  this.scriptFunction = script_function;
+}
+
+CompileEvent.prototype.details = function() {
+  var result = "";
+  result = "Script added"
+  if (this.scriptData) {
+    result += ": '";
+    result += this.scriptData;
+    result += "'";
+  }
+  return result;
+};
+
+CompileEvent.prototype.debugPrompt = function() {
+  var result = "source"
+  if (this.scriptData) {
+    result += " '";
+    result += this.scriptData;
+    result += "'";
+  }
+  if (this.func) {
+    result += " added";
+  } else {
+    result += " compiled";
+  }
+  return result;
+};
+
+function MakeNewFunctionEvent(func) {
+  return new NewFunctionEvent(func);
+}
+
+function NewFunctionEvent(func) {
+  this.func = func;
+}
+
+NewFunctionEvent.prototype.details = function() {
+  var result = "";
+  result = "Function added: ";
+  result += this.func.name;
+  return result;
+};
+
+NewFunctionEvent.prototype.debugPrompt = function() {
+  var result = "function";
+  if (this.func.name) {
+    result += " '";
+    result += this.func.name;
+    result += "'";
+  }
+  result += " added";
+  return result;
+};
+
+NewFunctionEvent.prototype.name = function() {
+  return this.func.name;
+};
+
+NewFunctionEvent.prototype.setBreakPoint = function(p) {
+  Debug.setBreakPoint(this.func, p || 0);
+};
+
+function DebugCommandProcessor(exec_state) {
+  this.exec_state_ = exec_state;
+};
+
+
+// Convenience function for C debugger code to process a text command. This
+// function converts the text command to a JSON request, performs the request
+// and converts the request to a text result for display. The result is an
+// object containing the text result and the intermediate results.
+DebugCommandProcessor.prototype.processDebugCommand = function (command) {
+  var request;
+  var response;
+  var text_result;
+  var running;
+
+  request = this.commandToJSONRequest(command);
+  response = this.processDebugJSONRequest(request);
+  text_result = this.responseToText(response);
+  running = this.isRunning(response);
+
+  return { "request"       : request,
+           "response"      : response,
+           "text_result"   : text_result,
+           "running"       : running };
+}
+
+
+// Converts a text command to a JSON request.
+DebugCommandProcessor.prototype.commandToJSONRequest = function(cmd_line) {
+  // If the wery first character is a { assume that a JSON request have been
+  // entered as a command. Converting that to a JSON request is trivial.
+  if (cmd_line && cmd_line.length > 0 && cmd_line.charAt(0) == '{') {
+    return cmd_line;
+  }
+
+  // Trim string for leading and trailing whitespace.
+  cmd_line = cmd_line.replace(/^\s+|\s+$/g, "");
+
+  // Find the command.
+  var pos = cmd_line.indexOf(" ");
+  var cmd;
+  var args;
+  if (pos == -1) {
+    cmd = cmd_line;
+    args = "";
+  } else {
+    cmd = cmd_line.slice(0, pos);
+    args = cmd_line.slice(pos).replace(/^\s+|\s+$/g, "");
+  }
+
+  // Switch on command.
+  if (cmd == 'continue' || cmd == 'c') {
+    return this.continueCommandToJSONRequest_(args);
+  } else if (cmd == 'step' || cmd == 's') {
+    return this.stepCommandToJSONRequest_(args);
+  } else if (cmd == 'backtrace' || cmd == 'bt') {
+    return this.backtraceCommandToJSONRequest_(args);
+  } else if (cmd == 'frame' || cmd == 'f') {
+    return this.frameCommandToJSONRequest_(args);
+  } else if (cmd == 'print' || cmd == 'p') {
+    return this.printCommandToJSONRequest_(args);
+  } else if (cmd == 'source') {
+    return this.sourceCommandToJSONRequest_(args);
+  } else if (cmd == 'scripts') {
+    return this.scriptsCommandToJSONRequest_(args);
+  } else if (cmd[0] == '{') {
+    return cmd_line;
+  } else {
+    throw new Error('Unknown command "' + cmd + '"');
+  }
+};
+
+
+// Create a JSON request for the continue command.
+DebugCommandProcessor.prototype.continueCommandToJSONRequest_ = function(args) {
+  var request = this.createRequest('continue');
+  return request.toJSONProtocol();
+};
+
+
+// Create a JSON request for the step command.
+DebugCommandProcessor.prototype.stepCommandToJSONRequest_ = function(args) {
+  // Requesting a step is through the continue command with additional
+  // arguments.
+  var request = this.createRequest('continue');
+  request.arguments = {};
+
+  // Process arguments if any.
+  if (args && args.length > 0) {
+    args = args.split(/\s*[ ]+\s*/g);
+
+    if (args.length > 2) {
+      throw new Error('Invalid step arguments.');
+    }
+
+    if (args.length > 0) {
+      // Get step count argument if any.
+      if (args.length == 2) {
+        request.arguments.stepcount = %ToNumber(args[1]);
+      }
+
+      // Get the step action.
+      if (args[0] == 'in' || args[0] == 'i') {
+        request.arguments.stepaction = 'in';
+      } else if (args[0] == 'min' || args[0] == 'm') {
+        request.arguments.stepaction = 'min';
+      } else if (args[0] == 'next' || args[0] == 'n') {
+        request.arguments.stepaction = 'next';
+      } else if (args[0] == 'out' || args[0] == 'o') {
+        request.arguments.stepaction = 'out';
+      } else {
+        throw new Error('Invalid step argument "' + args[0] + '".');
+      }
+    }
+  } else {
+    // Default is step next.
+    request.arguments.stepaction = 'next';
+  }
+
+  return request.toJSONProtocol();
+};
+
+
+// Create a JSON request for the backtrace command.
+DebugCommandProcessor.prototype.backtraceCommandToJSONRequest_ = function(args) {
+  // Build a backtrace request from the text command.
+  var request = this.createRequest('backtrace');
+  args = args.split(/\s*[ ]+\s*/g);
+  if (args.length == 2) {
+    request.arguments = {};
+    request.arguments.fromFrame = %ToNumber(args[0]);
+    request.arguments.toFrame = %ToNumber(args[1]) + 1;
+  }
+  return request.toJSONProtocol();
+};
+
+
+// Create a JSON request for the frame command.
+DebugCommandProcessor.prototype.frameCommandToJSONRequest_ = function(args) {
+  // Build a frame request from the text command.
+  var request = this.createRequest('frame');
+  args = args.split(/\s*[ ]+\s*/g);
+  if (args.length > 0 && args[0].length > 0) {
+    request.arguments = {};
+    request.arguments.number = args[0];
+  }
+  return request.toJSONProtocol();
+};
+
+
+// Create a JSON request for the print command.
+DebugCommandProcessor.prototype.printCommandToJSONRequest_ = function(args) {
+  // Build a evaluate request from the text command.
+  var request = this.createRequest('evaluate');
+  if (args.length == 0) {
+    throw new Error('Missing expression.');
+  }
+
+  request.arguments = {};
+  request.arguments.expression = args;
+
+  return request.toJSONProtocol();
+};
+
+
+// Create a JSON request for the source command.
+DebugCommandProcessor.prototype.sourceCommandToJSONRequest_ = function(args) {
+  // Build a evaluate request from the text command.
+  var request = this.createRequest('source');
+
+  // Default is one line before and two lines after current location.
+  var before = 1;
+  var after = 2;
+
+  // Parse the arguments.
+  args = args.split(/\s*[ ]+\s*/g);
+  if (args.length > 1 && args[0].length > 0 && args[1].length > 0) {
+    before = %ToNumber(args[0]);
+    after = %ToNumber(args[1]);
+  } else if (args.length > 0 && args[0].length > 0) {
+    after = %ToNumber(args[0]);
+  }
+
+  // Request source arround current source location.
+  request.arguments = {};
+  request.arguments.fromLine = this.exec_state_.frame().sourceLine() - before;
+  if (request.arguments.fromLine < 0) {
+    request.arguments.fromLine = 0
+  }
+  request.arguments.toLine = this.exec_state_.frame().sourceLine() + after + 1;
+
+  return request.toJSONProtocol();
+};
+
+
+// Create a JSON request for the scripts command.
+DebugCommandProcessor.prototype.scriptsCommandToJSONRequest_ = function(args) {
+  // Build a evaluate request from the text command.
+  var request = this.createRequest('scripts');
+
+  // Process arguments if any.
+  if (args && args.length > 0) {
+    args = args.split(/\s*[ ]+\s*/g);
+
+    if (args.length > 1) {
+      throw new Error('Invalid scripts arguments.');
+    }
+
+    request.arguments = {};
+    if (args[0] == 'natives') {
+      request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Native);
+    } else if (args[0] == 'extensions') {
+      request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Extension);
+    } else if (args[0] == 'all') {
+      request.arguments.types =
+          ScriptTypeFlag(Debug.ScriptType.Normal) |
+          ScriptTypeFlag(Debug.ScriptType.Native) |
+          ScriptTypeFlag(Debug.ScriptType.Extension);
+    } else {
+      throw new Error('Invalid argument "' + args[0] + '".');
+    }
+  }
+
+  return request.toJSONProtocol();
+};
+
+
+// Convert a JSON response to text for display in a text based debugger.
+DebugCommandProcessor.prototype.responseToText = function(json_response) {
+  try {
+    // Convert the JSON string to an object.
+    response = %CompileString('(' + json_response + ')', 0, false)();
+
+    if (!response.success) {
+      return response.message;
+    }
+
+    if (response.command == 'backtrace') {
+      var body = response.body;
+      var result = 'Frames #' + body.fromFrame + ' to #' +
+          (body.toFrame - 1) + ' of ' + body.totalFrames + '\n';
+      for (i = 0; i < body.frames.length; i++) {
+        if (i != 0) result += '\n';
+        result += body.frames[i].text;
+      }
+      return result;
+    } else if (response.command == 'frame') {
+      return SourceUnderline(response.body.sourceLineText,
+                             response.body.column);
+    } else if (response.command == 'evaluate') {
+      return response.body.text;
+    } else if (response.command == 'source') {
+      // Get the source from the response.
+      var source = response.body.source;
+
+      // Get rid of last line terminator.
+      var remove_count = 0;
+      if (source[source.length - 1] == '\n') remove_count++;
+      if (source[source.length - 2] == '\r') remove_count++;
+      if (remove_count > 0) source = source.substring(0, source.length - remove_count);
+
+      return source;
+    } else if (response.command == 'scripts') {
+      var result = '';
+      for (i = 0; i < response.body.length; i++) {
+        if (i != 0) result += '\n';
+        if (response.body[i].name) {
+          result += response.body[i].name;
+        } else {
+          result += '[unnamed] ';
+          var sourceStart = response.body[i].sourceStart;
+          if (sourceStart.length > 40) {
+            sourceStart = sourceStart.substring(0, 37) + '...';
+          }
+          result += sourceStart;
+        }
+        result += ' (lines: ';
+        result += response.body[i].sourceLines;
+        result += ', length: ';
+        result += response.body[i].sourceLength;
+        if (response.body[i].type == Debug.ScriptType.Native) {
+          result += ', native';
+        } else if (response.body[i].type == Debug.ScriptType.Extension) {
+          result += ', extension';
+        }
+        result += ')';
+      }
+      return result;
+    }
+  } catch (e) {
+    return 'Error: "' + %ToString(e) + '" formatting response';
+  }
+};
+
+
+function SourceUnderline(source_text, position) {
+  if (IS_UNDEFINED(source_text)) {
+    return;
+  }
+
+  // Create an underline with a caret pointing to the source position. If the
+  // source contains a tab character the underline will have a tab character in
+  // the same place otherwise the underline will have a space character.
+  var underline = '';
+  for (var i = 0; i < position; i++) {
+    if (source_text[i] == '\t') {
+      underline += '\t';
+    } else {
+      underline += ' ';
+    }
+  }
+  underline += '^';
+
+  // Return the source line text with the underline beneath.
+  return source_text + '\n' + underline;
+}
+
+
+function FrameSourceUnderline(frame) {
+  var location = frame.sourceLocation();
+  if (location) {
+    return SourceUnderline(location.sourceText(), location.position - location.start);
+  }
+}
+
+
+function RequestPacket(command) {
+  this.seq = 0;
+  this.type = 'request';
+  this.command = command;
+}
+
+
+RequestPacket.prototype.toJSONProtocol = function() {
+  // Encode the protocol header.
+  var json = '{';
+  json += '"seq":' + this.seq;
+  json += ',"type":"' + this.type + '"';
+  if (this.command) {
+    json += ',"command":' + StringToJSON_(this.command);
+  }
+  if (this.arguments) {
+    json += ',"arguments":';
+    // Encode the arguments part.
+    if (this.arguments.toJSONProtocol) {
+      json += this.arguments.toJSONProtocol()
+    } else {
+      json += SimpleObjectToJSON_(this.arguments);
+    }
+  }
+  json += '}';
+  return json;
+}
+
+
+DebugCommandProcessor.prototype.createRequest = function(command) {
+  return new RequestPacket(command);
+};
+
+
+function ResponsePacket(request) {
+  // Build the initial response from the request.
+  this.seq = next_response_seq++;
+  this.type = 'response';
+  if (request) this.request_seq = request.seq;
+  if (request) this.command = request.command;
+  this.success = true;
+  this.running = false;
+}
+
+
+ResponsePacket.prototype.failed = function(message) {
+  this.success = false;
+  this.message = message;
+}
+
+
+ResponsePacket.prototype.toJSONProtocol = function() {
+  // Encode the protocol header.
+  var json = '{';
+  json += '"seq":' + this.seq;
+  if (this.request_seq) {
+    json += ',"request_seq":' + this.request_seq;
+  }
+  json += ',"type":"' + this.type + '"';
+  if (this.command) {
+    json += ',"command":' + StringToJSON_(this.command);
+  }
+  if (this.success) {
+    json += ',"success":' + this.success;
+  } else {
+    json += ',"success":false';
+  }
+  if (this.body) {
+    json += ',"body":';
+    // Encode the body part.
+    if (this.body.toJSONProtocol) {
+      json += this.body.toJSONProtocol(true);
+    } else if (this.body instanceof Array) {
+      json += '[';
+      for (var i = 0; i < this.body.length; i++) {
+        if (i != 0) json += ',';
+        if (this.body[i].toJSONProtocol) {
+          json += this.body[i].toJSONProtocol(true)
+        } else {
+          json += SimpleObjectToJSON_(this.body[i]);
+        }
+      }
+      json += ']';
+    } else {
+      json += SimpleObjectToJSON_(this.body);
+    }
+  }
+  if (this.message) {
+    json += ',"message":' + StringToJSON_(this.message) ;
+  }
+  if (this.running) {
+    json += ',"running":true';
+  } else {
+    json += ',"running":false';
+  }
+  json += '}';
+  return json;
+}
+
+
+DebugCommandProcessor.prototype.createResponse = function(request) {
+  return new ResponsePacket(request);
+};
+
+
+DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request, stopping) {
+  var request;  // Current request.
+  var response;  // Generated response.
+  try {
+    try {
+      // Convert the JSON string to an object.
+      request = %CompileString('(' + json_request + ')', 0, false)();
+
+      // Create an initial response.
+      response = this.createResponse(request);
+
+      if (!request.type) {
+        throw new Error('Type not specified');
+      }
+
+      if (request.type != 'request') {
+        throw new Error("Illegal type '" + request.type + "' in request");
+      }
+
+      if (!request.command) {
+        throw new Error('Command not specified');
+      }
+
+      if (request.command == 'continue') {
+        this.continueRequest_(request, response);
+      } else if (request.command == 'break') {
+        this.breakRequest_(request, response);
+      } else if (request.command == 'setbreakpoint') {
+        this.setBreakPointRequest_(request, response);
+      } else if (request.command == 'changebreakpoint') {
+        this.changeBreakPointRequest_(request, response);
+      } else if (request.command == 'clearbreakpoint') {
+        this.clearBreakPointRequest_(request, response);
+      } else if (request.command == 'backtrace') {
+        this.backtraceRequest_(request, response);
+      } else if (request.command == 'frame') {
+        this.frameRequest_(request, response);
+      } else if (request.command == 'evaluate') {
+        this.evaluateRequest_(request, response);
+      } else if (request.command == 'source') {
+        this.sourceRequest_(request, response);
+      } else if (request.command == 'scripts') {
+        this.scriptsRequest_(request, response);
+      } else {
+        throw new Error('Unknown command "' + request.command + '" in request');
+      }
+    } catch (e) {
+      // If there is no response object created one (without command).
+      if (!response) {
+        response = this.createResponse();
+      }
+      response.success = false;
+      response.message = %ToString(e);
+    }
+
+    // Return the response as a JSON encoded string.
+    try {
+      // Set the running state to what indicated.
+      if (!IS_UNDEFINED(stopping)) {
+        response.running = !stopping;
+      }
+      return response.toJSONProtocol();
+    } catch (e) {
+      // Failed to generate response - return generic error.
+      return '{"seq":' + response.seq + ',' +
+              '"request_seq":' + request.seq + ',' +
+              '"type":"response",' +
+              '"success":false,' +
+              '"message":"Internal error: ' + %ToString(e) + '"}';
+    }
+  } catch (e) {
+    // Failed in one of the catch blocks above - most generic error.
+    return '{"seq":0,"type":"response","success":false,"message":"Internal error"}';
+  }
+};
+
+
+DebugCommandProcessor.prototype.continueRequest_ = function(request, response) {
+  // Check for arguments for continue.
+  if (request.arguments) {
+    var count = 1;
+    var action = Debug.StepAction.StepIn;
+
+    // Pull out arguments.
+    var stepaction = request.arguments.stepaction;
+    var stepcount = request.arguments.stepcount;
+
+    // Get the stepcount argument if any.
+    if (stepcount) {
+      count = %ToNumber(stepcount);
+      if (count < 0) {
+        throw new Error('Invalid stepcount argument "' + stepcount + '".');
+      }
+    }
+
+    // Get the stepaction argument.
+    if (stepaction) {
+      if (stepaction == 'in') {
+        action = Debug.StepAction.StepIn;
+      } else if (stepaction == 'min') {
+        action = Debug.StepAction.StepMin;
+      } else if (stepaction == 'next') {
+        action = Debug.StepAction.StepNext;
+      } else if (stepaction == 'out') {
+        action = Debug.StepAction.StepOut;
+      } else {
+        throw new Error('Invalid stepaction argument "' + stepaction + '".');
+      }
+    }
+
+    // Setup the VM for stepping.
+    this.exec_state_.prepareStep(action, count);
+  }
+
+  // VM should be running after executing this request.
+  response.running = true;
+};
+
+
+DebugCommandProcessor.prototype.breakRequest_ = function(request, response) {
+  // Ignore as break command does not do anything when broken.
+};
+
+
+DebugCommandProcessor.prototype.setBreakPointRequest_ =
+    function(request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var type = request.arguments.type;
+  var target = request.arguments.target;
+  var line = request.arguments.line;
+  var column = request.arguments.column;
+  var enabled = IS_UNDEFINED(request.arguments.enabled) ?
+      true : request.arguments.enabled;
+  var condition = request.arguments.condition;
+  var ignoreCount = request.arguments.ignoreCount;
+
+  // Check for legal arguments.
+  if (!type || !target) {
+    response.failed('Missing argument "type" or "target"');
+    return;
+  }
+  if (type != 'function' && type != 'script') {
+    response.failed('Illegal type "' + type + '"');
+    return;
+  }
+
+  // Either function or script break point.
+  var break_point_number;
+  if (type == 'function') {
+    // Handle function break point.
+    if (!IS_STRING(target)) {
+      response.failed('Argument "target" is not a string value');
+      return;
+    }
+    var f;
+    try {
+      // Find the function through a global evaluate.
+      f = this.exec_state_.evaluateGlobal(target).value();
+    } catch (e) {
+      response.failed('Error: "' + %ToString(e) +
+                      '" evaluating "' + target + '"');
+      return;
+    }
+    if (!IS_FUNCTION(f)) {
+      response.failed('"' + target + '" does not evaluate to a function');
+      return;
+    }
+
+    // Set function break point.
+    break_point_number = Debug.setBreakPoint(f, line, column, condition);
+  } else {
+    // set script break point.
+    break_point_number = Debug.setScriptBreakPoint(target,
+                                                   line, column,
+                                                   condition);
+  }
+
+  // Set additional break point properties.
+  var break_point = Debug.findBreakPoint(break_point_number);
+  if (ignoreCount) {
+    Debug.changeBreakPointIgnoreCount(break_point_number, ignoreCount);
+  }
+  if (!enabled) {
+    Debug.disableBreakPoint(break_point_number);
+  }
+
+  // Add the break point number to the response.
+  response.body = { type: type,
+                    breakpoint: break_point_number }
+
+  // Add break point information to the response.
+  if (break_point instanceof ScriptBreakPoint) {
+    response.body.type = 'script';
+    response.body.script_name = break_point.script_name();
+    response.body.line = break_point.line();
+    response.body.column = break_point.column();
+  } else {
+    response.body.type = 'function';
+  }
+};
+
+
+DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var break_point = %ToNumber(request.arguments.breakpoint);
+  var enabled = request.arguments.enabled;
+  var condition = request.arguments.condition;
+  var ignoreCount = request.arguments.ignoreCount;
+
+  // Check for legal arguments.
+  if (!break_point) {
+    response.failed('Missing argument "breakpoint"');
+    return;
+  }
+
+  // Change enabled state if supplied.
+  if (!IS_UNDEFINED(enabled)) {
+    if (enabled) {
+      Debug.enableBreakPoint(break_point);
+    } else {
+      Debug.disableBreakPoint(break_point);
+    }
+  }
+
+  // Change condition if supplied
+  if (!IS_UNDEFINED(condition)) {
+    Debug.changeBreakPointCondition(break_point, condition);
+  }
+
+  // Change ignore count if supplied
+  if (!IS_UNDEFINED(ignoreCount)) {
+    Debug.changeBreakPointIgnoreCount(break_point, ignoreCount);
+  }
+}
+
+
+DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(request, response) {
+  // Check for legal request.
+  if (!request.arguments) {
+    response.failed('Missing arguments');
+    return;
+  }
+
+  // Pull out arguments.
+  var break_point = %ToNumber(request.arguments.breakpoint);
+
+  // Check for legal arguments.
+  if (!break_point) {
+    response.failed('Missing argument "breakpoint"');
+    return;
+  }
+
+  // Clear break point.
+  Debug.clearBreakPoint(break_point);
+}
+
+
+DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response) {
+  // Get the number of frames.
+  var total_frames = this.exec_state_.frameCount();
+
+  // Default frame range to include in backtrace.
+  var from_index = 0
+  var to_index = kDefaultBacktraceLength;
+
+  // Get the range from the arguments.
+  if (request.arguments) {
+    from_index = request.arguments.fromFrame;
+    if (from_index < 0) {
+      return response.failed('Invalid frame number');
+    }
+    to_index = request.arguments.toFrame;
+    if (to_index < 0) {
+      return response.failed('Invalid frame number');
+    }
+  }
+
+  // Adjust the index.
+  to_index = Math.min(total_frames, to_index);
+
+  if (to_index <= from_index) {
+    var error = 'Invalid frame range';
+    return response.failed(error);
+  }
+
+  // Create the response body.
+  var frames = [];
+  for (var i = from_index; i < to_index; i++) {
+    frames.push(this.exec_state_.frame(i));
+  }
+  response.body = {
+    fromFrame: from_index,
+    toFrame: to_index,
+    totalFrames: total_frames,
+    frames: frames
+  }
+};
+
+
+DebugCommandProcessor.prototype.backtracec = function(cmd, args) {
+  return this.exec_state_.cframesValue();
+};
+
+
+DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
+  // With no arguments just keep the selected frame.
+  if (request.arguments && request.arguments.number >= 0) {
+    this.exec_state_.setSelectedFrame(request.arguments.number);
+  }
+  response.body = this.exec_state_.frame();
+};
+
+
+DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) {
+  if (!request.arguments) {
+    return response.failed('Missing arguments');
+  }
+
+  // Pull out arguments.
+  var expression = request.arguments.expression;
+  var frame = request.arguments.frame;
+  var global = request.arguments.global;
+  var disable_break = request.arguments.disable_break;
+
+  // The expression argument could be an integer so we convert it to a
+  // string.
+  try {
+    expression = String(expression);
+  } catch(e) {
+    return response.failed('Failed to convert expression argument to string');
+  }
+
+  // Check for legal arguments.
+  if (!IS_UNDEFINED(frame) && global) {
+    return response.failed('Arguments "frame" and "global" are exclusive');
+  }
+
+  // Global evaluate.
+  if (global) {
+    // Evaluate in the global context.
+    response.body =
+        this.exec_state_.evaluateGlobal(expression), Boolean(disable_break);
+    return;
+  }
+
+  // Default value for disable_break is true.
+  if (IS_UNDEFINED(disable_break)) {
+    disable_break = true;
+  }
+
+  // Check whether a frame was specified.
+  if (!IS_UNDEFINED(frame)) {
+    var frame_number = %ToNumber(frame);
+    if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
+      return response.failed('Invalid frame "' + frame + '"');
+    }
+    // Evaluate in the specified frame.
+    response.body = this.exec_state_.frame(frame_number).evaluate(
+        expression, Boolean(disable_break));
+    return;
+  } else {
+    // Evaluate in the selected frame.
+    response.body = this.exec_state_.frame().evaluate(
+        expression, Boolean(disable_break));
+    return;
+  }
+};
+
+
+DebugCommandProcessor.prototype.sourceRequest_ = function(request, response) {
+  var from_line;
+  var to_line;
+  var frame = this.exec_state_.frame();
+  if (request.arguments) {
+    // Pull out arguments.
+    from_line = request.arguments.fromLine;
+    to_line = request.arguments.toLine;
+
+    if (!IS_UNDEFINED(request.arguments.frame)) {
+      var frame_number = %ToNumber(request.arguments.frame);
+      if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
+        return response.failed('Invalid frame "' + frame + '"');
+      }
+      frame = this.exec_state_.frame(frame_number);
+    }
+  }
+
+  // Get the script selected.
+  var script = frame.func().script();
+  if (!script) {
+    return response.failed('No source');
+  }
+
+  // Get the source slice and fill it into the response.
+  var slice = script.sourceSlice(from_line, to_line);
+  if (!slice) {
+    return response.failed('Invalid line interval');
+  }
+  response.body = {};
+  response.body.source = slice.sourceText();
+  response.body.fromLine = slice.from_line;
+  response.body.toLine = slice.to_line;
+  response.body.fromPosition = slice.from_position;
+  response.body.toPosition = slice.to_position;
+  response.body.totalLines = script.lineCount();
+};
+
+
+DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
+  var types = ScriptTypeFlag(Debug.ScriptType.Normal);
+  if (request.arguments) {
+    // Pull out arguments.
+    if (!IS_UNDEFINED(request.arguments.types)) {
+      types = %ToNumber(request.arguments.types);
+      if (isNaN(types) || types < 0) {
+        return response.failed('Invalid types "' + request.arguments.types + '"');
+      }
+    }
+  }
+
+  // Collect all scripts in the heap.
+  var scripts = %DebugGetLoadedScripts();
+
+  response.body = [];
+
+  for (var i = 0; i < scripts.length; i++) {
+    if (types & ScriptTypeFlag(scripts[i].type)) {
+      var script = {};
+      if (scripts[i].name) {
+        script.name = scripts[i].name;
+      }
+      script.lineOffset = scripts[i].line_offset;
+      script.columnOffset = scripts[i].column_offset;
+      script.lineCount = scripts[i].lineCount();
+      script.sourceStart = scripts[i].source.substring(0, 80);
+      script.sourceLength = scripts[i].source.length;
+      script.type = scripts[i].type;
+      response.body.push(script);
+    }
+  }
+};
+
+
+// Check whether the JSON response indicate that the VM should be running.
+DebugCommandProcessor.prototype.isRunning = function(json_response) {
+  try {
+    // Convert the JSON string to an object.
+    response = %CompileString('(' + json_response + ')', 0, false)();
+
+    // Return whether VM should be running after this request.
+    return response.running;
+
+  } catch (e) {
+     return false;
+  }
+}
+
+
+DebugCommandProcessor.prototype.systemBreak = function(cmd, args) {
+  return %SystemBreak();
+};
+
+
+function NumberToHex8Str(n) {
+  var r = "";
+  for (var i = 0; i < 8; ++i) {
+    var c = hexCharArray[n & 0x0F];  // hexCharArray is defined in uri.js
+    r = c + r;
+    n = n >>> 4;
+  }
+  return r;
+};
+
+DebugCommandProcessor.prototype.formatCFrames = function(cframes_value) {
+  var result = "";
+  if (cframes_value == null || cframes_value.length == 0) {
+    result += "(stack empty)";
+  } else {
+    for (var i = 0; i < cframes_value.length; ++i) {
+      if (i != 0) result += "\n";
+      result += this.formatCFrame(cframes_value[i]);
+    }
+  }
+  return result;
+};
+
+
+DebugCommandProcessor.prototype.formatCFrame = function(cframe_value) {
+  var result = "";
+  result += "0x" + NumberToHex8Str(cframe_value.address);
+  if (!IS_UNDEFINED(cframe_value.text)) {
+    result += " " + cframe_value.text;
+  }
+  return result;
+}
+
+
+/**
+ * Convert an Object to its JSON representation (see http://www.json.org/).
+ * This implementation simply runs through all string property names and adds
+ * each property to the JSON representation for some predefined types. For type
+ * "object" the function calls itself recursively unless the object has the
+ * function property "toJSONProtocol" in which case that is used. This is not
+ * a general implementation but sufficient for the debugger. Note that circular
+ * structures will cause infinite recursion.
+ * @param {Object} object The object to format as JSON
+ * @return {string} JSON formatted object value
+ */
+function SimpleObjectToJSON_(object) {
+  var content = [];
+  for (var key in object) {
+    // Only consider string keys.
+    if (typeof key == 'string') {
+      var property_value = object[key];
+
+      // Format the value based on its type.
+      var property_value_json;
+      switch (typeof property_value) {
+        case 'object':
+          if (typeof property_value.toJSONProtocol == 'function') {
+            property_value_json = property_value.toJSONProtocol(true)
+          } else if (IS_ARRAY(property_value)){
+            property_value_json = SimpleArrayToJSON_(property_value);
+          } else {
+            property_value_json = SimpleObjectToJSON_(property_value);
+          }
+          break;
+
+        case 'boolean':
+          property_value_json = BooleanToJSON_(property_value);
+          break;
+
+        case 'number':
+          property_value_json = NumberToJSON_(property_value);
+          break;
+
+        case 'string':
+          property_value_json = StringToJSON_(property_value);
+          break;
+
+        default:
+          property_value_json = null;
+      }
+
+      // Add the property if relevant.
+      if (property_value_json) {
+        content.push(StringToJSON_(key) + ':' + property_value_json);
+      }
+    }
+  }
+
+  // Make JSON object representation.
+  return '{' + content.join(',') + '}';
+}
+
+/**
+ * Convert an array to its JSON representation. This is a VERY simple
+ * implementation just to support what is needed for the debugger.
+ * @param {Array} arrya The array to format as JSON
+ * @return {string} JSON formatted array value
+ */
+function SimpleArrayToJSON_(array) {
+  // Make JSON array representation.
+  var json = '[';
+  for (var i = 0; i < array.length; i++) {
+    if (i != 0) {
+      json += ',';
+    }
+    var elem = array[i];
+    if (elem.toJSONProtocol) {
+      json += elem.toJSONProtocol(true)
+    } else if (IS_OBJECT(elem))  {
+      json += SimpleObjectToJSON_(elem);
+    } else if (IS_BOOLEAN(elem)) {
+      json += BooleanToJSON_(elem);
+    } else if (IS_NUMBER(elem)) {
+      json += NumberToJSON_(elem);
+    } else if (IS_STRING(elem)) {
+      json += StringToJSON_(elem);
+    } else {
+      json += elem;
+    }
+  }
+  json += ']';
+  return json;
+}
diff --git a/regexp2000/src/debug.cc b/regexp2000/src/debug.cc
new file mode 100644 (file)
index 0000000..33fafe7
--- /dev/null
@@ -0,0 +1,1972 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "arguments.h"
+#include "bootstrapper.h"
+#include "code-stubs.h"
+#include "compiler.h"
+#include "debug.h"
+#include "execution.h"
+#include "global-handles.h"
+#include "natives.h"
+#include "stub-cache.h"
+#include "log.h"
+
+namespace v8 { namespace internal {
+
+static void PrintLn(v8::Local<v8::Value> value) {
+  v8::Local<v8::String> s = value->ToString();
+  char* data = NewArray<char>(s->Length() + 1);
+  if (data == NULL) {
+    V8::FatalProcessOutOfMemory("PrintLn");
+    return;
+  }
+  s->WriteAscii(data);
+  PrintF("%s\n", data);
+  DeleteArray(data);
+}
+
+
+static Handle<Code> ComputeCallDebugBreak(int argc) {
+  CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc), Code);
+}
+
+
+static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) {
+  CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code);
+}
+
+
+BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
+                                             BreakLocatorType type) {
+  debug_info_ = debug_info;
+  type_ = type;
+  reloc_iterator_ = NULL;
+  reloc_iterator_original_ = NULL;
+  Reset();  // Initialize the rest of the member variables.
+}
+
+
+BreakLocationIterator::~BreakLocationIterator() {
+  ASSERT(reloc_iterator_ != NULL);
+  ASSERT(reloc_iterator_original_ != NULL);
+  delete reloc_iterator_;
+  delete reloc_iterator_original_;
+}
+
+
+void BreakLocationIterator::Next() {
+  AssertNoAllocation nogc;
+  ASSERT(!RinfoDone());
+
+  // Iterate through reloc info for code and original code stopping at each
+  // breakable code target.
+  bool first = break_point_ == -1;
+  while (!RinfoDone()) {
+    if (!first) RinfoNext();
+    first = false;
+    if (RinfoDone()) return;
+
+    // Whenever a statement position or (plain) position is passed update the
+    // current value of these.
+    if (RelocInfo::IsPosition(rmode())) {
+      if (RelocInfo::IsStatementPosition(rmode())) {
+        statement_position_ =
+            rinfo()->data() - debug_info_->shared()->start_position();
+      }
+      // Always update the position as we don't want that to be before the
+      // statement position.
+      position_ = rinfo()->data() - debug_info_->shared()->start_position();
+      ASSERT(position_ >= 0);
+      ASSERT(statement_position_ >= 0);
+    }
+
+    // Check for breakable code target. Look in the original code as setting
+    // break points can cause the code targets in the running (debugged) code to
+    // be of a different kind than in the original code.
+    if (RelocInfo::IsCodeTarget(rmode())) {
+      Address target = original_rinfo()->target_address();
+      Code* code = Debug::GetCodeTarget(target);
+      if (code->is_inline_cache_stub() || RelocInfo::IsConstructCall(rmode())) {
+        break_point_++;
+        return;
+      }
+      if (code->kind() == Code::STUB) {
+        if (type_ == ALL_BREAK_LOCATIONS) {
+          if (Debug::IsBreakStub(code)) {
+            break_point_++;
+            return;
+          }
+        } else {
+          ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
+          if (Debug::IsSourceBreakStub(code)) {
+            break_point_++;
+            return;
+          }
+        }
+      }
+    }
+
+    // Check for break at return.
+    if (RelocInfo::IsJSReturn(rmode())) {
+      // Set the positions to the end of the function.
+      if (debug_info_->shared()->HasSourceCode()) {
+        position_ = debug_info_->shared()->end_position() -
+                    debug_info_->shared()->start_position();
+      } else {
+        position_ = 0;
+      }
+      statement_position_ = position_;
+      break_point_++;
+      return;
+    }
+  }
+}
+
+
+void BreakLocationIterator::Next(int count) {
+  while (count > 0) {
+    Next();
+    count--;
+  }
+}
+
+
+// Find the break point closest to the supplied address.
+void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
+  // Run through all break points to locate the one closest to the address.
+  int closest_break_point = 0;
+  int distance = kMaxInt;
+  while (!Done()) {
+    // Check if this break point is closer that what was previously found.
+    if (this->pc() < pc && pc - this->pc() < distance) {
+      closest_break_point = break_point();
+      distance = pc - this->pc();
+      // Check whether we can't get any closer.
+      if (distance == 0) break;
+    }
+    Next();
+  }
+
+  // Move to the break point found.
+  Reset();
+  Next(closest_break_point);
+}
+
+
+// Find the break point closest to the supplied source position.
+void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
+  // Run through all break points to locate the one closest to the source
+  // position.
+  int closest_break_point = 0;
+  int distance = kMaxInt;
+  while (!Done()) {
+    // Check if this break point is closer that what was previously found.
+    if (position <= statement_position() &&
+        statement_position() - position < distance) {
+      closest_break_point = break_point();
+      distance = statement_position() - position;
+      // Check whether we can't get any closer.
+      if (distance == 0) break;
+    }
+    Next();
+  }
+
+  // Move to the break point found.
+  Reset();
+  Next(closest_break_point);
+}
+
+
+void BreakLocationIterator::Reset() {
+  // Create relocation iterators for the two code objects.
+  if (reloc_iterator_ != NULL) delete reloc_iterator_;
+  if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
+  reloc_iterator_ = new RelocIterator(debug_info_->code());
+  reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
+
+  // Position at the first break point.
+  break_point_ = -1;
+  position_ = 1;
+  statement_position_ = 1;
+  Next();
+}
+
+
+bool BreakLocationIterator::Done() const {
+  return RinfoDone();
+}
+
+
+void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
+  // If there is not already a real break point here patch code with debug
+  // break.
+  if (!HasBreakPoint()) {
+    SetDebugBreak();
+  }
+  ASSERT(IsDebugBreak());
+  // Set the break point information.
+  DebugInfo::SetBreakPoint(debug_info_, code_position(),
+                           position(), statement_position(),
+                           break_point_object);
+}
+
+
+void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
+  // Clear the break point information.
+  DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
+  // If there are no more break points here remove the debug break.
+  if (!HasBreakPoint()) {
+    ClearDebugBreak();
+    ASSERT(!IsDebugBreak());
+  }
+}
+
+
+void BreakLocationIterator::SetOneShot() {
+  // If there is a real break point here no more to do.
+  if (HasBreakPoint()) {
+    ASSERT(IsDebugBreak());
+    return;
+  }
+
+  // Patch code with debug break.
+  SetDebugBreak();
+}
+
+
+void BreakLocationIterator::ClearOneShot() {
+  // If there is a real break point here no more to do.
+  if (HasBreakPoint()) {
+    ASSERT(IsDebugBreak());
+    return;
+  }
+
+  // Patch code removing debug break.
+  ClearDebugBreak();
+  ASSERT(!IsDebugBreak());
+}
+
+
+void BreakLocationIterator::SetDebugBreak() {
+  // If there is already a break point here just return. This might happen if
+  // the same code is flooded with break points twice. Flooding the same
+  // function twice might happen when stepping in a function with an exception
+  // handler as the handler and the function is the same.
+  if (IsDebugBreak()) {
+    return;
+  }
+
+  if (RelocInfo::IsJSReturn(rmode())) {
+    // This path is currently only used on IA32 as JSExitFrame on ARM uses a
+    // stub.
+    // Patch the JS frame exit code with a debug break call. See
+    // VisitReturnStatement and ExitJSFrame in codegen-ia32.cc for the
+    // precise return instructions sequence.
+    ASSERT(Debug::kIa32JSReturnSequenceLength >=
+           Debug::kIa32CallInstructionLength);
+    rinfo()->patch_code_with_call(Debug::debug_break_return_entry()->entry(),
+        Debug::kIa32JSReturnSequenceLength - Debug::kIa32CallInstructionLength);
+  } else {
+    // Patch the original code with the current address as the current address
+    // might have changed by the inline caching since the code was copied.
+    original_rinfo()->set_target_address(rinfo()->target_address());
+
+    // Patch the code to invoke the builtin debug break function matching the
+    // calling convention used by the call site.
+    Handle<Code> dbgbrk_code(Debug::FindDebugBreak(rinfo()));
+    rinfo()->set_target_address(dbgbrk_code->entry());
+  }
+  ASSERT(IsDebugBreak());
+}
+
+
+void BreakLocationIterator::ClearDebugBreak() {
+  if (RelocInfo::IsJSReturn(rmode())) {
+    // Restore the JS frame exit code.
+    rinfo()->patch_code(original_rinfo()->pc(),
+                        Debug::kIa32JSReturnSequenceLength);
+  } else {
+    // Patch the code to the original invoke.
+    rinfo()->set_target_address(original_rinfo()->target_address());
+  }
+  ASSERT(!IsDebugBreak());
+}
+
+
+void BreakLocationIterator::PrepareStepIn() {
+  // Step in can only be prepared if currently positioned on an IC call or
+  // construct call.
+  Address target = rinfo()->target_address();
+  Code* code = Debug::GetCodeTarget(target);
+  if (code->is_call_stub()) {
+    // Step in through IC call is handled by the runtime system. Therefore make
+    // sure that the any current IC is cleared and the runtime system is
+    // called. If the executing code has a debug break at the location change
+    // the call in the original code as it is the code there that will be
+    // executed in place of the debug break call.
+    Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count());
+    if (IsDebugBreak()) {
+      original_rinfo()->set_target_address(stub->entry());
+    } else {
+      rinfo()->set_target_address(stub->entry());
+    }
+  } else {
+    // Step in through constructs call requires no changes to the running code.
+    ASSERT(RelocInfo::IsConstructCall(rmode()));
+  }
+}
+
+
+// Check whether the break point is at a position which will exit the function.
+bool BreakLocationIterator::IsExit() const {
+  return (RelocInfo::IsJSReturn(rmode()));
+}
+
+
+bool BreakLocationIterator::HasBreakPoint() {
+  return debug_info_->HasBreakPoint(code_position());
+}
+
+
+// Check whether there is a debug break at the current position.
+bool BreakLocationIterator::IsDebugBreak() {
+  if (RelocInfo::IsJSReturn(rmode())) {
+    // This is IA32 specific but works as long as the ARM version
+    // still uses a stub for JSExitFrame.
+    //
+    // TODO(1240753): Make the test architecture independent or split
+    // parts of the debugger into architecture dependent files.
+    return (*(rinfo()->pc()) == 0xE8);
+  } else {
+    return Debug::IsDebugBreak(rinfo()->target_address());
+  }
+}
+
+
+Object* BreakLocationIterator::BreakPointObjects() {
+  return debug_info_->GetBreakPointObjects(code_position());
+}
+
+
+bool BreakLocationIterator::RinfoDone() const {
+  ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
+  return reloc_iterator_->done();
+}
+
+
+void BreakLocationIterator::RinfoNext() {
+  reloc_iterator_->next();
+  reloc_iterator_original_->next();
+#ifdef DEBUG
+  ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
+  if (!reloc_iterator_->done()) {
+    ASSERT(rmode() == original_rmode());
+  }
+#endif
+}
+
+
+bool Debug::has_break_points_ = false;
+DebugInfoListNode* Debug::debug_info_list_ = NULL;
+
+
+// Threading support.
+void Debug::ThreadInit() {
+  thread_local_.last_step_action_ = StepNone;
+  thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
+  thread_local_.step_count_ = 0;
+  thread_local_.last_fp_ = 0;
+  thread_local_.step_into_fp_ = 0;
+  thread_local_.after_break_target_ = 0;
+}
+
+
+JSCallerSavedBuffer Debug::registers_;
+Debug::ThreadLocal Debug::thread_local_;
+
+
+char* Debug::ArchiveDebug(char* storage) {
+  char* to = storage;
+  memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
+  to += sizeof(ThreadLocal);
+  memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
+  ThreadInit();
+  ASSERT(to <= storage + ArchiveSpacePerThread());
+  return storage + ArchiveSpacePerThread();
+}
+
+
+char* Debug::RestoreDebug(char* storage) {
+  char* from = storage;
+  memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
+  from += sizeof(ThreadLocal);
+  memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
+  ASSERT(from <= storage + ArchiveSpacePerThread());
+  return storage + ArchiveSpacePerThread();
+}
+
+
+int Debug::ArchiveSpacePerThread() {
+  return sizeof(ThreadLocal) + sizeof(registers_);
+}
+
+
+// Default break enabled.
+bool Debug::disable_break_ = false;
+
+// Default call debugger on uncaught exception.
+bool Debug::break_on_exception_ = false;
+bool Debug::break_on_uncaught_exception_ = true;
+
+Handle<Context> Debug::debug_context_ = Handle<Context>();
+Code* Debug::debug_break_return_entry_ = NULL;
+Code* Debug::debug_break_return_ = NULL;
+
+
+void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
+  DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
+  RemoveDebugInfo(node->debug_info());
+#ifdef DEBUG
+  node = Debug::debug_info_list_;
+  while (node != NULL) {
+    ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
+    node = node->next();
+  }
+#endif
+}
+
+
+DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
+  // Globalize the request debug info object and make it weak.
+  debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
+  GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
+                          this, Debug::HandleWeakDebugInfo);
+}
+
+
+DebugInfoListNode::~DebugInfoListNode() {
+  GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
+}
+
+
+void Debug::Setup(bool create_heap_objects) {
+  ThreadInit();
+  if (create_heap_objects) {
+    // Get code to handle entry to debug break on return.
+    debug_break_return_entry_ =
+        Builtins::builtin(Builtins::Return_DebugBreakEntry);
+    ASSERT(debug_break_return_entry_->IsCode());
+
+    // Get code to handle debug break on return.
+    debug_break_return_ =
+        Builtins::builtin(Builtins::Return_DebugBreak);
+    ASSERT(debug_break_return_->IsCode());
+  }
+}
+
+
+bool Debug::CompileDebuggerScript(int index) {
+  HandleScope scope;
+
+  // Bail out if the index is invalid.
+  if (index == -1) {
+    return false;
+  }
+
+  // Find source and name for the requested script.
+  Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
+  Vector<const char> name = Natives::GetScriptName(index);
+  Handle<String> script_name = Factory::NewStringFromAscii(name);
+
+  // Compile the script.
+  bool allow_natives_syntax = FLAG_allow_natives_syntax;
+  FLAG_allow_natives_syntax = true;
+  Handle<JSFunction> boilerplate;
+  boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL);
+  FLAG_allow_natives_syntax = allow_natives_syntax;
+
+  // Silently ignore stack overflows during compilation.
+  if (boilerplate.is_null()) {
+    ASSERT(Top::has_pending_exception());
+    Top::clear_pending_exception();
+    return false;
+  }
+
+  // Execute the boilerplate function in the debugger context.
+  Handle<Context> context = Top::global_context();
+  bool caught_exception = false;
+  Handle<JSFunction> function =
+      Factory::NewFunctionFromBoilerplate(boilerplate, context);
+  Handle<Object> result =
+      Execution::TryCall(function, Handle<Object>(context->global()),
+                         0, NULL, &caught_exception);
+
+  // Check for caught exceptions.
+  if (caught_exception) {
+    Handle<Object> message = MessageHandler::MakeMessageObject(
+        "error_loading_debugger", NULL, HandleVector<Object>(&result, 1),
+        Handle<String>());
+    MessageHandler::ReportMessage(NULL, message);
+    return false;
+  }
+
+  // Mark this script as native and return successfully.
+  Handle<Script> script(Script::cast(function->shared()->script()));
+  script->set_type(Smi::FromInt(SCRIPT_TYPE_NATIVE));
+  return true;
+}
+
+
+bool Debug::Load() {
+  // Return if debugger is already loaded.
+  if (IsLoaded()) return true;
+
+  // Bail out if we're already in the process of compiling the native
+  // JavaScript source code for the debugger.
+  if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
+    return false;
+  Debugger::set_loading_debugger(true);
+
+  // Disable breakpoints and interrupts while compiling and running the
+  // debugger scripts including the context creation code.
+  DisableBreak disable(true);
+  PostponeInterruptsScope postpone;
+
+  // Create the debugger context.
+  HandleScope scope;
+  Handle<Context> context =
+      Bootstrapper::CreateEnvironment(Handle<Object>::null(),
+                                      v8::Handle<ObjectTemplate>(),
+                                      NULL);
+
+  // Use the debugger context.
+  SaveContext save;
+  Top::set_context(*context);
+
+  // Expose the builtins object in the debugger context.
+  Handle<String> key = Factory::LookupAsciiSymbol("builtins");
+  Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
+  SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
+
+  // Compile the JavaScript for the debugger in the debugger context.
+  Debugger::set_compiling_natives(true);
+  bool caught_exception =
+      !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
+      !CompileDebuggerScript(Natives::GetIndex("debug"));
+  Debugger::set_compiling_natives(false);
+
+  // Make sure we mark the debugger as not loading before we might
+  // return.
+  Debugger::set_loading_debugger(false);
+
+  // Check for caught exceptions.
+  if (caught_exception) return false;
+
+  // Debugger loaded.
+  debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
+  return true;
+}
+
+
+void Debug::Unload() {
+  // Return debugger is not loaded.
+  if (!IsLoaded()) {
+    return;
+  }
+
+  // Clear debugger context global handle.
+  GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
+  debug_context_ = Handle<Context>();
+}
+
+
+void Debug::Iterate(ObjectVisitor* v) {
+#define VISIT(field) v->VisitPointer(bit_cast<Object**, Code**>(&(field)));
+  VISIT(debug_break_return_entry_);
+  VISIT(debug_break_return_);
+#undef VISIT
+}
+
+
+Object* Debug::Break(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 0);
+
+  // Get the top-most JavaScript frame.
+  JavaScriptFrameIterator it;
+  JavaScriptFrame* frame = it.frame();
+
+  // Just continue if breaks are disabled or debugger cannot be loaded.
+  if (disable_break() || !Load()) {
+    SetAfterBreakTarget(frame);
+    return Heap::undefined_value();
+  }
+
+  // Enter the debugger.
+  EnterDebugger debugger;
+  if (debugger.FailedToEnter()) {
+    return Heap::undefined_value();
+  }
+
+  // Postpone interrupt during breakpoint processing.
+  PostponeInterruptsScope postpone;
+
+  // Get the debug info (create it if it does not exist).
+  Handle<SharedFunctionInfo> shared =
+      Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
+  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
+
+  // Find the break point where execution has stopped.
+  BreakLocationIterator break_location_iterator(debug_info,
+                                                ALL_BREAK_LOCATIONS);
+  break_location_iterator.FindBreakLocationFromAddress(frame->pc());
+
+  // Check whether step next reached a new statement.
+  if (!StepNextContinue(&break_location_iterator, frame)) {
+    // Decrease steps left if performing multiple steps.
+    if (thread_local_.step_count_ > 0) {
+      thread_local_.step_count_--;
+    }
+  }
+
+  // If there is one or more real break points check whether any of these are
+  // triggered.
+  Handle<Object> break_points_hit(Heap::undefined_value());
+  if (break_location_iterator.HasBreakPoint()) {
+    Handle<Object> break_point_objects =
+        Handle<Object>(break_location_iterator.BreakPointObjects());
+    break_points_hit = CheckBreakPoints(break_point_objects);
+  }
+
+  // Notify debugger if a real break point is triggered or if performing single
+  // stepping with no more steps to perform. Otherwise do another step.
+  if (!break_points_hit->IsUndefined() ||
+    (thread_local_.last_step_action_ != StepNone &&
+     thread_local_.step_count_ == 0)) {
+    // Clear all current stepping setup.
+    ClearStepping();
+
+    // Notify the debug event listeners.
+    Debugger::OnDebugBreak(break_points_hit);
+  } 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_;
+
+    // Clear all current stepping setup.
+    ClearStepping();
+
+    // Set up for the remaining steps.
+    PrepareStep(step_action, step_count);
+  }
+
+  // Install jump to the call address which was overwritten.
+  SetAfterBreakTarget(frame);
+
+  return Heap::undefined_value();
+}
+
+
+// Check the break point objects for whether one or more are actually
+// triggered. This function returns a JSArray with the break point objects
+// which is triggered.
+Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
+  int break_points_hit_count = 0;
+  Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
+
+  // If there are multiple break points they are in a FixedArray.
+  ASSERT(!break_point_objects->IsUndefined());
+  if (break_point_objects->IsFixedArray()) {
+    Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
+    for (int i = 0; i < array->length(); i++) {
+      Handle<Object> o(array->get(i));
+      if (CheckBreakPoint(o)) {
+        break_points_hit->SetElement(break_points_hit_count++, *o);
+      }
+    }
+  } else {
+    if (CheckBreakPoint(break_point_objects)) {
+      break_points_hit->SetElement(break_points_hit_count++,
+                                   *break_point_objects);
+    }
+  }
+
+  // Return undefined if no break points where triggered.
+  if (break_points_hit_count == 0) {
+    return Factory::undefined_value();
+  }
+  return break_points_hit;
+}
+
+
+// Check whether a single break point object is triggered.
+bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
+  // Ignore check if break point object is not a JSObject.
+  if (!break_point_object->IsJSObject()) return true;
+
+  // Get the function CheckBreakPoint (defined in debug.js).
+  Handle<JSFunction> check_break_point =
+    Handle<JSFunction>(JSFunction::cast(
+      debug_context()->global()->GetProperty(
+          *Factory::LookupAsciiSymbol("IsBreakPointTriggered"))));
+
+  // Get the break id as an object.
+  Handle<Object> break_id = Factory::NewNumberFromInt(Top::break_id());
+
+  // Call HandleBreakPointx.
+  bool caught_exception = false;
+  const int argc = 2;
+  Object** argv[argc] = {
+    break_id.location(),
+    reinterpret_cast<Object**>(break_point_object.location())
+  };
+  Handle<Object> result = Execution::TryCall(check_break_point,
+                                             Top::builtins(), argc, argv,
+                                             &caught_exception);
+
+  // If exception or non boolean result handle as not triggered
+  if (caught_exception || !result->IsBoolean()) {
+    return false;
+  }
+
+  // Return whether the break point is triggered.
+  return *result == Heap::true_value();
+}
+
+
+// Check whether the function has debug information.
+bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
+  return !shared->debug_info()->IsUndefined();
+}
+
+
+// Return the debug info for this function. EnsureDebugInfo must be called
+// prior to ensure the debug info has been generated for shared.
+Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
+  ASSERT(HasDebugInfo(shared));
+  return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
+}
+
+
+void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
+                          int source_position,
+                          Handle<Object> break_point_object) {
+  if (!EnsureDebugInfo(shared)) {
+    // Return if retrieving debug info failed.
+    return;
+  }
+
+  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
+  // Source positions starts with zero.
+  ASSERT(source_position >= 0);
+
+  // Find the break point and change it.
+  BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
+  it.FindBreakLocationFromPosition(source_position);
+  it.SetBreakPoint(break_point_object);
+
+  // At least one active break point now.
+  ASSERT(debug_info->GetBreakPointCount() > 0);
+}
+
+
+void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
+  DebugInfoListNode* node = debug_info_list_;
+  while (node != NULL) {
+    Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
+                                                   break_point_object);
+    if (!result->IsUndefined()) {
+      // Get information in the break point.
+      BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
+      Handle<DebugInfo> debug_info = node->debug_info();
+      Handle<SharedFunctionInfo> shared(debug_info->shared());
+      int source_position =  break_point_info->statement_position()->value();
+
+      // Source positions starts with zero.
+      ASSERT(source_position >= 0);
+
+      // Find the break point and clear it.
+      BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
+      it.FindBreakLocationFromPosition(source_position);
+      it.ClearBreakPoint(break_point_object);
+
+      // If there are no more break points left remove the debug info for this
+      // function.
+      if (debug_info->GetBreakPointCount() == 0) {
+        RemoveDebugInfo(debug_info);
+      }
+
+      return;
+    }
+    node = node->next();
+  }
+}
+
+
+void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
+  // Make sure the function has setup the debug info.
+  if (!EnsureDebugInfo(shared)) {
+    // Return if we failed to retrieve the debug info.
+    return;
+  }
+
+  // Flood the function with break points.
+  BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
+  while (!it.Done()) {
+    it.SetOneShot();
+    it.Next();
+  }
+}
+
+
+void Debug::FloodHandlerWithOneShot() {
+  StackFrame::Id id = Top::break_frame_id();
+  for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
+    JavaScriptFrame* frame = it.frame();
+    if (frame->HasHandler()) {
+      Handle<SharedFunctionInfo> shared =
+          Handle<SharedFunctionInfo>(
+              JSFunction::cast(frame->function())->shared());
+      // Flood the function with the catch block with break points
+      FloodWithOneShot(shared);
+      return;
+    }
+  }
+}
+
+
+void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
+  if (type == BreakUncaughtException) {
+    break_on_uncaught_exception_ = enable;
+  } else {
+    break_on_exception_ = enable;
+  }
+}
+
+
+void Debug::PrepareStep(StepAction step_action, int step_count) {
+  HandleScope scope;
+  ASSERT(Debug::InDebugger());
+
+  // Remember this step action and count.
+  thread_local_.last_step_action_ = step_action;
+  thread_local_.step_count_ = step_count;
+
+  // Get the frame where the execution has stopped and skip the debug frame if
+  // any. The debug frame will only be present if execution was stopped due to
+  // hitting a break point. In other situations (e.g. unhandled exception) the
+  // debug frame is not present.
+  StackFrame::Id id = Top::break_frame_id();
+  JavaScriptFrameIterator frames_it(id);
+  JavaScriptFrame* frame = frames_it.frame();
+
+  // First of all ensure there is one-shot break points in the top handler
+  // if any.
+  FloodHandlerWithOneShot();
+
+  // If the function on the top frame is unresolved perform step out. This will
+  // be the case when calling unknown functions and having the debugger stopped
+  // in an unhandled exception.
+  if (!frame->function()->IsJSFunction()) {
+    // Step out: Find the calling JavaScript frame and flood it with
+    // breakpoints.
+    frames_it.Advance();
+    // Fill the function to return to with one-shot break points.
+    JSFunction* function = JSFunction::cast(frames_it.frame()->function());
+    FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
+    return;
+  }
+
+  // Get the debug info (create it if it does not exist).
+  Handle<SharedFunctionInfo> shared =
+      Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
+  if (!EnsureDebugInfo(shared)) {
+    // Return if ensuring debug info failed.
+    return;
+  }
+  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
+
+  // Find the break location where execution has stopped.
+  BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
+  it.FindBreakLocationFromAddress(frame->pc());
+
+  // Compute whether or not the target is a call target.
+  bool is_call_target = false;
+  if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
+    Address target = it.rinfo()->target_address();
+    Code* code = Debug::GetCodeTarget(target);
+    if (code->is_call_stub()) is_call_target = true;
+  }
+
+  // If this is the last break code target step out is the only possibility.
+  if (it.IsExit() || step_action == StepOut) {
+    // Step out: If there is a JavaScript caller frame, we need to
+    // flood it with breakpoints.
+    frames_it.Advance();
+    if (!frames_it.done()) {
+      // Fill the function to return to with one-shot break points.
+      JSFunction* function = JSFunction::cast(frames_it.frame()->function());
+      FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
+    }
+  } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) ||
+             step_action == StepNext || step_action == StepMin) {
+    // Step next or step min.
+
+    // Fill the current function with one-shot break points.
+    FloodWithOneShot(shared);
+
+    // Remember source position and frame to handle step next.
+    thread_local_.last_statement_position_ =
+        debug_info->code()->SourceStatementPosition(frame->pc());
+    thread_local_.last_fp_ = frame->fp();
+  } else {
+    // Fill the current function with one-shot break points even for step in on
+    // a call target as the function called might be a native function for
+    // which step in will not stop.
+    FloodWithOneShot(shared);
+
+    // Step in or Step in min
+    it.PrepareStepIn();
+    ActivateStepIn(frame);
+  }
+}
+
+
+// Check whether the current debug break should be reported to the debugger. It
+// is used to have step next and step in only report break back to the debugger
+// if on a different frame or in a different statement. In some situations
+// there will be several break points in the same statement when the code is
+// flooded with one-shot break points. This function helps to perform several
+// steps before reporting break back to the debugger.
+bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
+                             JavaScriptFrame* frame) {
+  // 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 ||
+      thread_local_.last_step_action_ == StepIn) {
+    // Never continue if returning from function.
+    if (break_location_iterator->IsExit()) return false;
+
+    // Continue if we are still on the same frame and in the same statement.
+    int current_statement_position =
+        break_location_iterator->code()->SourceStatementPosition(frame->pc());
+    return thread_local_.last_fp_ == frame->fp() &&
+        thread_local_.last_statement_position_ == current_statement_position;
+  }
+
+  // No step next action - don't continue.
+  return false;
+}
+
+
+// Check whether the code object at the specified address is a debug break code
+// object.
+bool Debug::IsDebugBreak(Address addr) {
+  Code* code = GetCodeTarget(addr);
+  return code->ic_state() == DEBUG_BREAK;
+}
+
+
+// Check whether a code stub with the specified major key is a possible break
+// point location when looking for source break locations.
+bool Debug::IsSourceBreakStub(Code* code) {
+  CodeStub::Major major_key = code->major_key();
+  return major_key == CodeStub::CallFunction;
+}
+
+
+// Check whether a code stub with the specified major key is a possible break
+// location.
+bool Debug::IsBreakStub(Code* code) {
+  CodeStub::Major major_key = code->major_key();
+  return major_key == CodeStub::CallFunction ||
+         major_key == CodeStub::StackCheck;
+}
+
+
+// Find the builtin to use for invoking the debug break
+Handle<Code> Debug::FindDebugBreak(RelocInfo* rinfo) {
+  // Find the builtin debug break function matching the calling convention
+  // used by the call site.
+  RelocInfo::Mode mode = rinfo->rmode();
+
+  if (RelocInfo::IsCodeTarget(mode)) {
+    Address target = rinfo->target_address();
+    Code* code = Debug::GetCodeTarget(target);
+    if (code->is_inline_cache_stub()) {
+      if (code->is_call_stub()) {
+        return ComputeCallDebugBreak(code->arguments_count());
+      }
+      if (code->is_load_stub()) {
+        return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
+      }
+      if (code->is_store_stub()) {
+        return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
+      }
+      if (code->is_keyed_load_stub()) {
+        Handle<Code> result =
+            Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
+        return result;
+      }
+      if (code->is_keyed_store_stub()) {
+        Handle<Code> result =
+            Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
+        return result;
+      }
+    }
+    if (RelocInfo::IsConstructCall(mode)) {
+      Handle<Code> result =
+          Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
+      return result;
+    }
+    if (code->kind() == Code::STUB) {
+      ASSERT(code->major_key() == CodeStub::CallFunction ||
+             code->major_key() == CodeStub::StackCheck);
+      Handle<Code> result =
+          Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
+      return result;
+    }
+  }
+
+  UNREACHABLE();
+  return Handle<Code>::null();
+}
+
+
+// Simple function for returning the source positions for active break points.
+Handle<Object> Debug::GetSourceBreakLocations(
+    Handle<SharedFunctionInfo> shared) {
+  if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
+  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
+  if (debug_info->GetBreakPointCount() == 0) {
+    return Handle<Object>(Heap::undefined_value());
+  }
+  Handle<FixedArray> locations =
+      Factory::NewFixedArray(debug_info->GetBreakPointCount());
+  int count = 0;
+  for (int i = 0; i < debug_info->break_points()->length(); i++) {
+    if (!debug_info->break_points()->get(i)->IsUndefined()) {
+      BreakPointInfo* break_point_info =
+          BreakPointInfo::cast(debug_info->break_points()->get(i));
+      if (break_point_info->GetBreakPointCount() > 0) {
+        locations->set(count++, break_point_info->statement_position());
+      }
+    }
+  }
+  return locations;
+}
+
+
+void Debug::ClearStepping() {
+  // Clear the various stepping setup.
+  ClearOneShot();
+  ClearStepIn();
+  ClearStepNext();
+
+  // Clear multiple step counter.
+  thread_local_.step_count_ = 0;
+}
+
+// Clears all the one-shot break points that are currently set. Normally this
+// function is called each time a break point is hit as one shot break points
+// are used to support stepping.
+void Debug::ClearOneShot() {
+  // The current implementation just runs through all the breakpoints. When the
+  // last break point for a function is removed that function is automatically
+  // removed from the list.
+
+  DebugInfoListNode* node = debug_info_list_;
+  while (node != NULL) {
+    BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
+    while (!it.Done()) {
+      it.ClearOneShot();
+      it.Next();
+    }
+    node = node->next();
+  }
+}
+
+
+void Debug::ActivateStepIn(StackFrame* frame) {
+  thread_local_.step_into_fp_ = frame->fp();
+}
+
+
+void Debug::ClearStepIn() {
+  thread_local_.step_into_fp_ = 0;
+}
+
+
+void Debug::ClearStepNext() {
+  thread_local_.last_step_action_ = StepNone;
+  thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
+  thread_local_.last_fp_ = 0;
+}
+
+
+bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
+  if (shared->is_compiled()) return true;
+  return CompileLazyShared(shared, CLEAR_EXCEPTION);
+}
+
+
+// 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;
+
+  // Ensure shared in compiled. Return false if this failed.
+  if (!EnsureCompiled(shared)) return false;
+
+  // Create the debug info object.
+  Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
+
+  // Add debug info to the list.
+  DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
+  node->set_next(debug_info_list_);
+  debug_info_list_ = node;
+
+  // Now there is at least one break point.
+  has_break_points_ = true;
+
+  return true;
+}
+
+
+void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
+  ASSERT(debug_info_list_ != NULL);
+  // Run through the debug info objects to find this one and remove it.
+  DebugInfoListNode* prev = NULL;
+  DebugInfoListNode* current = debug_info_list_;
+  while (current != NULL) {
+    if (*current->debug_info() == *debug_info) {
+      // Unlink from list. If prev is NULL we are looking at the first element.
+      if (prev == NULL) {
+        debug_info_list_ = current->next();
+      } else {
+        prev->set_next(current->next());
+      }
+      current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
+      delete current;
+
+      // If there are no more debug info objects there are not more break
+      // points.
+      has_break_points_ = debug_info_list_ != NULL;
+
+      return;
+    }
+    // Move to next in list.
+    prev = current;
+    current = current->next();
+  }
+  UNREACHABLE();
+}
+
+
+void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
+  // Get the executing function in which the debug break occurred.
+  Handle<SharedFunctionInfo> shared =
+      Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
+  if (!EnsureDebugInfo(shared)) {
+    // Return if we failed to retrieve the debug info.
+    return;
+  }
+  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
+  Handle<Code> code(debug_info->code());
+  Handle<Code> original_code(debug_info->original_code());
+#ifdef DEBUG
+  // Get the code which is actually executing.
+  Handle<Code> frame_code(frame->FindCode());
+  ASSERT(frame_code.is_identical_to(code));
+#endif
+
+  // Find the call address in the running code. This address holds the call to
+  // either a DebugBreakXXX or to the debug break return entry code if the
+  // break point is still active after processing the break point.
+  Address addr = frame->pc() - Assembler::kTargetAddrToReturnAddrDist;
+
+  // Check if the location is at JS exit.
+  bool at_js_exit = false;
+  RelocIterator it(debug_info->code());
+  while (!it.done()) {
+    if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
+      at_js_exit = it.rinfo()->pc() == addr - 1;
+    }
+    it.next();
+  }
+
+  // Handle the jump to continue execution after break point depending on the
+  // break location.
+  if (at_js_exit) {
+    // First check if the call in the code is still the debug break return
+    // entry code. If it is the break point is still active. If not the break
+    // point was removed during break point processing.
+    if (Assembler::target_address_at(addr) ==
+        debug_break_return_entry()->entry()) {
+      // Break point still active. Jump to the corresponding place in the
+      // original code.
+      addr +=  original_code->instruction_start() - code->instruction_start();
+    }
+
+    // Move one byte back to where the call instruction was placed.
+    thread_local_.after_break_target_ = addr - 1;
+  } else {
+    // Check if there still is a debug break call at the target address. If the
+    // break point has been removed it will have disappeared. If it have
+    // disappeared don't try to look in the original code as the running code
+    // will have the right address. This takes care of the case where the last
+    // break point is removed from the function and therefore no "original code"
+    // is available. If the debug break call is still there find the address in
+    // the original code.
+    if (IsDebugBreak(Assembler::target_address_at(addr))) {
+      // If the break point is still there find the call address which was
+      // overwritten in the original code by the call to DebugBreakXXX.
+
+      // Find the corresponding address in the original code.
+      addr += original_code->instruction_start() - code->instruction_start();
+    }
+
+    // Install jump to the call address in the original code. This will be the
+    // call which was overwritten by the call to DebugBreakXXX.
+    thread_local_.after_break_target_ = Assembler::target_address_at(addr);
+  }
+}
+
+
+Code* Debug::GetCodeTarget(Address target) {
+  // Maybe this can be refactored with the stuff in ic-inl.h?
+  Code* result =
+      Code::cast(HeapObject::FromAddress(target - Code::kHeaderSize));
+  return result;
+}
+
+
+bool Debug::IsDebugGlobal(GlobalObject* global) {
+  return IsLoaded() && global == Debug::debug_context()->global();
+}
+
+
+bool Debugger::debugger_active_ = false;
+bool Debugger::compiling_natives_ = false;
+bool Debugger::is_loading_debugger_ = false;
+DebugMessageThread* Debugger::message_thread_ = NULL;
+v8::DebugMessageHandler Debugger::debug_message_handler_ = NULL;
+void* Debugger::debug_message_handler_data_ = NULL;
+
+
+Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
+                                      int argc, Object*** argv,
+                                      bool* caught_exception) {
+  ASSERT(Top::context() == *Debug::debug_context());
+
+  // Create the execution state object.
+  Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
+  Handle<Object> constructor(Top::global()->GetProperty(*constructor_str));
+  ASSERT(constructor->IsJSFunction());
+  if (!constructor->IsJSFunction()) {
+    *caught_exception = true;
+    return Factory::undefined_value();
+  }
+  Handle<Object> js_object = Execution::TryCall(
+      Handle<JSFunction>::cast(constructor),
+      Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
+      caught_exception);
+  return js_object;
+}
+
+
+Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
+  // Create the execution state object.
+  Handle<Object> break_id = Factory::NewNumberFromInt(Top::break_id());
+  const int argc = 1;
+  Object** argv[argc] = { break_id.location() };
+  return MakeJSObject(CStrVector("MakeExecutionState"),
+                      argc, argv, caught_exception);
+}
+
+
+Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
+                                        Handle<Object> break_points_hit,
+                                        bool* caught_exception) {
+  // Create the new break event object.
+  const int argc = 2;
+  Object** argv[argc] = { exec_state.location(),
+                          break_points_hit.location() };
+  return MakeJSObject(CStrVector("MakeBreakEvent"),
+                      argc,
+                      argv,
+                      caught_exception);
+}
+
+
+Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
+                                            Handle<Object> exception,
+                                            bool uncaught,
+                                            bool* caught_exception) {
+  // Create the new exception event object.
+  const int argc = 3;
+  Object** argv[argc] = { exec_state.location(),
+                          exception.location(),
+                          uncaught ? Factory::true_value().location() :
+                                     Factory::false_value().location()};
+  return MakeJSObject(CStrVector("MakeExceptionEvent"),
+                      argc, argv, caught_exception);
+}
+
+
+Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
+                                              bool* caught_exception) {
+  // Create the new function event object.
+  const int argc = 1;
+  Object** argv[argc] = { function.location() };
+  return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
+                      argc, argv, caught_exception);
+}
+
+
+Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
+                                          Handle<Object> script_function,
+                                          bool* caught_exception) {
+  // Create the compile event object.
+  Handle<Object> exec_state = MakeExecutionState(caught_exception);
+  Handle<Object> script_source(script->source());
+  Handle<Object> script_name(script->name());
+  const int argc = 3;
+  Object** argv[argc] = { script_source.location(),
+                          script_name.location(),
+                          script_function.location() };
+  return MakeJSObject(CStrVector("MakeCompileEvent"),
+                      argc,
+                      argv,
+                      caught_exception);
+}
+
+
+Handle<String> Debugger::ProcessRequest(Handle<Object> exec_state,
+                                        Handle<Object> request,
+                                        bool stopped) {
+  // Get the function ProcessDebugRequest (declared in debug.js).
+  Handle<JSFunction> process_denbug_request =
+    Handle<JSFunction>(JSFunction::cast(
+    Debug::debug_context()->global()->GetProperty(
+        *Factory::LookupAsciiSymbol("ProcessDebugRequest"))));
+
+  // Call ProcessDebugRequest expect String result. The ProcessDebugRequest
+  // will never throw an exception (see debug.js).
+  bool caught_exception;
+  const int argc = 3;
+  Object** argv[argc] = { exec_state.location(),
+                          request.location(),
+                          stopped ? Factory::true_value().location() :
+                                    Factory::false_value().location()};
+  Handle<Object> result = Execution::TryCall(process_denbug_request,
+                                             Factory::undefined_value(),
+                                             argc, argv,
+                                             &caught_exception);
+  if (caught_exception) {
+    return Factory::empty_symbol();
+  }
+
+  return Handle<String>::cast(result);
+}
+
+
+void Debugger::OnException(Handle<Object> exception, bool uncaught) {
+  HandleScope scope;
+
+  // Bail out based on state or if there is no listener for this event
+  if (Debug::InDebugger()) return;
+  if (!Debugger::EventActive(v8::Exception)) return;
+
+  // Bail out if exception breaks are not active
+  if (uncaught) {
+    // Uncaught exceptions are reported by either flags.
+    if (!(Debug::break_on_uncaught_exception() ||
+          Debug::break_on_exception())) return;
+  } else {
+    // Caught exceptions are reported is activated.
+    if (!Debug::break_on_exception()) return;
+  }
+
+  // Enter the debugger.
+  EnterDebugger debugger;
+  if (debugger.FailedToEnter()) return;
+
+  // Clear all current stepping setup.
+  Debug::ClearStepping();
+  // Create the event data object.
+  bool caught_exception = false;
+  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
+  Handle<Object> event_data;
+  if (!caught_exception) {
+    event_data = MakeExceptionEvent(exec_state, exception, uncaught,
+                                    &caught_exception);
+  }
+  // Bail out and don't call debugger if exception.
+  if (caught_exception) {
+    return;
+  }
+
+  // Process debug event
+  ProcessDebugEvent(v8::Exception, event_data);
+  // Return to continue execution from where the exception was thrown.
+}
+
+
+void Debugger::OnDebugBreak(Handle<Object> break_points_hit) {
+  HandleScope scope;
+
+  // Debugger has already been entered by caller.
+  ASSERT(Top::context() == *Debug::debug_context());
+
+  // Bail out if there is no listener for this event
+  if (!Debugger::EventActive(v8::Break)) return;
+
+  // Debugger must be entered in advance.
+  ASSERT(Top::context() == *Debug::debug_context());
+
+  // Create the event data object.
+  bool caught_exception = false;
+  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
+  Handle<Object> event_data;
+  if (!caught_exception) {
+    event_data = MakeBreakEvent(exec_state, break_points_hit,
+                                &caught_exception);
+  }
+  // Bail out and don't call debugger if exception.
+  if (caught_exception) {
+    return;
+  }
+
+  // Process debug event
+  ProcessDebugEvent(v8::Break, event_data);
+}
+
+
+void Debugger::OnBeforeCompile(Handle<Script> script) {
+  HandleScope scope;
+
+  // Bail out based on state or if there is no listener for this event
+  if (Debug::InDebugger()) return;
+  if (compiling_natives()) return;
+  if (!EventActive(v8::BeforeCompile)) return;
+
+  // Enter the debugger.
+  EnterDebugger debugger;
+  if (debugger.FailedToEnter()) return;
+
+  // Create the event data object.
+  bool caught_exception = false;
+  Handle<Object> event_data = MakeCompileEvent(script,
+                                               Factory::undefined_value(),
+                                               &caught_exception);
+  // Bail out and don't call debugger if exception.
+  if (caught_exception) {
+    return;
+  }
+
+  // Process debug event
+  ProcessDebugEvent(v8::BeforeCompile, event_data);
+}
+
+
+// Handle debugger actions when a new script is compiled.
+void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
+  HandleScope scope;
+
+  // No compile events while compiling natives.
+  if (compiling_natives()) return;
+
+  // No more to do if not debugging.
+  if (!debugger_active()) return;
+
+  // Enter the debugger.
+  EnterDebugger debugger;
+  if (debugger.FailedToEnter()) return;
+
+  // If debugging there might be script break points registered for this
+  // script. Make sure that these break points are set.
+
+  // Get the function UpdateScriptBreakPoints (defined in debug-delay.js).
+  Handle<Object> update_script_break_points =
+      Handle<Object>(Debug::debug_context()->global()->GetProperty(
+          *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
+  if (!update_script_break_points->IsJSFunction()) {
+    return;
+  }
+  ASSERT(update_script_break_points->IsJSFunction());
+
+  // Wrap the script object in a proper JS object before passing it
+  // to JavaScript.
+  Handle<JSValue> wrapper = GetScriptWrapper(script);
+
+  // Call UpdateScriptBreakPoints expect no exceptions.
+  bool caught_exception = false;
+  const int argc = 1;
+  Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
+  Handle<Object> result = Execution::TryCall(
+      Handle<JSFunction>::cast(update_script_break_points),
+      Top::builtins(), argc, argv,
+      &caught_exception);
+  if (caught_exception) {
+    return;
+  }
+  // Bail out based on state or if there is no listener for this event
+  if (Debug::InDebugger()) return;
+  if (!Debugger::EventActive(v8::AfterCompile)) return;
+
+  // Create the compile state object.
+  Handle<Object> event_data = MakeCompileEvent(script,
+                                               Factory::undefined_value(),
+                                               &caught_exception);
+  // Bail out and don't call debugger if exception.
+  if (caught_exception) {
+    return;
+  }
+  // Process debug event
+  ProcessDebugEvent(v8::AfterCompile, event_data);
+}
+
+
+void Debugger::OnNewFunction(Handle<JSFunction> function) {
+  return;
+  HandleScope scope;
+
+  // Bail out based on state or if there is no listener for this event
+  if (Debug::InDebugger()) return;
+  if (compiling_natives()) return;
+  if (!Debugger::EventActive(v8::NewFunction)) return;
+
+  // Enter the debugger.
+  EnterDebugger debugger;
+  if (debugger.FailedToEnter()) return;
+
+  // Create the event object.
+  bool caught_exception = false;
+  Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception);
+  // Bail out and don't call debugger if exception.
+  if (caught_exception) {
+    return;
+  }
+  // Process debug event.
+  ProcessDebugEvent(v8::NewFunction, event_data);
+}
+
+
+void Debugger::ProcessDebugEvent(v8::DebugEvent event,
+                                 Handle<Object> event_data) {
+  // Create the execution state.
+  bool caught_exception = false;
+  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
+  if (caught_exception) {
+    return;
+  }
+  // First notify the builtin debugger.
+  if (message_thread_ != NULL) {
+    message_thread_->DebugEvent(event, exec_state, event_data);
+  }
+  // Notify registered debug event listeners. The list can contain both C and
+  // JavaScript functions.
+  v8::NeanderArray listeners(Factory::debug_event_listeners());
+  int length = listeners.length();
+  for (int i = 0; i < length; i++) {
+    if (listeners.get(i)->IsUndefined()) continue;   // Skip deleted ones.
+    v8::NeanderObject listener(JSObject::cast(listeners.get(i)));
+    Handle<Object> callback_data(listener.get(1));
+    if (listener.get(0)->IsProxy()) {
+      // C debug event listener.
+      Handle<Proxy> callback_obj(Proxy::cast(listener.get(0)));
+      v8::DebugEventCallback callback =
+            FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy());
+      callback(event,
+               v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
+               v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)),
+               v8::Utils::ToLocal(callback_data));
+    } else {
+      // JavaScript debug event listener.
+      ASSERT(listener.get(0)->IsJSFunction());
+      Handle<JSFunction> fun(JSFunction::cast(listener.get(0)));
+
+      // Invoke the JavaScript debug event listener.
+      const int argc = 4;
+      Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
+                              exec_state.location(),
+                              event_data.location(),
+                              callback_data.location() };
+      Handle<Object> result = Execution::TryCall(fun, Top::global(),
+                                                 argc, argv, &caught_exception);
+      if (caught_exception) {
+        // Silently ignore exceptions from debug event listeners.
+      }
+    }
+  }
+}
+
+
+void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data) {
+  debug_message_handler_ = handler;
+  debug_message_handler_data_ = data;
+  if (!message_thread_) {
+    message_thread_  = new DebugMessageThread();
+    message_thread_->Start();
+  }
+  UpdateActiveDebugger();
+}
+
+
+// Posts an output message from the debugger to the debug_message_handler
+// callback.  This callback is part of the public API.  Messages are
+// kept internally as Vector<uint16_t> strings, which are allocated in various
+// places and deallocated by the calling function sometime after this call.
+void Debugger::SendMessage(Vector< uint16_t> message) {
+  if (debug_message_handler_ != NULL) {
+    debug_message_handler_(message.start(), message.length(),
+                           debug_message_handler_data_);
+  }
+}
+
+
+void Debugger::ProcessCommand(Vector<const uint16_t> command) {
+  if (message_thread_ != NULL) {
+    message_thread_->ProcessCommand(
+        Vector<uint16_t>(const_cast<uint16_t *>(command.start()),
+                         command.length()));
+  }
+}
+
+
+void Debugger::UpdateActiveDebugger() {
+  v8::NeanderArray listeners(Factory::debug_event_listeners());
+  int length = listeners.length();
+  bool active_listener = false;
+  for (int i = 0; i < length && !active_listener; i++) {
+    active_listener = !listeners.get(i)->IsUndefined();
+  }
+  set_debugger_active((Debugger::message_thread_ != NULL &&
+                       Debugger::debug_message_handler_ != NULL) ||
+                       active_listener);
+  if (!debugger_active() && message_thread_)
+    message_thread_->OnDebuggerInactive();
+}
+
+
+DebugMessageThread::DebugMessageThread()
+    : host_running_(true),
+      command_queue_(kQueueInitialSize),
+      message_queue_(kQueueInitialSize) {
+  command_received_ = OS::CreateSemaphore(0);
+  message_received_ = OS::CreateSemaphore(0);
+}
+
+// Does not free resources held by DebugMessageThread
+// because this cannot be done thread-safely.
+DebugMessageThread::~DebugMessageThread() {
+}
+
+
+// Puts an event coming from V8 on the queue.  Creates
+// a copy of the JSON formatted event string managed by the V8.
+// Called by the V8 thread.
+// The new copy of the event string is destroyed in Run().
+void DebugMessageThread::SendMessage(Vector<uint16_t> message) {
+  Vector<uint16_t> message_copy = message.Clone();
+  Logger::DebugTag("Put message on event message_queue.");
+  message_queue_.Put(message_copy);
+  message_received_->Signal();
+}
+
+
+void DebugMessageThread::SetEventJSONFromEvent(Handle<Object> event_data) {
+  v8::HandleScope scope;
+  // Call toJSONProtocol on the debug event object.
+  v8::Local<v8::Object> api_event_data =
+      v8::Utils::ToLocal(Handle<JSObject>::cast(event_data));
+  v8::Local<v8::String> fun_name = v8::String::New("toJSONProtocol");
+  v8::Local<v8::Function> fun =
+      v8::Function::Cast(*api_event_data->Get(fun_name));
+  v8::TryCatch try_catch;
+  v8::Local<v8::Value> json_event = *fun->Call(api_event_data, 0, NULL);
+  v8::Local<v8::String> json_event_string;
+  if (!try_catch.HasCaught()) {
+    if (!json_event->IsUndefined()) {
+      json_event_string = json_event->ToString();
+      if (FLAG_trace_debug_json) {
+        PrintLn(json_event_string);
+      }
+      v8::String::Value val(json_event_string);
+      Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
+                           json_event_string->Length());
+      SendMessage(str);
+    } else {
+      SendMessage(Vector<uint16_t>::empty());
+    }
+  } else {
+    PrintLn(try_catch.Exception());
+    SendMessage(Vector<uint16_t>::empty());
+  }
+}
+
+
+void DebugMessageThread::Run() {
+  // Sends debug events to an installed debugger message callback.
+  while (true) {
+    // Wait and Get are paired so that semaphore count equals queue length.
+    message_received_->Wait();
+    Logger::DebugTag("Get message from event message_queue.");
+    Vector<uint16_t> message = message_queue_.Get();
+    if (message.length() > 0) {
+      Debugger::SendMessage(message);
+    }
+  }
+}
+
+
+// This method is called by the V8 thread whenever a debug event occurs in
+// the VM.
+void DebugMessageThread::DebugEvent(v8::DebugEvent event,
+                                    Handle<Object> exec_state,
+                                    Handle<Object> event_data) {
+  if (!Debug::Load()) return;
+
+  // Process the individual events.
+  bool interactive = false;
+  switch (event) {
+    case v8::Break:
+      interactive = true;  // Break event is always interactive
+      break;
+    case v8::Exception:
+      interactive = true;  // Exception event is always interactive
+      break;
+    case v8::BeforeCompile:
+      break;
+    case v8::AfterCompile:
+      break;
+    case v8::NewFunction:
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  // Done if not interactive.
+  if (!interactive) return;
+
+  // Get the DebugCommandProcessor.
+  v8::Local<v8::Object> api_exec_state =
+      v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
+  v8::Local<v8::String> fun_name =
+      v8::String::New("debugCommandProcessor");
+  v8::Local<v8::Function> fun =
+      v8::Function::Cast(*api_exec_state->Get(fun_name));
+  v8::TryCatch try_catch;
+  v8::Local<v8::Object> cmd_processor =
+      v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL));
+  if (try_catch.HasCaught()) {
+    PrintLn(try_catch.Exception());
+    return;
+  }
+
+  // Notify the debugger that a debug event has occurred.
+  host_running_ = false;
+  SetEventJSONFromEvent(event_data);
+
+  // Wait for commands from the debugger.
+  while (true) {
+    command_received_->Wait();
+    Logger::DebugTag("Get command from command queue, in interactive loop.");
+    Vector<uint16_t> command = command_queue_.Get();
+    ASSERT(!host_running_);
+    if (!Debugger::debugger_active()) {
+      host_running_ = true;
+      return;
+    }
+
+    // Invoke the JavaScript to convert the debug command line to a JSON
+    // request, invoke the JSON request and convert the JSON response to a text
+    // representation.
+    v8::Local<v8::String> fun_name;
+    v8::Local<v8::Function> fun;
+    v8::Local<v8::Value> args[1];
+    v8::TryCatch try_catch;
+    fun_name = v8::String::New("processDebugCommand");
+    fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
+    args[0] = v8::String::New(reinterpret_cast<uint16_t*>(command.start()),
+                              command.length());
+    v8::Local<v8::Value> result_val = fun->Call(cmd_processor, 1, args);
+
+    // Get the result of the command.
+    v8::Local<v8::String> result_string;
+    bool running = false;
+    if (!try_catch.HasCaught()) {
+      // Get the result as an object.
+      v8::Local<v8::Object> result = v8::Object::Cast(*result_val);
+
+      // Log the JSON request/response.
+      if (FLAG_trace_debug_json) {
+        PrintLn(result->Get(v8::String::New("request")));
+        PrintLn(result->Get(v8::String::New("response")));
+      }
+
+      // Get the running state.
+      running = result->Get(v8::String::New("running"))->ToBoolean()->Value();
+
+      // Get result text.
+      v8::Local<v8::Value> text_result =
+          result->Get(v8::String::New("response"));
+      if (!text_result->IsUndefined()) {
+        result_string = text_result->ToString();
+      } else {
+        result_string = v8::String::New("");
+      }
+    } else {
+      // In case of failure the result text is the exception text.
+      result_string = try_catch.Exception()->ToString();
+    }
+
+    // Convert text result to C string.
+    v8::String::Value val(result_string);
+    Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
+                        result_string->Length());
+
+    // Set host_running_ correctly for nested debugger evaluations.
+    host_running_ = running;
+
+    // Return the result.
+    SendMessage(str);
+
+    // Return from debug event processing is VM should be running.
+    if (running) {
+      return;
+    }
+  }
+}
+
+
+// Puts a command coming from the public API on the queue.  Creates
+// a copy of the command string managed by the debugger.  Up to this
+// point, the command data was managed by the API client.  Called
+// by the API client thread.  This is where the API client hands off
+// processing of the command to the DebugMessageThread thread.
+// The new copy of the command is destroyed in HandleCommand().
+void DebugMessageThread::ProcessCommand(Vector<uint16_t> command) {
+  Vector<uint16_t> command_copy = command.Clone();
+  Logger::DebugTag("Put command on command_queue.");
+  command_queue_.Put(command_copy);
+  command_received_->Signal();
+}
+
+
+void DebugMessageThread::OnDebuggerInactive() {
+  // Send an empty command to the debugger if in a break to make JavaScript run
+  // again if the debugger is closed.
+  if (!host_running_) {
+    ProcessCommand(Vector<uint16_t>::empty());
+  }
+}
+
+
+MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) {
+  messages_ = NewArray<Vector<uint16_t> >(size);
+}
+
+
+MessageQueue::~MessageQueue() {
+  DeleteArray(messages_);
+}
+
+
+Vector<uint16_t> MessageQueue::Get() {
+  ASSERT(!IsEmpty());
+  int result = start_;
+  start_ = (start_ + 1) % size_;
+  return messages_[result];
+}
+
+
+void MessageQueue::Put(const Vector<uint16_t>& message) {
+  if ((end_ + 1) % size_ == start_) {
+    Expand();
+  }
+  messages_[end_] = message;
+  end_ = (end_ + 1) % size_;
+}
+
+
+void MessageQueue::Expand() {
+  MessageQueue new_queue(size_ * 2);
+  while (!IsEmpty()) {
+    new_queue.Put(Get());
+  }
+  Vector<uint16_t>* array_to_free = messages_;
+  *this = new_queue;
+  new_queue.messages_ = array_to_free;
+  // Automatic destructor called on new_queue, freeing array_to_free.
+}
+
+
+LockingMessageQueue::LockingMessageQueue(int size) : queue_(size) {
+  lock_ = OS::CreateMutex();
+}
+
+
+LockingMessageQueue::~LockingMessageQueue() {
+  delete lock_;
+}
+
+
+bool LockingMessageQueue::IsEmpty() const {
+  ScopedLock sl(lock_);
+  return queue_.IsEmpty();
+}
+
+
+Vector<uint16_t> LockingMessageQueue::Get() {
+  ScopedLock sl(lock_);
+  Vector<uint16_t> result = queue_.Get();
+  Logger::DebugEvent("Get", result);
+  return result;
+}
+
+
+void LockingMessageQueue::Put(const Vector<uint16_t>& message) {
+  ScopedLock sl(lock_);
+  queue_.Put(message);
+  Logger::DebugEvent("Put", message);
+}
+
+
+void LockingMessageQueue::Clear() {
+  ScopedLock sl(lock_);
+  queue_.Clear();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/debug.h b/regexp2000/src/debug.h
new file mode 100644 (file)
index 0000000..69e2aaa
--- /dev/null
@@ -0,0 +1,582 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_V8_DEBUG_H_
+#define V8_V8_DEBUG_H_
+
+#include "../include/v8-debug.h"
+#include "assembler.h"
+#include "code-stubs.h"
+#include "execution.h"
+#include "factory.h"
+#include "platform.h"
+#include "string-stream.h"
+
+
+namespace v8 { namespace internal {
+
+// Step actions. NOTE: These values are in macros.py as well.
+enum StepAction {
+  StepNone = -1,  // Stepping not prepared.
+  StepOut = 0,   // Step out of the current function.
+  StepNext = 1,  // Step to the next statement in the current function.
+  StepIn = 2,    // Step into new functions invoked or the next statement
+                 // in the current function.
+  StepMin = 3,   // Perform a minimum step in the current function.
+  StepInMin = 4  // Step into new functions invoked or perform a minimum step
+                 // in the current function.
+};
+
+
+// Type of exception break. NOTE: These values are in macros.py as well.
+enum ExceptionBreakType {
+  BreakException = 0,
+  BreakUncaughtException = 1
+};
+
+
+// Type of exception break. NOTE: These values are in macros.py as well.
+enum BreakLocatorType {
+  ALL_BREAK_LOCATIONS = 0,
+  SOURCE_BREAK_LOCATIONS = 1
+};
+
+
+// Class for iterating through the break points in a function and changing
+// them.
+class BreakLocationIterator {
+ public:
+  explicit BreakLocationIterator(Handle<DebugInfo> debug_info,
+                                 BreakLocatorType type);
+  virtual ~BreakLocationIterator();
+
+  void Next();
+  void Next(int count);
+  void FindBreakLocationFromAddress(Address pc);
+  void FindBreakLocationFromPosition(int position);
+  void Reset();
+  bool Done() const;
+  void SetBreakPoint(Handle<Object> break_point_object);
+  void ClearBreakPoint(Handle<Object> break_point_object);
+  void SetOneShot();
+  void ClearOneShot();
+  void PrepareStepIn();
+  bool IsExit() const;
+  bool HasBreakPoint();
+  bool IsDebugBreak();
+  Object* BreakPointObjects();
+
+
+  inline int code_position() { return pc() - debug_info_->code()->entry(); }
+  inline int break_point() { return break_point_; }
+  inline int position() { return position_; }
+  inline int statement_position() { return statement_position_; }
+  inline Address pc() { return reloc_iterator_->rinfo()->pc(); }
+  inline Code* code() { return debug_info_->code(); }
+  inline RelocInfo* rinfo() { return reloc_iterator_->rinfo(); }
+  inline RelocInfo::Mode rmode() const {
+    return reloc_iterator_->rinfo()->rmode();
+  }
+  inline RelocInfo* original_rinfo() {
+    return reloc_iterator_original_->rinfo();
+  }
+  inline RelocInfo::Mode original_rmode() const {
+    return reloc_iterator_original_->rinfo()->rmode();
+  }
+
+ protected:
+  bool RinfoDone() const;
+  void RinfoNext();
+
+  BreakLocatorType type_;
+  int break_point_;
+  int position_;
+  int statement_position_;
+  Handle<DebugInfo> debug_info_;
+  RelocIterator* reloc_iterator_;
+  RelocIterator* reloc_iterator_original_;
+
+ private:
+  void SetDebugBreak();
+  void ClearDebugBreak();
+
+  DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator);
+};
+
+
+// Linked list holding debug info objects. The debug info objects are kept as
+// weak handles to avoid a debug info object to keep a function alive.
+class DebugInfoListNode {
+ public:
+  explicit DebugInfoListNode(DebugInfo* debug_info);
+  virtual ~DebugInfoListNode();
+
+  DebugInfoListNode* next() { return next_; }
+  void set_next(DebugInfoListNode* next) { next_ = next; }
+  Handle<DebugInfo> debug_info() { return debug_info_; }
+
+ private:
+  // Global (weak) handle to the debug info object.
+  Handle<DebugInfo> debug_info_;
+
+  // Next pointer for linked list.
+  DebugInfoListNode* next_;
+};
+
+
+// This class contains the debugger support. The main purpose is to handle
+// setting break points in the code.
+//
+// This class controls the debug info for all functions which currently have
+// active breakpoints in them. This debug info is held in the heap root object
+// debug_info which is a FixedArray. Each entry in this list is of class
+// DebugInfo.
+class Debug {
+ public:
+  static void Setup(bool create_heap_objects);
+  static bool Load();
+  static void Unload();
+  static bool IsLoaded() { return !debug_context_.is_null(); }
+  static bool InDebugger() { return Top::is_break(); }
+  static void Iterate(ObjectVisitor* v);
+
+  static Object* Break(Arguments args);
+  static void SetBreakPoint(Handle<SharedFunctionInfo> shared,
+                            int source_position,
+                            Handle<Object> break_point_object);
+  static void ClearBreakPoint(Handle<Object> break_point_object);
+  static void FloodWithOneShot(Handle<SharedFunctionInfo> shared);
+  static void FloodHandlerWithOneShot();
+  static void ChangeBreakOnException(ExceptionBreakType type, bool enable);
+  static void PrepareStep(StepAction step_action, int step_count);
+  static void ClearStepping();
+  static bool StepNextContinue(BreakLocationIterator* break_location_iterator,
+                               JavaScriptFrame* frame);
+  static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
+  static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
+
+  // Returns whether the operation succedded.
+  static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
+
+  static bool IsDebugBreak(Address addr);
+
+  // Check whether a code stub with the specified major key is a possible break
+  // point location.
+  static bool IsSourceBreakStub(Code* code);
+  static bool IsBreakStub(Code* code);
+
+  // Find the builtin to use for invoking the debug break
+  static Handle<Code> FindDebugBreak(RelocInfo* rinfo);
+
+  static Handle<Object> GetSourceBreakLocations(
+      Handle<SharedFunctionInfo> shared);
+  static Code* GetCodeTarget(Address target);
+
+  // Getter for the debug_context.
+  inline static Handle<Context> debug_context() { return debug_context_; }
+
+  // Check whether a global object is the debug global object.
+  static bool IsDebugGlobal(GlobalObject* global);
+
+  // Fast check to see if any break points are active.
+  inline static bool has_break_points() { return has_break_points_; }
+
+  static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
+  static Address step_in_fp() { return thread_local_.step_into_fp_; }
+  static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; }
+
+  // Getter and setter for the disable break state.
+  static bool disable_break() { return disable_break_; }
+  static void set_disable_break(bool disable_break) {
+    disable_break_ = disable_break;
+  }
+
+  // Getters for the current exception break state.
+  static bool break_on_exception() { return break_on_exception_; }
+  static bool break_on_uncaught_exception() {
+    return break_on_uncaught_exception_;
+  }
+
+  enum AddressId {
+    k_after_break_target_address,
+    k_debug_break_return_address,
+    k_register_address
+  };
+
+  // Support for setting the address to jump to when returning from break point.
+  static Address* after_break_target_address() {
+    return reinterpret_cast<Address*>(&thread_local_.after_break_target_);
+  }
+
+  // Support for saving/restoring registers when handling debug break calls.
+  static Object** register_address(int r) {
+    return &registers_[r];
+  }
+
+  // Address of the debug break return entry code.
+  static Code* debug_break_return_entry() { return debug_break_return_entry_; }
+
+  // Support for getting the address of the debug break on return code.
+  static Code** debug_break_return_address() {
+    return &debug_break_return_;
+  }
+
+  static const int kEstimatedNofDebugInfoEntries = 16;
+  static const int kEstimatedNofBreakPointsInFunction = 16;
+
+  static void HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data);
+
+  friend class Debugger;
+  friend Handle<FixedArray> GetDebuggedFunctions();  // Found in test-debug.cc
+
+  // Threading support.
+  static char* ArchiveDebug(char* to);
+  static char* RestoreDebug(char* from);
+  static int ArchiveSpacePerThread();
+
+  // Code generation assumptions.
+  static const int kIa32CallInstructionLength = 5;
+  static const int kIa32JSReturnSequenceLength = 6;
+
+ private:
+  static bool CompileDebuggerScript(int index);
+  static void ClearOneShot();
+  static void ActivateStepIn(StackFrame* frame);
+  static void ClearStepIn();
+  static void ClearStepNext();
+  // Returns whether the compile succedded.
+  static bool EnsureCompiled(Handle<SharedFunctionInfo> shared);
+  static void RemoveDebugInfo(Handle<DebugInfo> debug_info);
+  static void SetAfterBreakTarget(JavaScriptFrame* frame);
+  static Handle<Object> CheckBreakPoints(Handle<Object> break_point);
+  static bool CheckBreakPoint(Handle<Object> break_point_object);
+
+  // Global handle to debug context where all the debugger JavaScript code is
+  // loaded.
+  static Handle<Context> debug_context_;
+
+  // Boolean state indicating whether any break points are set.
+  static bool has_break_points_;
+  static DebugInfoListNode* debug_info_list_;
+
+  static bool disable_break_;
+  static bool break_on_exception_;
+  static bool break_on_uncaught_exception_;
+
+  // Per-thread:
+  class ThreadLocal {
+   public:
+    // Step action for last step performed.
+    StepAction last_step_action_;
+
+    // Source statement position from last step next action.
+    int last_statement_position_;
+
+    // Number of steps left to perform before debug event.
+    int step_count_;
+
+    // Frame pointer from last step next action.
+    Address last_fp_;
+
+    // Frame pointer for frame from which step in was performed.
+    Address step_into_fp_;
+
+    // Storage location for jump when exiting debug break calls.
+    Address after_break_target_;
+  };
+
+  // Storage location for registers when handling debug break calls
+  static JSCallerSavedBuffer registers_;
+  static ThreadLocal thread_local_;
+  static void ThreadInit();
+
+  // Code object for debug break return entry code.
+  static Code* debug_break_return_entry_;
+
+  // Code to call for handling debug break on return.
+  static Code* debug_break_return_;
+
+  DISALLOW_COPY_AND_ASSIGN(Debug);
+};
+
+
+class DebugMessageThread;
+
+class Debugger {
+ public:
+  static void DebugRequest(const uint16_t* json_request, int length);
+
+  static Handle<Object> MakeJSObject(Vector<const char> constructor_name,
+                                     int argc, Object*** argv,
+                                     bool* caught_exception);
+  static Handle<Object> MakeExecutionState(bool* caught_exception);
+  static Handle<Object> MakeBreakEvent(Handle<Object> exec_state,
+                                       Handle<Object> break_points_hit,
+                                       bool* caught_exception);
+  static Handle<Object> MakeExceptionEvent(Handle<Object> exec_state,
+                                           Handle<Object> exception,
+                                           bool uncaught,
+                                           bool* caught_exception);
+  static Handle<Object> MakeNewFunctionEvent(Handle<Object> func,
+                                             bool* caught_exception);
+  static Handle<Object> MakeCompileEvent(Handle<Script> script,
+                                         Handle<Object> script_function,
+                                         bool* caught_exception);
+  static Handle<String> ProcessRequest(Handle<Object> exec_state,
+                                       Handle<Object> request,
+                                       bool stopped);
+  static void OnDebugBreak(Handle<Object> break_points_hit);
+  static void OnException(Handle<Object> exception, bool uncaught);
+  static void OnBeforeCompile(Handle<Script> script);
+  static void OnAfterCompile(Handle<Script> script,
+                           Handle<JSFunction> fun);
+  static void OnNewFunction(Handle<JSFunction> fun);
+  static void ProcessDebugEvent(v8::DebugEvent event,
+                                Handle<Object> event_data);
+  static void SetMessageHandler(v8::DebugMessageHandler handler, void* data);
+  static void SendMessage(Vector<uint16_t> message);
+  static void ProcessCommand(Vector<const uint16_t> command);
+  static void UpdateActiveDebugger();
+  inline static bool EventActive(v8::DebugEvent event) {
+    // Currently argument event is not used.
+    return !Debugger::compiling_natives_ && Debugger::debugger_active_;
+  }
+
+  static void set_debugger_active(bool debugger_active) {
+    Debugger::debugger_active_ = debugger_active;
+  }
+  static bool debugger_active() { return Debugger::debugger_active_; }
+  static void set_compiling_natives(bool compiling_natives) {
+    Debugger::compiling_natives_ = compiling_natives;
+  }
+  static bool compiling_natives() { return Debugger::compiling_natives_; }
+  static void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
+  static bool is_loading_debugger() { return Debugger::is_loading_debugger_; }
+
+ private:
+  static bool debugger_active_;  // Are there any active debugger?
+  static bool compiling_natives_;  // Are we compiling natives?
+  static bool is_loading_debugger_;  // Are we loading the debugger?
+  static DebugMessageThread* message_thread_;
+  static v8::DebugMessageHandler debug_message_handler_;
+  static void* debug_message_handler_data_;
+};
+
+
+// A Queue of Vector<uint16_t> objects.  A thread-safe version is
+// LockingMessageQueue, based on this class.
+class MessageQueue BASE_EMBEDDED {
+ public:
+  explicit MessageQueue(int size);
+  ~MessageQueue();
+  bool IsEmpty() const { return start_ == end_; }
+  Vector<uint16_t> Get();
+  void Put(const Vector<uint16_t>& message);
+  void Clear() { start_ = end_ = 0; }  // Queue is empty after Clear().
+ private:
+  // Doubles the size of the message queue, and copies the messages.
+  void Expand();
+
+  Vector<uint16_t>* messages_;
+  int start_;
+  int end_;
+  int size_;  // The size of the queue buffer.  Queue can hold size-1 messages.
+};
+
+
+// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t>
+// messages.  The message data is not managed by LockingMessageQueue.
+// Pointers to the data are passed in and out. Implemented by adding a
+// Mutex to MessageQueue.  Includes logging of all puts and gets.
+class LockingMessageQueue BASE_EMBEDDED {
+ public:
+  explicit LockingMessageQueue(int size);
+  ~LockingMessageQueue();
+  bool IsEmpty() const;
+  Vector<uint16_t> Get();
+  void Put(const Vector<uint16_t>& message);
+  void Clear();
+ private:
+  MessageQueue queue_;
+  Mutex* lock_;
+  DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue);
+};
+
+
+/* This class is the data for a running thread that serializes
+ * event messages and command processing for the debugger.
+ * All uncommented methods are called only from this message thread.
+ */
+class DebugMessageThread: public Thread {
+ public:
+  DebugMessageThread();  // Called from API thread.
+  virtual ~DebugMessageThread();  // Never called.
+  // Called by V8 thread.  Reports events from V8 VM.
+  // Also handles command processing in stopped state of V8,
+  // when host_running_ is false.
+  void DebugEvent(v8::DebugEvent,
+                  Handle<Object> exec_state,
+                  Handle<Object> event_data);
+  // Puts event on the output queue.  Called by V8.
+  // This is where V8 hands off
+  // processing of the event to the DebugMessageThread thread,
+  // which forwards it to the debug_message_handler set by the API.
+  void SendMessage(Vector<uint16_t> event_json);
+  // Formats an event into JSON, and calls SendMessage.
+  void SetEventJSONFromEvent(Handle<Object> event_data);
+  // Puts a command coming from the public API on the queue.  Called
+  // by the API client thread.  This is where the API client hands off
+  // processing of the command to the DebugMessageThread thread.
+  void ProcessCommand(Vector<uint16_t> command);
+  void OnDebuggerInactive();
+
+  // Main function of DebugMessageThread thread.
+  void Run();
+
+  bool host_running_;  // Is the debugging host running or stopped?
+  Semaphore* command_received_;  // Non-zero when command queue is non-empty.
+  Semaphore* message_received_;  // Exactly equal to message queue length.
+ private:
+  bool TwoByteEqualsAscii(Vector<uint16_t> two_byte, const char* ascii);
+
+  static const int kQueueInitialSize = 4;
+  LockingMessageQueue command_queue_;
+  LockingMessageQueue message_queue_;
+  DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
+};
+
+
+// This class is used for entering the debugger. Create an instance in the stack
+// to enter the debugger. This will set the current break state, make sure the
+// debugger is loaded and switch to the debugger context. If the debugger for
+// some reason could not be entered FailedToEnter will return true.
+class EnterDebugger BASE_EMBEDDED {
+ public:
+  EnterDebugger() : set_(!it_.done()) {
+    // If there is no JavaScript frames on the stack don't switch to new break
+    // and break frame.
+    if (set_) {
+      // Store the previous break is and frame id.
+      break_id_ = Top::break_id();
+      break_frame_id_ = Top::break_frame_id();
+
+      // Create the new break info.
+      Top::new_break(it_.frame()->id());
+    }
+
+    // Make sure that debugger is loaded and enter the debugger context.
+    load_failed_ = !Debug::Load();
+    if (!load_failed_) {
+      // NOTE the member variable save which saves the previous context before
+      // this change.
+      Top::set_context(*Debug::debug_context());
+    }
+  }
+
+  ~EnterDebugger() {
+    if (set_) {
+      // Restore to the previous break state.
+      Top::set_break(break_frame_id_, break_id_);
+    }
+  }
+
+  // Check whether the debugger could be entered.
+  inline bool FailedToEnter() { return load_failed_; }
+
+ private:
+  JavaScriptFrameIterator it_;
+  const bool set_;  // Was the break actually set?
+  StackFrame::Id break_frame_id_;  // Previous break frame id.
+  int break_id_;  // Previous break id.
+  bool load_failed_;  // Did the debugger fail to load?
+  SaveContext save_;  // Saves previous context.
+};
+
+
+// Stack allocated class for disabling break.
+class DisableBreak BASE_EMBEDDED {
+ public:
+  // Enter the debugger by storing the previous top context and setting the
+  // current top context to the debugger context.
+  explicit DisableBreak(bool disable_break)  {
+    prev_disable_break_ = Debug::disable_break();
+    Debug::set_disable_break(disable_break);
+  }
+  ~DisableBreak() {
+    Debug::set_disable_break(prev_disable_break_);
+  }
+
+ private:
+  // The previous state of the disable break used to restore the value when this
+  // object is destructed.
+  bool prev_disable_break_;
+};
+
+
+// Debug_Address encapsulates the Address pointers used in generating debug
+// code.
+class Debug_Address {
+ public:
+  Debug_Address(Debug::AddressId id, int reg = 0)
+    : id_(id), reg_(reg) {
+    ASSERT(reg == 0 || id == Debug::k_register_address);
+  }
+
+  static Debug_Address AfterBreakTarget() {
+    return Debug_Address(Debug::k_after_break_target_address);
+  }
+
+  static Debug_Address DebugBreakReturn() {
+    return Debug_Address(Debug::k_debug_break_return_address);
+  }
+
+  static Debug_Address Register(int reg) {
+    return Debug_Address(Debug::k_register_address, reg);
+  }
+
+  Address address() const {
+    switch (id_) {
+      case Debug::k_after_break_target_address:
+        return reinterpret_cast<Address>(Debug::after_break_target_address());
+      case Debug::k_debug_break_return_address:
+        return reinterpret_cast<Address>(Debug::debug_break_return_address());
+      case Debug::k_register_address:
+        return reinterpret_cast<Address>(Debug::register_address(reg_));
+      default:
+        UNREACHABLE();
+        return NULL;
+    }
+  }
+ private:
+  Debug::AddressId id_;
+  int reg_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_V8_DEBUG_H_
diff --git a/regexp2000/src/disasm-arm.cc b/regexp2000/src/disasm-arm.cc
new file mode 100644 (file)
index 0000000..4aa9b78
--- /dev/null
@@ -0,0 +1,937 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef WIN32
+#include <stdint.h>
+#endif
+
+#include "v8.h"
+
+#include "disasm.h"
+#include "macro-assembler.h"
+#include "platform.h"
+
+namespace assembler { namespace arm {
+
+namespace v8i = v8::internal;
+
+
+//------------------------------------------------------------------------------
+
+// Decoder decodes and disassembles instructions into an output buffer.
+// It uses the converter to convert register names and call destinations into
+// more informative description.
+class Decoder {
+ public:
+  Decoder(const disasm::NameConverter& converter,
+          v8::internal::Vector<char> out_buffer)
+    : converter_(converter),
+      out_buffer_(out_buffer),
+      out_buffer_pos_(0) {
+    out_buffer_[out_buffer_pos_] = '\0';
+  }
+
+  ~Decoder() {}
+
+  // Writes one disassembled instruction into 'buffer' (0-terminated).
+  // Returns the length of the disassembled machine instruction in bytes.
+  int InstructionDecode(byte* instruction);
+
+ private:
+  const disasm::NameConverter& converter_;
+  v8::internal::Vector<char> out_buffer_;
+  int out_buffer_pos_;
+
+  void PrintChar(const char ch);
+  void Print(const char* str);
+
+  void PrintRegister(int reg);
+  void PrintCondition(Instr* instr);
+  void PrintShiftRm(Instr* instr);
+  void PrintShiftImm(Instr* instr);
+
+  int FormatOption(Instr* instr, const char* option);
+  void Format(Instr* instr, const char* format);
+  void Unknown(Instr* instr);
+
+  void DecodeType0(Instr* instr);
+  void DecodeType1(Instr* instr);
+  void DecodeType2(Instr* instr);
+  void DecodeType3(Instr* instr);
+  void DecodeType4(Instr* instr);
+  void DecodeType5(Instr* instr);
+  void DecodeType6(Instr* instr);
+  void DecodeType7(Instr* instr);
+};
+
+
+// Append the ch to the output buffer.
+void Decoder::PrintChar(const char ch) {
+  out_buffer_[out_buffer_pos_++] = ch;
+}
+
+
+// Append the str to the output buffer.
+void Decoder::Print(const char* str) {
+  char cur = *str++;
+  while (cur != 0 && (out_buffer_pos_ < (out_buffer_.length()-1))) {
+    PrintChar(cur);
+    cur = *str++;
+  }
+  out_buffer_[out_buffer_pos_] = 0;
+}
+
+
+static const char* cond_names[16] = {
+"eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
+"hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
+};
+
+
+// Print the condition guarding the instruction.
+void Decoder::PrintCondition(Instr* instr) {
+  Print(cond_names[instr->ConditionField()]);
+}
+
+
+// Print the register name according to the active name converter.
+void Decoder::PrintRegister(int reg) {
+  Print(converter_.NameOfCPURegister(reg));
+}
+
+
+static const char* shift_names[4] = {
+  "lsl", "lsr", "asr", "ror"
+};
+
+
+// Print the register shift operands for the instruction. Generally used for
+// data processing instructions.
+void Decoder::PrintShiftRm(Instr* instr) {
+  Shift shift = instr->ShiftField();
+  int shift_amount = instr->ShiftAmountField();
+  int rm = instr->RmField();
+
+  PrintRegister(rm);
+
+  if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) {
+    // Special case for using rm only.
+    return;
+  }
+  if (instr->RegShiftField() == 0) {
+    // by immediate
+    if ((shift == ROR) && (shift_amount == 0)) {
+      Print(", RRX");
+      return;
+    } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
+      shift_amount = 32;
+    }
+    out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                         ", %s #%d",
+                                         shift_names[shift], shift_amount);
+  } else {
+    // by register
+    int rs = instr->RsField();
+    out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                         ", %s ", shift_names[shift]);
+    PrintRegister(rs);
+  }
+}
+
+
+// Print the immediate operand for the instruction. Generally used for data
+// processing instructions.
+void Decoder::PrintShiftImm(Instr* instr) {
+  int rotate = instr->RotateField() * 2;
+  int immed8 = instr->Immed8Field();
+  int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
+  out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                       "#%d", imm);
+}
+
+
+// FormatOption takes a formatting string and interprets it based on
+// the current instructions. The format string points to the first
+// character of the option string (the option escape has already been
+// consumed by the caller.)  FormatOption returns the number of
+// characters that were consumed from the formatting string.
+int Decoder::FormatOption(Instr* instr, const char* format) {
+  switch (format[0]) {
+    case 'a': {  // 'a: accumulate multiplies
+      if (instr->Bit(21) == 0) {
+        Print("ul");
+      } else {
+        Print("la");
+      }
+      return 1;
+      break;
+    }
+    case 'b': {  // 'b: byte loads or stores
+      if (instr->HasB()) {
+        Print("b");
+      }
+      return 1;
+      break;
+    }
+    case 'c': {  // 'cond: conditional execution
+      ASSERT((format[1] == 'o') && (format[2] == 'n') && (format[3] =='d'));
+      PrintCondition(instr);
+      return 4;
+      break;
+    }
+    case 'h': {  // 'h: halfword operation for extra loads and stores
+      if (instr->HasH()) {
+        Print("h");
+      } else {
+        Print("b");
+      }
+      return 1;
+      break;
+    }
+    case 'i': {  // 'imm: immediate value for data processing instructions
+      ASSERT((format[1] == 'm') && (format[2] == 'm'));
+      PrintShiftImm(instr);
+      return 3;
+      break;
+    }
+    case 'l': {  // 'l: branch and link
+      if (instr->HasLink()) {
+        Print("l");
+      }
+      return 1;
+      break;
+    }
+    case 'm': {  // 'msg: for simulator break instructions
+      if (format[1] == 'e') {
+        ASSERT((format[2] == 'm') && (format[3] == 'o') && (format[4] == 'p'));
+        if (instr->HasL()) {
+          Print("ldr");
+        } else {
+          Print("str");
+        }
+        return 5;
+      } else {
+        ASSERT(format[1] == 's' && format[2] == 'g');
+        byte* str =
+            reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff);
+        out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                             "%s", converter_.NameInCode(str));
+        return 3;
+      }
+      break;
+    }
+    case 'o': {
+      ASSERT(format[1] == 'f' && format[2] == 'f');
+      if (format[3] == '1') {
+        // 'off12: 12-bit offset for load and store instructions
+        ASSERT(format[4] == '2');
+        out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                             "%d", instr->Offset12Field());
+        return 5;
+      } else {
+        // 'off8: 8-bit offset for extra load and store instructions
+        ASSERT(format[3] == '8');
+        int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField();
+        out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                             "%d", offs8);
+        return 4;
+      }
+      break;
+    }
+    case 'p': {  // 'pu: P and U bits for load and store instructions
+      ASSERT(format[1] == 'u');
+      switch (instr->PUField()) {
+        case 0: {
+          Print("da");
+          break;
+        }
+        case 1: {
+          Print("ia");
+          break;
+        }
+        case 2: {
+          Print("db");
+          break;
+        }
+        case 3: {
+          Print("ib");
+          break;
+        }
+        default: {
+          UNREACHABLE();
+          break;
+        }
+      }
+      return 2;
+      break;
+    }
+    case 'r': {
+      if (format[1] == 'n') {  // 'rn: Rn register
+        int reg = instr->RnField();
+        PrintRegister(reg);
+        return 2;
+      } else if (format[1] == 'd') {  // 'rd: Rd register
+        int reg = instr->RdField();
+        PrintRegister(reg);
+        return 2;
+      } else if (format[1] == 's') {  // 'rs: Rs register
+        int reg = instr->RsField();
+        PrintRegister(reg);
+        return 2;
+      } else if (format[1] == 'm') {  // 'rm: Rm register
+        int reg = instr->RmField();
+        PrintRegister(reg);
+        return 2;
+      } else if (format[1] == 'l') {
+        // 'rlist: register list for load and store multiple instructions
+        ASSERT(format[2] == 'i' && format[3] == 's' && format[4] == 't');
+        int rlist = instr->RlistField();
+        int reg = 0;
+        Print("{");
+        while (rlist != 0) {
+          if ((rlist & 1) != 0) {
+            PrintRegister(reg);
+            if ((rlist >> 1) != 0) {
+              Print(", ");
+            }
+          }
+          reg++;
+          rlist >>= 1;
+        }
+        Print("}");
+        return 5;
+      } else {
+        UNREACHABLE();
+      }
+      UNREACHABLE();
+      return -1;
+      break;
+    }
+    case 's': {
+      if (format[1] == 'h') {  // 'shift_rm: register shift operands
+        ASSERT(format[2] == 'i' && format[3] == 'f' && format[4] == 't'
+               && format[5] == '_' && format[6] == 'r' && format[7] == 'm');
+        PrintShiftRm(instr);
+        return 8;
+      } else if (format[1] == 'w') {
+        ASSERT(format[2] == 'i');
+        SoftwareInterruptCodes swi = instr->SwiField();
+        switch (swi) {
+          case call_rt_r5:
+            Print("call_rt_r5");
+            break;
+          case call_rt_r2:
+            Print("call_rt_r2");
+            break;
+          case break_point:
+            Print("break_point");
+            break;
+          default:
+            out_buffer_pos_ += v8i::OS::SNPrintF(
+                out_buffer_ + out_buffer_pos_,
+                "%d",
+                swi);
+            break;
+        }
+        return 3;
+      } else if (format[1] == 'i') {  // 'sign: signed extra loads and stores
+        ASSERT(format[2] == 'g' && format[3] == 'n');
+        if (instr->HasSign()) {
+          Print("s");
+        }
+        return 4;
+        break;
+      } else {  // 's: S field of data processing instructions
+        if (instr->HasS()) {
+          Print("s");
+        }
+        return 1;
+      }
+      break;
+    }
+    case 't': {  // 'target: target of branch instructions
+      ASSERT(format[1] == 'a' && format[2] == 'r' && format[3] == 'g'
+             && format[4] == 'e' && format[5] == 't');
+      int off = (instr->SImmed24Field() << 2) + 8;
+      out_buffer_pos_ += v8i::OS::SNPrintF(
+          out_buffer_ + out_buffer_pos_,
+          "%+d -> %s",
+          off,
+          converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
+      return 6;
+      break;
+    }
+    case 'u': {  // 'u: signed or unsigned multiplies
+      if (instr->Bit(22) == 0) {
+        Print("u");
+      } else {
+        Print("s");
+      }
+      return 1;
+      break;
+    }
+    case 'w': {  // 'w: W field of load and store instructions
+      if (instr->HasW()) {
+        Print("!");
+      }
+      return 1;
+      break;
+    }
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+  UNREACHABLE();
+  return -1;
+}
+
+
+// Format takes a formatting string for a whole instruction and prints it into
+// the output buffer. All escaped options are handed to FormatOption to be
+// parsed further.
+void Decoder::Format(Instr* instr, const char* format) {
+  char cur = *format++;
+  while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
+    if (cur == '\'') {  // Single quote is used as the formatting escape.
+      format += FormatOption(instr, format);
+    } else {
+      out_buffer_[out_buffer_pos_++] = cur;
+    }
+    cur = *format++;
+  }
+  out_buffer_[out_buffer_pos_]  = '\0';
+}
+
+
+// For currently unimplemented decodings the disassembler calls Unknown(instr)
+// which will just print "unknown" of the instruction bits.
+void Decoder::Unknown(Instr* instr) {
+  Format(instr, "unknown");
+}
+
+
+void Decoder::DecodeType0(Instr* instr) {
+  if (instr->IsSpecialType0()) {
+    // multiply instruction or extra loads and stores
+    if (instr->Bits(7, 4) == 9) {
+      if (instr->Bit(24) == 0) {
+        // multiply instructions
+        if (instr->Bit(23) == 0) {
+          if (instr->Bit(21) == 0) {
+            Format(instr, "mul'cond's 'rd, 'rm, 'rs");
+          } else {
+            Format(instr, "mla'cond's 'rd, 'rm, 'rs, 'rn");
+          }
+        } else {
+          Format(instr, "'um'al'cond's 'rn, 'rd, 'rs, 'rm");
+        }
+      } else {
+        Unknown(instr);  // not used by V8
+      }
+    } else {
+      // extra load/store instructions
+      switch (instr->PUField()) {
+        case 0: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
+          } else {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
+          }
+          break;
+        }
+        case 1: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
+          } else {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
+          }
+          break;
+        }
+        case 2: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
+          } else {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
+          }
+          break;
+        }
+        case 3: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
+          } else {
+            Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
+          }
+          break;
+        }
+        default: {
+          // The PU field is a 2-bit field.
+          UNREACHABLE();
+          break;
+        }
+      }
+      return;
+    }
+  } else {
+    switch (instr->OpcodeField()) {
+      case AND: {
+        Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case EOR: {
+        Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case SUB: {
+        Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case RSB: {
+        Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case ADD: {
+        Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case ADC: {
+        Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case SBC: {
+        Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case RSC: {
+        Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case TST: {
+        if (instr->HasS()) {
+          Format(instr, "tst'cond 'rn, 'shift_rm");
+        } else {
+          Unknown(instr);  // not used by V8
+          return;
+        }
+        break;
+      }
+      case TEQ: {
+        if (instr->HasS()) {
+          Format(instr, "teq'cond 'rn, 'shift_rm");
+        } else {
+          Unknown(instr);  // not used by V8
+          return;
+        }
+        break;
+      }
+      case CMP: {
+        if (instr->HasS()) {
+          Format(instr, "cmp'cond 'rn, 'shift_rm");
+        } else {
+          Unknown(instr);  // not used by V8
+          return;
+        }
+        break;
+      }
+      case CMN: {
+        if (instr->HasS()) {
+          Format(instr, "cmn'cond 'rn, 'shift_rm");
+        } else {
+          Unknown(instr);  // not used by V8
+          return;
+        }
+        break;
+      }
+      case ORR: {
+        Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case MOV: {
+        Format(instr, "mov'cond's 'rd, 'shift_rm");
+        break;
+      }
+      case BIC: {
+        Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
+        break;
+      }
+      case MVN: {
+        Format(instr, "mvn'cond's 'rd, 'shift_rm");
+        break;
+      }
+      default: {
+        // The Opcode field is a 4-bit field.
+        UNREACHABLE();
+        break;
+      }
+    }
+  }
+}
+
+
+void Decoder::DecodeType1(Instr* instr) {
+  switch (instr->OpcodeField()) {
+    case AND: {
+      Format(instr, "and'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case EOR: {
+      Format(instr, "eor'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case SUB: {
+      Format(instr, "sub'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case RSB: {
+      Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case ADD: {
+      Format(instr, "add'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case ADC: {
+      Format(instr, "adc'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case SBC: {
+      Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case RSC: {
+      Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case TST: {
+      if (instr->HasS()) {
+        Format(instr, "tst'cond 'rn, 'imm");
+      } else {
+        Unknown(instr);  // not used by V8
+        return;
+      }
+      break;
+    }
+    case TEQ: {
+      if (instr->HasS()) {
+        Format(instr, "teq'cond 'rn, 'imm");
+      } else {
+        Unknown(instr);  // not used by V8
+        return;
+      }
+      break;
+    }
+    case CMP: {
+      if (instr->HasS()) {
+        Format(instr, "cmp'cond 'rn, 'imm");
+      } else {
+        Unknown(instr);  // not used by V8
+        return;
+      }
+      break;
+    }
+    case CMN: {
+      if (instr->HasS()) {
+        Format(instr, "cmn'cond 'rn, 'imm");
+      } else {
+        Unknown(instr);  // not used by V8
+        return;
+      }
+      break;
+    }
+    case ORR: {
+      Format(instr, "orr'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case MOV: {
+      Format(instr, "mov'cond's 'rd, 'imm");
+      break;
+    }
+    case BIC: {
+      Format(instr, "bic'cond's 'rd, 'rn, 'imm");
+      break;
+    }
+    case MVN: {
+      Format(instr, "mvn'cond's 'rd, 'imm");
+      break;
+    }
+    default: {
+      // The Opcode field is a 4-bit field.
+      UNREACHABLE();
+      break;
+    }
+  }
+}
+
+
+void Decoder::DecodeType2(Instr* instr) {
+  switch (instr->PUField()) {
+    case 0: {
+      if (instr->HasW()) {
+        Unknown(instr);  // not used in V8
+        return;
+      }
+      Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
+      break;
+    }
+    case 1: {
+      if (instr->HasW()) {
+        Unknown(instr);  // not used in V8
+        return;
+      }
+      Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
+      break;
+    }
+    case 2: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
+      break;
+    }
+    case 3: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
+      break;
+    }
+    default: {
+      // The PU field is a 2-bit field.
+      UNREACHABLE();
+      break;
+    }
+  }
+}
+
+
+void Decoder::DecodeType3(Instr* instr) {
+  switch (instr->PUField()) {
+    case 0: {
+      ASSERT(!instr->HasW());
+      Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
+      break;
+    }
+    case 1: {
+      ASSERT(!instr->HasW());
+      Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
+      break;
+    }
+    case 2: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
+      break;
+    }
+    case 3: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
+      break;
+    }
+    default: {
+      // The PU field is a 2-bit field.
+      UNREACHABLE();
+      break;
+    }
+  }
+}
+
+
+void Decoder::DecodeType4(Instr* instr) {
+  ASSERT(instr->Bit(22) == 0);  // Privileged mode currently not supported.
+  if (instr->HasL()) {
+    Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
+  } else {
+    Format(instr, "stm'cond'pu 'rn'w, 'rlist");
+  }
+}
+
+
+void Decoder::DecodeType5(Instr* instr) {
+  Format(instr, "b'l'cond 'target");
+}
+
+
+void Decoder::DecodeType6(Instr* instr) {
+  // Coprocessor instructions currently not supported.
+  Unknown(instr);
+}
+
+
+void Decoder::DecodeType7(Instr* instr) {
+  if (instr->Bit(24) == 1) {
+    Format(instr, "swi'cond 'swi");
+  } else {
+    // Coprocessor instructions currently not supported.
+    Unknown(instr);
+  }
+}
+
+
+// Disassemble the instruction at *instr_ptr into the output buffer.
+int Decoder::InstructionDecode(byte* instr_ptr) {
+  Instr* instr = Instr::At(instr_ptr);
+  // Print raw instruction bytes.
+  out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                       "%08x       ",
+                                       instr->InstructionBits());
+  if (instr->ConditionField() == special_condition) {
+    Format(instr, "break 'msg");
+    return Instr::kInstrSize;
+  }
+  switch (instr->TypeField()) {
+    case 0: {
+      DecodeType0(instr);
+      break;
+    }
+    case 1: {
+      DecodeType1(instr);
+      break;
+    }
+    case 2: {
+      DecodeType2(instr);
+      break;
+    }
+    case 3: {
+      DecodeType3(instr);
+      break;
+    }
+    case 4: {
+      DecodeType4(instr);
+      break;
+    }
+    case 5: {
+      DecodeType5(instr);
+      break;
+    }
+    case 6: {
+      DecodeType6(instr);
+      break;
+    }
+    case 7: {
+      DecodeType7(instr);
+      break;
+    }
+    default: {
+      // The type field is 3-bits in the ARM encoding.
+      UNREACHABLE();
+      break;
+    }
+  }
+  return Instr::kInstrSize;
+}
+
+
+} }  // namespace assembler::arm
+
+
+
+//------------------------------------------------------------------------------
+
+namespace disasm {
+
+static const char* reg_names[16] = {
+  "r0", "r1", "r2" , "r3" , "r4" , "r5" , "r6" , "r7" ,
+  "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc",
+};
+
+
+const char* NameConverter::NameOfAddress(byte* addr) const {
+  static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
+  v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
+  return tmp_buffer.start();
+}
+
+
+const char* NameConverter::NameOfConstant(byte* addr) const {
+  return NameOfAddress(addr);
+}
+
+
+const char* NameConverter::NameOfCPURegister(int reg) const {
+  const char* result;
+  if ((0 <= reg) && (reg < 16)) {
+    result = reg_names[reg];
+  } else {
+    result = "noreg";
+  }
+  return result;
+}
+
+
+const char* NameConverter::NameOfXMMRegister(int reg) const {
+  UNREACHABLE();  // ARM does not have any XMM registers
+  return "noxmmreg";
+}
+
+
+const char* NameConverter::NameInCode(byte* addr) const {
+  // The default name converter is called for unknown code. So we will not try
+  // to access any memory.
+  return "";
+}
+
+
+//------------------------------------------------------------------------------
+
+static NameConverter defaultConverter;
+
+Disassembler::Disassembler() : converter_(defaultConverter) {}
+
+
+Disassembler::Disassembler(const NameConverter& converter)
+    : converter_(converter) {}
+
+
+Disassembler::~Disassembler() {}
+
+
+int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
+                                    byte* instruction) {
+  assembler::arm::Decoder d(converter_, buffer);
+  return d.InstructionDecode(instruction);
+}
+
+
+int Disassembler::ConstantPoolSizeAt(byte* instruction) {
+  int instruction_bits = *(reinterpret_cast<int*>(instruction));
+  if ((instruction_bits & 0xfff00000) == 0x03000000) {
+    return instruction_bits & 0x0000ffff;
+  } else {
+    return -1;
+  }
+}
+
+
+void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
+  Disassembler d;
+  for (byte* pc = begin; pc < end;) {
+    v8::internal::EmbeddedVector<char, 128> buffer;
+    buffer[0] = '\0';
+    byte* prev_pc = pc;
+    pc += d.InstructionDecode(buffer, pc);
+    fprintf(f, "%p    %08x      %s\n",
+            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
+  }
+}
+
+
+}  // namespace disasm
diff --git a/regexp2000/src/disasm-ia32.cc b/regexp2000/src/disasm-ia32.cc
new file mode 100644 (file)
index 0000000..1648d69
--- /dev/null
@@ -0,0 +1,1142 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "v8.h"
+#include "disasm.h"
+
+namespace disasm {
+
+enum OperandOrder {
+  UNSET_OP_ORDER = 0,
+  REG_OPER_OP_ORDER,
+  OPER_REG_OP_ORDER
+};
+
+
+//------------------------------------------------------------------
+// Tables
+//------------------------------------------------------------------
+struct ByteMnemonic {
+  int b;  // -1 terminates, otherwise must be in range (0..255)
+  const char* mnem;
+  OperandOrder op_order_;
+};
+
+
+static ByteMnemonic two_operands_instr[] = {
+  {0x03, "add", REG_OPER_OP_ORDER},
+  {0x21, "and", OPER_REG_OP_ORDER},
+  {0x23, "and", REG_OPER_OP_ORDER},
+  {0x3B, "cmp", REG_OPER_OP_ORDER},
+  {0x8D, "lea", REG_OPER_OP_ORDER},
+  {0x09, "or", OPER_REG_OP_ORDER},
+  {0x0B, "or", REG_OPER_OP_ORDER},
+  {0x1B, "sbb", REG_OPER_OP_ORDER},
+  {0x29, "sub", OPER_REG_OP_ORDER},
+  {0x2B, "sub", REG_OPER_OP_ORDER},
+  {0x85, "test", REG_OPER_OP_ORDER},
+  {0x31, "xor", OPER_REG_OP_ORDER},
+  {0x33, "xor", REG_OPER_OP_ORDER},
+  {0x8A, "mov_b", REG_OPER_OP_ORDER},
+  {0x8B, "mov", REG_OPER_OP_ORDER},
+  {-1, "", UNSET_OP_ORDER}
+};
+
+
+static ByteMnemonic zero_operands_instr[] = {
+  {0xC3, "ret", UNSET_OP_ORDER},
+  {0xC9, "leave", UNSET_OP_ORDER},
+  {0x90, "nop", UNSET_OP_ORDER},
+  {0xF4, "hlt", UNSET_OP_ORDER},
+  {0xCC, "int3", UNSET_OP_ORDER},
+  {0x60, "pushad", UNSET_OP_ORDER},
+  {0x61, "popad", UNSET_OP_ORDER},
+  {0x9C, "pushfd", UNSET_OP_ORDER},
+  {0x9D, "popfd", UNSET_OP_ORDER},
+  {0x9E, "sahf", UNSET_OP_ORDER},
+  {0x99, "cdq", UNSET_OP_ORDER},
+  {0x9B, "fwait", UNSET_OP_ORDER},
+  {-1, "", UNSET_OP_ORDER}
+};
+
+
+static ByteMnemonic call_jump_instr[] = {
+  {0xE8, "call", UNSET_OP_ORDER},
+  {0xE9, "jmp", UNSET_OP_ORDER},
+  {-1, "", UNSET_OP_ORDER}
+};
+
+
+static ByteMnemonic short_immediate_instr[] = {
+  {0x05, "add", UNSET_OP_ORDER},
+  {0x0D, "or", UNSET_OP_ORDER},
+  {0x15, "adc", UNSET_OP_ORDER},
+  {0x25, "and", UNSET_OP_ORDER},
+  {0x2D, "sub", UNSET_OP_ORDER},
+  {0x35, "xor", UNSET_OP_ORDER},
+  {0x3D, "cmp", UNSET_OP_ORDER},
+  {-1, "", UNSET_OP_ORDER}
+};
+
+
+static const char* jump_conditional_mnem[] = {
+  /*0*/ "jo", "jno", "jc", "jnc",
+  /*4*/ "jz", "jnz", "jna", "ja",
+  /*8*/ "js", "jns", "jpe", "jpo",
+  /*12*/ "jl", "jnl", "jng", "jg"
+};
+
+
+enum InstructionType {
+  NO_INSTR,
+  ZERO_OPERANDS_INSTR,
+  TWO_OPERANDS_INSTR,
+  JUMP_CONDITIONAL_SHORT_INSTR,
+  REGISTER_INSTR,
+  MOVE_REG_INSTR,
+  CALL_JUMP_INSTR,
+  SHORT_IMMEDIATE_INSTR
+};
+
+
+struct InstructionDesc {
+  const char* mnem;
+  InstructionType type;
+  OperandOrder op_order_;
+};
+
+
+class InstructionTable {
+ public:
+  InstructionTable();
+  const InstructionDesc& Get(byte x) const { return instructions_[x]; }
+
+ private:
+  InstructionDesc instructions_[256];
+  void Clear();
+  void Init();
+  void CopyTable(ByteMnemonic bm[], InstructionType type);
+  void SetTableRange(InstructionType type,
+                     byte start,
+                     byte end,
+                     const char* mnem);
+  void AddJumpConditionalShort();
+};
+
+
+InstructionTable::InstructionTable() {
+  Clear();
+  Init();
+}
+
+
+void InstructionTable::Clear() {
+  for (int i = 0; i < 256; i++) {
+    instructions_[i].mnem = "";
+    instructions_[i].type = NO_INSTR;
+    instructions_[i].op_order_ = UNSET_OP_ORDER;
+  }
+}
+
+
+void InstructionTable::Init() {
+  CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
+  CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
+  CopyTable(call_jump_instr, CALL_JUMP_INSTR);
+  CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
+  AddJumpConditionalShort();
+  SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
+  SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
+  SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
+  SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
+  SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
+}
+
+
+void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
+  for (int i = 0; bm[i].b >= 0; i++) {
+    InstructionDesc* id = &instructions_[bm[i].b];
+    id->mnem = bm[i].mnem;
+    id->op_order_ = bm[i].op_order_;
+    assert(id->type == NO_INSTR);  // Information already entered
+    id->type = type;
+  }
+}
+
+
+void InstructionTable::SetTableRange(InstructionType type,
+                                     byte start,
+                                     byte end,
+                                     const char* mnem) {
+  for (byte b = start; b <= end; b++) {
+    InstructionDesc* id = &instructions_[b];
+    assert(id->type == NO_INSTR);  // Information already entered
+    id->mnem = mnem;
+    id->type = type;
+  }
+}
+
+
+void InstructionTable::AddJumpConditionalShort() {
+  for (byte b = 0x70; b <= 0x7F; b++) {
+    InstructionDesc* id = &instructions_[b];
+    assert(id->type == NO_INSTR);  // Information already entered
+    id->mnem = jump_conditional_mnem[b & 0x0F];
+    id->type = JUMP_CONDITIONAL_SHORT_INSTR;
+  }
+}
+
+
+static InstructionTable instruction_table;
+
+
+// The IA32 disassembler implementation.
+class DisassemblerIA32 {
+ public:
+  DisassemblerIA32(const NameConverter& converter,
+                   bool abort_on_unimplemented = true)
+      : converter_(converter),
+        tmp_buffer_pos_(0),
+        abort_on_unimplemented_(abort_on_unimplemented) {
+    tmp_buffer_[0] = '\0';
+  }
+
+  virtual ~DisassemblerIA32() {}
+
+  // Writes one disassembled instruction into 'buffer' (0-terminated).
+  // Returns the length of the disassembled machine instruction in bytes.
+  int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
+
+ private:
+  const NameConverter& converter_;
+  v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
+  unsigned int tmp_buffer_pos_;
+  bool abort_on_unimplemented_;
+
+
+  enum {
+    eax = 0,
+    ecx = 1,
+    edx = 2,
+    ebx = 3,
+    esp = 4,
+    ebp = 5,
+    esi = 6,
+    edi = 7
+  };
+
+
+  const char* NameOfCPURegister(int reg) const {
+    return converter_.NameOfCPURegister(reg);
+  }
+
+
+  const char* NameOfXMMRegister(int reg) const {
+    return converter_.NameOfXMMRegister(reg);
+  }
+
+
+  const char* NameOfAddress(byte* addr) const {
+    return converter_.NameOfAddress(addr);
+  }
+
+
+  // Disassembler helper functions.
+  static void get_modrm(byte data, int* mod, int* regop, int* rm) {
+    *mod = (data >> 6) & 3;
+    *regop = (data & 0x38) >> 3;
+    *rm = data & 7;
+  }
+
+
+  static void get_sib(byte data, int* scale, int* index, int* base) {
+    *scale = (data >> 6) & 3;
+    *index = (data >> 3) & 7;
+    *base = data & 7;
+  }
+
+
+  int PrintRightOperand(byte* modrmp);
+  int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
+  int PrintImmediateOp(byte* data);
+  int F7Instruction(byte* data);
+  int D1D3C1Instruction(byte* data);
+  int JumpShort(byte* data);
+  int JumpConditional(byte* data, const char* comment);
+  int JumpConditionalShort(byte* data, const char* comment);
+  int FPUInstruction(byte* data);
+  void AppendToBuffer(const char* format, ...);
+
+
+  void UnimplementedInstruction() {
+    if (abort_on_unimplemented_) {
+      UNIMPLEMENTED();
+    } else {
+      AppendToBuffer("'Unimplemented Instruction'");
+    }
+  }
+};
+
+
+void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
+  v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
+  va_list args;
+  va_start(args, format);
+  int result = v8::internal::OS::VSNPrintF(buf, format, args);
+  va_end(args);
+  tmp_buffer_pos_ += result;
+}
+
+
+// Returns number of bytes used including the current *modrmp.
+// Writes instruction's right operand to 'tmp_buffer_'.
+int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
+  int mod, regop, rm;
+  get_modrm(*modrmp, &mod, &regop, &rm);
+  switch (mod) {
+    case 0:
+      if (rm == ebp) {
+        int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
+        AppendToBuffer("[0x%x]", disp);
+        return 5;
+      } else if (rm == esp) {
+        byte sib = *(modrmp + 1);
+        int scale, index, base;
+        get_sib(sib, &scale, &index, &base);
+        if (index == esp && base == esp && scale == 0 /*times_1*/) {
+          AppendToBuffer("[%s]", NameOfCPURegister(rm));
+          return 2;
+        } else if (base == ebp) {
+          int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
+          AppendToBuffer("[%s*%d+0x%x]",
+                         NameOfCPURegister(index),
+                         1 << scale,
+                         disp);
+          return 6;
+        } else if (index != esp && base != ebp) {
+          // [base+index*scale]
+          AppendToBuffer("[%s+%s*%d]",
+                         NameOfCPURegister(base),
+                         NameOfCPURegister(index),
+                         1 << scale);
+          return 2;
+        } else {
+          UnimplementedInstruction();
+          return 1;
+        }
+      } else {
+        AppendToBuffer("[%s]", NameOfCPURegister(rm));
+        return 1;
+      }
+      break;
+    case 1:  // fall through
+    case 2:
+      if (rm == esp) {
+        byte sib = *(modrmp + 1);
+        int scale, index, base;
+        get_sib(sib, &scale, &index, &base);
+        int disp =
+            mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
+        if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
+          AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp);
+        } else {
+          AppendToBuffer("[%s+%s*%d+0x%x]",
+                         NameOfCPURegister(base),
+                         NameOfCPURegister(index),
+                         1 << scale,
+                         disp);
+        }
+        return mod == 2 ? 6 : 3;
+      } else {
+        // No sib.
+        int disp =
+            mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
+        AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp);
+        return mod == 2 ? 5 : 2;
+      }
+      break;
+    case 3:
+      AppendToBuffer("%s", NameOfCPURegister(rm));
+      return 1;
+    default:
+      UnimplementedInstruction();
+      return 1;
+  }
+  UNREACHABLE();
+}
+
+
+// Returns number of bytes used including the current *data.
+// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
+int DisassemblerIA32::PrintOperands(const char* mnem,
+                                    OperandOrder op_order,
+                                    byte* data) {
+  byte modrm = *data;
+  int mod, regop, rm;
+  get_modrm(modrm, &mod, &regop, &rm);
+  int advance = 0;
+  switch (op_order) {
+    case REG_OPER_OP_ORDER: {
+      AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
+      advance = PrintRightOperand(data);
+      break;
+    }
+    case OPER_REG_OP_ORDER: {
+      AppendToBuffer("%s ", mnem);
+      advance = PrintRightOperand(data);
+      AppendToBuffer(",%s", NameOfCPURegister(regop));
+      break;
+    }
+    default:
+      UNREACHABLE();
+      break;
+  }
+  return advance;
+}
+
+
+// Returns number of bytes used by machine instruction, including *data byte.
+// Writes immediate instructions to 'tmp_buffer_'.
+int DisassemblerIA32::PrintImmediateOp(byte* data) {
+  bool sign_extension_bit = (*data & 0x02) != 0;
+  byte modrm = *(data+1);
+  int mod, regop, rm;
+  get_modrm(modrm, &mod, &regop, &rm);
+  const char* mnem = "Imm???";
+  switch (regop) {
+    case 0: mnem = "add"; break;
+    case 1: mnem = "or"; break;
+    case 2: mnem = "adc"; break;
+    case 4: mnem = "and"; break;
+    case 5: mnem = "sub"; break;
+    case 6: mnem = "xor"; break;
+    case 7: mnem = "cmp"; break;
+    default: UnimplementedInstruction();
+  }
+  AppendToBuffer("%s ", mnem);
+  int count = PrintRightOperand(data+1);
+  if (sign_extension_bit) {
+    AppendToBuffer(",0x%x", *(data + 1 + count));
+    return 1 + count + 1 /*int8*/;
+  } else {
+    AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
+    return 1 + count + 4 /*int32_t*/;
+  }
+}
+
+
+// Returns number of bytes used, including *data.
+int DisassemblerIA32::F7Instruction(byte* data) {
+  assert(*data == 0xF7);
+  byte modrm = *(data+1);
+  int mod, regop, rm;
+  get_modrm(modrm, &mod, &regop, &rm);
+  if (mod == 3 && regop != 0) {
+    const char* mnem = NULL;
+    switch (regop) {
+      case 2: mnem = "not"; break;
+      case 3: mnem = "neg"; break;
+      case 4: mnem = "mul"; break;
+      case 7: mnem = "idiv"; break;
+      default: UnimplementedInstruction();
+    }
+    AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
+    return 2;
+  } else if (mod == 3 && regop == eax) {
+    int32_t imm = *reinterpret_cast<int32_t*>(data+2);
+    AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
+    return 6;
+  } else if (regop == eax) {
+    AppendToBuffer("test ");
+    int count = PrintRightOperand(data+1);
+    int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
+    AppendToBuffer(",0x%x", imm);
+    return 1+count+4 /*int32_t*/;
+  } else {
+    UnimplementedInstruction();
+    return 2;
+  }
+}
+
+int DisassemblerIA32::D1D3C1Instruction(byte* data) {
+  byte op = *data;
+  assert(op == 0xD1 || op == 0xD3 || op == 0xC1);
+  byte modrm = *(data+1);
+  int mod, regop, rm;
+  get_modrm(modrm, &mod, &regop, &rm);
+  int imm8 = -1;
+  int num_bytes = 2;
+  if (mod == 3) {
+    const char* mnem = NULL;
+    if (op == 0xD1) {
+      imm8 = 1;
+      switch (regop) {
+        case edx: mnem = "rcl"; break;
+        case edi: mnem = "sar"; break;
+        case esp: mnem = "shl"; break;
+        default: UnimplementedInstruction();
+      }
+    } else if (op == 0xC1) {
+      imm8 = *(data+2);
+      num_bytes = 3;
+      switch (regop) {
+        case edx: mnem = "rcl"; break;
+        case esp: mnem = "shl"; break;
+        case ebp: mnem = "shr"; break;
+        case edi: mnem = "sar"; break;
+        default: UnimplementedInstruction();
+      }
+    } else if (op == 0xD3) {
+      switch (regop) {
+        case esp: mnem = "shl"; break;
+        case ebp: mnem = "shr"; break;
+        case edi: mnem = "sar"; break;
+        default: UnimplementedInstruction();
+      }
+    }
+    assert(mnem != NULL);
+    AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
+    if (imm8 > 0) {
+      AppendToBuffer("%d", imm8);
+    } else {
+      AppendToBuffer("cl");
+    }
+  } else {
+    UnimplementedInstruction();
+  }
+  return num_bytes;
+}
+
+
+// Returns number of bytes used, including *data.
+int DisassemblerIA32::JumpShort(byte* data) {
+  assert(*data == 0xEB);
+  byte b = *(data+1);
+  byte* dest = data + static_cast<int8_t>(b) + 2;
+  AppendToBuffer("jmp %s", NameOfAddress(dest));
+  return 2;
+}
+
+
+// Returns number of bytes used, including *data.
+int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
+  assert(*data == 0x0F);
+  byte cond = *(data+1) & 0x0F;
+  byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
+  const char* mnem = jump_conditional_mnem[cond];
+  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
+  if (comment != NULL) {
+    AppendToBuffer(", %s", comment);
+  }
+  return 6;  // includes 0x0F
+}
+
+
+// Returns number of bytes used, including *data.
+int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
+  byte cond = *data & 0x0F;
+  byte b = *(data+1);
+  byte* dest = data + static_cast<int8_t>(b) + 2;
+  const char* mnem = jump_conditional_mnem[cond];
+  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
+  if (comment != NULL) {
+    AppendToBuffer(", %s", comment);
+  }
+  return 2;
+}
+
+
+// Returns number of bytes used, including *data.
+int DisassemblerIA32::FPUInstruction(byte* data) {
+  byte b1 = *data;
+  byte b2 = *(data + 1);
+  if (b1 == 0xD9) {
+    const char* mnem = NULL;
+    switch (b2) {
+      case 0xE8: mnem = "fld1"; break;
+      case 0xEE: mnem = "fldz"; break;
+      case 0xE1: mnem = "fabs"; break;
+      case 0xE0: mnem = "fchs"; break;
+      case 0xF8: mnem = "fprem"; break;
+      case 0xF5: mnem = "fprem1"; break;
+      case 0xF7: mnem = "fincstp"; break;
+      case 0xE4: mnem = "ftst"; break;
+    }
+    if (mnem != NULL) {
+      AppendToBuffer("%s", mnem);
+      return 2;
+    } else if ((b2 & 0xF8) == 0xC8) {
+      AppendToBuffer("fxch st%d", b2 & 0x7);
+      return 2;
+    } else {
+      int mod, regop, rm;
+      get_modrm(*(data+1), &mod, &regop, &rm);
+      const char* mnem = "?";
+      switch (regop) {
+        case eax: mnem = "fld_s"; break;
+        case ebx: mnem = "fstp_s"; break;
+        default: UnimplementedInstruction();
+      }
+      AppendToBuffer("%s ", mnem);
+      int count = PrintRightOperand(data + 1);
+      return count + 1;
+    }
+  } else if (b1 == 0xDD) {
+    if ((b2 & 0xF8) == 0xC0) {
+      AppendToBuffer("ffree st%d", b2 & 0x7);
+      return 2;
+    } else {
+      int mod, regop, rm;
+      get_modrm(*(data+1), &mod, &regop, &rm);
+      const char* mnem = "?";
+      switch (regop) {
+        case eax: mnem = "fld_d"; break;
+        case ebx: mnem = "fstp_d"; break;
+        default: UnimplementedInstruction();
+      }
+      AppendToBuffer("%s ", mnem);
+      int count = PrintRightOperand(data + 1);
+      return count + 1;
+    }
+  } else if (b1 == 0xDB) {
+    int mod, regop, rm;
+    get_modrm(*(data+1), &mod, &regop, &rm);
+    const char* mnem = "?";
+    switch (regop) {
+      case eax: mnem = "fild_s"; break;
+      case edx: mnem = "fist_s"; break;
+      case ebx: mnem = "fistp_s"; break;
+      default: UnimplementedInstruction();
+    }
+    AppendToBuffer("%s ", mnem);
+    int count = PrintRightOperand(data + 1);
+    return count + 1;
+  } else if (b1 == 0xDF) {
+    if (b2 == 0xE0) {
+      AppendToBuffer("fnstsw_ax");
+      return 2;
+    }
+    int mod, regop, rm;
+    get_modrm(*(data+1), &mod, &regop, &rm);
+    const char* mnem = "?";
+    switch (regop) {
+      case ebp: mnem = "fild_d"; break;
+      case edi: mnem = "fistp_d"; break;
+      default: UnimplementedInstruction();
+    }
+    AppendToBuffer("%s ", mnem);
+    int count = PrintRightOperand(data + 1);
+    return count + 1;
+  } else if (b1 == 0xDC || b1 == 0xDE) {
+    bool is_pop = (b1 == 0xDE);
+    if (is_pop && b2 == 0xD9) {
+      AppendToBuffer("fcompp");
+      return 2;
+    }
+    const char* mnem = "FP0xDC";
+    switch (b2 & 0xF8) {
+      case 0xC0: mnem = "fadd"; break;
+      case 0xE8: mnem = "fsub"; break;
+      case 0xC8: mnem = "fmul"; break;
+      case 0xF8: mnem = "fdiv"; break;
+      default: UnimplementedInstruction();
+    }
+    AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7);
+    return 2;
+  } else if (b1 == 0xDA && b2 == 0xE9) {
+    const char* mnem = "fucompp";
+    AppendToBuffer("%s", mnem);
+    return 2;
+  }
+  AppendToBuffer("Unknown FP instruction");
+  return 2;
+}
+
+
+// Mnemonics for instructions 0xF0 byte.
+// Returns NULL if the instruction is not handled here.
+static const char* F0Mnem(byte f0byte) {
+  switch (f0byte) {
+    case 0xA2: return "cpuid";
+    case 0x31: return "rdtsc";
+    case 0xBE: return "movsx_b";
+    case 0xBF: return "movsx_w";
+    case 0xB6: return "movzx_b";
+    case 0xB7: return "movzx_w";
+    case 0xAF: return "imul";
+    case 0xA5: return "shld";
+    case 0xAD: return "shrd";
+    case 0xAB: return "bts";
+    default: return NULL;
+  }
+}
+
+
+// Disassembled instruction '*instr' and writes it intro 'out_buffer'.
+int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
+                                        byte* instr) {
+  tmp_buffer_pos_ = 0;  // starting to write as position 0
+  byte* data = instr;
+  // Check for hints.
+  const char* branch_hint = NULL;
+  // We use this two prefixes only with branch prediction
+  if (*data == 0x3E /*ds*/) {
+    branch_hint = "predicted taken";
+    data++;
+  } else if (*data == 0x2E /*cs*/) {
+    branch_hint = "predicted not taken";
+    data++;
+  }
+  bool processed = true;  // Will be set to false if the current instruction
+                          // is not in 'instructions' table.
+  const InstructionDesc& idesc = instruction_table.Get(*data);
+  switch (idesc.type) {
+    case ZERO_OPERANDS_INSTR:
+      AppendToBuffer(idesc.mnem);
+      data++;
+      break;
+
+    case TWO_OPERANDS_INSTR:
+      data++;
+      data += PrintOperands(idesc.mnem, idesc.op_order_, data);
+      break;
+
+    case JUMP_CONDITIONAL_SHORT_INSTR:
+      data += JumpConditionalShort(data, branch_hint);
+      break;
+
+    case REGISTER_INSTR:
+      AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
+      data++;
+      break;
+
+    case MOVE_REG_INSTR: {
+      byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
+      AppendToBuffer("mov %s,%s",
+                     NameOfCPURegister(*data & 0x07),
+                     NameOfAddress(addr));
+      data += 5;
+      break;
+    }
+
+    case CALL_JUMP_INSTR: {
+      byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
+      AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
+      data += 5;
+      break;
+    }
+
+    case SHORT_IMMEDIATE_INSTR: {
+      byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
+      AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
+      data += 5;
+      break;
+    }
+
+    case NO_INSTR:
+      processed = false;
+      break;
+
+    default:
+      UNIMPLEMENTED();  // This type is not implemented.
+  }
+  //----------------------------
+  if (!processed) {
+    switch (*data) {
+      case 0xC2:
+        AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
+        data += 3;
+        break;
+
+      case 0x69:  // fall through
+      case 0x6B:
+        { int mod, regop, rm;
+          get_modrm(*(data+1), &mod, &regop, &rm);
+          int32_t imm =
+              *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
+          AppendToBuffer("imul %s,%s,0x%x",
+                         NameOfCPURegister(regop),
+                         NameOfCPURegister(rm),
+                         imm);
+          data += 2 + (*data == 0x6B ? 1 : 4);
+        }
+        break;
+
+      case 0xF6:
+        { int mod, regop, rm;
+          get_modrm(*(data+1), &mod, &regop, &rm);
+          if (mod == 3 && regop == eax) {
+            AppendToBuffer("test_b %s,%d", NameOfCPURegister(rm), *(data+2));
+          } else {
+            UnimplementedInstruction();
+          }
+          data += 3;
+        }
+        break;
+
+      case 0x81:  // fall through
+      case 0x83:  // 0x81 with sign extension bit set
+        data += PrintImmediateOp(data);
+        break;
+
+      case 0x0F:
+        { byte f0byte = *(data+1);
+          const char* f0mnem = F0Mnem(f0byte);
+          if (f0byte == 0xA2 || f0byte == 0x31) {
+            AppendToBuffer("%s", f0mnem);
+            data += 2;
+          } else if ((f0byte & 0xF0) == 0x80) {
+            data += JumpConditional(data, branch_hint);
+          } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
+                     f0byte == 0xB7 || f0byte == 0xAF) {
+            data += 2;
+            data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
+          } else {
+            data += 2;
+            if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
+              // shrd, shld, bts
+              AppendToBuffer("%s ", f0mnem);
+              int mod, regop, rm;
+              get_modrm(*data, &mod, &regop, &rm);
+              data += PrintRightOperand(data);
+              if (f0byte == 0xAB) {
+                AppendToBuffer(",%s", NameOfCPURegister(regop));
+              } else {
+                AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
+              }
+            } else {
+              UnimplementedInstruction();
+            }
+          }
+        }
+        break;
+
+      case 0x8F:
+        { data++;
+          int mod, regop, rm;
+          get_modrm(*data, &mod, &regop, &rm);
+          if (regop == eax) {
+            AppendToBuffer("pop ");
+            data += PrintRightOperand(data);
+          }
+        }
+        break;
+
+      case 0xFF:
+        { data++;
+          int mod, regop, rm;
+          get_modrm(*data, &mod, &regop, &rm);
+          const char* mnem = NULL;
+          switch (regop) {
+            case esi: mnem = "push"; break;
+            case eax: mnem = "inc"; break;
+            case edx: mnem = "call"; break;
+            case esp: mnem = "jmp"; break;
+            default: mnem = "???";
+          }
+          AppendToBuffer("%s ", mnem);
+          data += PrintRightOperand(data);
+        }
+        break;
+
+      case 0xC7:  // imm32, fall through
+      case 0xC6:  // imm8
+        { bool is_byte = *data == 0xC6;
+          data++;
+          AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
+          data += PrintRightOperand(data);
+          int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
+          AppendToBuffer(",0x%x", imm);
+          data += is_byte ? 1 : 4;
+        }
+        break;
+
+      case 0x88:  // 8bit, fall through
+      case 0x89:  // 32bit
+        { bool is_byte = *data == 0x88;
+          int mod, regop, rm;
+          data++;
+          get_modrm(*data, &mod, &regop, &rm);
+          AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
+          data += PrintRightOperand(data);
+          AppendToBuffer(",%s", NameOfCPURegister(regop));
+        }
+        break;
+
+      case 0x66:  // prefix
+        data++;
+        if (*data == 0x8B) {
+          data++;
+          data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
+        } else if (*data == 0x89) {
+          data++;
+          int mod, regop, rm;
+          get_modrm(*data, &mod, &regop, &rm);
+          AppendToBuffer("mov_w ");
+          data += PrintRightOperand(data);
+          AppendToBuffer(",%s", NameOfCPURegister(regop));
+        } else {
+          UnimplementedInstruction();
+        }
+        break;
+
+      case 0xFE:
+        { data++;
+          int mod, regop, rm;
+          get_modrm(*data, &mod, &regop, &rm);
+          if (mod == 3 && regop == ecx) {
+            AppendToBuffer("dec_b %s", NameOfCPURegister(rm));
+          } else {
+            UnimplementedInstruction();
+          }
+          data++;
+        }
+        break;
+
+      case 0x68:
+        AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
+        data += 5;
+        break;
+
+      case 0x6A:
+        AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
+        data += 2;
+        break;
+
+      case 0xA8:
+        AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
+        data += 2;
+        break;
+
+      case 0xA9:
+        AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
+        data += 5;
+        break;
+
+      case 0xD1:  // fall through
+      case 0xD3:  // fall through
+      case 0xC1:
+        data += D1D3C1Instruction(data);
+        break;
+
+      case 0xD9:  // fall through
+      case 0xDA:  // fall through
+      case 0xDB:  // fall through
+      case 0xDC:  // fall through
+      case 0xDD:  // fall through
+      case 0xDE:  // fall through
+      case 0xDF:
+        data += FPUInstruction(data);
+        break;
+
+      case 0xEB:
+        data += JumpShort(data);
+        break;
+
+      case 0xF2:
+        if (*(data+1) == 0x0F) {
+          byte b2 = *(data+2);
+          if (b2 == 0x11) {
+            AppendToBuffer("movsd ");
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            data += PrintRightOperand(data);
+            AppendToBuffer(",%s", NameOfXMMRegister(regop));
+          } else if (b2 == 0x10) {
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
+            data += PrintRightOperand(data);
+          } else {
+            const char* mnem = "?";
+            switch (b2) {
+              case 0x2A: mnem = "cvtsi2sd"; break;
+              case 0x58: mnem = "addsd"; break;
+              case 0x59: mnem = "mulsd"; break;
+              case 0x5C: mnem = "subsd"; break;
+              case 0x5E: mnem = "divsd"; break;
+            }
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            if (b2 == 0x2A) {
+              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+              data += PrintRightOperand(data);
+            } else {
+              AppendToBuffer("%s %s,%s",
+                             mnem,
+                             NameOfXMMRegister(regop),
+                             NameOfXMMRegister(rm));
+              data++;
+            }
+          }
+        } else {
+          UnimplementedInstruction();
+        }
+        break;
+
+      case 0xF3:
+        if (*(data+1) == 0x0F && *(data+2) == 0x2C) {
+          data += 3;
+          data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
+        } else {
+          UnimplementedInstruction();
+        }
+        break;
+
+      case 0xF7:
+        data += F7Instruction(data);
+        break;
+
+      default:
+        UnimplementedInstruction();
+    }
+  }
+
+  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
+    tmp_buffer_[tmp_buffer_pos_] = '\0';
+  }
+
+  int instr_len = data - instr;
+  ASSERT(instr_len > 0);  // Ensure progress.
+
+  int outp = 0;
+  // Instruction bytes.
+  for (byte* bp = instr; bp < data; bp++) {
+    outp += v8::internal::OS::SNPrintF(out_buffer + outp,
+                                       "%02x",
+                                       *bp);
+  }
+  for (int i = 6 - instr_len; i >= 0; i--) {
+    outp += v8::internal::OS::SNPrintF(out_buffer + outp,
+                                       "  ");
+  }
+
+  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
+                                     " %s",
+                                     tmp_buffer_.start());
+  return instr_len;
+}
+
+
+//------------------------------------------------------------------------------
+
+
+static const char* cpu_regs[8] = {
+  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
+};
+
+
+static const char* xmm_regs[8] = {
+  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+};
+
+
+const char* NameConverter::NameOfAddress(byte* addr) const {
+  static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
+  v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
+  return tmp_buffer.start();
+}
+
+
+const char* NameConverter::NameOfConstant(byte* addr) const {
+  return NameOfAddress(addr);
+}
+
+
+const char* NameConverter::NameOfCPURegister(int reg) const {
+  if (0 <= reg && reg < 8) return cpu_regs[reg];
+  return "noreg";
+}
+
+
+const char* NameConverter::NameOfXMMRegister(int reg) const {
+  if (0 <= reg && reg < 8) return xmm_regs[reg];
+  return "noxmmreg";
+}
+
+
+const char* NameConverter::NameInCode(byte* addr) const {
+  // IA32 does not embed debug strings at the moment.
+  UNREACHABLE();
+  return "";
+}
+
+
+//------------------------------------------------------------------------------
+
+static NameConverter defaultConverter;
+
+Disassembler::Disassembler() : converter_(defaultConverter) {}
+
+
+Disassembler::Disassembler(const NameConverter& converter)
+    : converter_(converter) {}
+
+
+Disassembler::~Disassembler() {}
+
+
+int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
+                                    byte* instruction) {
+  DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
+  return d.InstructionDecode(buffer, instruction);
+}
+
+
+// The IA-32 assembler does not currently use constant pools.
+int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
+
+
+/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
+  Disassembler d;
+  for (byte* pc = begin; pc < end;) {
+    v8::internal::EmbeddedVector<char, 128> buffer;
+    buffer[0] = '\0';
+    byte* prev_pc = pc;
+    pc += d.InstructionDecode(buffer, pc);
+    fprintf(f, "%p", prev_pc);
+    fprintf(f, "    ");
+
+    for (byte* bp = prev_pc; bp < pc; bp++) {
+      fprintf(f, "%02x",  *bp);
+    }
+    for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
+      fprintf(f, "  ");
+    }
+    fprintf(f, "  %s\n", buffer.start());
+  }
+}
+
+
+}  // namespace disasm
diff --git a/regexp2000/src/disasm.h b/regexp2000/src/disasm.h
new file mode 100644 (file)
index 0000000..1b72ee1
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_DISASM_H_
+#define V8_DISASM_H_
+
+namespace disasm {
+
+typedef unsigned char byte;
+
+// Interface and default implementation for converting addresses and
+// register-numbers to text.  The default implementation is machine
+// specific.
+class NameConverter {
+ public:
+  virtual ~NameConverter() {}
+  virtual const char* NameOfCPURegister(int reg) const;
+  virtual const char* NameOfXMMRegister(int reg) const;
+  virtual const char* NameOfAddress(byte* addr) const;
+  virtual const char* NameOfConstant(byte* addr) const;
+  virtual const char* NameInCode(byte* addr) const;
+};
+
+
+// A generic Disassembler interface
+class Disassembler {
+ public:
+  // Uses default NameConverter.
+  Disassembler();
+
+  // Caller deallocates converter.
+  explicit Disassembler(const NameConverter& converter);
+
+  virtual ~Disassembler();
+
+  // Writes one disassembled instruction into 'buffer' (0-terminated).
+  // Returns the length of the disassembled machine instruction in bytes.
+  int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
+
+  // Returns -1 if instruction does not mark the beginning of a constant pool,
+  // or the number of entries in the constant pool beginning here.
+  int ConstantPoolSizeAt(byte* instruction);
+
+  // Write disassembly into specified file 'f' using specified NameConverter
+  // (see constructor).
+  static void Disassemble(FILE* f, byte* begin, byte* end);
+ private:
+  const NameConverter& converter_;
+};
+
+}  // namespace disasm
+
+#endif  // V8_DISASM_H_
diff --git a/regexp2000/src/disassembler.cc b/regexp2000/src/disassembler.cc
new file mode 100644 (file)
index 0000000..12183d5
--- /dev/null
@@ -0,0 +1,309 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "code-stubs.h"
+#include "codegen.h"
+#include "debug.h"
+#include "disasm.h"
+#include "disassembler.h"
+#include "macro-assembler.h"
+#include "serialize.h"
+#include "string-stream.h"
+
+namespace v8 { namespace internal {
+
+#ifdef ENABLE_DISASSEMBLER
+
+void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
+  for (byte* pc = begin; pc < end; pc++) {
+    if (f == NULL) {
+      PrintF("%p  %4d  %02x\n", pc, pc - begin, *pc);
+    } else {
+      fprintf(f, "%p  %4d  %02x\n", pc, pc - begin, *pc);
+    }
+  }
+}
+
+
+class V8NameConverter: public disasm::NameConverter {
+ public:
+  explicit V8NameConverter(Code* code) : code_(code) {}
+  virtual const char* NameOfAddress(byte* pc) const;
+  virtual const char* NameInCode(byte* addr) const;
+  Code* code() const { return code_; }
+ private:
+  Code* code_;
+};
+
+
+const char* V8NameConverter::NameOfAddress(byte* pc) const {
+  static v8::internal::EmbeddedVector<char, 128> buffer;
+
+  const char* name = Builtins::Lookup(pc);
+  if (name != NULL) {
+    OS::SNPrintF(buffer, "%s  (%p)", name, pc);
+    return buffer.start();
+  }
+
+  if (code_ != NULL) {
+    int offs = pc - code_->instruction_start();
+    // print as code offset, if it seems reasonable
+    if (0 <= offs && offs < code_->instruction_size()) {
+      OS::SNPrintF(buffer, "%d  (%p)", offs, pc);
+      return buffer.start();
+    }
+  }
+
+  return disasm::NameConverter::NameOfAddress(pc);
+}
+
+
+const char* V8NameConverter::NameInCode(byte* addr) const {
+  // The V8NameConverter is used for well known code, so we can "safely"
+  // dereference pointers in generated code.
+  return (code_ != NULL) ? reinterpret_cast<const char*>(addr) : "";
+}
+
+
+static void DumpBuffer(FILE* f, char* buff) {
+  if (f == NULL) {
+    PrintF("%s", buff);
+  } else {
+    fprintf(f, "%s", buff);
+  }
+}
+
+static const int kOutBufferSize = 256 + String::kMaxShortPrintLength;
+static const int kRelocInfoPosition = 57;
+
+static int DecodeIt(FILE* f,
+                    const V8NameConverter& converter,
+                    byte* begin,
+                    byte* end) {
+  NoHandleAllocation ha;
+  AssertNoAllocation no_alloc;
+  ExternalReferenceEncoder ref_encoder;
+
+  v8::internal::EmbeddedVector<char, 128> decode_buffer;
+  v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
+  byte* pc = begin;
+  disasm::Disassembler d(converter);
+  RelocIterator* it = NULL;
+  if (converter.code() != NULL) {
+    it = new RelocIterator(converter.code());
+  } else {
+    // No relocation information when printing code stubs.
+  }
+  int constants = -1;  // no constants being decoded at the start
+
+  while (pc < end) {
+    // First decode instruction so that we know its length.
+    byte* prev_pc = pc;
+    if (constants > 0) {
+      OS::SNPrintF(decode_buffer,
+                   "%08x       constant",
+                   *reinterpret_cast<int32_t*>(pc));
+      constants--;
+      pc += 4;
+    } else {
+      int num_const = d.ConstantPoolSizeAt(pc);
+      if (num_const >= 0) {
+        OS::SNPrintF(decode_buffer,
+                     "%08x       constant pool begin",
+                     *reinterpret_cast<int32_t*>(pc));
+        constants = num_const;
+        pc += 4;
+      } else if (it != NULL && !it->done() && it->rinfo()->pc() == pc &&
+          it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) {
+        // raw pointer embedded in code stream, e.g., jump table
+        byte* ptr = *reinterpret_cast<byte**>(pc);
+        OS::SNPrintF(decode_buffer,
+                     "%08x      jump table entry %4d",
+                     reinterpret_cast<int32_t>(ptr),
+                     ptr - begin);
+        pc += 4;
+      } else {
+        decode_buffer[0] = '\0';
+        pc += d.InstructionDecode(decode_buffer, pc);
+      }
+    }
+
+    // Collect RelocInfo for this instruction (prev_pc .. pc-1)
+    List<const char*> comments(4);
+    List<byte*> pcs(1);
+    List<RelocInfo::Mode> rmodes(1);
+    List<intptr_t> datas(1);
+    if (it != NULL) {
+      while (!it->done() && it->rinfo()->pc() < pc) {
+        if (RelocInfo::IsComment(it->rinfo()->rmode())) {
+          // For comments just collect the text.
+          comments.Add(reinterpret_cast<const char*>(it->rinfo()->data()));
+        } else {
+          // For other reloc info collect all data.
+          pcs.Add(it->rinfo()->pc());
+          rmodes.Add(it->rinfo()->rmode());
+          datas.Add(it->rinfo()->data());
+        }
+        it->next();
+      }
+    }
+
+    StringBuilder out(out_buffer.start(), out_buffer.length());
+
+    // Comments.
+    for (int i = 0; i < comments.length(); i++) {
+      out.AddFormatted("                  %s\n", comments[i]);
+    }
+
+    // Write out comments, resets outp so that we can format the next line.
+    DumpBuffer(f, out.Finalize());
+    out.Reset();
+
+    // Instruction address and instruction offset.
+    out.AddFormatted("%p  %4d  ", prev_pc, prev_pc - begin);
+
+    // Instruction.
+    out.AddFormatted("%s", decode_buffer.start());
+
+    // Print all the reloc info for this instruction which are not comments.
+    for (int i = 0; i < pcs.length(); i++) {
+      // Put together the reloc info
+      RelocInfo relocinfo(pcs[i], rmodes[i], datas[i]);
+
+      // Indent the printing of the reloc info.
+      if (i == 0) {
+        // The first reloc info is printed after the disassembled instruction.
+        out.AddPadding(' ', kRelocInfoPosition - out.position());
+      } else {
+        // Additional reloc infos are printed on separate lines.
+        out.AddFormatted("\n");
+        out.AddPadding(' ', kRelocInfoPosition);
+      }
+
+      RelocInfo::Mode rmode = relocinfo.rmode();
+      if (RelocInfo::IsPosition(rmode)) {
+        if (RelocInfo::IsStatementPosition(rmode)) {
+          out.AddFormatted("    ;; debug: statement %d", relocinfo.data());
+        } else {
+          out.AddFormatted("    ;; debug: position %d", relocinfo.data());
+        }
+      } else if (rmode == RelocInfo::EMBEDDED_OBJECT) {
+        HeapStringAllocator allocator;
+        StringStream accumulator(&allocator);
+        relocinfo.target_object()->ShortPrint(&accumulator);
+        SmartPointer<char> obj_name = accumulator.ToCString();
+        out.AddFormatted("    ;; object: %s", *obj_name);
+      } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+        const char* reference_name =
+            ref_encoder.NameOfAddress(*relocinfo.target_reference_address());
+        out.AddFormatted("    ;; external reference (%s)", reference_name);
+      } else if (RelocInfo::IsCodeTarget(rmode)) {
+        out.AddFormatted("    ;; code:");
+        if (rmode == RelocInfo::CONSTRUCT_CALL) {
+          out.AddFormatted(" constructor,");
+        }
+        Code* code = Debug::GetCodeTarget(relocinfo.target_address());
+        Code::Kind kind = code->kind();
+        if (code->is_inline_cache_stub()) {
+          if (rmode == RelocInfo::CODE_TARGET_CONTEXT) {
+            out.AddFormatted(" contextual,");
+          }
+          InlineCacheState ic_state = code->ic_state();
+          out.AddFormatted(" %s, %s", Code::Kind2String(kind),
+              Code::ICState2String(ic_state));
+          if (kind == Code::CALL_IC) {
+            out.AddFormatted(", argc = %d", code->arguments_count());
+          }
+        } else if (kind == Code::STUB) {
+          // Reverse lookup required as the minor key cannot be retrieved
+          // from the code object.
+          Object* obj = Heap::code_stubs()->SlowReverseLookup(code);
+          if (obj != Heap::undefined_value()) {
+            ASSERT(obj->IsSmi());
+            // Get the STUB key and extract major and minor key.
+            uint32_t key = Smi::cast(obj)->value();
+            uint32_t minor_key = CodeStub::MinorKeyFromKey(key);
+            ASSERT(code->major_key() == CodeStub::MajorKeyFromKey(key));
+            out.AddFormatted(" %s, %s, ",
+                             Code::Kind2String(kind),
+                             CodeStub::MajorName(code->major_key()));
+            switch (code->major_key()) {
+              case CodeStub::CallFunction:
+                out.AddFormatted("argc = %d", minor_key);
+                break;
+              case CodeStub::Runtime: {
+                const char* name =
+                    RuntimeStub::GetNameFromMinorKey(minor_key);
+                out.AddFormatted("%s", name);
+                break;
+              }
+              default:
+                out.AddFormatted("minor: %d", minor_key);
+            }
+          }
+        } else {
+          out.AddFormatted(" %s", Code::Kind2String(kind));
+        }
+      } else {
+        out.AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
+      }
+    }
+    out.AddString("\n");
+    DumpBuffer(f, out.Finalize());
+    out.Reset();
+  }
+
+  delete it;
+  return pc - begin;
+}
+
+
+int Disassembler::Decode(FILE* f, byte* begin, byte* end) {
+  V8NameConverter defaultConverter(NULL);
+  return DecodeIt(f, defaultConverter, begin, end);
+}
+
+
+// Called by Code::CodePrint.
+void Disassembler::Decode(FILE* f, Code* code) {
+  byte* begin = Code::cast(code)->instruction_start();
+  byte* end = begin + Code::cast(code)->instruction_size();
+  V8NameConverter v8NameConverter(code);
+  DecodeIt(f, v8NameConverter, begin, end);
+}
+
+#else  // ENABLE_DISASSEMBLER
+
+void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
+int Disassembler::Decode(FILE* f, byte* begin, byte* end) { return 0; }
+void Disassembler::Decode(FILE* f, Code* code) {}
+
+#endif  // ENABLE_DISASSEMBLER
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/disassembler.h b/regexp2000/src/disassembler.h
new file mode 100644 (file)
index 0000000..5003c00
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_DISASSEMBLER_H_
+#define V8_DISASSEMBLER_H_
+
+namespace v8 { namespace internal {
+
+class Disassembler : public AllStatic {
+ public:
+  // Print the bytes in the interval [begin, end) into f.
+  static void Dump(FILE* f, byte* begin, byte* end);
+
+  // Decode instructions in the the interval [begin, end) and print the
+  // code into f. Returns the number of bytes disassembled or 1 if no
+  // instruction could be decoded.
+  static int Decode(FILE* f, byte* begin, byte* end);
+
+  // Decode instructions in code.
+  static void Decode(FILE* f, Code* code);
+ private:
+  // Decode instruction at pc and print disassembled instruction into f.
+  // Returns the instruction length in bytes, or 1 if the instruction could
+  // not be decoded.  The number of characters written is written into
+  // the out parameter char_count.
+  static int Decode(FILE* f, byte* pc, int* char_count);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_DISASSEMBLER_H_
diff --git a/regexp2000/src/dtoa-config.c b/regexp2000/src/dtoa-config.c
new file mode 100644 (file)
index 0000000..cb73c17
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007-2008 the V8 project authors. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Dtoa needs to have a particular environment set up for it so
+ * instead of using it directly you should use this file.
+ *
+ * The way it works is that when you link with it, its definitions
+ * of dtoa, strtod etc. override the default ones.  So if you fail
+ * to link with this library everything will still work, it's just
+ * subtly wrong.
+ */
+
+#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32)
+#include <endian.h>
+#endif
+#include <math.h>
+#include <float.h>
+
+/* The floating point word order on ARM is big endian when floating point
+ * emulation is used, even if the byte order is little endian */
+#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \
+  __FLOAT_WORD_ORDER == __BIG_ENDIAN
+#define  IEEE_MC68k
+#else
+#define  IEEE_8087
+#endif
+
+#define __MATH_H__
+#if defined(__APPLE__) && defined(__MACH__)
+/* stdlib.h on Apple's 10.5 and later SDKs will mangle the name of strtod.
+ * If it's included after strtod is redefined as gay_strtod, it will mangle
+ * the name of gay_strtod, which is unwanted. */
+#include <stdlib.h>
+#endif
+/* Make sure we use the David M. Gay version of strtod(). On Linux, we
+ * cannot use the same name (maybe the function does not have weak
+ * linkage?). */
+#define strtod gay_strtod
+#include "third_party/dtoa/dtoa.c"
diff --git a/regexp2000/src/execution.cc b/regexp2000/src/execution.cc
new file mode 100644 (file)
index 0000000..03541a8
--- /dev/null
@@ -0,0 +1,529 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "api.h"
+#include "codegen-inl.h"
+
+#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+#include "simulator-arm.h"
+#else  // ia32
+#include "simulator-ia32.h"
+#endif
+
+namespace v8 { namespace internal {
+
+
+static Handle<Object> Invoke(bool construct,
+                             Handle<JSFunction> func,
+                             Handle<Object> receiver,
+                             int argc,
+                             Object*** args,
+                             bool* has_pending_exception) {
+  // Make sure we have a real function, not a boilerplate function.
+  ASSERT(!func->IsBoilerplate());
+
+  // Entering JavaScript.
+  VMState state(JS);
+
+  // Guard the stack against too much recursion.
+  StackGuard guard;
+
+  // Placeholder for return value.
+  Object* value = reinterpret_cast<Object*>(kZapValue);
+
+  typedef Object* (*JSEntryFunction)(
+    byte* entry,
+    Object* function,
+    Object* receiver,
+    int argc,
+    Object*** args);
+
+  Handle<Code> code;
+  if (construct) {
+    JSConstructEntryStub stub;
+    code = stub.GetCode();
+  } else {
+    JSEntryStub stub;
+    code = stub.GetCode();
+  }
+
+  {
+    // Save and restore context around invocation and block the
+    // allocation of handles without explicit handle scopes.
+    SaveContext save;
+    NoHandleAllocation na;
+    JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
+
+    // Call the function through the right JS entry stub.
+    value = CALL_GENERATED_CODE(entry, func->code()->entry(), *func,
+                                *receiver, argc, args);
+  }
+
+#ifdef DEBUG
+  value->Verify();
+#endif
+
+  // Update the pending exception and external caught flag and return the value.
+  *has_pending_exception = value->IsException();
+  ASSERT(*has_pending_exception == Top::has_pending_exception());
+  Top::propagate_external_caught();
+
+  // If the pending exception is OutOfMemoryException set out_of_memory in
+  // the global context.  Note: We have to mark the global context here
+  // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
+  // set it.
+  if (*has_pending_exception) {
+    if (Top::pending_exception() == Failure::OutOfMemoryException()) {
+      Top::context()->mark_out_of_memory();
+    }
+  }
+
+  return Handle<Object>(value);
+}
+
+
+Handle<Object> Execution::Call(Handle<JSFunction> func,
+                               Handle<Object> receiver,
+                               int argc,
+                               Object*** args,
+                               bool* pending_exception) {
+  return Invoke(false, func, receiver, argc, args, pending_exception);
+}
+
+
+Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
+                              Object*** args, bool* pending_exception) {
+  return Invoke(true, func, Top::global(), argc, args, pending_exception);
+}
+
+
+Handle<Object> Execution::TryCall(Handle<JSFunction> func,
+                                  Handle<Object> receiver,
+                                  int argc,
+                                  Object*** args,
+                                  bool* caught_exception) {
+  // Enter a try-block while executing the JavaScript code. To avoid
+  // duplicate error printing it must be non-verbose.  Also, to avoid
+  // creating message objects during stack overflow we shouldn't
+  // capture messages.
+  v8::TryCatch catcher;
+  catcher.SetVerbose(false);
+  catcher.SetCaptureMessage(false);
+
+  Handle<Object> result = Invoke(false, func, receiver, argc, args,
+                                 caught_exception);
+
+  if (*caught_exception) {
+    ASSERT(catcher.HasCaught());
+    ASSERT(Top::has_pending_exception());
+    ASSERT(Top::external_caught_exception());
+    Top::optional_reschedule_exception(true);
+    result = v8::Utils::OpenHandle(*catcher.Exception());
+  }
+
+  ASSERT(!Top::has_pending_exception());
+  ASSERT(!Top::external_caught_exception());
+  return result;
+}
+
+
+Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
+  ASSERT(!object->IsJSFunction());
+
+  // If you return a function from here, it will be called when an
+  // attempt is made to call the given object as a function.
+
+  // The regular expression code here is really meant more as an
+  // example than anything else. KJS does not support calling regular
+  // expressions as functions, but SpiderMonkey does.
+  if (FLAG_call_regexp) {
+    bool is_regexp =
+        object->IsHeapObject() &&
+        (HeapObject::cast(*object)->map()->constructor() ==
+         *Top::regexp_function());
+
+    if (is_regexp) {
+      Handle<String> exec = Factory::exec_symbol();
+      return Handle<Object>(object->GetProperty(*exec));
+    }
+  }
+
+  // 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()) {
+    return Handle<JSFunction>(
+        Top::global_context()->call_as_function_delegate());
+  }
+
+  return Factory::undefined_value();
+}
+
+
+// Static state for stack guards.
+StackGuard::ThreadLocal StackGuard::thread_local_;
+
+
+StackGuard::StackGuard() {
+  ExecutionAccess access;
+  if (thread_local_.nesting_++ == 0 &&
+      thread_local_.jslimit_ != kInterruptLimit) {
+    // NOTE: We assume that the stack grows towards lower addresses.
+    ASSERT(thread_local_.jslimit_ == kIllegalLimit);
+    ASSERT(thread_local_.climit_ == kIllegalLimit);
+
+    thread_local_.initial_jslimit_ = thread_local_.jslimit_ =
+        GENERATED_CODE_STACK_LIMIT(kLimitSize);
+    // NOTE: The check for overflow is not safe as there is no guarantee that
+    // the running thread has its stack in all memory up to address 0x00000000.
+    thread_local_.initial_climit_ = thread_local_.climit_ =
+        reinterpret_cast<uintptr_t>(this) >= kLimitSize ?
+            reinterpret_cast<uintptr_t>(this) - kLimitSize : 0;
+
+    if (thread_local_.interrupt_flags_ != 0) {
+      set_limits(kInterruptLimit, access);
+    }
+  }
+  // make sure we have proper limits setup
+  ASSERT(thread_local_.jslimit_ != kIllegalLimit &&
+         thread_local_.climit_ != kIllegalLimit);
+}
+
+
+StackGuard::~StackGuard() {
+  ExecutionAccess access;
+  if (--thread_local_.nesting_ == 0) {
+    set_limits(kIllegalLimit, access);
+  }
+}
+
+
+bool StackGuard::IsStackOverflow() {
+  ExecutionAccess access;
+  return (thread_local_.jslimit_ != kInterruptLimit &&
+          thread_local_.climit_ != kInterruptLimit);
+}
+
+
+void StackGuard::EnableInterrupts() {
+  ExecutionAccess access;
+  if (IsSet(access)) {
+    set_limits(kInterruptLimit, access);
+  }
+}
+
+
+void StackGuard::SetStackLimit(uintptr_t limit) {
+  ExecutionAccess access;
+  // If the current limits are special (eg due to a pending interrupt) then
+  // leave them alone.
+  if (thread_local_.jslimit_ == thread_local_.initial_jslimit_) {
+    thread_local_.jslimit_ = limit;
+  }
+  if (thread_local_.climit_ == thread_local_.initial_climit_) {
+    thread_local_.climit_ = limit;
+  }
+  thread_local_.initial_climit_ = limit;
+  thread_local_.initial_jslimit_ = limit;
+}
+
+
+void StackGuard::DisableInterrupts() {
+  ExecutionAccess access;
+  reset_limits(access);
+}
+
+
+bool StackGuard::IsSet(const ExecutionAccess& lock) {
+  return thread_local_.interrupt_flags_ != 0;
+}
+
+
+bool StackGuard::IsInterrupted() {
+  ExecutionAccess access;
+  return thread_local_.interrupt_flags_ & INTERRUPT;
+}
+
+
+void StackGuard::Interrupt() {
+  ExecutionAccess access;
+  thread_local_.interrupt_flags_ |= INTERRUPT;
+  set_limits(kInterruptLimit, access);
+}
+
+
+bool StackGuard::IsPreempted() {
+  ExecutionAccess access;
+  return thread_local_.interrupt_flags_ & PREEMPT;
+}
+
+
+void StackGuard::Preempt() {
+  ExecutionAccess access;
+  thread_local_.interrupt_flags_ |= PREEMPT;
+  set_limits(kInterruptLimit, access);
+}
+
+
+bool StackGuard::IsDebugBreak() {
+  ExecutionAccess access;
+  return thread_local_.interrupt_flags_ & DEBUGBREAK;
+}
+
+
+void StackGuard::DebugBreak() {
+  ExecutionAccess access;
+  thread_local_.interrupt_flags_ |= DEBUGBREAK;
+  set_limits(kInterruptLimit, access);
+}
+
+
+void StackGuard::Continue(InterruptFlag after_what) {
+  ExecutionAccess access;
+  thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what);
+  if (thread_local_.interrupt_flags_ == 0) {
+    reset_limits(access);
+  }
+}
+
+
+int StackGuard::ArchiveSpacePerThread() {
+  return sizeof(ThreadLocal);
+}
+
+
+char* StackGuard::ArchiveStackGuard(char* to) {
+  ExecutionAccess access;
+  memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
+  ThreadLocal blank;
+  thread_local_ = blank;
+  return to + sizeof(ThreadLocal);
+}
+
+
+char* StackGuard::RestoreStackGuard(char* from) {
+  ExecutionAccess access;
+  memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
+  return from + sizeof(ThreadLocal);
+}
+
+
+// --- C a l l s   t o   n a t i v e s ---
+
+#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \
+  do {                                                              \
+    Object** args[argc] = argv;                                     \
+    ASSERT(has_pending_exception != NULL);                          \
+    return Call(Top::name##_fun(), Top::builtins(), argc, args,     \
+                has_pending_exception);                             \
+  } while (false)
+
+
+Handle<Object> Execution::ToBoolean(Handle<Object> obj) {
+  // See the similar code in runtime.js:ToBoolean.
+  if (obj->IsBoolean()) return obj;
+  bool result = true;
+  if (obj->IsString()) {
+    result = Handle<String>::cast(obj)->length() != 0;
+  } else if (obj->IsNull() || obj->IsUndefined()) {
+    result = false;
+  } else if (obj->IsNumber()) {
+    double value = obj->Number();
+    result = !((value == 0) || isnan(value));
+  }
+  return Handle<Object>(Heap::ToBoolean(result));
+}
+
+
+Handle<Object> Execution::ToNumber(Handle<Object> obj, bool* exc) {
+  RETURN_NATIVE_CALL(to_number, 1, { obj.location() }, exc);
+}
+
+
+Handle<Object> Execution::ToString(Handle<Object> obj, bool* exc) {
+  RETURN_NATIVE_CALL(to_string, 1, { obj.location() }, exc);
+}
+
+
+Handle<Object> Execution::ToDetailString(Handle<Object> obj, bool* exc) {
+  RETURN_NATIVE_CALL(to_detail_string, 1, { obj.location() }, exc);
+}
+
+
+Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) {
+  if (obj->IsJSObject()) return obj;
+  RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc);
+}
+
+
+Handle<Object> Execution::ToInteger(Handle<Object> obj, bool* exc) {
+  RETURN_NATIVE_CALL(to_integer, 1, { obj.location() }, exc);
+}
+
+
+Handle<Object> Execution::ToUint32(Handle<Object> obj, bool* exc) {
+  RETURN_NATIVE_CALL(to_uint32, 1, { obj.location() }, exc);
+}
+
+
+Handle<Object> Execution::ToInt32(Handle<Object> obj, bool* exc) {
+  RETURN_NATIVE_CALL(to_int32, 1, { obj.location() }, exc);
+}
+
+
+Handle<Object> Execution::NewDate(double time, bool* exc) {
+  Handle<Object> time_obj = Factory::NewNumber(time);
+  RETURN_NATIVE_CALL(create_date, 1, { time_obj.location() }, exc);
+}
+
+
+#undef RETURN_NATIVE_CALL
+
+
+Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) {
+  int int_index = static_cast<int>(index);
+  if (int_index < 0 || int_index >= string->length()) {
+    return Factory::undefined_value();
+  }
+
+  Handle<Object> char_at =
+      GetProperty(Top::builtins(), Factory::char_at_symbol());
+  if (!char_at->IsJSFunction()) {
+    return Factory::undefined_value();
+  }
+
+  bool caught_exception;
+  Handle<Object> index_object = Factory::NewNumberFromInt(int_index);
+  Object** index_arg[] = { index_object.location() };
+  Handle<Object> result = TryCall(Handle<JSFunction>::cast(char_at),
+                                  string,
+                                  ARRAY_SIZE(index_arg),
+                                  index_arg,
+                                  &caught_exception);
+  if (caught_exception) {
+    return Factory::undefined_value();
+  }
+  return result;
+}
+
+
+Handle<JSFunction> Execution::InstantiateFunction(
+    Handle<FunctionTemplateInfo> data, bool* exc) {
+  // Fast case: see if the function has already been instantiated
+  int serial_number = Smi::cast(data->serial_number())->value();
+  Object* elm =
+      Top::global_context()->function_cache()->GetElement(serial_number);
+  if (!elm->IsUndefined()) return Handle<JSFunction>(JSFunction::cast(elm));
+  // The function has not yet been instantiated in this context; do it.
+  Object** args[1] = { Handle<Object>::cast(data).location() };
+  Handle<Object> result =
+      Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc);
+  if (*exc) return Handle<JSFunction>::null();
+  return Handle<JSFunction>::cast(result);
+}
+
+
+Handle<JSObject> Execution::InstantiateObject(Handle<ObjectTemplateInfo> data,
+                                              bool* exc) {
+  if (data->property_list()->IsUndefined() &&
+      !data->constructor()->IsUndefined()) {
+    Object* result;
+    {
+      HandleScope scope;
+      Handle<FunctionTemplateInfo> cons_template =
+          Handle<FunctionTemplateInfo>(
+              FunctionTemplateInfo::cast(data->constructor()));
+      Handle<JSFunction> cons = InstantiateFunction(cons_template, exc);
+      if (*exc) return Handle<JSObject>::null();
+      Handle<Object> value = New(cons, 0, NULL, exc);
+      if (*exc) return Handle<JSObject>::null();
+      result = *value;
+    }
+    ASSERT(!*exc);
+    return Handle<JSObject>(JSObject::cast(result));
+  } else {
+    Object** args[1] = { Handle<Object>::cast(data).location() };
+    Handle<Object> result =
+        Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc);
+    if (*exc) return Handle<JSObject>::null();
+    return Handle<JSObject>::cast(result);
+  }
+}
+
+
+void Execution::ConfigureInstance(Handle<Object> instance,
+                                  Handle<Object> instance_template,
+                                  bool* exc) {
+  Object** args[2] = { instance.location(), instance_template.location() };
+  Execution::Call(Top::configure_instance_fun(), Top::builtins(), 2, args, exc);
+}
+
+
+Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
+                                            Handle<JSFunction> fun,
+                                            Handle<Object> pos,
+                                            Handle<Object> is_global) {
+  const int argc = 4;
+  Object** args[argc] = { recv.location(),
+                          Handle<Object>::cast(fun).location(),
+                          pos.location(),
+                          is_global.location() };
+  bool caught_exception = false;
+  Handle<Object> result = TryCall(Top::get_stack_trace_line_fun(),
+                                  Top::builtins(), argc, args,
+                                  &caught_exception);
+  if (caught_exception || !result->IsString()) return Factory::empty_symbol();
+  return Handle<String>::cast(result);
+}
+
+
+// --- G C   E x t e n s i o n ---
+
+const char* GCExtension::kSource = "native function gc();";
+
+
+v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction(
+    v8::Handle<v8::String> str) {
+  return v8::FunctionTemplate::New(GCExtension::GC);
+}
+
+
+v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
+  // All allocation spaces other than NEW_SPACE have the same effect.
+  Heap::CollectGarbage(0, OLD_DATA_SPACE);
+  return v8::Undefined();
+}
+
+
+static GCExtension kGCExtension;
+v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension);
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/execution.h b/regexp2000/src/execution.h
new file mode 100644 (file)
index 0000000..25a987f
--- /dev/null
@@ -0,0 +1,262 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_EXECUTION_H_
+#define V8_EXECUTION_H_
+
+namespace v8 { namespace internal {
+
+
+// Flag used to set the interrupt causes.
+enum InterruptFlag {
+  INTERRUPT = 1 << 0,
+  DEBUGBREAK = 1 << 1,
+  PREEMPT = 1 << 2
+};
+
+class Execution : public AllStatic {
+ public:
+  // Call a function, the caller supplies a receiver and an array
+  // of arguments. Arguments are Object* type. After function returns,
+  // pointers in 'args' might be invalid.
+  //
+  // *pending_exception tells whether the invoke resulted in
+  // a pending exception.
+  //
+  static Handle<Object> Call(Handle<JSFunction> func,
+                             Handle<Object> receiver,
+                             int argc,
+                             Object*** args,
+                             bool* pending_exception);
+
+  // Construct object from function, the caller supplies an array of
+  // arguments. Arguments are Object* type. After function returns,
+  // pointers in 'args' might be invalid.
+  //
+  // *pending_exception tells whether the invoke resulted in
+  // a pending exception.
+  //
+  static Handle<Object> New(Handle<JSFunction> func,
+                            int argc,
+                            Object*** args,
+                            bool* pending_exception);
+
+  // Call a function, just like Call(), but make sure to silently catch
+  // any thrown exceptions. The return value is either the result of
+  // calling the function (if caught exception is false) or the exception
+  // that occurred (if caught exception is true).
+  static Handle<Object> TryCall(Handle<JSFunction> func,
+                                Handle<Object> receiver,
+                                int argc,
+                                Object*** args,
+                                bool* caught_exception);
+
+  // ECMA-262 9.2
+  static Handle<Object> ToBoolean(Handle<Object> obj);
+
+  // ECMA-262 9.3
+  static Handle<Object> ToNumber(Handle<Object> obj, bool* exc);
+
+  // ECMA-262 9.4
+  static Handle<Object> ToInteger(Handle<Object> obj, bool* exc);
+
+  // ECMA-262 9.5
+  static Handle<Object> ToInt32(Handle<Object> obj, bool* exc);
+
+  // ECMA-262 9.6
+  static Handle<Object> ToUint32(Handle<Object> obj, bool* exc);
+
+  // ECMA-262 9.8
+  static Handle<Object> ToString(Handle<Object> obj, bool* exc);
+
+  // ECMA-262 9.8
+  static Handle<Object> ToDetailString(Handle<Object> obj, bool* exc);
+
+  // ECMA-262 9.9
+  static Handle<Object> ToObject(Handle<Object> obj, bool* exc);
+
+  // Create a new date object from 'time'.
+  static Handle<Object> NewDate(double time, bool* exc);
+
+  // Used to implement [] notation on strings (calls JS code)
+  static Handle<Object> CharAt(Handle<String> str, uint32_t index);
+
+  static Handle<Object> GetFunctionFor();
+  static Handle<JSFunction> InstantiateFunction(
+      Handle<FunctionTemplateInfo> data, bool* exc);
+  static Handle<JSObject> InstantiateObject(Handle<ObjectTemplateInfo> data,
+                                            bool* exc);
+  static void ConfigureInstance(Handle<Object> instance,
+                                Handle<Object> data,
+                                bool* exc);
+  static Handle<String> GetStackTraceLine(Handle<Object> recv,
+                                          Handle<JSFunction> fun,
+                                          Handle<Object> pos,
+                                          Handle<Object> is_global);
+
+  // Get a function delegate (or undefined) for the given non-function
+  // object. Used for support calling objects as functions.
+  static Handle<Object> GetFunctionDelegate(Handle<Object> object);
+};
+
+
+class ExecutionAccess;
+
+
+// Stack guards are used to limit the number of nested invocations of
+// JavaScript and the stack size used in each invocation.
+class StackGuard BASE_EMBEDDED {
+ public:
+  StackGuard();
+
+  ~StackGuard();
+
+  static void SetStackLimit(uintptr_t limit);
+
+  static Address address_of_jslimit() {
+    return reinterpret_cast<Address>(&thread_local_.jslimit_);
+  }
+
+  // Threading support.
+  static char* ArchiveStackGuard(char* to);
+  static char* RestoreStackGuard(char* from);
+  static int ArchiveSpacePerThread();
+
+  static bool IsStackOverflow();
+  static bool IsPreempted();
+  static void Preempt();
+  static bool IsInterrupted();
+  static void Interrupt();
+  static bool IsDebugBreak();
+  static void DebugBreak();
+  static void Continue(InterruptFlag after_what);
+
+ private:
+  // You should hold the ExecutionAccess lock when calling this method.
+  static bool IsSet(const ExecutionAccess& lock);
+
+  // This provides an asynchronous read of the stack limit for the current
+  // thread.  There are no locks protecting this, but it is assumed that you
+  // have the global V8 lock if you are using multiple V8 threads.
+  static uintptr_t climit() {
+    return thread_local_.climit_;
+  }
+
+  // You should hold the ExecutionAccess lock when calling this method.
+  static void set_limits(uintptr_t value, const ExecutionAccess& lock) {
+    thread_local_.jslimit_ = value;
+    thread_local_.climit_ = value;
+  }
+
+  // Reset limits to initial values. For example after handling interrupt.
+  // You should hold the ExecutionAccess lock when calling this method.
+  static void reset_limits(const ExecutionAccess& lock) {
+    if (thread_local_.nesting_ == 0) {
+      // No limits have been set yet.
+      set_limits(kIllegalLimit, lock);
+    } else {
+      thread_local_.jslimit_ = thread_local_.initial_jslimit_;
+      thread_local_.climit_ = thread_local_.initial_climit_;
+    }
+  }
+
+  // Enable or disable interrupts.
+  static void EnableInterrupts();
+  static void DisableInterrupts();
+
+  static const uintptr_t kLimitSize = 512 * KB;
+  static const uintptr_t kInterruptLimit = 0xfffffffe;
+  static const uintptr_t kIllegalLimit = 0xffffffff;
+
+  class ThreadLocal {
+   public:
+    ThreadLocal()
+     : initial_jslimit_(kIllegalLimit),
+       jslimit_(kIllegalLimit),
+       initial_climit_(kIllegalLimit),
+       climit_(kIllegalLimit),
+       nesting_(0),
+       postpone_interrupts_nesting_(0),
+       interrupt_flags_(0) {}
+    uintptr_t initial_jslimit_;
+    uintptr_t jslimit_;
+    uintptr_t initial_climit_;
+    uintptr_t climit_;
+    int nesting_;
+    int postpone_interrupts_nesting_;
+    int interrupt_flags_;
+  };
+
+  static ThreadLocal thread_local_;
+
+  friend class StackLimitCheck;
+  friend class PostponeInterruptsScope;
+};
+
+
+// Support for checking for stack-overflows in C++ code.
+class StackLimitCheck BASE_EMBEDDED {
+ public:
+  bool HasOverflowed() const {
+    return reinterpret_cast<uintptr_t>(this) < StackGuard::climit();
+  }
+};
+
+
+// Support for temporarily postponing interrupts. When the outermost
+// postpone scope is left the interrupts will be re-enabled and any
+// interrupts that occurred while in the scope will be taken into
+// account.
+class PostponeInterruptsScope BASE_EMBEDDED {
+ public:
+  PostponeInterruptsScope() {
+    StackGuard::thread_local_.postpone_interrupts_nesting_++;
+    StackGuard::DisableInterrupts();
+  }
+
+  ~PostponeInterruptsScope() {
+    if (--StackGuard::thread_local_.postpone_interrupts_nesting_ == 0) {
+      StackGuard::EnableInterrupts();
+    }
+  }
+};
+
+
+class GCExtension : public v8::Extension {
+ public:
+  GCExtension() : v8::Extension("v8/gc", kSource) {}
+  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
+      v8::Handle<v8::String> name);
+  static v8::Handle<v8::Value> GC(const v8::Arguments& args);
+ private:
+  static const char* kSource;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_EXECUTION_H_
diff --git a/regexp2000/src/factory.cc b/regexp2000/src/factory.cc
new file mode 100644 (file)
index 0000000..55af33d
--- /dev/null
@@ -0,0 +1,841 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "debug.h"
+#include "execution.h"
+#include "factory.h"
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+
+Handle<FixedArray> Factory::NewFixedArray(int size, PretenureFlag pretenure) {
+  ASSERT(0 <= size);
+  CALL_HEAP_FUNCTION(Heap::AllocateFixedArray(size, pretenure), FixedArray);
+}
+
+
+Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors) {
+  ASSERT(0 <= number_of_descriptors);
+  CALL_HEAP_FUNCTION(DescriptorArray::Allocate(number_of_descriptors),
+                     DescriptorArray);
+}
+
+
+// Symbols are created in the old generation (data space).
+Handle<String> Factory::LookupSymbol(Vector<const char> string) {
+  CALL_HEAP_FUNCTION(Heap::LookupSymbol(string), String);
+}
+
+
+Handle<String> Factory::NewStringFromAscii(Vector<const char> string,
+                                           PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(Heap::AllocateStringFromAscii(string, pretenure), String);
+}
+
+Handle<String> Factory::NewStringFromUtf8(Vector<const char> string,
+                                          PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(Heap::AllocateStringFromUtf8(string, pretenure), String);
+}
+
+
+Handle<String> Factory::NewStringFromTwoByte(Vector<const uc16> string) {
+  CALL_HEAP_FUNCTION(Heap::AllocateStringFromTwoByte(string), String);
+}
+
+
+Handle<String> Factory::NewRawTwoByteString(int length,
+                                            PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(length, pretenure), String);
+}
+
+
+Handle<String> Factory::NewConsString(Handle<String> first,
+                                      Handle<String> second) {
+  if (first->length() == 0) return second;
+  if (second->length() == 0) return first;
+  CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first, *second), String);
+}
+
+
+Handle<String> Factory::NewStringSlice(Handle<String> str, int begin, int end) {
+  CALL_HEAP_FUNCTION(str->Slice(begin, end), String);
+}
+
+
+Handle<String> Factory::NewExternalStringFromAscii(
+    ExternalAsciiString::Resource* resource) {
+  CALL_HEAP_FUNCTION(Heap::AllocateExternalStringFromAscii(resource), String);
+}
+
+
+Handle<String> Factory::NewExternalStringFromTwoByte(
+    ExternalTwoByteString::Resource* resource) {
+  CALL_HEAP_FUNCTION(Heap::AllocateExternalStringFromTwoByte(resource), String);
+}
+
+
+Handle<Context> Factory::NewGlobalContext() {
+  CALL_HEAP_FUNCTION(Heap::AllocateGlobalContext(), Context);
+}
+
+
+Handle<Context> Factory::NewFunctionContext(int length,
+                                            Handle<JSFunction> closure) {
+  CALL_HEAP_FUNCTION(Heap::AllocateFunctionContext(length, *closure), Context);
+}
+
+
+Handle<Context> Factory::NewWithContext(Handle<Context> previous,
+                                        Handle<JSObject> extension) {
+  CALL_HEAP_FUNCTION(Heap::AllocateWithContext(*previous, *extension), Context);
+}
+
+
+Handle<Struct> Factory::NewStruct(InstanceType type) {
+  CALL_HEAP_FUNCTION(Heap::AllocateStruct(type), Struct);
+}
+
+
+Handle<AccessorInfo> Factory::NewAccessorInfo() {
+  Handle<AccessorInfo> info =
+      Handle<AccessorInfo>::cast(NewStruct(ACCESSOR_INFO_TYPE));
+  info->set_flag(0);  // Must clear the flag, it was initialized as undefined.
+  return info;
+}
+
+
+Handle<Script> Factory::NewScript(Handle<String> source) {
+  Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE));
+  script->set_source(*source);
+  script->set_name(Heap::undefined_value());
+  script->set_line_offset(Smi::FromInt(0));
+  script->set_column_offset(Smi::FromInt(0));
+  script->set_wrapper(*Factory::NewProxy(0, TENURED));
+  script->set_type(Smi::FromInt(SCRIPT_TYPE_NORMAL));
+  return script;
+}
+
+
+Handle<Proxy> Factory::NewProxy(Address addr, PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(Heap::AllocateProxy(addr, pretenure), Proxy);
+}
+
+
+Handle<Proxy> Factory::NewProxy(const AccessorDescriptor* desc) {
+  return NewProxy((Address) desc, TENURED);
+}
+
+
+Handle<ByteArray> Factory::NewByteArray(int length) {
+  ASSERT(0 <= length);
+  CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length), ByteArray);
+}
+
+
+Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
+  CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map);
+}
+
+
+Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
+  CALL_HEAP_FUNCTION(Heap::AllocateFunctionPrototype(*function), JSObject);
+}
+
+
+Handle<Map> Factory::CopyMap(Handle<Map> src) {
+  CALL_HEAP_FUNCTION(src->Copy(), Map);
+}
+
+
+Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
+  CALL_HEAP_FUNCTION(src->CopyDropTransitions(), Map);
+}
+
+
+Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
+  CALL_HEAP_FUNCTION(array->Copy(), FixedArray);
+}
+
+
+Handle<JSFunction> Factory::BaseNewFunctionFromBoilerplate(
+    Handle<JSFunction> boilerplate,
+    Handle<Map> function_map) {
+  ASSERT(boilerplate->IsBoilerplate());
+  ASSERT(!boilerplate->has_initial_map());
+  ASSERT(!boilerplate->has_prototype());
+  ASSERT(boilerplate->properties() == Heap::empty_fixed_array());
+  ASSERT(boilerplate->elements() == Heap::empty_fixed_array());
+  CALL_HEAP_FUNCTION(Heap::AllocateFunction(*function_map,
+                                            boilerplate->shared(),
+                                            Heap::the_hole_value()),
+                     JSFunction);
+}
+
+
+Handle<JSFunction> Factory::NewFunctionFromBoilerplate(
+    Handle<JSFunction> boilerplate,
+    Handle<Context> context) {
+  Handle<JSFunction> result =
+      BaseNewFunctionFromBoilerplate(boilerplate, Top::function_map());
+  result->set_context(*context);
+  int number_of_literals = boilerplate->NumberOfLiterals();
+  Handle<FixedArray> literals =
+      Factory::NewFixedArray(number_of_literals, TENURED);
+  if (number_of_literals > 0) {
+    // Store the object, regexp and array functions in the literals
+    // array prefix.  These functions will be used when creating
+    // object, regexp and array literals in this function.
+    literals->set(JSFunction::kLiteralGlobalContextIndex,
+                  context->global_context());
+  }
+  result->set_literals(*literals);
+  ASSERT(!result->IsBoilerplate());
+  return result;
+}
+
+
+Handle<Object> Factory::NewNumber(double value,
+                                  PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(Heap::NumberFromDouble(value, pretenure), Object);
+}
+
+
+Handle<Object> Factory::NewNumberFromInt(int value) {
+  CALL_HEAP_FUNCTION(Heap::NumberFromInt32(value), Object);
+}
+
+
+Handle<JSObject> Factory::NewNeanderObject() {
+  CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(Heap::neander_map()),
+                     JSObject);
+}
+
+
+Handle<Object> Factory::NewTypeError(const char* type,
+                                     Vector< Handle<Object> > args) {
+  return NewError("MakeTypeError", type, args);
+}
+
+
+Handle<Object> Factory::NewTypeError(Handle<String> message) {
+  return NewError("$TypeError", message);
+}
+
+
+Handle<Object> Factory::NewRangeError(const char* type,
+                                      Vector< Handle<Object> > args) {
+  return NewError("MakeRangeError", type, args);
+}
+
+
+Handle<Object> Factory::NewRangeError(Handle<String> message) {
+  return NewError("$RangeError", message);
+}
+
+
+Handle<Object> Factory::NewSyntaxError(const char* type, Handle<JSArray> args) {
+  return NewError("MakeSyntaxError", type, args);
+}
+
+
+Handle<Object> Factory::NewSyntaxError(Handle<String> message) {
+  return NewError("$SyntaxError", message);
+}
+
+
+Handle<Object> Factory::NewReferenceError(const char* type,
+                                          Vector< Handle<Object> > args) {
+  return NewError("MakeReferenceError", type, args);
+}
+
+
+Handle<Object> Factory::NewReferenceError(Handle<String> message) {
+  return NewError("$ReferenceError", message);
+}
+
+
+Handle<Object> Factory::NewError(const char* maker, const char* type,
+    Vector< Handle<Object> > args) {
+  HandleScope scope;
+  Handle<FixedArray> array = Factory::NewFixedArray(args.length());
+  for (int i = 0; i < args.length(); i++) {
+    array->set(i, *args[i]);
+  }
+  Handle<JSArray> object = Factory::NewJSArrayWithElements(array);
+  Handle<Object> result = NewError(maker, type, object);
+  return result.EscapeFrom(&scope);
+}
+
+
+Handle<Object> Factory::NewEvalError(const char* type,
+                                     Vector< Handle<Object> > args) {
+  return NewError("MakeEvalError", type, args);
+}
+
+
+Handle<Object> Factory::NewError(const char* type,
+                                 Vector< Handle<Object> > args) {
+  return NewError("MakeError", type, args);
+}
+
+
+Handle<Object> Factory::NewError(const char* maker,
+                                 const char* type,
+                                 Handle<JSArray> args) {
+  Handle<String> make_str = Factory::LookupAsciiSymbol(maker);
+  Handle<JSFunction> fun =
+      Handle<JSFunction>(
+          JSFunction::cast(
+              Top::builtins()->GetProperty(*make_str)));
+  Handle<Object> type_obj = Factory::LookupAsciiSymbol(type);
+  Object** argv[2] = { type_obj.location(),
+                       Handle<Object>::cast(args).location() };
+
+  // Invoke the JavaScript factory method. If an exception is thrown while
+  // running the factory method, use the exception as the result.
+  bool caught_exception;
+  Handle<Object> result = Execution::TryCall(fun,
+                                             Top::builtins(),
+                                             2,
+                                             argv,
+                                             &caught_exception);
+  return result;
+}
+
+
+Handle<Object> Factory::NewError(Handle<String> message) {
+  return NewError("$Error", message);
+}
+
+
+Handle<Object> Factory::NewError(const char* constructor,
+                                 Handle<String> message) {
+  Handle<String> constr = Factory::LookupAsciiSymbol(constructor);
+  Handle<JSFunction> fun =
+      Handle<JSFunction>(
+          JSFunction::cast(
+              Top::builtins()->GetProperty(*constr)));
+  Object** argv[1] = { Handle<Object>::cast(message).location() };
+
+  // Invoke the JavaScript factory method. If an exception is thrown while
+  // running the factory method, use the exception as the result.
+  bool caught_exception;
+  Handle<Object> result = Execution::TryCall(fun,
+                                             Top::builtins(),
+                                             1,
+                                             argv,
+                                             &caught_exception);
+  return result;
+}
+
+
+Handle<JSFunction> Factory::NewFunction(Handle<String> name,
+                                        InstanceType type,
+                                        int instance_size,
+                                        Handle<Code> code,
+                                        bool force_initial_map) {
+  // Allocate the function
+  Handle<JSFunction> function = NewFunction(name, the_hole_value());
+  function->set_code(*code);
+
+  if (force_initial_map ||
+      type != JS_OBJECT_TYPE ||
+      instance_size != JSObject::kHeaderSize) {
+    Handle<Map> initial_map = NewMap(type, instance_size);
+    Handle<JSObject> prototype = NewFunctionPrototype(function);
+    initial_map->set_prototype(*prototype);
+    function->set_initial_map(*initial_map);
+    initial_map->set_constructor(*function);
+  } else {
+    ASSERT(!function->has_initial_map());
+    ASSERT(!function->has_prototype());
+  }
+
+  return function;
+}
+
+
+Handle<JSFunction> Factory::NewFunctionBoilerplate(Handle<String> name,
+                                                   int number_of_literals,
+                                                   bool contains_array_literal,
+                                                   Handle<Code> code) {
+  Handle<JSFunction> function = NewFunctionBoilerplate(name);
+  function->set_code(*code);
+  int literals_array_size = number_of_literals;
+  // If the function contains object, regexp or array literals,
+  // allocate extra space for a literals array prefix containing the
+  // object, regexp and array constructor functions.
+  if (number_of_literals > 0 || contains_array_literal) {
+    literals_array_size += JSFunction::kLiteralsPrefixSize;
+  }
+  Handle<FixedArray> literals =
+      Factory::NewFixedArray(literals_array_size, TENURED);
+  function->set_literals(*literals);
+  ASSERT(!function->has_initial_map());
+  ASSERT(!function->has_prototype());
+  return function;
+}
+
+
+Handle<JSFunction> Factory::NewFunctionBoilerplate(Handle<String> name) {
+  Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(name);
+  CALL_HEAP_FUNCTION(Heap::AllocateFunction(Heap::boilerplate_function_map(),
+                                            *shared,
+                                            Heap::the_hole_value()),
+                     JSFunction);
+}
+
+
+Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
+                                                     InstanceType type,
+                                                     int instance_size,
+                                                     Handle<JSObject> prototype,
+                                                     Handle<Code> code,
+                                                     bool force_initial_map) {
+  // Allocate the function
+  Handle<JSFunction> function = NewFunction(name, prototype);
+
+  function->set_code(*code);
+
+  if (force_initial_map ||
+      type != JS_OBJECT_TYPE ||
+      instance_size != JSObject::kHeaderSize) {
+    Handle<Map> initial_map = NewMap(type, instance_size);
+    function->set_initial_map(*initial_map);
+    initial_map->set_constructor(*function);
+  }
+
+  // Set function.prototype and give the prototype a constructor
+  // property that refers to the function.
+  SetPrototypeProperty(function, prototype);
+  SetProperty(prototype, Factory::constructor_symbol(), function, DONT_ENUM);
+  return function;
+}
+
+Handle<Code> Factory::NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
+                              Code::Flags flags) {
+  CALL_HEAP_FUNCTION(Heap::CreateCode(desc, sinfo, flags), Code);
+}
+
+
+Handle<Code> Factory::CopyCode(Handle<Code> code) {
+  CALL_HEAP_FUNCTION(Heap::CopyCode(*code), Code);
+}
+
+
+#define CALL_GC(RETRY)                                                     \
+  do {                                                                     \
+    if (!Heap::CollectGarbage(Failure::cast(RETRY)->requested(),           \
+                              Failure::cast(RETRY)->allocation_space())) { \
+      /* TODO(1181417): Fix this. */                                       \
+      V8::FatalProcessOutOfMemory("Factory CALL_GC");                      \
+    }                                                                      \
+  } while (false)
+
+
+// Allocate the new array. We cannot use the CALL_HEAP_FUNCTION macro here,
+// because the stack-allocated CallbacksDescriptor instance is not GC safe.
+Handle<DescriptorArray> Factory::CopyAppendProxyDescriptor(
+    Handle<DescriptorArray> array,
+    Handle<String> key,
+    Handle<Object> value,
+    PropertyAttributes attributes) {
+  GC_GREEDY_CHECK();
+  CallbacksDescriptor desc(*key, *value, attributes);
+  Object* obj = array->CopyInsert(&desc, REMOVE_TRANSITIONS);
+  if (obj->IsFailure()) {
+    if (obj->IsRetryAfterGC()) {
+      CALL_GC(obj);
+      CallbacksDescriptor desc(*key, *value, attributes);
+      obj = array->CopyInsert(&desc, REMOVE_TRANSITIONS);
+    }
+    if (obj->IsFailure()) {
+      // TODO(1181417): Fix this.
+      V8::FatalProcessOutOfMemory("CopyAppendProxyDescriptor");
+    }
+  }
+  return Handle<DescriptorArray>(DescriptorArray::cast(obj));
+}
+
+#undef CALL_GC
+
+
+Handle<String> Factory::SymbolFromString(Handle<String> value) {
+  CALL_HEAP_FUNCTION(Heap::LookupSymbol(*value), String);
+}
+
+
+Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
+    Handle<DescriptorArray> array,
+    Handle<Object> descriptors) {
+  v8::NeanderArray callbacks(descriptors);
+  int nof_callbacks = callbacks.length();
+  Handle<DescriptorArray> result =
+      NewDescriptorArray(array->number_of_descriptors() + nof_callbacks);
+
+  // Number of descriptors added to the result so far.
+  int descriptor_count = 0;
+
+  // Copy the descriptors from the array.
+  DescriptorWriter w(*result);
+  for (DescriptorReader r(*array); !r.eos(); r.advance()) {
+    w.WriteFrom(&r);
+    descriptor_count++;
+  }
+
+  // Number of duplicates detected.
+  int duplicates = 0;
+
+  // Fill in new callback descriptors.  Process the callbacks from
+  // back to front so that the last callback with a given name takes
+  // precedence over previously added callbacks with that name.
+  for (int i = nof_callbacks - 1; i >= 0; i--) {
+    Handle<AccessorInfo> entry =
+        Handle<AccessorInfo>(AccessorInfo::cast(callbacks.get(i)));
+    // Ensure the key is a symbol before writing into the instance descriptor.
+    Handle<String> key =
+        SymbolFromString(Handle<String>(String::cast(entry->name())));
+    // Check if a descriptor with this name already exists before writing.
+    if (result->LinearSearch(*key, descriptor_count) ==
+        DescriptorArray::kNotFound) {
+      CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
+      w.Write(&desc);
+      descriptor_count++;
+    } else {
+      duplicates++;
+    }
+  }
+
+  // If duplicates were detected, allocate a result of the right size
+  // and transfer the elements.
+  if (duplicates > 0) {
+    Handle<DescriptorArray> new_result =
+        NewDescriptorArray(result->number_of_descriptors() - duplicates);
+    DescriptorWriter w(*new_result);
+    DescriptorReader r(*result);
+    while (!w.eos()) {
+      w.WriteFrom(&r);
+      r.advance();
+    }
+    result = new_result;
+  }
+
+  // Sort the result before returning.
+  result->Sort();
+  return result;
+}
+
+
+Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor,
+                                      PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(Heap::AllocateJSObject(*constructor, pretenure), JSObject);
+}
+
+
+Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map) {
+  CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, NOT_TENURED),
+                     JSObject);
+}
+
+
+Handle<JSObject> Factory::NewObjectLiteral(int expected_number_of_properties) {
+  Handle<Map> map = Handle<Map>(Top::object_function()->initial_map());
+  map = Factory::CopyMap(map);
+  map->set_instance_descriptors(Heap::empty_descriptor_array());
+  map->set_unused_property_fields(expected_number_of_properties);
+  CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, TENURED),
+                     JSObject);
+}
+
+
+Handle<JSArray> Factory::NewArrayLiteral(int length) {
+  return NewJSArrayWithElements(NewFixedArray(length), TENURED);
+}
+
+
+Handle<JSArray> Factory::NewJSArray(int length,
+                                    PretenureFlag pretenure) {
+  Handle<JSObject> obj = NewJSObject(Top::array_function(), pretenure);
+  CALL_HEAP_FUNCTION(Handle<JSArray>::cast(obj)->Initialize(length), JSArray);
+}
+
+
+Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArray> elements,
+                                                PretenureFlag pretenure) {
+  Handle<JSArray> result =
+      Handle<JSArray>::cast(NewJSObject(Top::array_function(), pretenure));
+  result->SetContent(*elements);
+  return result;
+}
+
+
+Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
+  CALL_HEAP_FUNCTION(Heap::AllocateSharedFunctionInfo(*name),
+                     SharedFunctionInfo);
+}
+
+
+Handle<Dictionary> Factory::DictionaryAtNumberPut(Handle<Dictionary> dictionary,
+                                                  uint32_t key,
+                                                  Handle<Object> value) {
+  CALL_HEAP_FUNCTION(dictionary->AtNumberPut(key, *value), Dictionary);
+}
+
+
+Handle<JSFunction> Factory::NewFunctionHelper(Handle<String> name,
+                                              Handle<Object> prototype) {
+  Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
+  CALL_HEAP_FUNCTION(Heap::AllocateFunction(*Top::function_map(),
+                                            *function_share,
+                                            *prototype),
+                     JSFunction);
+}
+
+
+Handle<JSFunction> Factory::NewFunction(Handle<String> name,
+                                        Handle<Object> prototype) {
+  Handle<JSFunction> fun = NewFunctionHelper(name, prototype);
+  fun->set_context(Top::context()->global_context());
+  return fun;
+}
+
+
+Handle<Object> Factory::ToObject(Handle<Object> object,
+                                 Handle<Context> global_context) {
+  CALL_HEAP_FUNCTION(object->ToObject(*global_context), Object);
+}
+
+
+Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) {
+  // Get the original code of the function.
+  Handle<Code> code(shared->code());
+
+  // Create a copy of the code before allocating the debug info object to avoid
+  // allocation while setting up the debug info object.
+  Handle<Code> original_code(*Factory::CopyCode(code));
+
+  // Allocate initial fixed array for active break points before allocating the
+  // debug info object to avoid allocation while setting up the debug info
+  // object.
+  Handle<FixedArray> break_points(
+      Factory::NewFixedArray(Debug::kEstimatedNofBreakPointsInFunction));
+
+  // Create and set up the debug info object. Debug info contains function, a
+  // copy of the original code, the executing code and initial fixed array for
+  // active break points.
+  Handle<DebugInfo> debug_info =
+      Handle<DebugInfo>::cast(Factory::NewStruct(DEBUG_INFO_TYPE));
+  debug_info->set_shared(*shared);
+  debug_info->set_original_code(*original_code);
+  debug_info->set_code(*code);
+  debug_info->set_break_points(*break_points);
+
+  // Link debug info to function.
+  shared->set_debug_info(*debug_info);
+
+  return debug_info;
+}
+
+
+Handle<JSObject> Factory::NewArgumentsObject(Handle<Object> callee,
+                                             int length) {
+  CALL_HEAP_FUNCTION(Heap::AllocateArgumentsObject(*callee, length), JSObject);
+}
+
+
+Handle<JSFunction> Factory::CreateApiFunction(
+    Handle<FunctionTemplateInfo> obj, ApiInstanceType instance_type) {
+  Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::HandleApiCall));
+
+  int internal_field_count = 0;
+  if (!obj->instance_template()->IsUndefined()) {
+    Handle<ObjectTemplateInfo> instance_template =
+        Handle<ObjectTemplateInfo>(
+            ObjectTemplateInfo::cast(obj->instance_template()));
+    internal_field_count =
+        Smi::cast(instance_template->internal_field_count())->value();
+  }
+
+  int instance_size = kPointerSize * internal_field_count;
+  InstanceType type = INVALID_TYPE;
+  switch (instance_type) {
+    case JavaScriptObject:
+      type = JS_OBJECT_TYPE;
+      instance_size += JSObject::kHeaderSize;
+      break;
+    case InnerGlobalObject:
+      type = JS_GLOBAL_OBJECT_TYPE;
+      instance_size += JSGlobalObject::kSize;
+      break;
+    case OuterGlobalObject:
+      type = JS_GLOBAL_PROXY_TYPE;
+      instance_size += JSGlobalProxy::kSize;
+      break;
+    default:
+      break;
+  }
+  ASSERT(type != INVALID_TYPE);
+
+  Handle<JSFunction> result =
+      Factory::NewFunction(Factory::empty_symbol(), type, instance_size,
+                           code, true);
+  // Set class name.
+  Handle<Object> class_name = Handle<Object>(obj->class_name());
+  if (class_name->IsString()) {
+    result->shared()->set_instance_class_name(*class_name);
+    result->shared()->set_name(*class_name);
+  }
+
+  Handle<Map> map = Handle<Map>(result->initial_map());
+
+  // Mark as undetectable if needed.
+  if (obj->undetectable()) {
+    map->set_is_undetectable();
+  }
+
+  // Mark as hidden for the __proto__ accessor if needed.
+  if (obj->hidden_prototype()) {
+    map->set_is_hidden_prototype();
+  }
+
+  // Mark as needs_access_check if needed.
+  if (obj->needs_access_check()) {
+    map->set_is_access_check_needed();
+  }
+
+  // Set interceptor information in the map.
+  if (!obj->named_property_handler()->IsUndefined()) {
+    map->set_has_named_interceptor();
+  }
+  if (!obj->indexed_property_handler()->IsUndefined()) {
+    map->set_has_indexed_interceptor();
+  }
+
+  // Set instance call-as-function information in the map.
+  if (!obj->instance_call_handler()->IsUndefined()) {
+    map->set_has_instance_call_handler();
+  }
+
+  result->shared()->set_function_data(*obj);
+  result->shared()->DontAdaptArguments();
+
+  // Recursively copy parent templates' accessors, 'data' may be modified.
+  Handle<DescriptorArray> array =
+      Handle<DescriptorArray>(map->instance_descriptors());
+  while (true) {
+    Handle<Object> props = Handle<Object>(obj->property_accessors());
+    if (!props->IsUndefined()) {
+      array = Factory::CopyAppendCallbackDescriptors(array, props);
+    }
+    Handle<Object> parent = Handle<Object>(obj->parent_template());
+    if (parent->IsUndefined()) break;
+    obj = Handle<FunctionTemplateInfo>::cast(parent);
+  }
+  if (!array->IsEmpty()) {
+    map->set_instance_descriptors(*array);
+  }
+
+  return result;
+}
+
+
+Handle<MapCache> Factory::NewMapCache(int at_least_space_for) {
+  CALL_HEAP_FUNCTION(MapCache::Allocate(at_least_space_for), MapCache);
+}
+
+
+static Object* UpdateMapCacheWith(Context* context,
+                                  FixedArray* keys,
+                                  Map* map) {
+  Object* result = MapCache::cast(context->map_cache())->Put(keys, map);
+  if (!result->IsFailure()) context->set_map_cache(MapCache::cast(result));
+  return result;
+}
+
+
+Handle<MapCache> Factory::AddToMapCache(Handle<Context> context,
+                                        Handle<FixedArray> keys,
+                                        Handle<Map> map) {
+  CALL_HEAP_FUNCTION(UpdateMapCacheWith(*context, *keys, *map), MapCache);
+}
+
+
+Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<Context> context,
+                                               Handle<FixedArray> keys) {
+  if (context->map_cache()->IsUndefined()) {
+    // Allocate the new map cache for the global context.
+    Handle<MapCache> new_cache = NewMapCache(24);
+    context->set_map_cache(*new_cache);
+  }
+  // Check to see whether there is a maching element in the cache.
+  Handle<MapCache> cache =
+      Handle<MapCache>(MapCache::cast(context->map_cache()));
+  Handle<Object> result = Handle<Object>(cache->Lookup(*keys));
+  if (result->IsMap()) return Handle<Map>::cast(result);
+  // Create a new map and add it to the cache.
+  Handle<Map> map =
+      CopyMap(Handle<Map>(context->object_function()->initial_map()));
+  AddToMapCache(context, keys, map);
+  return Handle<Map>(map);
+}
+
+
+void Factory::SetRegExpData(Handle<JSRegExp> regexp,
+                            JSRegExp::Type type,
+                            Handle<String> source,
+                            JSRegExp::Flags flags,
+                            Handle<Object> data) {
+  Handle<FixedArray> store = NewFixedArray(JSRegExp::kDataSize);
+  store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
+  store->set(JSRegExp::kSourceIndex, *source);
+  store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
+  store->set(JSRegExp::kAtomPatternIndex, *data);
+  regexp->set_data(*store);
+}
+
+
+void Factory::ConfigureInstance(Handle<FunctionTemplateInfo> desc,
+                                Handle<JSObject> instance,
+                                bool* pending_exception) {
+  // Configure the instance by adding the properties specified by the
+  // instance template.
+  Handle<Object> instance_template = Handle<Object>(desc->instance_template());
+  if (!instance_template->IsUndefined()) {
+    Execution::ConfigureInstance(instance,
+                                 instance_template,
+                                 pending_exception);
+  } else {
+    *pending_exception = false;
+  }
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/factory.h b/regexp2000/src/factory.h
new file mode 100644 (file)
index 0000000..bb04b6b
--- /dev/null
@@ -0,0 +1,343 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FACTORY_H_
+#define V8_FACTORY_H_
+
+#include "heap.h"
+
+namespace v8 { namespace internal {
+
+
+// Interface for handle based allocation.
+
+class Factory : public AllStatic {
+ public:
+  // Allocate a new fixed array.
+  static Handle<FixedArray> NewFixedArray(
+      int size,
+      PretenureFlag pretenure = NOT_TENURED);
+
+  static Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
+
+  static Handle<String> LookupSymbol(Vector<const char> str);
+  static Handle<String> LookupAsciiSymbol(const char* str) {
+    return LookupSymbol(CStrVector(str));
+  }
+
+
+  // String creation functions.  Most of the string creation functions take
+  // a Heap::PretenureFlag argument to optionally request that they be
+  // allocated in the old generation.  The pretenure flag defaults to
+  // DONT_TENURE.
+  //
+  // Creates a new String object.  There are two String encodings: ASCII and
+  // two byte.  One should choose between the three string factory functions
+  // based on the encoding of the string buffer that the string is
+  // initialized from.
+  //   - ...FromAscii initializes the string from a buffer that is ASCII
+  //     encoded (it does not check that the buffer is ASCII encoded) and
+  //     the result will be ASCII encoded.
+  //   - ...FromUtf8 initializes the string from a buffer that is UTF-8
+  //     encoded.  If the characters are all single-byte characters, the
+  //     result will be ASCII encoded, otherwise it will converted to two
+  //     byte.
+  //   - ...FromTwoByte initializes the string from a buffer that is two
+  //     byte encoded.  If the characters are all single-byte characters,
+  //     the result will be converted to ASCII, otherwise it will be left as
+  //     two byte.
+  //
+  // ASCII strings are pretenured when used as keys in the SourceCodeCache.
+  static Handle<String> NewStringFromAscii(
+      Vector<const char> str,
+      PretenureFlag pretenure = NOT_TENURED);
+
+  // UTF8 strings are pretenured when used for regexp literal patterns and
+  // flags in the parser.
+  static Handle<String> NewStringFromUtf8(
+      Vector<const char> str,
+      PretenureFlag pretenure = NOT_TENURED);
+
+  static Handle<String> NewStringFromTwoByte(Vector<const uc16> str);
+
+  // Allocates and partially initializes a TwoByte String. The characters of
+  // the string are uninitialized. Currently used in regexp code only, where
+  // they are pretenured.
+  static Handle<String> NewRawTwoByteString(
+      int length,
+      PretenureFlag pretenure = NOT_TENURED);
+
+  // Create a new cons string object which consists of a pair of strings.
+  static Handle<String> NewConsString(Handle<String> first,
+                                      Handle<String> second);
+
+  // Create a new sliced string object which represents a substring of a
+  // backing string.
+  static Handle<String> NewStringSlice(Handle<String> str, int begin, int end);
+
+  // Creates a new external String object.  There are two String encodings
+  // in the system: ASCII and two byte.  Unlike other String types, it does
+  // not make sense to have a UTF-8 factory function for external strings,
+  // because we cannot change the underlying buffer.
+  static Handle<String> NewExternalStringFromAscii(
+      ExternalAsciiString::Resource* resource);
+  static Handle<String> NewExternalStringFromTwoByte(
+      ExternalTwoByteString::Resource* resource);
+
+  // Create a global (but otherwise uninitialized) context.
+  static Handle<Context> NewGlobalContext();
+
+  // Create a function context.
+  static Handle<Context> NewFunctionContext(int length,
+                                            Handle<JSFunction> closure);
+
+  // Create a 'with' context.
+  static Handle<Context> NewWithContext(Handle<Context> previous,
+                                        Handle<JSObject> extension);
+
+  // Return the Symbol maching the passed in string.
+  static Handle<String> SymbolFromString(Handle<String> value);
+
+  // Allocate a new struct.  The struct is pretenured (allocated directly in
+  // the old generation).
+  static Handle<Struct> NewStruct(InstanceType type);
+
+  static Handle<AccessorInfo> NewAccessorInfo();
+
+  static Handle<Script> NewScript(Handle<String> source);
+
+  // Proxies are pretenured when allocated by the bootstrapper.
+  static Handle<Proxy> NewProxy(Address addr,
+                                PretenureFlag pretenure = NOT_TENURED);
+
+  // Allocate a new proxy.  The proxy is pretenured (allocated directly in
+  // the old generation).
+  static Handle<Proxy> NewProxy(const AccessorDescriptor* proxy);
+
+  static Handle<ByteArray> NewByteArray(int length);
+
+  static Handle<Map> NewMap(InstanceType type, int instance_size);
+
+  static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
+
+  static Handle<Map> CopyMap(Handle<Map> map);
+
+  static Handle<Map> CopyMapDropTransitions(Handle<Map> map);
+
+  static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
+
+  // Numbers (eg, literals) are pretenured by the parser.
+  static Handle<Object> NewNumber(double value,
+                                  PretenureFlag pretenure = NOT_TENURED);
+
+  static Handle<Object> NewNumberFromInt(int value);
+
+  // These objects are used by the api to create env-independent data
+  // structures in the heap.
+  static Handle<JSObject> NewNeanderObject();
+
+  static Handle<JSObject> NewArgumentsObject(Handle<Object> callee, int length);
+
+  // JS objects are pretenured when allocated by the bootstrapper and
+  // runtime.
+  static Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
+                                      PretenureFlag pretenure = NOT_TENURED);
+
+  // JS objects are pretenured when allocated by the bootstrapper and
+  // runtime.
+  static Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
+
+  // Allocate a JS object representing an object literal.  The object is
+  // pretenured (allocated directly in the old generation).
+  static Handle<JSObject> NewObjectLiteral(int expected_number_of_properties);
+
+  // Allocate a JS array representing an array literal.  The array is
+  // pretenured (allocated directly in the old generation).
+  static Handle<JSArray> NewArrayLiteral(int length);
+
+  // JS arrays are pretenured when allocated by the parser.
+  static Handle<JSArray> NewJSArray(int init_length,
+                                    PretenureFlag pretenure = NOT_TENURED);
+
+  static Handle<JSArray> NewJSArrayWithElements(
+      Handle<FixedArray> elements,
+      PretenureFlag pretenure = NOT_TENURED);
+
+  static Handle<JSFunction> NewFunction(Handle<String> name,
+                                        Handle<Object> prototype);
+
+  static Handle<JSFunction> NewFunction(Handle<Object> super, bool is_global);
+
+  static Handle<JSFunction> NewFunctionFromBoilerplate(
+      Handle<JSFunction> boilerplate,
+      Handle<Context> context);
+
+  static Handle<Code> NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
+                              Code::Flags flags);
+
+  static Handle<Code> CopyCode(Handle<Code> code);
+
+  static Handle<Object> ToObject(Handle<Object> object,
+                                 Handle<Context> global_context);
+
+  // Interface for creating error objects.
+
+  static Handle<Object> NewError(const char* maker, const char* type,
+                                 Handle<JSArray> args);
+  static Handle<Object> NewError(const char* maker, const char* type,
+                                 Vector< Handle<Object> > args);
+  static Handle<Object> NewError(const char* type,
+                                 Vector< Handle<Object> > args);
+  static Handle<Object> NewError(Handle<String> message);
+  static Handle<Object> NewError(const char* constructor,
+                                 Handle<String> message);
+
+  static Handle<Object> NewTypeError(const char* type,
+                                     Vector< Handle<Object> > args);
+  static Handle<Object> NewTypeError(Handle<String> message);
+
+  static Handle<Object> NewRangeError(const char* type,
+                                      Vector< Handle<Object> > args);
+  static Handle<Object> NewRangeError(Handle<String> message);
+
+  static Handle<Object> NewSyntaxError(const char* type, Handle<JSArray> args);
+  static Handle<Object> NewSyntaxError(Handle<String> message);
+
+  static Handle<Object> NewReferenceError(const char* type,
+                                          Vector< Handle<Object> > args);
+  static Handle<Object> NewReferenceError(Handle<String> message);
+
+  static Handle<Object> NewEvalError(const char* type,
+                                     Vector< Handle<Object> > args);
+
+
+  static Handle<JSFunction> NewFunction(Handle<String> name,
+                                        InstanceType type,
+                                        int instance_size,
+                                        Handle<Code> code,
+                                        bool force_initial_map);
+
+  static Handle<JSFunction> NewFunctionBoilerplate(Handle<String> name,
+                                                   int number_of_literals,
+                                                   bool contains_array_literal,
+                                                   Handle<Code> code);
+
+  static Handle<JSFunction> NewFunctionBoilerplate(Handle<String> name);
+
+  static Handle<JSFunction> NewFunction(Handle<Map> function_map,
+      Handle<SharedFunctionInfo> shared, Handle<Object> prototype);
+
+
+  static Handle<JSFunction> NewFunctionWithPrototype(Handle<String> name,
+                                                     InstanceType type,
+                                                     int instance_size,
+                                                     Handle<JSObject> prototype,
+                                                     Handle<Code> code,
+                                                     bool force_initial_map);
+
+  static Handle<DescriptorArray> CopyAppendProxyDescriptor(
+      Handle<DescriptorArray> array,
+      Handle<String> key,
+      Handle<Object> value,
+      PropertyAttributes attributes);
+
+  enum ApiInstanceType {
+    JavaScriptObject,
+    InnerGlobalObject,
+    OuterGlobalObject
+  };
+
+  static Handle<JSFunction> CreateApiFunction(
+      Handle<FunctionTemplateInfo> data,
+      ApiInstanceType type = JavaScriptObject);
+
+  static Handle<JSFunction> InstallMembers(Handle<JSFunction> function);
+
+  // Installs interceptors on the instance.  'desc' is a function template,
+  // and instance is an object instance created by the function of this
+  // function tempalte.
+  static void ConfigureInstance(Handle<FunctionTemplateInfo> desc,
+                                Handle<JSObject> instance,
+                                bool* pending_exception);
+
+#define ROOT_ACCESSOR(type, name) \
+  static Handle<type> name() { return Handle<type>(&Heap::name##_); }
+  ROOT_LIST(ROOT_ACCESSOR)
+#undef ROOT_ACCESSOR_ACCESSOR
+
+#define SYMBOL_ACCESSOR(name, str) \
+  static Handle<String> name() { return Handle<String>(&Heap::name##_); }
+  SYMBOL_LIST(SYMBOL_ACCESSOR)
+#undef SYMBOL_ACCESSOR
+
+  static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
+
+  static Handle<Dictionary> DictionaryAtNumberPut(Handle<Dictionary>,
+                                                  uint32_t key,
+                                                  Handle<Object> value);
+
+  static Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
+
+
+  // Return a map using the map cache in the global context.
+  // The key the an ordered set of property names.
+  static Handle<Map> ObjectLiteralMapFromCache(Handle<Context> context,
+                                               Handle<FixedArray> keys);
+
+  // Creates a new FixedArray that holds the data associated with the
+  // regexp and stores it in the regexp.
+  static void SetRegExpData(Handle<JSRegExp> regexp,
+                            JSRegExp::Type type,
+                            Handle<String> source,
+                            JSRegExp::Flags flags,
+                            Handle<Object> data);
+
+ private:
+  static Handle<JSFunction> NewFunctionHelper(Handle<String> name,
+                                              Handle<Object> prototype);
+
+  static Handle<DescriptorArray> CopyAppendCallbackDescriptors(
+      Handle<DescriptorArray> array,
+      Handle<Object> descriptors);
+
+  static Handle<JSFunction> BaseNewFunctionFromBoilerplate(
+      Handle<JSFunction> boilerplate,
+      Handle<Map> function_map);
+
+  // Create a new map cache.
+  static Handle<MapCache> NewMapCache(int at_least_space_for);
+
+  // Update the map cache in the global context with (keys, map)
+  static Handle<MapCache> AddToMapCache(Handle<Context> context,
+                                        Handle<FixedArray> keys,
+                                        Handle<Map> map);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_FACTORY_H_
diff --git a/regexp2000/src/flag-definitions.h b/regexp2000/src/flag-definitions.h
new file mode 100644 (file)
index 0000000..9ef2518
--- /dev/null
@@ -0,0 +1,323 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file defines all of the flags.  It is separated into different section,
+// for Debug, Release, Logging and Profiling, etc.  To add a new flag, find the
+// correct section, and use one of the DEFINE_ macros, without a trailing ';'.
+//
+// This include does not have a guard, because it is a template-style include,
+// which can be included multiple times in different modes.  It expects to have
+// a mode defined before it's included.  The modes are FLAG_MODE_... below:
+
+// We want to declare the names of the variables for the header file.  Normally
+// this will just be an extern declaration, but for a readonly flag we let the
+// compiler make better optimizations by giving it the value.
+#if defined(FLAG_MODE_DECLARE)
+#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
+  extern ctype FLAG_##nam;
+#define FLAG_READONLY(ftype, ctype, nam, def, cmt) \
+  static ctype const FLAG_##nam = def;
+
+// We want to supply the actual storage and value for the flag variable in the
+// .cc file.  We only do this for writable flags.
+#elif defined(FLAG_MODE_DEFINE)
+#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
+  ctype FLAG_##nam = def;
+#define FLAG_READONLY(ftype, ctype, nam, def, cmt)
+
+// We need to define all of our default values so that the Flag structure can
+// access them by pointer.  These are just used internally inside of one .cc,
+// for MODE_META, so there is no impact on the flags interface.
+#elif defined(FLAG_MODE_DEFINE_DEFAULTS)
+#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
+  static ctype const FLAGDEFAULT_##nam = def;
+#define FLAG_READONLY(ftype, ctype, nam, def, cmt)
+
+
+// We want to write entries into our meta data table, for internal parsing and
+// printing / etc in the flag parser code.  We only do this for writable flags.
+#elif defined(FLAG_MODE_META)
+#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
+  { Flag::TYPE_##ftype, #nam, &FLAG_##nam, &FLAGDEFAULT_##nam, cmt },
+#define FLAG_READONLY(ftype, ctype, nam, def, cmt)
+
+#else
+#error No mode supplied when including flags.defs
+#endif
+
+#define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
+#define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
+#define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
+#define DEFINE_string(nam, def, cmt) FLAG(STRING, const char*, nam, def, cmt)
+
+//
+// Flags in all modes.
+//
+#define FLAG FLAG_FULL
+
+// assembler-ia32.cc / assembler-arm.cc
+DEFINE_bool(debug_code, false,
+            "generate extra code (comments, assertions) for debugging")
+DEFINE_bool(emit_branch_hints, false, "emit branch hints")
+DEFINE_bool(push_pop_elimination, true,
+            "eliminate redundant push/pops in assembly code")
+DEFINE_bool(print_push_pop_elimination, false,
+            "print elimination of redundant push/pops in assembly code")
+
+// bootstrapper.cc
+DEFINE_string(expose_natives_as, NULL, "expose natives in global object")
+DEFINE_string(expose_debug_as, NULL, "expose debug in global object")
+DEFINE_string(natives_file, NULL, "alternative natives file")
+DEFINE_bool(expose_gc, false, "expose gc extension")
+
+// builtins-ia32.cc
+DEFINE_bool(inline_new, true, "use fast inline allocation")
+
+// checks.cc
+DEFINE_bool(stack_trace_on_abort, true,
+            "print a stack trace if an assertion failure occurs")
+
+// codegen-ia32.cc / codegen-arm.cc
+DEFINE_bool(trace, false, "trace function calls")
+DEFINE_bool(defer_negation, true, "defer negation operation")
+DEFINE_bool(check_stack, true,
+            "check stack for overflow, interrupt, breakpoint")
+
+// codegen.cc
+DEFINE_bool(lazy, true, "use lazy compilation")
+DEFINE_bool(debug_info, true, "add debug information to compiled functions")
+
+// compiler.cc
+DEFINE_bool(strict, false, "strict error checking")
+DEFINE_int(min_preparse_length, 1024,
+           "Minimum length for automatic enable preparsing")
+
+// debug.cc
+DEFINE_bool(remote_debugging, false, "enable remote debugging")
+DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
+
+// execution.cc
+DEFINE_bool(call_regexp, false, "allow calls to RegExp objects")
+
+// frames.cc
+DEFINE_int(max_stack_trace_source_length, 300,
+           "maximum length of function source code printed in a stack trace.")
+
+// heap.cc
+DEFINE_int(new_space_size, 0, "size of (each semispace in) the new generation")
+DEFINE_int(old_space_size, 0, "size of the old generation")
+DEFINE_bool(gc_global, false, "always perform global GCs")
+DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
+DEFINE_bool(trace_gc, false,
+            "print one trace line following each garbage collection")
+
+// ic.cc
+DEFINE_bool(use_ic, true, "use inline caching")
+
+// macro-assembler-ia32.cc
+DEFINE_bool(native_code_counters, false,
+            "generate extra code for manipulating stats counters")
+
+// mark-compact.cc
+DEFINE_bool(always_compact, false, "Perform compaction on every full GC")
+DEFINE_bool(never_compact, false,
+            "Never perform compaction on full GC - testing only")
+DEFINE_bool(cleanup_ics_at_gc, true,
+            "Flush inline caches prior to mark compact collection.")
+DEFINE_bool(cleanup_caches_in_maps_at_gc, true,
+            "Flush code caches in maps during mark compact cycle.")
+
+DEFINE_bool(canonicalize_object_literal_maps, true,
+            "Canonicalize maps for object literals.")
+
+// mksnapshot.cc
+DEFINE_bool(h, false, "print this message")
+
+// parser.cc
+DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
+
+// simulator-arm.cc
+DEFINE_bool(trace_sim, false, "trace simulator execution")
+DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions")
+
+// top.cc
+DEFINE_bool(trace_exception, false,
+            "print stack trace when throwing exceptions")
+DEFINE_bool(preallocate_message_memory, false,
+            "preallocate some memory to build stack traces.")
+
+// usage-analyzer.cc
+DEFINE_bool(usage_computation, true, "compute variable usage counts")
+
+// v8.cc
+DEFINE_bool(preemption, false,
+            "activate a 100ms timer that switches between V8 threads")
+
+// Testing flags test/cctest/test-{flags,api,serialization}.cc
+DEFINE_bool(testing_bool_flag, true, "testing_bool_flag")
+DEFINE_int(testing_int_flag, 13, "testing_int_flag")
+DEFINE_float(testing_float_flag, 2.5, "float-flag")
+DEFINE_string(testing_string_flag, "Hello, world!", "string-flag")
+DEFINE_int(testing_prng_seed, 42, "Seed used for threading test randomness")
+#ifdef WIN32
+DEFINE_string(testing_serialization_file, "C:\\Windows\\Temp\\serdes",
+              "file in which to testing_serialize heap")
+#else
+DEFINE_string(testing_serialization_file, "/tmp/serdes",
+              "file in which to serialize heap")
+#endif
+
+//
+// Dev shell flags
+//
+
+DEFINE_bool(dump_counters, false, "Dump counters on exit")
+
+//
+// Debug only flags
+//
+#undef FLAG
+#ifdef DEBUG
+#define FLAG FLAG_FULL
+#else
+#define FLAG FLAG_READONLY
+#endif
+
+// checks.cc
+DEFINE_bool(enable_slow_asserts, false,
+            "enable asserts that are slow to execute")
+
+// code-stubs.cc
+DEFINE_bool(print_code_stubs, false, "print code stubs")
+
+// codegen-ia32.cc / codegen-arm.cc
+DEFINE_bool(trace_codegen, false,
+            "print name of functions for which code is generated")
+DEFINE_bool(print_builtin_code, false, "print generated code for builtins")
+DEFINE_bool(print_source, false, "pretty print source code")
+DEFINE_bool(print_builtin_source, false,
+            "pretty print source code for builtins")
+DEFINE_bool(print_ast, false, "print source AST")
+DEFINE_bool(print_builtin_ast, false, "print source AST for builtins")
+DEFINE_bool(trace_calls, false, "trace calls")
+DEFINE_bool(trace_builtin_calls, false, "trace builtins calls")
+DEFINE_string(stop_at, "", "function name where to insert a breakpoint")
+
+// compiler.cc
+DEFINE_bool(print_builtin_scopes, false, "print scopes for builtins")
+DEFINE_bool(print_scopes, false, "print scopes")
+
+// contexts.cc
+DEFINE_bool(trace_contexts, false, "trace contexts operations")
+
+// heap.cc
+DEFINE_bool(gc_greedy, false, "perform GC prior to some allocations")
+DEFINE_bool(gc_verbose, false, "print stuff during garbage collection")
+DEFINE_bool(heap_stats, false, "report heap statistics before and after GC")
+DEFINE_bool(code_stats, false, "report code statistics after GC")
+DEFINE_bool(verify_heap, false, "verify heap pointers before and after GC")
+DEFINE_bool(print_handles, false, "report handles after GC")
+DEFINE_bool(print_global_handles, false, "report global handles after GC")
+DEFINE_bool(print_rset, false, "print remembered sets before GC")
+
+// ic.cc
+DEFINE_bool(trace_ic, false, "trace inline cache state transitions")
+
+// objects.cc
+DEFINE_bool(trace_normalization,
+            false,
+            "prints when objects are turned into dictionaries.")
+
+// runtime.cc
+DEFINE_bool(trace_lazy, false, "trace lazy compilation")
+
+// serialize.cc
+DEFINE_bool(debug_serialization, false,
+            "write debug information into the snapshot.")
+
+// spaces.cc
+DEFINE_bool(collect_heap_spill_statistics, false,
+            "report heap spill statistics along with heap_stats "
+            "(requires heap_stats)")
+
+DEFINE_bool(trace_regexps, false, "trace regexp execution")
+
+//
+// Logging and profiling only flags
+//
+#undef FLAG
+#ifdef ENABLE_LOGGING_AND_PROFILING
+#define FLAG FLAG_FULL
+#else
+#define FLAG FLAG_READONLY
+#endif
+
+// log.cc
+DEFINE_bool(log, false,
+            "Minimal logging (no API, code, GC, suspect, or handles samples).")
+DEFINE_bool(log_all, false, "Log all events to the log file.")
+DEFINE_bool(log_api, false, "Log API events to the log file.")
+DEFINE_bool(log_code, false,
+            "Log code events to the log file without profiling.")
+DEFINE_bool(log_gc, false,
+            "Log heap samples on garbage collection for the hp2ps tool.")
+DEFINE_bool(log_handles, false, "Log global handle events.")
+DEFINE_bool(log_state_changes, false, "Log state changes.")
+DEFINE_bool(log_suspect, false, "Log suspect operations.")
+DEFINE_bool(prof, false,
+            "Log statistical profiling information (implies --log-code).")
+DEFINE_bool(log_regexp, false, "Log regular expression execution.")
+DEFINE_bool(sliding_state_window, false,
+            "Update sliding state window counters.")
+DEFINE_string(logfile, "v8.log", "Specify the name of the log file.")
+
+//
+// Disassembler only flags
+//
+#undef FLAG
+#ifdef ENABLE_DISASSEMBLER
+#define FLAG FLAG_FULL
+#else
+#define FLAG FLAG_READONLY
+#endif
+
+// codegen-ia32.cc / codegen-arm.cc
+DEFINE_bool(print_code, false, "print generated code")
+
+// Cleanup...
+#undef FLAG_FULL
+#undef FLAG_READONLY
+#undef FLAG
+
+#undef DEFINE_bool
+#undef DEFINE_int
+#undef DEFINE_string
+
+#undef FLAG_MODE_DECLARE
+#undef FLAG_MODE_DEFINE
+#undef FLAG_MODE_DEFINE_DEFAULTS
+#undef FLAG_MODE_META
diff --git a/regexp2000/src/flags.cc b/regexp2000/src/flags.cc
new file mode 100644 (file)
index 0000000..73bb855
--- /dev/null
@@ -0,0 +1,459 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+
+namespace v8 { namespace internal {
+
+// Define all of our flags.
+#define FLAG_MODE_DEFINE
+#include "flag-definitions.h"
+
+// Define all of our flags default values.
+#define FLAG_MODE_DEFINE_DEFAULTS
+#include "flag-definitions.h"
+
+namespace {
+
+// This structure represents a single entry in the flag system, with a pointer
+// to the actual flag, default value, comment, etc.  This is designed to be POD
+// initialized as to avoid requiring static constructors.
+struct Flag {
+  enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING };
+
+  FlagType type_;           // What type of flag, bool, int, or string.
+  const char* name_;        // Name of the flag, ex "my_flag".
+  void* valptr_;            // Pointer to the global flag variable.
+  const void* defptr_;      // Pointer to the default value.
+  const char* cmt_;         // A comment about the flags purpose.
+
+  FlagType type() const { return type_; }
+
+  const char* name() const { return name_; }
+
+  const char* comment() const { return cmt_; }
+
+  bool* bool_variable() const {
+    ASSERT(type_ == TYPE_BOOL);
+    return reinterpret_cast<bool*>(valptr_);
+  }
+
+  int* int_variable() const {
+    ASSERT(type_ == TYPE_INT);
+    return reinterpret_cast<int*>(valptr_);
+  }
+
+  double* float_variable() const {
+    ASSERT(type_ == TYPE_FLOAT);
+    return reinterpret_cast<double*>(valptr_);
+  }
+
+  const char** string_variable() const {
+    ASSERT(type_ == TYPE_STRING);
+    return reinterpret_cast<const char**>(valptr_);
+  }
+
+  bool bool_default() const {
+    ASSERT(type_ == TYPE_BOOL);
+    return *reinterpret_cast<const bool*>(defptr_);
+  }
+
+  int int_default() const {
+    ASSERT(type_ == TYPE_INT);
+    return *reinterpret_cast<const int*>(defptr_);
+  }
+
+  double float_default() const {
+    ASSERT(type_ == TYPE_FLOAT);
+    return *reinterpret_cast<const double*>(defptr_);
+  }
+
+  const char* string_default() const {
+    ASSERT(type_ == TYPE_STRING);
+    return *reinterpret_cast<const char* const *>(defptr_);
+  }
+
+  // Compare this flag's current value against the default.
+  bool IsDefault() const {
+    switch (type_) {
+      case TYPE_BOOL:
+        return *bool_variable() == bool_default();
+      case TYPE_INT:
+        return *int_variable() == int_default();
+      case TYPE_FLOAT:
+        return *float_variable() == float_default();
+      case TYPE_STRING:
+        const char* str1 = *string_variable();
+        const char* str2 = string_default();
+        if (str2 == NULL) return str1 == NULL;
+        if (str1 == NULL) return str2 == NULL;
+        return strcmp(str1, str2) == 0;
+    }
+    UNREACHABLE();
+    return true;
+  }
+
+  // Set a flag back to it's default value.
+  void Reset() {
+    switch (type_) {
+      case TYPE_BOOL:
+        *bool_variable() = bool_default();
+        break;
+      case TYPE_INT:
+        *int_variable() = int_default();
+        break;
+      case TYPE_FLOAT:
+        *float_variable() = float_default();
+        break;
+      case TYPE_STRING:
+        *string_variable() = string_default();
+        break;
+    }
+  }
+};
+
+Flag flags[] = {
+#define FLAG_MODE_META
+#include "flag-definitions.h"
+};
+
+const size_t num_flags = sizeof(flags) / sizeof(*flags);
+
+}  // namespace
+
+
+static const char* Type2String(Flag::FlagType type) {
+  switch (type) {
+    case Flag::TYPE_BOOL: return "bool";
+    case Flag::TYPE_INT: return "int";
+    case Flag::TYPE_FLOAT: return "float";
+    case Flag::TYPE_STRING: return "string";
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+static char* ToString(Flag* flag) {
+  Vector<char> value;
+  switch (flag->type()) {
+    case Flag::TYPE_BOOL:
+      value = Vector<char>::New(6);
+      OS::SNPrintF(value, "%s", (*flag->bool_variable() ? "true" : "false"));
+      break;
+    case Flag::TYPE_INT:
+      value = Vector<char>::New(12);
+      OS::SNPrintF(value, "%d", *flag->int_variable());
+      break;
+    case Flag::TYPE_FLOAT:
+      value = Vector<char>::New(20);
+      OS::SNPrintF(value, "%f", *flag->float_variable());
+      break;
+    case Flag::TYPE_STRING:
+      const char* str = *flag->string_variable();
+      if (str) {
+        int length = strlen(str) + 1;
+        value = Vector<char>::New(length);
+        OS::SNPrintF(value, "%s", str);
+      } else {
+        value = Vector<char>::New(5);
+        OS::SNPrintF(value, "NULL");
+      }
+      break;
+  }
+  ASSERT(!value.is_empty());
+  return value.start();
+}
+
+
+// static
+List<char *>* FlagList::argv() {
+  List<char *>* args = new List<char*>(8);
+  for (size_t i = 0; i < num_flags; ++i) {
+    Flag* f = &flags[i];
+    if (!f->IsDefault()) {
+      Vector<char> cmdline_flag;
+      if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
+        int length = strlen(f->name()) + 2 + 1;
+        cmdline_flag = Vector<char>::New(length);
+        OS::SNPrintF(cmdline_flag, "--%s", f->name());
+      } else {
+        int length = strlen(f->name()) + 4 + 1;
+        cmdline_flag = Vector<char>::New(length);
+        OS::SNPrintF(cmdline_flag, "--no%s", f->name());
+      }
+      args->Add(cmdline_flag.start());
+      if (f->type() != Flag::TYPE_BOOL) {
+        args->Add(ToString(f));
+      }
+    }
+  }
+
+  return args;
+}
+
+
+// Helper function to parse flags: Takes an argument arg and splits it into
+// a flag name and flag value (or NULL if they are missing). is_bool is set
+// if the arg started with "-no" or "--no". The buffer may be used to NUL-
+// terminate the name, it must be large enough to hold any possible name.
+static void SplitArgument(const char* arg,
+                          char* buffer,
+                          int buffer_size,
+                          const char** name,
+                          const char** value,
+                          bool* is_bool) {
+  *name = NULL;
+  *value = NULL;
+  *is_bool = false;
+
+  if (*arg == '-') {
+    // find the begin of the flag name
+    arg++;  // remove 1st '-'
+    if (*arg == '-')
+      arg++;  // remove 2nd '-'
+    if (arg[0] == 'n' && arg[1] == 'o') {
+      arg += 2;  // remove "no"
+      *is_bool = true;
+    }
+    *name = arg;
+
+    // find the end of the flag name
+    while (*arg != '\0' && *arg != '=')
+      arg++;
+
+    // get the value if any
+    if (*arg == '=') {
+      // make a copy so we can NUL-terminate flag name
+      int n = arg - *name;
+      CHECK(n < buffer_size);  // buffer is too small
+      memcpy(buffer, *name, n);
+      buffer[n] = '\0';
+      *name = buffer;
+      // get the value
+      *value = arg + 1;
+    }
+  }
+}
+
+
+inline char NormalizeChar(char ch) {
+  return ch == '_' ? '-' : ch;
+}
+
+
+static bool EqualNames(const char* a, const char* b) {
+  for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
+    if (a[i] == '\0') {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+static Flag* FindFlag(const char* name) {
+  for (size_t i = 0; i < num_flags; ++i) {
+    if (EqualNames(name, flags[i].name()))
+      return &flags[i];
+  }
+  return NULL;
+}
+
+
+// static
+int FlagList::SetFlagsFromCommandLine(int* argc,
+                                      char** argv,
+                                      bool remove_flags) {
+  // parse arguments
+  for (int i = 1; i < *argc;) {
+    int j = i;  // j > 0
+    const char* arg = argv[i++];
+
+    // split arg into flag components
+    char buffer[1*KB];
+    const char* name;
+    const char* value;
+    bool is_bool;
+    SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
+
+    if (name != NULL) {
+      // lookup the flag
+      Flag* flag = FindFlag(name);
+      if (flag == NULL) {
+        if (remove_flags) {
+          // We don't recognize this flag but since we're removing
+          // the flags we recognize we assume that the remaining flags
+          // will be processed somewhere else so this flag might make
+          // sense there.
+          continue;
+        } else {
+          fprintf(stderr, "Error: unrecognized flag %s\n", arg);
+          return j;
+        }
+      }
+
+      // if we still need a flag value, use the next argument if available
+      if (flag->type() != Flag::TYPE_BOOL && value == NULL) {
+        if (i < *argc) {
+          value = argv[i++];
+        } else {
+          fprintf(stderr, "Error: missing value for flag %s of type %s\n",
+                  arg, Type2String(flag->type()));
+          return j;
+        }
+      }
+
+      // set the flag
+      char* endp = const_cast<char*>("");  // *endp is only read
+      switch (flag->type()) {
+        case Flag::TYPE_BOOL:
+          *flag->bool_variable() = !is_bool;
+          break;
+        case Flag::TYPE_INT:
+          *flag->int_variable() = strtol(value, &endp, 10);  // NOLINT
+          break;
+        case Flag::TYPE_FLOAT:
+          *flag->float_variable() = strtod(value, &endp);
+          break;
+        case Flag::TYPE_STRING:
+          *flag->string_variable() = value;
+          break;
+      }
+
+      // handle errors
+      if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
+          (flag->type() != Flag::TYPE_BOOL && is_bool) ||
+          *endp != '\0') {
+        fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
+                arg, Type2String(flag->type()));
+        return j;
+      }
+
+      // remove the flag & value from the command
+      if (remove_flags)
+        while (j < i)
+          argv[j++] = NULL;
+    }
+  }
+
+  // shrink the argument list
+  if (remove_flags) {
+    int j = 1;
+    for (int i = 1; i < *argc; i++) {
+      if (argv[i] != NULL)
+        argv[j++] = argv[i];
+    }
+    *argc = j;
+  }
+
+  // parsed all flags successfully
+  return 0;
+}
+
+
+static char* SkipWhiteSpace(char* p) {
+  while (*p != '\0' && isspace(*p) != 0) p++;
+  return p;
+}
+
+
+static char* SkipBlackSpace(char* p) {
+  while (*p != '\0' && isspace(*p) == 0) p++;
+  return p;
+}
+
+
+// static
+int FlagList::SetFlagsFromString(const char* str, int len) {
+  // make a 0-terminated copy of str
+  char* copy0 = NewArray<char>(len + 1);
+  memcpy(copy0, str, len);
+  copy0[len] = '\0';
+
+  // strip leading white space
+  char* copy = SkipWhiteSpace(copy0);
+
+  // count the number of 'arguments'
+  int argc = 1;  // be compatible with SetFlagsFromCommandLine()
+  for (char* p = copy; *p != '\0'; argc++) {
+    p = SkipBlackSpace(p);
+    p = SkipWhiteSpace(p);
+  }
+
+  // allocate argument array
+  char** argv = NewArray<char*>(argc);
+
+  // split the flags string into arguments
+  argc = 1;  // be compatible with SetFlagsFromCommandLine()
+  for (char* p = copy; *p != '\0'; argc++) {
+    argv[argc] = p;
+    p = SkipBlackSpace(p);
+    if (*p != '\0') *p++ = '\0';  // 0-terminate argument
+    p = SkipWhiteSpace(p);
+  }
+
+  // set the flags
+  int result = SetFlagsFromCommandLine(&argc, argv, false);
+
+  // cleanup
+  DeleteArray(argv);
+  // don't delete copy0 since the substrings
+  // may be pointed to by FLAG variables!
+  // (this is a memory leak, but it's minor since this
+  // code is only used for debugging, or perhaps once
+  // during initialization).
+
+  return result;
+}
+
+
+// static
+void FlagList::ResetAllFlags() {
+  for (size_t i = 0; i < num_flags; ++i) {
+    flags[i].Reset();
+  }
+}
+
+
+// static
+void FlagList::PrintHelp() {
+  for (size_t i = 0; i < num_flags; ++i) {
+    Flag* f = &flags[i];
+    char* value = ToString(f);
+    printf("  --%s (%s)  type: %s  default: %s\n",
+           f->name(), f->comment(), Type2String(f->type()), value);
+    DeleteArray(value);
+  }
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/flags.h b/regexp2000/src/flags.h
new file mode 100644 (file)
index 0000000..813ea95
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef V8_FLAGS_H_
+#define V8_FLAGS_H_
+
+#include "checks.h"
+
+namespace v8 { namespace internal {
+
+// Declare all of our flags.
+#define FLAG_MODE_DECLARE
+#include "flag-definitions.h"
+
+// The global list of all flags.
+class FlagList {
+ public:
+  // The list of all flags with a value different from the default
+  // and their values. The format of the list is like the format of the
+  // argv array passed to the main function, e.g.
+  // ("--prof", "--log-file", "v8.prof", "--nolazy").
+  //
+  // The caller is responsible for disposing the list.
+  static List<char *>* argv();
+
+  // Set the flag values by parsing the command line. If remove_flags is
+  // set, the flags and associated values are removed from (argc,
+  // argv). Returns 0 if no error occurred. Otherwise, returns the argv
+  // index > 0 for the argument where an error occurred. In that case,
+  // (argc, argv) will remain unchanged indepdendent of the remove_flags
+  // value, and no assumptions about flag settings should be made.
+  //
+  // The following syntax for flags is accepted (both '-' and '--' are ok):
+  //
+  //   --flag        (bool flags only)
+  //   --noflag      (bool flags only)
+  //   --flag=value  (non-bool flags only, no spaces around '=')
+  //   --flag value  (non-bool flags only)
+  static int SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags);
+
+  // Set the flag values by parsing the string str. Splits string into argc
+  // substrings argv[], each of which consisting of non-white-space chars,
+  // and then calls SetFlagsFromCommandLine() and returns its result.
+  static int SetFlagsFromString(const char* str, int len);
+
+  // Reset all flags to their default value.
+  static void ResetAllFlags();
+
+  // Print help to stdout with flags, types, and default values.
+  static void PrintHelp();
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_FLAGS_H_
diff --git a/regexp2000/src/frames-arm.cc b/regexp2000/src/frames-arm.cc
new file mode 100644 (file)
index 0000000..f7e7452
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "frames-inl.h"
+#include "assembler-arm-inl.h"
+
+
+namespace v8 { namespace internal {
+
+
+StackFrame::Type StackFrame::ComputeType(State* state) {
+  ASSERT(state->fp != NULL);
+  if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
+    return ARGUMENTS_ADAPTOR;
+  }
+  // The marker and function offsets overlap. If the marker isn't a
+  // smi then the frame is a JavaScript frame -- and the marker is
+  // really the function.
+  const int offset = StandardFrameConstants::kMarkerOffset;
+  Object* marker = Memory::Object_at(state->fp + offset);
+  if (!marker->IsSmi()) return JAVA_SCRIPT;
+  return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
+}
+
+
+StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
+  if (fp == 0) return NONE;
+  // Compute frame type and stack pointer.
+  Address sp = fp + ExitFrameConstants::kSPDisplacement;
+  Type type;
+  if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) {
+    type = EXIT_DEBUG;
+    sp -= kNumJSCallerSaved * kPointerSize;
+  } else {
+    type = EXIT;
+  }
+  // Fill in the state.
+  state->sp = sp;
+  state->fp = fp;
+  state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
+  return type;
+}
+
+
+void ExitFrame::Iterate(ObjectVisitor* v) const {
+  // Do nothing
+}
+
+
+int JavaScriptFrame::GetProvidedParametersCount() const {
+  return ComputeParametersCount();
+}
+
+
+Address JavaScriptFrame::GetCallerStackPointer() const {
+  int arguments;
+  if (Heap::gc_state() != Heap::NOT_IN_GC) {
+    // The arguments for cooked frames are traversed as if they were
+    // expression stack elements of the calling frame. The reason for
+    // this rather strange decision is that we cannot access the
+    // function during mark-compact GCs when the stack is cooked.
+    // In fact accessing heap objects (like function->shared() below)
+    // at all during GC is problematic.
+    arguments = 0;
+  } else {
+    // Compute the number of arguments by getting the number of formal
+    // parameters of the function. We must remember to take the
+    // receiver into account (+1).
+    JSFunction* function = JSFunction::cast(this->function());
+    arguments = function->shared()->formal_parameter_count() + 1;
+  }
+  const int offset = StandardFrameConstants::kCallerSPOffset;
+  return fp() + offset + (arguments * kPointerSize);
+}
+
+
+Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
+  const int arguments = Smi::cast(GetExpression(0))->value();
+  const int offset = StandardFrameConstants::kCallerSPOffset;
+  return fp() + offset + (arguments + 1) * kPointerSize;
+}
+
+
+Address InternalFrame::GetCallerStackPointer() const {
+  // Internal frames have no arguments. The stack pointer of the
+  // caller is at a fixed offset from the frame pointer.
+  return fp() + StandardFrameConstants::kCallerSPOffset;
+}
+
+
+Code* JavaScriptFrame::FindCode() const {
+  JSFunction* function = JSFunction::cast(this->function());
+  return function->shared()->code();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/frames-arm.h b/regexp2000/src/frames-arm.h
new file mode 100644 (file)
index 0000000..0d1a27c
--- /dev/null
@@ -0,0 +1,381 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FRAMES_ARM_H_
+#define V8_FRAMES_ARM_H_
+
+namespace v8 { namespace internal {
+
+
+// The ARM ABI does not specify the usage of register r9, which may be reserved
+// as the static base or thread register on some platforms, in which case we
+// leave it alone. Adjust the value of kR9Available accordingly:
+static const int kR9Available = 1;  // 1 if available to us, 0 if reserved
+
+
+// Register list in load/store instructions
+// Note that the bit values must match those used in actual instruction encoding
+static const int kNumRegs = 16;
+
+
+// Caller-saved/arguments registers
+static const RegList kJSCallerSaved =
+  1 << 0 |  // r0 a1
+  1 << 1 |  // r1 a2
+  1 << 2 |  // r2 a3
+  1 << 3;   // r3 a4
+
+static const int kNumJSCallerSaved = 4;
+
+typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
+
+// Return the code of the n-th caller-saved register available to JavaScript
+// e.g. JSCallerSavedReg(0) returns r0.code() == 0
+int JSCallerSavedCode(int n);
+
+
+// Callee-saved registers preserved when switching from C to JavaScript
+static const RegList kCalleeSaved =
+  1 <<  4 |  //  r4 v1
+  1 <<  5 |  //  r5 v2
+  1 <<  6 |  //  r6 v3
+  1 <<  7 |  //  r7 v4
+  1 <<  8 |  //  r8 v5 (cp in JavaScript code)
+  kR9Available
+    <<  9 |  //  r9 v6
+  1 << 10 |  // r10 v7 (pp in JavaScript code)
+  1 << 11;   // r11 v8 (fp in JavaScript code)
+
+static const int kNumCalleeSaved = 7 + kR9Available;
+
+
+// ----------------------------------------------------
+
+
+class StackHandlerConstants : public AllStatic {
+ public:
+  // TODO(1233780): Get rid of the code slot in stack handlers.
+  static const int kCodeOffset  = 0 * kPointerSize;
+  static const int kNextOffset  = 1 * kPointerSize;
+  static const int kStateOffset = 2 * kPointerSize;
+  static const int kPPOffset    = 3 * kPointerSize;
+  static const int kFPOffset    = 4 * kPointerSize;
+  static const int kPCOffset    = 5 * kPointerSize;
+
+  static const int kAddressDisplacement = -1 * kPointerSize;
+  static const int kSize = kPCOffset + kPointerSize;
+};
+
+
+class EntryFrameConstants : public AllStatic {
+ public:
+  static const int kCallerFPOffset      = -3 * kPointerSize;
+};
+
+
+class ExitFrameConstants : public AllStatic {
+ public:
+  // Exit frames have a debug marker on the stack.
+  static const int kSPDisplacement = -1 * kPointerSize;
+
+  // The debug marker is just above the frame pointer.
+  static const int kDebugMarkOffset = -1 * kPointerSize;
+
+  static const int kSavedRegistersOffset = 0 * kPointerSize;
+
+  // Let the parameters pointer for exit frames point just below the
+  // frame structure on the stack.
+  static const int kPPDisplacement = 3 * kPointerSize;
+
+  // The caller fields are below the frame pointer on the stack.
+  static const int kCallerFPOffset = +0 * kPointerSize;
+  static const int kCallerPPOffset = +1 * kPointerSize;
+  static const int kCallerPCOffset = +2 * kPointerSize;
+};
+
+
+class StandardFrameConstants : public AllStatic {
+ public:
+  static const int kExpressionsOffset = -3 * kPointerSize;
+  static const int kMarkerOffset      = -2 * kPointerSize;
+  static const int kContextOffset     = -1 * kPointerSize;
+  static const int kCallerFPOffset    =  0 * kPointerSize;
+  static const int kCallerPCOffset    = +1 * kPointerSize;
+  static const int kCallerSPOffset    = +2 * kPointerSize;
+};
+
+
+class JavaScriptFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
+  static const int kSavedRegistersOffset = +2 * kPointerSize;
+  static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
+
+  // PP-relative.
+  static const int kParam0Offset   = -2 * kPointerSize;
+  static const int kReceiverOffset = -1 * kPointerSize;
+};
+
+
+class ArgumentsAdaptorFrameConstants : public AllStatic {
+ public:
+  static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
+};
+
+
+class InternalFrameConstants : public AllStatic {
+ public:
+  static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
+};
+
+
+inline Object* JavaScriptFrame::function() const {
+  const int offset = JavaScriptFrameConstants::kFunctionOffset;
+  Object* result = Memory::Object_at(fp() + offset);
+  ASSERT(result->IsJSFunction());
+  return result;
+}
+
+
+// ----------------------------------------------------
+
+
+
+
+  //    lower    |    Stack    |
+  //  addresses  |      ^      |
+  //             |      |      |
+  //             |             |
+  //             |  JS frame   |
+  //             |             |
+  //             |             |
+  // ----------- +=============+ <--- sp (stack pointer)
+  //             |  function   |
+  //             +-------------+
+  //             +-------------+
+  //             |             |
+  //             | expressions |
+  //             |             |
+  //             +-------------+
+  //             |             |
+  //      a      |   locals    |
+  //      c      |             |
+  //      t      +- - - - - - -+ <---
+  //      i   -4 |   local0    |   ^
+  //      v      +-------------+   |
+  //      a   -3 |    code     |   |
+  //      t      +-------------+   | kLocal0Offset
+  //      i   -2 |   context   |   |
+  //      o      +-------------+   |
+  //      n   -1 | args_length |   v
+  //             +-------------+ <--- fp (frame pointer)
+  //           0 |  caller_pp  |
+  //      f      +-------------+
+  //      r    1 |  caller_fp  |
+  //      a      +-------------+
+  //      m    2 |  sp_on_exit |  (pp if return, caller_sp if no return)
+  //      e      +-------------+
+  //           3 |  caller_pc  |
+  //             +-------------+ <--- caller_sp (incl. parameters)
+  //             |             |
+  //             | parameters  |
+  //             |             |
+  //             +- - - - - - -+ <---
+  //          -2 | parameter0  |   ^
+  //             +-------------+   | kParam0Offset
+  //          -1 |  receiver   |   v
+  // ----------- +=============+ <--- pp (parameter pointer, r10)
+  //           0 |  function   |
+  //             +-------------+
+  //             |             |
+  //             |caller-saved |  (must be valid JS values, traversed during GC)
+  //             |    regs     |
+  //             |             |
+  //             +-------------+
+  //             |             |
+  //             |   caller    |
+  //   higher    | expressions |
+  //  addresses  |             |
+  //             |             |
+  //             |  JS frame   |
+
+
+
+  // Handler frames (part of expressions of JS frames):
+
+  //    lower    |    Stack    |
+  //  addresses  |      ^      |
+  //             |      |      |
+  //             |             |
+  //      h      | expressions |
+  //      a      |             |
+  //      n      +-------------+
+  //      d   -1 |    code     |
+  //      l      +-------------+ <--- handler sp
+  //      e    0 |   next_sp   |  link to next handler (next handler's sp)
+  //      r      +-------------+
+  //           1 |    state    |
+  //      f      +-------------+
+  //      r    2 |     pp      |
+  //      a      +-------------+
+  //      m    3 |     fp      |
+  //      e      +-------------+
+  //           4 |     pc      |
+  //             +-------------+
+  //             |             |
+  //   higher    | expressions |
+  //  addresses  |             |
+
+
+
+  // JS entry frames: When calling from C to JS, we construct two extra
+  // frames: An entry frame (C) and a trampoline frame (JS). The
+  // following pictures shows the two frames:
+
+  //    lower    |    Stack    |
+  //  addresses  |      ^      |
+  //             |      |      |
+  //             |             |
+  //             |  JS frame   |
+  //             |             |
+  //             |             |
+  // ----------- +=============+ <--- sp (stack pointer)
+  //             |             |
+  //             | parameters  |
+  //      t      |             |
+  //      r      +- - - - - - -+
+  //      a      | parameter0  |
+  //      m      +-------------+
+  //      p      |  receiver   |
+  //      o      +-------------+
+  //      l      |  function   |
+  //      i      +-------------+
+  //      n   -3 |    code     |
+  //      e      +-------------+
+  //          -2 |    NULL     |  context is always NULL
+  //             +-------------+
+  //      f   -1 |      0      |  args_length is always zero
+  //      r      +-------------+ <--- fp (frame pointer)
+  //      a    0 |    NULL     |  caller pp is always NULL for entries
+  //      m      +-------------+
+  //      e    1 |  caller_fp  |
+  //             +-------------+
+  //           2 |  sp_on_exit |  (caller_sp)
+  //             +-------------+
+  //           3 |  caller_pc  |
+  // ----------- +=============+ <--- caller_sp == pp
+  //                    .          ^
+  //                    .          |  try-handler, fake, not GC'ed
+  //                    .          v
+  //             +-------------+ <---
+  //          -2 | next top pp |
+  //             +-------------+
+  //          -1 | next top fp |
+  //             +-------------+ <--- fp
+  //             |     r4      |  r4-r9 holding non-JS values must be preserved
+  //             +-------------+
+  //      J      |     r5      |  before being initialized not to confuse GC
+  //      S      +-------------+
+  //             |     r6      |
+  //             +-------------+
+  //      e      |     r7      |
+  //      n      +-------------+
+  //      t      |     r8      |
+  //      r      +-------------+
+  //      y    [ |     r9      | ]  only if r9 available
+  //             +-------------+
+  //             |     r10     |
+  //      f      +-------------+
+  //      r      |     r11     |
+  //      a      +-------------+
+  //      m      |  caller_sp  |
+  //      e      +-------------+
+  //             |  caller_pc  |
+  //             +-------------+ <--- caller_sp
+  //             |    argv     |    passed on stack from C code
+  //             +-------------+
+  //             |             |
+  //   higher    |             |
+  //  addresses  |   C frame   |
+
+
+  // The first 4 args are passed from C in r0-r3 and are not spilled on entry:
+  // r0: code entry
+  // r1: function
+  // r2: receiver
+  // r3: argc
+  // [sp+0]: argv
+
+
+  // C entry frames: When calling from JS to C, we construct one extra
+  // frame:
+
+  //    lower    |    Stack    |
+  //  addresses  |      ^      |
+  //             |      |      |
+  //             |             |
+  //             |   C frame   |
+  //             |             |
+  //             |             |
+  // ----------- +=============+ <--- sp (stack pointer)
+  //             |             |
+  //             | parameters  |  (first 4 args are passed in r0-r3)
+  //             |             |
+  //             +-------------+ <--- fp (frame pointer)
+  //      f  4/5 |  caller_fp  |
+  //      r      +-------------+
+  //      a  5/6 |  sp_on_exit |  (pp)
+  //      m      +-------------+
+  //      e  6/7 |  caller_pc  |
+  //             +-------------+ <--- caller_sp (incl. parameters)
+  //         7/8 |             |
+  //             | parameters  |
+  //             |             |
+  //             +- - - - - - -+ <---
+  //          -2 | parameter0  |   ^
+  //             +-------------+   | kParam0Offset
+  //          -1 |  receiver   |   v
+  // ----------- +=============+ <--- pp (parameter pointer, r10)
+  //           0 |  function   |
+  //             +-------------+
+  //             |             |
+  //             |caller-saved |
+  //             |    regs     |
+  //             |             |
+  //             +-------------+
+  //             |             |
+  //             |   caller    |
+  //             | expressions |
+  //             |             |
+  //   higher    |             |
+  //  addresses  |  JS frame   |
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_FRAMES_ARM_H_
diff --git a/regexp2000/src/frames-ia32.cc b/regexp2000/src/frames-ia32.cc
new file mode 100644 (file)
index 0000000..ddf4bfd
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "frames-inl.h"
+
+namespace v8 { namespace internal {
+
+
+StackFrame::Type StackFrame::ComputeType(State* state) {
+  ASSERT(state->fp != NULL);
+  if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
+    return ARGUMENTS_ADAPTOR;
+  }
+  // The marker and function offsets overlap. If the marker isn't a
+  // smi then the frame is a JavaScript frame -- and the marker is
+  // really the function.
+  const int offset = StandardFrameConstants::kMarkerOffset;
+  Object* marker = Memory::Object_at(state->fp + offset);
+  if (!marker->IsSmi()) return JAVA_SCRIPT;
+  return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
+}
+
+
+StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
+  if (fp == 0) return NONE;
+  // Compute the stack pointer.
+  Address sp = Memory::Address_at(fp + ExitFrameConstants::kSPOffset);
+  // Fill in the state.
+  state->fp = fp;
+  state->sp = sp;
+  state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
+  // Determine frame type.
+  if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) {
+    return EXIT_DEBUG;
+  } else {
+    return EXIT;
+  }
+}
+
+
+void ExitFrame::Iterate(ObjectVisitor* v) const {
+  // Exit frames on IA-32 do not contain any pointers. The arguments
+  // are traversed as part of the expression stack of the calling
+  // frame.
+}
+
+
+int JavaScriptFrame::GetProvidedParametersCount() const {
+  return ComputeParametersCount();
+}
+
+
+Address JavaScriptFrame::GetCallerStackPointer() const {
+  int arguments;
+  if (Heap::gc_state() != Heap::NOT_IN_GC) {
+    // The arguments for cooked frames are traversed as if they were
+    // expression stack elements of the calling frame. The reason for
+    // this rather strange decision is that we cannot access the
+    // function during mark-compact GCs when the stack is cooked.
+    // In fact accessing heap objects (like function->shared() below)
+    // at all during GC is problematic.
+    arguments = 0;
+  } else {
+    // Compute the number of arguments by getting the number of formal
+    // parameters of the function. We must remember to take the
+    // receiver into account (+1).
+    JSFunction* function = JSFunction::cast(this->function());
+    arguments = function->shared()->formal_parameter_count() + 1;
+  }
+  const int offset = StandardFrameConstants::kCallerSPOffset;
+  return fp() + offset + (arguments * kPointerSize);
+}
+
+
+Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
+  const int arguments = Smi::cast(GetExpression(0))->value();
+  const int offset = StandardFrameConstants::kCallerSPOffset;
+  return fp() + offset + (arguments + 1) * kPointerSize;
+}
+
+
+Address InternalFrame::GetCallerStackPointer() const {
+  // Internal frames have no arguments. The stack pointer of the
+  // caller is at a fixed offset from the frame pointer.
+  return fp() + StandardFrameConstants::kCallerSPOffset;
+}
+
+
+Code* JavaScriptFrame::FindCode() const {
+  JSFunction* function = JSFunction::cast(this->function());
+  return function->shared()->code();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/frames-ia32.h b/regexp2000/src/frames-ia32.h
new file mode 100644 (file)
index 0000000..e31906d
--- /dev/null
@@ -0,0 +1,293 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FRAMES_IA32_H_
+#define V8_FRAMES_IA32_H_
+
+namespace v8 { namespace internal {
+
+
+// Register lists
+// Note that the bit values must match those used in actual instruction encoding
+static const int kNumRegs = 8;
+
+
+// Caller-saved registers
+static const RegList kJSCallerSaved =
+  1 << 0 |  // eax
+  1 << 1 |  // ecx
+  1 << 2 |  // edx
+  1 << 3 |  // ebx - used as a caller-saved register in JavaScript code
+  1 << 7;   // edi - callee function
+
+static const int kNumJSCallerSaved = 5;
+
+typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
+
+// ----------------------------------------------------
+
+
+class StackHandlerConstants : public AllStatic {
+ public:
+  static const int kNextOffset  = 0 * kPointerSize;
+  static const int kPPOffset    = 1 * kPointerSize;
+  static const int kFPOffset    = 2 * kPointerSize;
+
+  // TODO(1233780): Get rid of the code slot in stack handlers.
+  static const int kCodeOffset  = 3 * kPointerSize;
+
+  static const int kStateOffset = 4 * kPointerSize;
+  static const int kPCOffset    = 5 * kPointerSize;
+
+  static const int kAddressDisplacement = -1 * kPointerSize;
+  static const int kSize = kPCOffset + kPointerSize;
+};
+
+
+class EntryFrameConstants : public AllStatic {
+ public:
+  static const int kCallerFPOffset      = -6 * kPointerSize;
+
+  static const int kFunctionArgOffset   = +3 * kPointerSize;
+  static const int kReceiverArgOffset   = +4 * kPointerSize;
+  static const int kArgcOffset          = +5 * kPointerSize;
+  static const int kArgvOffset          = +6 * kPointerSize;
+};
+
+
+class ExitFrameConstants : public AllStatic {
+ public:
+  static const int kDebugMarkOffset = -2 * kPointerSize;
+  static const int kSPOffset        = -1 * kPointerSize;
+
+  // Let the parameters pointer for exit frames point just below the
+  // frame structure on the stack (frame pointer and return address).
+  static const int kPPDisplacement = +2 * kPointerSize;
+
+  static const int kCallerFPOffset =  0 * kPointerSize;
+  static const int kCallerPCOffset = +1 * kPointerSize;
+};
+
+
+class StandardFrameConstants : public AllStatic {
+ public:
+  static const int kExpressionsOffset = -3 * kPointerSize;
+  static const int kMarkerOffset      = -2 * kPointerSize;
+  static const int kContextOffset     = -1 * kPointerSize;
+  static const int kCallerFPOffset    =  0 * kPointerSize;
+  static const int kCallerPCOffset    = +1 * kPointerSize;
+  static const int kCallerSPOffset    = +2 * kPointerSize;
+};
+
+
+class JavaScriptFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
+  static const int kSavedRegistersOffset = +2 * kPointerSize;
+  static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
+
+  // CallerSP-relative (aka PP-relative)
+  static const int kParam0Offset   = -2 * kPointerSize;
+  static const int kReceiverOffset = -1 * kPointerSize;
+};
+
+
+class ArgumentsAdaptorFrameConstants : public AllStatic {
+ public:
+  static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
+};
+
+
+class InternalFrameConstants : public AllStatic {
+ public:
+  static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
+};
+
+
+inline Object* JavaScriptFrame::function() const {
+  const int offset = JavaScriptFrameConstants::kFunctionOffset;
+  Object* result = Memory::Object_at(fp() + offset);
+  ASSERT(result->IsJSFunction());
+  return result;
+}
+
+
+// ----------------------------------------------------
+
+
+
+
+  // C Entry frames:
+
+  //    lower    |    Stack    |
+  //  addresses  |      ^      |
+  //             |      |      |
+  //             |             |
+  //             +-------------+
+  //             |  entry_pc   |
+  //             +-------------+ <--+ entry_sp
+  //                    .           |
+  //                    .           |
+  //                    .           |
+  //             +-------------+    |
+  //          -3 |  entry_sp --+----+
+  //      e      +-------------+
+  //      n   -2 | C function  |
+  //      t      +-------------+
+  //      r   -1 |  caller_pp  |
+  //      y      +-------------+ <--- fp (frame pointer, ebp)
+  //           0 |  caller_fp  |
+  //      f      +-------------+
+  //      r    1 |  caller_pc  |
+  //      a      +-------------+ <--- caller_sp (stack pointer, esp)
+  //      m    2 |             |
+  //      e      |  arguments  |
+  //             |             |
+  //             +- - - - - - -+
+  //             |  argument0  |
+  //             +=============+
+  //             |             |
+  //             |   caller    |
+  //   higher    | expressions |
+  //  addresses  |             |
+
+
+  // Proper JS frames:
+
+  //    lower    |    Stack    |
+  //  addresses  |      ^      |
+  //             |      |      |
+  //             |             |
+  // ----------- +=============+ <--- sp (stack pointer, esp)
+  //             |  function   |
+  //             +-------------+
+  //             |             |
+  //             | expressions |
+  //             |             |
+  //             +-------------+
+  //      a      |             |
+  //      c      |   locals    |
+  //      t      |             |
+  //      i      +- - - - - - -+ <---
+  //      v   -4 |   local0    |   ^
+  //      a      +-------------+   |
+  //      t   -3 |    code     |   |
+  //      i      +-------------+   |
+  //      o   -2 |   context   |   | kLocal0Offset
+  //      n      +-------------+   |
+  //          -1 |  caller_pp  |   v
+  //      f      +-------------+ <--- fp (frame pointer, ebp)
+  //      r    0 |  caller_fp  |
+  //      a      +-------------+
+  //      m    1 |  caller_pc  |
+  //      e      +-------------+ <--- caller_sp (incl. parameters)
+  //           2 |             |
+  //             | parameters  |
+  //             |             |
+  //             +- - - - - - -+ <---
+  //          -2 | parameter0  |   ^
+  //             +-------------+   | kParam0Offset
+  //          -1 |  receiver   |   v
+  // ----------- +=============+ <--- pp (parameter pointer, edi)
+  //           0 |  function   |
+  //             +-------------+
+  //             |             |
+  //             |   caller    |
+  //   higher    | expressions |
+  //  addresses  |             |
+
+
+  // JS entry frames: When calling from C to JS, we construct two extra
+  // frames: An entry frame (C) and a trampoline frame (JS). The
+  // following pictures shows the two frames:
+
+  //    lower    |    Stack    |
+  //  addresses  |      ^      |
+  //             |      |      |
+  //             |             |
+  // ----------- +=============+ <--- sp (stack pointer, esp)
+  //             |             |
+  //             | parameters  |
+  //      t      |             |
+  //      r      +- - - - - - -+
+  //      a      | parameter0  |
+  //      m      +-------------+
+  //      p      |  receiver   |
+  //      o      +-------------+ <---
+  //      l      |  function   |   ^
+  //      i      +-------------+   |
+  //      n   -3 |    code     |   | kLocal0Offset
+  //      e      +-------------+
+  //          -2 |    NULL     | context is always NULL
+  //             +-------------+
+  //      f   -1 |    NULL     | caller pp is always NULL for entry frames
+  //      r      +-------------+ <--- fp (frame pointer, ebp)
+  //      a    0 |  caller fp  |
+  //      m      +-------------+
+  //      e    1 |  caller pc  |
+  //             +-------------+ <--- caller_sp (incl. parameters)
+  //             |      0      |
+  // ----------- +=============+ <--- pp (parameter pointer, edi)
+  //             |      0      |
+  //             +-------------+ <---
+  //                    .          ^
+  //                    .          |  try-handler (HandlerOffsets::kSize)
+  //                    .          v
+  //             +-------------+ <---
+  //          -5 | next top pp |
+  //             +-------------+
+  //      e   -4 | next top fp |
+  //      n      +-------------+ <---
+  //      t   -3 |     ebx     |   ^
+  //      r      +-------------+   |
+  //      y   -2 |     esi     |   |  callee-saved registers
+  //             +-------------+   |
+  //          -1 |     edi     |   v
+  //      f      +-------------+ <--- fp
+  //      r    0 |  caller fp  |
+  //      a      +-------------+      pp == NULL (parameter pointer)
+  //      m    1 |  caller pc  |
+  //      e      +-------------+ <--- caller sp
+  //           2 | code  entry |   ^
+  //             +-------------+   |
+  //           3 |  function   |   |
+  //             +-------------+   |  arguments passed from C code
+  //           4 |  receiver   |   |
+  //             +-------------+   |
+  //           5 |    argc     |   |
+  //             +-------------+   |
+  //           6 |    argv     |   v
+  //             +-------------+ <---
+  //             |             |
+  //   higher    |             |
+  //  addresses  |             |
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_FRAMES_IA32_H_
diff --git a/regexp2000/src/frames-inl.h b/regexp2000/src/frames-inl.h
new file mode 100644 (file)
index 0000000..2b50d55
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FRAMES_INL_H_
+#define V8_FRAMES_INL_H_
+
+#include "frames.h"
+#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+#include "frames-arm.h"
+#else
+#include "frames-ia32.h"
+#endif
+
+
+namespace v8 { namespace internal {
+
+
+inline Address StackHandler::address() const {
+  // NOTE: There's an obvious problem with the address of the NULL
+  // stack handler. Right now, it benefits us that the subtraction
+  // leads to a very high address (above everything else on the
+  // stack), but maybe we should stop relying on it?
+  const int displacement = StackHandlerConstants::kAddressDisplacement;
+  Address address = reinterpret_cast<Address>(const_cast<StackHandler*>(this));
+  return address + displacement;
+}
+
+
+inline StackHandler* StackHandler::next() const {
+  const int offset = StackHandlerConstants::kNextOffset;
+  return FromAddress(Memory::Address_at(address() + offset));
+}
+
+
+inline bool StackHandler::includes(Address address) const {
+  Address start = this->address();
+  Address end = start + StackHandlerConstants::kSize;
+  return start <= address && address <= end;
+}
+
+
+inline void StackHandler::Iterate(ObjectVisitor* v) const {
+  // Stack handlers do not contain any pointers that need to be
+  // traversed. The only field that have to worry about is the code
+  // field which is unused and should always be uninitialized.
+#ifdef DEBUG
+  const int offset = StackHandlerConstants::kCodeOffset;
+  Object* code = Memory::Object_at(address() + offset);
+  ASSERT(Smi::cast(code)->value() == StackHandler::kCodeNotPresent);
+#endif
+}
+
+
+inline StackHandler* StackHandler::FromAddress(Address address) {
+  return reinterpret_cast<StackHandler*>(address);
+}
+
+
+inline StackHandler::State StackHandler::state() const {
+  const int offset = StackHandlerConstants::kStateOffset;
+  return static_cast<State>(Memory::int_at(address() + offset));
+}
+
+
+inline Address StackHandler::pc() const {
+  const int offset = StackHandlerConstants::kPCOffset;
+  return Memory::Address_at(address() + offset);
+}
+
+
+inline void StackHandler::set_pc(Address value) {
+  const int offset = StackHandlerConstants::kPCOffset;
+  Memory::Address_at(address() + offset) = value;
+}
+
+
+inline StackHandler* StackFrame::top_handler() const {
+  return iterator_->handler();
+}
+
+
+inline Object* StandardFrame::GetExpression(int index) const {
+  return Memory::Object_at(GetExpressionAddress(index));
+}
+
+
+inline void StandardFrame::SetExpression(int index, Object* value) {
+  Memory::Object_at(GetExpressionAddress(index)) = value;
+}
+
+
+inline Object* StandardFrame::context() const {
+  const int offset = StandardFrameConstants::kContextOffset;
+  return Memory::Object_at(fp() + offset);
+}
+
+
+inline Address StandardFrame::caller_sp() const {
+  return pp();
+}
+
+
+inline Address StandardFrame::caller_fp() const {
+  return Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset);
+}
+
+
+inline Address StandardFrame::caller_pc() const {
+  return Memory::Address_at(ComputePCAddress(fp()));
+}
+
+
+inline Address StandardFrame::ComputePCAddress(Address fp) {
+  return fp + StandardFrameConstants::kCallerPCOffset;
+}
+
+
+inline bool StandardFrame::IsArgumentsAdaptorFrame(Address fp) {
+  int context = Memory::int_at(fp + StandardFrameConstants::kContextOffset);
+  return context == ArgumentsAdaptorFrame::SENTINEL;
+}
+
+
+inline bool StandardFrame::IsConstructFrame(Address fp) {
+  Object* marker =
+      Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset);
+  return marker == Smi::FromInt(CONSTRUCT);
+}
+
+
+inline Object* JavaScriptFrame::receiver() const {
+  const int offset = JavaScriptFrameConstants::kReceiverOffset;
+  return Memory::Object_at(pp() + offset);
+}
+
+
+inline void JavaScriptFrame::set_receiver(Object* value) {
+  const int offset = JavaScriptFrameConstants::kReceiverOffset;
+  Memory::Object_at(pp() + offset) = value;
+}
+
+
+inline bool JavaScriptFrame::has_adapted_arguments() const {
+  return IsArgumentsAdaptorFrame(caller_fp());
+}
+
+
+inline JavaScriptFrame* JavaScriptFrameIterator::frame() const {
+  // TODO(1233797): The frame hierarchy needs to change. It's
+  // problematic that we can't use the safe-cast operator to cast to
+  // the JavaScript frame type, because we may encounter arguments
+  // adaptor frames.
+  StackFrame* frame = iterator_.frame();
+  ASSERT(frame->is_java_script() || frame->is_arguments_adaptor());
+  return static_cast<JavaScriptFrame*>(frame);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_FRAMES_INL_H_
diff --git a/regexp2000/src/frames.cc b/regexp2000/src/frames.cc
new file mode 100644 (file)
index 0000000..09c6a02
--- /dev/null
@@ -0,0 +1,589 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "frames-inl.h"
+#include "scopeinfo.h"
+#include "string-stream.h"
+#include "top.h"
+#include "zone-inl.h"
+
+namespace v8 { namespace internal {
+
+// Iterator that supports traversing the stack handlers of a
+// particular frame. Needs to know the top of the handler chain.
+class StackHandlerIterator BASE_EMBEDDED {
+ public:
+  StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
+      : limit_(frame->fp()), handler_(handler) {
+    // Make sure the handler has already been unwound to this frame.
+    ASSERT(frame->sp() <= handler->address());
+  }
+
+  StackHandler* handler() const { return handler_; }
+
+  bool done() { return handler_->address() > limit_; }
+  void Advance() {
+    ASSERT(!done());
+    handler_ = handler_->next();
+  }
+
+ private:
+  const Address limit_;
+  StackHandler* handler_;
+};
+
+
+// -------------------------------------------------------------------------
+
+
+#define INITIALIZE_SINGLETON(type, field) field##_(this),
+StackFrameIterator::StackFrameIterator()
+    : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
+      frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()) {
+  Reset();
+}
+StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
+    : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
+      frame_(NULL), handler_(NULL), thread_(t) {
+  Reset();
+}
+#undef INITIALIZE_SINGLETON
+
+
+void StackFrameIterator::Advance() {
+  ASSERT(!done());
+  // Compute the state of the calling frame before restoring
+  // callee-saved registers and unwinding handlers. This allows the
+  // frame code that computes the caller state to access the top
+  // handler and the value of any callee-saved register if needed.
+  StackFrame::State state;
+  StackFrame::Type type = frame_->GetCallerState(&state);
+
+  // Unwind handlers corresponding to the current frame.
+  StackHandlerIterator it(frame_, handler_);
+  while (!it.done()) it.Advance();
+  handler_ = it.handler();
+
+  // Advance to the calling frame.
+  frame_ = SingletonFor(type, &state);
+
+  // When we're done iterating over the stack frames, the handler
+  // chain must have been completely unwound.
+  ASSERT(!done() || handler_ == NULL);
+}
+
+
+void StackFrameIterator::Reset() {
+  Address fp = Top::c_entry_fp(thread_);
+  StackFrame::State state;
+  StackFrame::Type type = ExitFrame::GetStateForFramePointer(fp, &state);
+  frame_ = SingletonFor(type, &state);
+  handler_ = StackHandler::FromAddress(Top::handler(thread_));
+}
+
+
+StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
+                                             StackFrame::State* state) {
+#define FRAME_TYPE_CASE(type, field) \
+  case StackFrame::type: result = &field##_; break;
+
+  StackFrame* result = NULL;
+  switch (type) {
+    case StackFrame::NONE: return NULL;
+    STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
+    default: break;
+  }
+  ASSERT(result != NULL);
+  result->state_ = *state;
+  return result;
+
+#undef FRAME_TYPE_CASE
+}
+
+
+// -------------------------------------------------------------------------
+
+
+JavaScriptFrameIterator::JavaScriptFrameIterator(StackFrame::Id id) {
+  while (true) {
+    Advance();
+    if (frame()->id() == id) return;
+  }
+}
+
+
+void JavaScriptFrameIterator::Advance() {
+  do {
+    iterator_.Advance();
+  } while (!iterator_.done() && !iterator_.frame()->is_java_script());
+}
+
+
+void JavaScriptFrameIterator::AdvanceToArgumentsFrame() {
+  if (!frame()->has_adapted_arguments()) return;
+  iterator_.Advance();
+  ASSERT(iterator_.frame()->is_arguments_adaptor());
+}
+
+
+void JavaScriptFrameIterator::Reset() {
+  iterator_.Reset();
+  Advance();
+}
+
+
+// -------------------------------------------------------------------------
+
+
+void StackHandler::Cook(Code* code) {
+  ASSERT(code->contains(pc()));
+  set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
+}
+
+
+void StackHandler::Uncook(Code* code) {
+  set_pc(code->instruction_start() + OffsetFrom(pc()));
+  ASSERT(code->contains(pc()));
+}
+
+
+// -------------------------------------------------------------------------
+
+
+bool StackFrame::HasHandler() const {
+  StackHandlerIterator it(this, top_handler());
+  return !it.done();
+}
+
+
+void StackFrame::CookFramesForThread(ThreadLocalTop* thread) {
+  ASSERT(!thread->stack_is_cooked());
+  for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
+    it.frame()->Cook();
+  }
+  thread->set_stack_is_cooked(true);
+}
+
+
+void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
+  ASSERT(thread->stack_is_cooked());
+  for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
+    it.frame()->Uncook();
+  }
+  thread->set_stack_is_cooked(false);
+}
+
+
+void StackFrame::Cook() {
+  Code* code = FindCode();
+  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
+    it.handler()->Cook(code);
+  }
+  ASSERT(code->contains(pc()));
+  set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
+}
+
+
+void StackFrame::Uncook() {
+  Code* code = FindCode();
+  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
+    it.handler()->Uncook(code);
+  }
+  set_pc(code->instruction_start() + OffsetFrom(pc()));
+  ASSERT(code->contains(pc()));
+}
+
+
+Code* EntryFrame::FindCode() const {
+  return Heap::js_entry_code();
+}
+
+
+StackFrame::Type EntryFrame::GetCallerState(State* state) const {
+  const int offset = EntryFrameConstants::kCallerFPOffset;
+  Address fp = Memory::Address_at(this->fp() + offset);
+  return ExitFrame::GetStateForFramePointer(fp, state);
+}
+
+
+Code* EntryConstructFrame::FindCode() const {
+  return Heap::js_construct_entry_code();
+}
+
+
+Code* ExitFrame::FindCode() const {
+  return Heap::c_entry_code();
+}
+
+
+StackFrame::Type ExitFrame::GetCallerState(State* state) const {
+  // Setup the caller state.
+  state->sp = pp();
+  state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
+  state->pc_address
+      = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
+  return ComputeType(state);
+}
+
+
+Address ExitFrame::GetCallerStackPointer() const {
+  return fp() + ExitFrameConstants::kPPDisplacement;
+}
+
+
+Code* ExitDebugFrame::FindCode() const {
+  return Heap::c_entry_debug_break_code();
+}
+
+
+Address StandardFrame::GetExpressionAddress(int n) const {
+  const int offset = StandardFrameConstants::kExpressionsOffset;
+  return fp() + offset - n * kPointerSize;
+}
+
+
+int StandardFrame::ComputeExpressionsCount() const {
+  const int offset =
+      StandardFrameConstants::kExpressionsOffset + kPointerSize;
+  Address base = fp() + offset;
+  Address limit = sp();
+  ASSERT(base >= limit);  // stack grows downwards
+  // Include register-allocated locals in number of expressions.
+  return (base - limit) / kPointerSize;
+}
+
+
+StackFrame::Type StandardFrame::GetCallerState(State* state) const {
+  state->sp = caller_sp();
+  state->fp = caller_fp();
+  state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
+  return ComputeType(state);
+}
+
+
+bool StandardFrame::IsExpressionInsideHandler(int n) const {
+  Address address = GetExpressionAddress(n);
+  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
+    if (it.handler()->includes(address)) return true;
+  }
+  return false;
+}
+
+
+Object* JavaScriptFrame::GetParameter(int index) const {
+  ASSERT(index >= 0 && index < ComputeParametersCount());
+  const int offset = JavaScriptFrameConstants::kParam0Offset;
+  return Memory::Object_at(pp() + offset - (index * kPointerSize));
+}
+
+
+int JavaScriptFrame::ComputeParametersCount() const {
+  Address base  = pp() + JavaScriptFrameConstants::kReceiverOffset;
+  Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
+  return (base - limit) / kPointerSize;
+}
+
+
+bool JavaScriptFrame::IsConstructor() const {
+  Address fp = caller_fp();
+  if (has_adapted_arguments()) {
+    // Skip the arguments adaptor frame and look at the real caller.
+    fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
+  }
+  return IsConstructFrame(fp);
+}
+
+
+Code* ArgumentsAdaptorFrame::FindCode() const {
+  return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
+}
+
+
+Code* InternalFrame::FindCode() const {
+  const int offset = InternalFrameConstants::kCodeOffset;
+  Object* code = Memory::Object_at(fp() + offset);
+  if (code == NULL) {
+    // The code object isn't set; find it and set it.
+    code = Heap::FindCodeObject(pc());
+    ASSERT(!code->IsFailure());
+    Memory::Object_at(fp() + offset) = code;
+  }
+  ASSERT(code != NULL);
+  return Code::cast(code);
+}
+
+
+void StackFrame::PrintIndex(StringStream* accumulator,
+                            PrintMode mode,
+                            int index) {
+  accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
+}
+
+
+void JavaScriptFrame::Print(StringStream* accumulator,
+                            PrintMode mode,
+                            int index) const {
+  HandleScope scope;
+  Object* receiver = this->receiver();
+  Object* function = this->function();
+
+  accumulator->PrintSecurityTokenIfChanged(function);
+  PrintIndex(accumulator, mode, index);
+  Code* code = NULL;
+  if (IsConstructor()) accumulator->Add("new ");
+  accumulator->PrintFunction(function, receiver, &code);
+  accumulator->Add("(this=%o", receiver);
+
+  // Get scope information for nicer output, if possible. If code is
+  // NULL, or doesn't contain scope info, info will return 0 for the
+  // number of parameters, stack slots, or context slots.
+  ScopeInfo<PreallocatedStorage> info(code);
+
+  // Print the parameters.
+  int parameters_count = ComputeParametersCount();
+  for (int i = 0; i < parameters_count; i++) {
+    accumulator->Add(",");
+    // If we have a name for the parameter we print it. Nameless
+    // parameters are either because we have more actual parameters
+    // than formal parameters or because we have no scope information.
+    if (i < info.number_of_parameters()) {
+      accumulator->PrintName(*info.parameter_name(i));
+      accumulator->Add("=");
+    }
+    accumulator->Add("%o", GetParameter(i));
+  }
+
+  accumulator->Add(")");
+  if (mode == OVERVIEW) {
+    accumulator->Add("\n");
+    return;
+  }
+  accumulator->Add(" {\n");
+
+  // Compute the number of locals and expression stack elements.
+  int stack_locals_count = info.number_of_stack_slots();
+  int heap_locals_count = info.number_of_context_slots();
+  int expressions_count = ComputeExpressionsCount();
+
+  // Print stack-allocated local variables.
+  if (stack_locals_count > 0) {
+    accumulator->Add("  // stack-allocated locals\n");
+  }
+  for (int i = 0; i < stack_locals_count; i++) {
+    accumulator->Add("  var ");
+    accumulator->PrintName(*info.stack_slot_name(i));
+    accumulator->Add(" = ");
+    if (i < expressions_count) {
+      accumulator->Add("%o", GetExpression(i));
+    } else {
+      accumulator->Add("// no expression found - inconsistent frame?");
+    }
+    accumulator->Add("\n");
+  }
+
+  // Try to get hold of the context of this frame.
+  Context* context = NULL;
+  if (this->context() != NULL && this->context()->IsContext()) {
+    context = Context::cast(this->context());
+  }
+
+  // Print heap-allocated local variables.
+  if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
+    accumulator->Add("  // heap-allocated locals\n");
+  }
+  for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
+    accumulator->Add("  var ");
+    accumulator->PrintName(*info.context_slot_name(i));
+    accumulator->Add(" = ");
+    if (context != NULL) {
+      if (i < context->length()) {
+        accumulator->Add("%o", context->get(i));
+      } else {
+        accumulator->Add(
+            "// warning: missing context slot - inconsistent frame?");
+      }
+    } else {
+      accumulator->Add("// warning: no context found - inconsistent frame?");
+    }
+    accumulator->Add("\n");
+  }
+
+  // Print the expression stack.
+  int expressions_start = stack_locals_count;
+  if (expressions_start < expressions_count) {
+    accumulator->Add("  // expression stack (top to bottom)\n");
+  }
+  for (int i = expressions_count - 1; i >= expressions_start; i--) {
+    if (IsExpressionInsideHandler(i)) continue;
+    accumulator->Add("  [%02d] : %o\n", i, GetExpression(i));
+  }
+
+  // Print details about the function.
+  if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
+    SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
+    accumulator->Add("--------- s o u r c e   c o d e ---------\n");
+    shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
+    accumulator->Add("\n-----------------------------------------\n");
+  }
+
+  accumulator->Add("}\n\n");
+}
+
+
+void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
+                                  PrintMode mode,
+                                  int index) const {
+  int actual = ComputeParametersCount();
+  int expected = -1;
+  Object* function = this->function();
+  if (function->IsJSFunction()) {
+    expected = JSFunction::cast(function)->shared()->formal_parameter_count();
+  }
+
+  PrintIndex(accumulator, mode, index);
+  accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
+  if (mode == OVERVIEW) {
+    accumulator->Add("\n");
+    return;
+  }
+  accumulator->Add(" {\n");
+
+  // Print actual arguments.
+  if (actual > 0) accumulator->Add("  // actual arguments\n");
+  for (int i = 0; i < actual; i++) {
+    accumulator->Add("  [%02d] : %o", i, GetParameter(i));
+    if (expected != -1 && i >= expected) {
+      accumulator->Add("  // not passed to callee");
+    }
+    accumulator->Add("\n");
+  }
+
+  accumulator->Add("}\n\n");
+}
+
+
+void EntryFrame::Iterate(ObjectVisitor* v) const {
+  StackHandlerIterator it(this, top_handler());
+  ASSERT(!it.done());
+  StackHandler* handler = it.handler();
+  ASSERT(handler->is_entry());
+  handler->Iterate(v);
+  // Make sure that there's the entry frame does not contain more than
+  // one stack handler.
+  if (kDebug) {
+    it.Advance();
+    ASSERT(it.done());
+  }
+}
+
+
+void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
+  const int offset = StandardFrameConstants::kContextOffset;
+  Object** base = &Memory::Object_at(sp());
+  Object** limit = &Memory::Object_at(fp() + offset) + 1;
+  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
+    StackHandler* handler = it.handler();
+    // Traverse pointers down to - but not including - the next
+    // handler in the handler chain. Update the base to skip the
+    // handler and allow the handler to traverse its own pointers.
+    const Address address = handler->address();
+    v->VisitPointers(base, reinterpret_cast<Object**>(address));
+    base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
+    // Traverse the pointers in the handler itself.
+    handler->Iterate(v);
+  }
+  v->VisitPointers(base, limit);
+}
+
+
+void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
+  IterateExpressions(v);
+
+  // Traverse callee-saved registers, receiver, and parameters.
+  const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
+  const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
+  Object** base = &Memory::Object_at(fp() + kBaseOffset);
+  Object** limit = &Memory::Object_at(pp() + kLimitOffset) + 1;
+  v->VisitPointers(base, limit);
+}
+
+
+void InternalFrame::Iterate(ObjectVisitor* v) const {
+  // Internal frames only have object pointers on the expression stack
+  // as they never have any arguments.
+  IterateExpressions(v);
+}
+
+
+// -------------------------------------------------------------------------
+
+
+JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
+  ASSERT(n >= 0);
+  for (int i = 0; i <= n; i++) {
+    while (!iterator_.frame()->is_java_script()) iterator_.Advance();
+    if (i == n) return JavaScriptFrame::cast(iterator_.frame());
+    iterator_.Advance();
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+// -------------------------------------------------------------------------
+
+
+int NumRegs(RegList reglist) {
+  int n = 0;
+  while (reglist != 0) {
+    n++;
+    reglist &= reglist - 1;  // clear one bit
+  }
+  return n;
+}
+
+
+int JSCallerSavedCode(int n) {
+  static int reg_code[kNumJSCallerSaved];
+  static bool initialized = false;
+  if (!initialized) {
+    initialized = true;
+    int i = 0;
+    for (int r = 0; r < kNumRegs; r++)
+      if ((kJSCallerSaved & (1 << r)) != 0)
+        reg_code[i++] = r;
+
+    ASSERT(i == kNumJSCallerSaved);
+  }
+  ASSERT(0 <= n && n < kNumJSCallerSaved);
+  return reg_code[n];
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/frames.h b/regexp2000/src/frames.h
new file mode 100644 (file)
index 0000000..662d237
--- /dev/null
@@ -0,0 +1,587 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_FRAMES_H_
+#define V8_FRAMES_H_
+
+namespace v8 { namespace internal {
+
+typedef uint32_t RegList;
+
+// Get the number of registers in a given register list.
+int NumRegs(RegList list);
+
+// Return the code of the n-th saved register available to JavaScript.
+int JSCallerSavedCode(int n);
+
+
+// Forward declarations.
+class StackFrameIterator;
+class Top;
+class ThreadLocalTop;
+
+
+class StackHandler BASE_EMBEDDED {
+ public:
+  enum State {
+    ENTRY,
+    TRY_CATCH,
+    TRY_FINALLY
+  };
+
+  // Get the address of this stack handler.
+  inline Address address() const;
+
+  // Get the next stack handler in the chain.
+  inline StackHandler* next() const;
+
+  // Tells whether the given address is inside this handler.
+  inline bool includes(Address address) const;
+
+  // Garbage collection support.
+  inline void Iterate(ObjectVisitor* v) const;
+
+  // Conversion support.
+  static inline StackHandler* FromAddress(Address address);
+
+  // Testers
+  bool is_entry() { return state() == ENTRY; }
+  bool is_try_catch() { return state() == TRY_CATCH; }
+  bool is_try_finally() { return state() == TRY_FINALLY; }
+
+  // Garbage collection support.
+  void Cook(Code* code);
+  void Uncook(Code* code);
+
+  // TODO(1233780): Get rid of the code slot in stack handlers.
+  static const int kCodeNotPresent = 0;
+
+ private:
+  // Accessors.
+  inline State state() const;
+
+  inline Address pc() const;
+  inline void set_pc(Address value);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
+};
+
+
+#define STACK_FRAME_TYPE_LIST(V)              \
+  V(ENTRY,             EntryFrame)            \
+  V(ENTRY_CONSTRUCT,   EntryConstructFrame)   \
+  V(EXIT,              ExitFrame)             \
+  V(EXIT_DEBUG,        ExitDebugFrame)        \
+  V(JAVA_SCRIPT,       JavaScriptFrame)       \
+  V(INTERNAL,          InternalFrame)         \
+  V(CONSTRUCT,         ConstructFrame)        \
+  V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame)
+
+
+// Abstract base class for all stack frames.
+class StackFrame BASE_EMBEDDED {
+ public:
+#define DECLARE_TYPE(type, ignore) type,
+  enum Type {
+    NONE = 0,
+    STACK_FRAME_TYPE_LIST(DECLARE_TYPE)
+    NUMBER_OF_TYPES
+  };
+#undef DECLARE_TYPE
+
+  // Opaque data type for identifying stack frames. Used extensively
+  // by the debugger.
+  enum Id { NO_ID = 0 };
+
+  // Type testers.
+  bool is_entry() const { return type() == ENTRY; }
+  bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
+  bool is_exit() const { return type() == EXIT; }
+  bool is_exit_debug() const { return type() == EXIT_DEBUG; }
+  bool is_java_script() const { return type() == JAVA_SCRIPT; }
+  bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
+  bool is_internal() const { return type() == INTERNAL; }
+  bool is_construct() const { return type() == CONSTRUCT; }
+  virtual bool is_standard() const { return false; }
+
+  // Accessors.
+  Address sp() const { return state_.sp; }
+  Address fp() const { return state_.fp; }
+  Address pp() const { return GetCallerStackPointer(); }
+
+  Address pc() const { return *pc_address(); }
+  void set_pc(Address pc) { *pc_address() = pc; }
+
+  Address* pc_address() const { return state_.pc_address; }
+
+  // Get the id of this stack frame.
+  Id id() const { return static_cast<Id>(OffsetFrom(pp())); }
+
+  // Checks if this frame includes any stack handlers.
+  bool HasHandler() const;
+
+  // Get the type of this frame.
+  virtual Type type() const = 0;
+
+  // Get the code associated with this frame.
+  virtual Code* FindCode() const = 0;
+
+  // Garbage collection support.
+  static void CookFramesForThread(ThreadLocalTop* thread);
+  static void UncookFramesForThread(ThreadLocalTop* thread);
+
+  virtual void Iterate(ObjectVisitor* v) const { }
+
+  // Printing support.
+  enum PrintMode { OVERVIEW, DETAILS };
+  virtual void Print(StringStream* accumulator,
+                     PrintMode mode,
+                     int index) const { }
+
+ protected:
+  struct State {
+    Address sp;
+    Address fp;
+    Address* pc_address;
+  };
+
+  explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { }
+  virtual ~StackFrame() { }
+
+  // Compute the stack pointer for the calling frame.
+  virtual Address GetCallerStackPointer() const = 0;
+
+  // Printing support.
+  static void PrintIndex(StringStream* accumulator,
+                         PrintMode mode,
+                         int index);
+
+  // Get the top handler from the current stack iterator.
+  inline StackHandler* top_handler() const;
+
+  // Compute the stack frame type for the given state.
+  static Type ComputeType(State* state);
+
+ private:
+  const StackFrameIterator* iterator_;
+  State state_;
+
+  // Get the type and the state of the calling frame.
+  virtual Type GetCallerState(State* state) const = 0;
+
+  // Cooking/uncooking support.
+  void Cook();
+  void Uncook();
+
+  friend class StackFrameIterator;
+  friend class StackHandlerIterator;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrame);
+};
+
+
+// Entry frames are used to enter JavaScript execution from C.
+class EntryFrame: public StackFrame {
+ public:
+  virtual Type type() const { return ENTRY; }
+
+  virtual Code* FindCode() const;
+
+  // Garbage collection support.
+  virtual void Iterate(ObjectVisitor* v) const;
+
+  static EntryFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_entry());
+    return static_cast<EntryFrame*>(frame);
+  }
+
+ protected:
+  explicit EntryFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
+
+  // The caller stack pointer for entry frames is always zero. The
+  // real information about the caller frame is available through the
+  // link to the top exit frame.
+  virtual Address GetCallerStackPointer() const { return 0; }
+
+ private:
+  virtual Type GetCallerState(State* state) const;
+
+  friend class StackFrameIterator;
+};
+
+
+class EntryConstructFrame: public EntryFrame {
+ public:
+  virtual Type type() const { return ENTRY_CONSTRUCT; }
+
+  virtual Code* FindCode() const;
+
+  static EntryConstructFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_entry_construct());
+    return static_cast<EntryConstructFrame*>(frame);
+  }
+
+ protected:
+  explicit EntryConstructFrame(StackFrameIterator* iterator)
+      : EntryFrame(iterator) { }
+
+ private:
+  friend class StackFrameIterator;
+};
+
+
+// Exit frames are used to exit JavaScript execution and go to C.
+class ExitFrame: public StackFrame {
+ public:
+  virtual Type type() const { return EXIT; }
+
+  virtual Code* FindCode() const;
+
+  // Garbage colletion support.
+  virtual void Iterate(ObjectVisitor* v) const;
+
+  static ExitFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_exit());
+    return static_cast<ExitFrame*>(frame);
+  }
+
+  // Compute the state and type of an exit frame given a frame
+  // pointer. Used when constructing the first stack frame seen by an
+  // iterator and the frames following entry frames.
+  static Type GetStateForFramePointer(Address fp, State* state);
+
+ protected:
+  explicit ExitFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
+
+  virtual Address GetCallerStackPointer() const;
+
+ private:
+  virtual Type GetCallerState(State* state) const;
+
+  friend class StackFrameIterator;
+};
+
+
+class ExitDebugFrame: public ExitFrame {
+ public:
+  virtual Type type() const { return EXIT_DEBUG; }
+
+  virtual Code* FindCode() const;
+
+  static ExitDebugFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_exit_debug());
+    return static_cast<ExitDebugFrame*>(frame);
+  }
+
+ protected:
+  explicit ExitDebugFrame(StackFrameIterator* iterator)
+      : ExitFrame(iterator) { }
+
+ private:
+  friend class StackFrameIterator;
+};
+
+
+class StandardFrame: public StackFrame {
+ public:
+  // Testers.
+  virtual bool is_standard() const { return true; }
+
+  // Accessors.
+  inline Object* context() const;
+
+  // Access the expressions in the stack frame including locals.
+  inline Object* GetExpression(int index) const;
+  inline void SetExpression(int index, Object* value);
+  int ComputeExpressionsCount() const;
+
+  static StandardFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_standard());
+    return static_cast<StandardFrame*>(frame);
+  }
+
+ protected:
+  explicit StandardFrame(StackFrameIterator* iterator)
+      : StackFrame(iterator) { }
+
+  virtual Type GetCallerState(State* state) const;
+
+  // Accessors.
+  inline Address caller_sp() const;
+  inline Address caller_fp() const;
+  inline Address caller_pc() const;
+
+  // Computes the address of the PC field in the standard frame given
+  // by the provided frame pointer.
+  static inline Address ComputePCAddress(Address fp);
+
+  // Iterate over expression stack including stack handlers, locals,
+  // and parts of the fixed part including context and code fields.
+  void IterateExpressions(ObjectVisitor* v) const;
+
+  // Returns the address of the n'th expression stack element.
+  Address GetExpressionAddress(int n) const;
+
+  // Determines if the n'th expression stack element is in a stack
+  // handler or not. Requires traversing all handlers in this frame.
+  bool IsExpressionInsideHandler(int n) const;
+
+  // Determines if the standard frame for the given frame pointer is
+  // an arguments adaptor frame.
+  static inline bool IsArgumentsAdaptorFrame(Address fp);
+
+  // Determines if the standard frame for the given frame pointer is a
+  // construct frame.
+  static inline bool IsConstructFrame(Address fp);
+
+ private:
+  friend class StackFrame;
+};
+
+
+class JavaScriptFrame: public StandardFrame {
+ public:
+  virtual Type type() const { return JAVA_SCRIPT; }
+
+  // Accessors.
+  inline Object* function() const;
+  inline Object* receiver() const;
+  inline void set_receiver(Object* value);
+
+  // Access the parameters.
+  Object* GetParameter(int index) const;
+  int ComputeParametersCount() const;
+
+  // Temporary way of getting access to the number of parameters
+  // passed on the stack by the caller. Once argument adaptor frames
+  // has been introduced on ARM, this number will always match the
+  // computed parameters count.
+  int GetProvidedParametersCount() const;
+
+  // Check if this frame is a constructor frame invoked through 'new'.
+  bool IsConstructor() const;
+
+  // Check if this frame has "adapted" arguments in the sense that the
+  // actual passed arguments are available in an arguments adaptor
+  // frame below it on the stack.
+  inline bool has_adapted_arguments() const;
+
+  // Garbage colletion support.
+  virtual void Iterate(ObjectVisitor* v) const;
+
+  // Printing support.
+  virtual void Print(StringStream* accumulator,
+                     PrintMode mode,
+                     int index) const;
+
+  // Determine the code for the frame.
+  virtual Code* FindCode() const;
+
+  static JavaScriptFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_java_script());
+    return static_cast<JavaScriptFrame*>(frame);
+  }
+
+ protected:
+  explicit JavaScriptFrame(StackFrameIterator* iterator)
+      : StandardFrame(iterator) { }
+
+  virtual Address GetCallerStackPointer() const;
+
+ private:
+  friend class StackFrameIterator;
+};
+
+
+// Arguments adaptor frames are automatically inserted below
+// JavaScript frames when the actual number of parameters does not
+// match the formal number of parameters.
+class ArgumentsAdaptorFrame: public JavaScriptFrame {
+ public:
+  // This sentinel value is temporarily used to distinguish arguments
+  // adaptor frames from ordinary JavaScript frames. If a frame has
+  // the sentinel as its context, it is an arguments adaptor frame. It
+  // must be tagged as a small integer to avoid GC issues. Crud.
+  enum {
+    SENTINEL = (1 << kSmiTagSize) | kSmiTag
+  };
+
+  virtual Type type() const { return ARGUMENTS_ADAPTOR; }
+
+  // Determine the code for the frame.
+  virtual Code* FindCode() const;
+
+  static ArgumentsAdaptorFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_arguments_adaptor());
+    return static_cast<ArgumentsAdaptorFrame*>(frame);
+  }
+
+  // Printing support.
+  virtual void Print(StringStream* accumulator,
+                     PrintMode mode,
+                     int index) const;
+ protected:
+  explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
+      : JavaScriptFrame(iterator) { }
+
+  virtual Address GetCallerStackPointer() const;
+
+ private:
+  friend class StackFrameIterator;
+};
+
+
+class InternalFrame: public StandardFrame {
+ public:
+  virtual Type type() const { return INTERNAL; }
+
+  // Garbage colletion support.
+  virtual void Iterate(ObjectVisitor* v) const;
+
+  // Determine the code for the frame.
+  virtual Code* FindCode() const;
+
+  static InternalFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_internal());
+    return static_cast<InternalFrame*>(frame);
+  }
+
+ protected:
+  explicit InternalFrame(StackFrameIterator* iterator)
+      : StandardFrame(iterator) { }
+
+  virtual Address GetCallerStackPointer() const;
+
+ private:
+  friend class StackFrameIterator;
+};
+
+
+// Construct frames are special trampoline frames introduced to handle
+// function invocations through 'new'.
+class ConstructFrame: public InternalFrame {
+ public:
+  virtual Type type() const { return CONSTRUCT; }
+
+  static ConstructFrame* cast(StackFrame* frame) {
+    ASSERT(frame->is_construct());
+    return static_cast<ConstructFrame*>(frame);
+  }
+
+ protected:
+  explicit ConstructFrame(StackFrameIterator* iterator)
+      : InternalFrame(iterator) { }
+
+ private:
+  friend class StackFrameIterator;
+};
+
+
+class StackFrameIterator BASE_EMBEDDED {
+ public:
+  // An iterator that iterates over the current thread's stack.
+  StackFrameIterator();
+
+  // An iterator that iterates over a given thread's stack.
+  explicit StackFrameIterator(ThreadLocalTop* thread);
+
+  StackFrame* frame() const {
+    ASSERT(!done());
+    return frame_;
+  }
+
+  bool done() const { return frame_ == NULL; }
+  void Advance();
+
+  // Go back to the first frame.
+  void Reset();
+
+ private:
+#define DECLARE_SINGLETON(ignore, type) type type##_;
+  STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON)
+#undef DECLARE_SINGLETON
+  StackFrame* frame_;
+  StackHandler* handler_;
+  ThreadLocalTop* thread_;
+
+  StackHandler* handler() const {
+    ASSERT(!done());
+    return handler_;
+  }
+
+  // Get the type-specific frame singleton in a given state.
+  StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state);
+
+  friend class StackFrame;
+  DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
+};
+
+
+// Iterator that supports iterating through all JavaScript frames.
+class JavaScriptFrameIterator BASE_EMBEDDED {
+ public:
+  JavaScriptFrameIterator() { if (!done()) Advance(); }
+
+  explicit JavaScriptFrameIterator(ThreadLocalTop* thread) : iterator_(thread) {
+    if (!done()) Advance();
+  }
+
+  // Skip frames until the frame with the given id is reached.
+  explicit JavaScriptFrameIterator(StackFrame::Id id);
+
+  inline JavaScriptFrame* frame() const;
+
+  bool done() const { return iterator_.done(); }
+  void Advance();
+
+  // Advance to the frame holding the arguments for the current
+  // frame. This only affects the current frame if it has adapted
+  // arguments.
+  void AdvanceToArgumentsFrame();
+
+  // Go back to the first frame.
+  void Reset();
+
+ private:
+  StackFrameIterator iterator_;
+};
+
+
+class StackFrameLocator BASE_EMBEDDED {
+ public:
+  // Find the nth JavaScript frame on the stack. The caller must
+  // guarantee that such a frame exists.
+  JavaScriptFrame* FindJavaScriptFrame(int n);
+
+ private:
+  StackFrameIterator iterator_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_FRAMES_H_
diff --git a/regexp2000/src/global-handles.cc b/regexp2000/src/global-handles.cc
new file mode 100644 (file)
index 0000000..bb36e35
--- /dev/null
@@ -0,0 +1,379 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "global-handles.h"
+
+namespace v8 { namespace internal {
+
+class GlobalHandles::Node : public Malloced {
+ public:
+
+  void Initialize(Object* object) {
+    // Set the initial value of the handle.
+    object_ = object;
+    state_  = NORMAL;
+    parameter_or_next_free_.parameter = NULL;
+    callback_ = NULL;
+  }
+
+  explicit Node(Object* object) {
+    Initialize(object);
+    // Initialize link structure.
+    next_ = NULL;
+  }
+
+  ~Node() {
+    if (state_ != DESTROYED) Destroy();
+#ifdef DEBUG
+    // Zap the values for eager trapping.
+    object_ = NULL;
+    next_ = NULL;
+    parameter_or_next_free_.next_free = NULL;
+#endif
+  }
+
+  void Destroy() {
+    if (state_ == WEAK || IsNearDeath()) {
+      GlobalHandles::number_of_weak_handles_--;
+      if (object_->IsJSGlobalObject()) {
+        GlobalHandles::number_of_global_object_weak_handles_--;
+      }
+    }
+    state_ = DESTROYED;
+  }
+
+  // Accessors for next_.
+  Node* next() { return next_; }
+  void set_next(Node* value) { next_ = value; }
+  Node** next_addr() { return &next_; }
+
+  // Accessors for next free node in the free list.
+  Node* next_free() {
+    ASSERT(state_ == DESTROYED);
+    return parameter_or_next_free_.next_free;
+  }
+  void set_next_free(Node* value) {
+    ASSERT(state_ == DESTROYED);
+    parameter_or_next_free_.next_free = value;
+  }
+
+  // Returns a link from the handle.
+  static Node* FromLocation(Object** location) {
+    ASSERT(OFFSET_OF(Node, object_) == 0);
+    return reinterpret_cast<Node*>(location);
+  }
+
+  // Returns the handle.
+  Handle<Object> handle() { return Handle<Object>(&object_); }
+
+  // Make this handle weak.
+  void MakeWeak(void* parameter, WeakReferenceCallback callback) {
+    LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
+    if (state_ != WEAK && !IsNearDeath()) {
+      GlobalHandles::number_of_weak_handles_++;
+      if (object_->IsJSGlobalObject()) {
+        GlobalHandles::number_of_global_object_weak_handles_++;
+      }
+    }
+    state_ = WEAK;
+    set_parameter(parameter);
+    callback_ = callback;
+  }
+
+  void ClearWeakness() {
+    LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
+    if (state_ == WEAK || IsNearDeath()) {
+      GlobalHandles::number_of_weak_handles_--;
+      if (object_->IsJSGlobalObject()) {
+        GlobalHandles::number_of_global_object_weak_handles_--;
+      }
+    }
+    state_ = NORMAL;
+    set_parameter(NULL);
+  }
+
+  bool IsNearDeath() {
+    // Check for PENDING to ensure correct answer when processing callbacks.
+    return state_ == PENDING || state_ == NEAR_DEATH;
+  }
+
+  bool IsWeak() {
+    return state_ == WEAK;
+  }
+
+  // Returns the id for this weak handle.
+  void set_parameter(void* parameter) {
+    ASSERT(state_ != DESTROYED);
+    parameter_or_next_free_.parameter = parameter;
+  }
+  void* parameter() {
+    ASSERT(state_ != DESTROYED);
+    return parameter_or_next_free_.parameter;
+  }
+
+  // Returns the callback for this weak handle.
+  WeakReferenceCallback callback() { return callback_; }
+
+  void PostGarbageCollectionProcessing() {
+    if (state_ != Node::PENDING) return;
+    LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
+    void* par = parameter();
+    state_ = NEAR_DEATH;
+    set_parameter(NULL);
+    // The callback function is resolved as late as possible to preserve old
+    // behavior.
+    WeakReferenceCallback func = callback();
+    if (func != NULL) {
+      func(v8::Persistent<v8::Object>(ToApi<v8::Object>(handle())), par);
+    }
+  }
+
+  // Place the handle address first to avoid offset computation.
+  Object* object_;  // Storage for object pointer.
+
+  // Transition diagram:
+  // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
+  enum State {
+    NORMAL,      // Normal global handle.
+    WEAK,        // Flagged as weak but not yet finalized.
+    PENDING,     // Has been recognized as only reachable by weak handles.
+    NEAR_DEATH,  // Callback has informed the handle is near death.
+    DESTROYED
+  };
+  State state_;
+
+ private:
+  // Handle specific callback.
+  WeakReferenceCallback callback_;
+  // Provided data for callback.  In DESTROYED state, this is used for
+  // the free list link.
+  union {
+    void* parameter;
+    Node* next_free;
+  } parameter_or_next_free_;
+
+  // Linkage for the list.
+  Node* next_;
+
+ public:
+  TRACK_MEMORY("GlobalHandles::Node")
+};
+
+
+Handle<Object> GlobalHandles::Create(Object* value) {
+  Counters::global_handles.Increment();
+  Node* result;
+  if (first_free() == NULL) {
+    // Allocate a new node.
+    result = new Node(value);
+    result->set_next(head());
+    set_head(result);
+  } else {
+    // Take the first node in the free list.
+    result = first_free();
+    set_first_free(result->next_free());
+    result->Initialize(value);
+  }
+  return result->handle();
+}
+
+
+void GlobalHandles::Destroy(Object** location) {
+  Counters::global_handles.Decrement();
+  if (location == NULL) return;
+  Node* node = Node::FromLocation(location);
+  node->Destroy();
+  // Link the destroyed.
+  node->set_next_free(first_free());
+  set_first_free(node);
+}
+
+
+void GlobalHandles::MakeWeak(Object** location, void* parameter,
+                             WeakReferenceCallback callback) {
+  ASSERT(callback != NULL);
+  Node::FromLocation(location)->MakeWeak(parameter, callback);
+}
+
+
+void GlobalHandles::ClearWeakness(Object** location) {
+  Node::FromLocation(location)->ClearWeakness();
+}
+
+
+bool GlobalHandles::IsNearDeath(Object** location) {
+  return Node::FromLocation(location)->IsNearDeath();
+}
+
+
+bool GlobalHandles::IsWeak(Object** location) {
+  return Node::FromLocation(location)->IsWeak();
+}
+
+
+void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
+  // Traversal of GC roots in the global handle list that are marked as
+  // WEAK or PENDING.
+  for (Node* current = head_; current != NULL; current = current->next()) {
+    if (current->state_ == Node::WEAK
+      || current->state_ == Node::PENDING
+      || current->state_ == Node::NEAR_DEATH) {
+      v->VisitPointer(&current->object_);
+    }
+  }
+}
+
+
+void GlobalHandles::MarkWeakRoots(WeakSlotCallback f) {
+  for (Node* current = head_; current != NULL; current = current->next()) {
+    if (current->state_ == Node::WEAK) {
+      if (f(&current->object_)) {
+        current->state_ = Node::PENDING;
+        LOG(HandleEvent("GlobalHandle::Pending", current->handle().location()));
+      }
+    }
+  }
+}
+
+
+void GlobalHandles::PostGarbageCollectionProcessing() {
+  // Process weak global handle callbacks. This must be done after the
+  // GC is completely done, because the callbacks may invoke arbitrary
+  // API functions.
+  // At the same time deallocate all DESTROYED nodes
+  ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
+  Node** p = &head_;
+  while (*p != NULL) {
+    (*p)->PostGarbageCollectionProcessing();
+    if ((*p)->state_ == Node::DESTROYED) {
+      // Delete the link.
+      Node* node = *p;
+      *p = node->next();  // Update the link.
+      delete node;
+    } else {
+      p = (*p)->next_addr();
+    }
+  }
+  set_first_free(NULL);
+}
+
+
+void GlobalHandles::IterateRoots(ObjectVisitor* v) {
+  // Traversal of global handles marked as NORMAL or NEAR_DEATH.
+  for (Node* current = head_; current != NULL; current = current->next()) {
+    if (current->state_ == Node::NORMAL) {
+      v->VisitPointer(&current->object_);
+    }
+  }
+}
+
+void GlobalHandles::TearDown() {
+  // Delete all the nodes in the linked list.
+  Node* current = head_;
+  while (current != NULL) {
+    Node* n = current;
+    current = current->next();
+    delete n;
+  }
+  // Reset the head and free_list.
+  set_head(NULL);
+  set_first_free(NULL);
+}
+
+
+int GlobalHandles::number_of_weak_handles_ = 0;
+int GlobalHandles::number_of_global_object_weak_handles_ = 0;
+
+GlobalHandles::Node* GlobalHandles::head_ = NULL;
+GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
+
+#ifdef DEBUG
+
+void GlobalHandles::PrintStats() {
+  int total = 0;
+  int weak = 0;
+  int pending = 0;
+  int near_death = 0;
+  int destroyed = 0;
+
+  for (Node* current = head_; current != NULL; current = current->next()) {
+    total++;
+    if (current->state_ == Node::WEAK) weak++;
+    if (current->state_ == Node::PENDING) pending++;
+    if (current->state_ == Node::NEAR_DEATH) near_death++;
+    if (current->state_ == Node::DESTROYED) destroyed++;
+  }
+
+  PrintF("Global Handle Statistics:\n");
+  PrintF("  allocated memory = %dB\n", sizeof(Node) * total);
+  PrintF("  # weak       = %d\n", weak);
+  PrintF("  # pending    = %d\n", pending);
+  PrintF("  # near_death = %d\n", near_death);
+  PrintF("  # destroyed  = %d\n", destroyed);
+  PrintF("  # total      = %d\n", total);
+}
+
+void GlobalHandles::Print() {
+  PrintF("Global handles:\n");
+  for (Node* current = head_; current != NULL; current = current->next()) {
+    PrintF("  handle %p to %p (weak=%d)\n", current->handle().location(),
+           *current->handle(), current->state_ == Node::WEAK);
+  }
+}
+
+#endif
+
+List<ObjectGroup*> GlobalHandles::object_groups_(4);
+
+void GlobalHandles::AddToGroup(void* id, Object** handle) {
+  for (int i = 0; i < object_groups_.length(); i++) {
+    ObjectGroup* entry = object_groups_[i];
+    if (entry->id_ == id) {
+      entry->objects_.Add(handle);
+      return;
+    }
+  }
+
+  // not found
+  ObjectGroup* new_entry = new ObjectGroup(id);
+  new_entry->objects_.Add(handle);
+  object_groups_.Add(new_entry);
+}
+
+
+void GlobalHandles::RemoveObjectGroups() {
+  for (int i = 0; i< object_groups_.length(); i++) {
+    delete object_groups_[i];
+  }
+  object_groups_.Clear();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/global-handles.h b/regexp2000/src/global-handles.h
new file mode 100644 (file)
index 0000000..78fb3a1
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_GLOBAL_HANDLES_H_
+#define V8_GLOBAL_HANDLES_H_
+
+#include "list-inl.h"
+
+namespace v8 { namespace internal {
+
+// Structure for tracking global handles.
+// A single list keeps all the allocated global handles.
+// Destroyed handles stay in the list but is added to the free list.
+// At GC the destroyed global handles are removed from the free list
+// and deallocated.
+
+// Callback function on handling weak global handles.
+// typedef bool (*WeakSlotCallback)(Object** pointer);
+
+// An object group is indexed by an id. An object group is treated like
+// a single JS object: if one of object in the group is alive,
+// all objects in the same group are considered alive.
+// An object group is used to simulate object relationship in a DOM tree.
+class ObjectGroup : public Malloced {
+ public:
+  explicit ObjectGroup(void* id) : id_(id), objects_(4) {}
+
+  void* id_;
+  List<Object**> objects_;
+};
+
+
+class GlobalHandles : public AllStatic {
+ public:
+  // Creates a new global handle that is alive until Destroy is called.
+  static Handle<Object> Create(Object* value);
+
+  // Destroy a global handle.
+  static void Destroy(Object** location);
+
+  // Make the global handle weak and set the callback parameter for the
+  // handle.  When the garbage collector recognizes that only weak global
+  // handles point to an object the handles are cleared and the callback
+  // function is invoked (for each handle) with the handle and corresponding
+  // parameter as arguments.  Note: cleared means set to Smi::FromInt(0). The
+  // reason is that Smi::FromInt(0) does not change during garage collection.
+  static void MakeWeak(Object** location,
+                       void* parameter,
+                       WeakReferenceCallback callback);
+
+  // Returns the current number of weak handles.
+  static int NumberOfWeakHandles() { return number_of_weak_handles_; }
+
+  // Returns the current number of weak handles to global objects.
+  // These handles are also included in NumberOfWeakHandles().
+  static int NumberOfGlobalObjectWeakHandles() {
+    return number_of_global_object_weak_handles_;
+  }
+
+  // Clear the weakness of a global handle.
+  static void ClearWeakness(Object** location);
+
+  // Tells whether global handle is near death.
+  static bool IsNearDeath(Object** location);
+
+  // Tells whether global handle is weak.
+  static bool IsWeak(Object** location);
+
+  // Process pending weak handles.
+  static void PostGarbageCollectionProcessing();
+
+  // Iterates over all handles.
+  static void IterateRoots(ObjectVisitor* v);
+
+  // Iterates over all weak roots in heap.
+  static void IterateWeakRoots(ObjectVisitor* v);
+
+  // Mark the weak pointers based on the callback.
+  static void MarkWeakRoots(WeakSlotCallback f);
+
+  // Add an object to a group indexed by an id.
+  // Should only used in GC callback function before a collection.
+  // All groups are destroyed after a mark-compact collection.
+  static void AddToGroup(void* id, Object** location);
+
+  // Returns the object groups.
+  static List<ObjectGroup*>& ObjectGroups() {
+    return object_groups_;
+  }
+
+  // Remove bags, this should only happen after GC.
+  static void RemoveObjectGroups();
+
+  // Tear down the global handle structure.
+  static void TearDown();
+
+#ifdef DEBUG
+  static void PrintStats();
+  static void Print();
+#endif
+ private:
+  // Internal node structure, one for each global handle.
+  class Node;
+
+  // Field always containing the number of weak and near-death handles.
+  static int number_of_weak_handles_;
+
+  // Field always containing the number of weak and near-death handles
+  // to global objects.  These objects are also included in
+  // number_of_weak_handles_.
+  static int number_of_global_object_weak_handles_;
+
+  // Global handles are kept in a single linked list pointed to by head_.
+  static Node* head_;
+  static Node* head() { return head_; }
+  static void set_head(Node* value) { head_ = value; }
+
+  // Free list for DESTROYED global handles not yet deallocated.
+  static Node* first_free_;
+  static Node* first_free() { return first_free_; }
+  static void set_first_free(Node* value) { first_free_ = value; }
+
+  // A list of object groups.
+  static List<ObjectGroup*> object_groups_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_GLOBAL_HANDLES_H_
diff --git a/regexp2000/src/globals.h b/regexp2000/src/globals.h
new file mode 100644 (file)
index 0000000..183baad
--- /dev/null
@@ -0,0 +1,507 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// -----------------------------------------------------------------------------
+// Types
+// Windows is missing the stdint.h header file. Instead we define standard
+// integer types for Windows here.
+
+#ifdef WIN32
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;  // NOLINT
+typedef unsigned short uint16_t;  // NOLINT
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdint.h>  // for intptr_t
+#endif
+
+
+namespace v8 { namespace internal {
+
+// Support for alternative bool type. This is only enabled if the code is
+// compiled with USE_MYBOOL defined. This catches some nasty type bugs.
+// For instance, 'bool b = "false";' results in b == true! This is a hidden
+// source of bugs.
+// However, redefining the bool type does have some negative impact on some
+// platforms. It gives rise to compiler warnings (i.e. with
+// MSVC) in the API header files when mixing code that uses the standard
+// bool with code that uses the redefined version.
+// This does not actually belong in the platform code, but needs to be
+// defined here because the platform code uses bool, and platform.h is
+// include very early in the main include file.
+
+#ifndef V8_GLOBALS_H_
+#define V8_GLOBALS_H_
+
+#ifdef USE_MYBOOL
+typedef unsigned int __my_bool__;
+#define bool __my_bool__  // use 'indirection' to avoid name clashes
+#endif
+
+typedef uint8_t byte;
+typedef byte* Address;
+
+// Code-point values in Unicode 4.0 are 21 bits wide.
+typedef uint16_t uc16;
+typedef signed int uc32;
+
+#ifndef ARM
+#define CAN_READ_UNALIGNED 1
+#endif
+
+// -----------------------------------------------------------------------------
+// Constants
+
+#ifdef DEBUG
+const bool kDebug = true;
+#else
+const bool kDebug = false;
+#endif  // DEBUG
+
+const int KB = 1024;
+const int MB = KB * KB;
+const int GB = KB * KB * KB;
+const int kMaxInt = 0x7FFFFFFF;
+const int kMinInt = -kMaxInt - 1;
+
+const int kCharSize     = sizeof(char);    // NOLINT
+const int kShortSize    = sizeof(short);   // NOLINT
+const int kIntSize      = sizeof(int);     // NOLINT
+const int kDoubleSize   = sizeof(double);  // NOLINT
+const int kPointerSize  = sizeof(void*);   // NOLINT
+
+const int kPointerSizeLog2 = 2;
+
+const int kObjectAlignmentBits = 2;
+const int kObjectAlignmentMask = (1 << kObjectAlignmentBits) - 1;
+const int kObjectAlignment = 1 << kObjectAlignmentBits;
+
+
+// Tag information for HeapObject.
+const int kHeapObjectTag = 1;
+const int kHeapObjectTagSize = 2;
+const int kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1;
+
+
+// Tag information for Smi.
+const int kSmiTag = 0;
+const int kSmiTagSize = 1;
+const int kSmiTagMask = (1 << kSmiTagSize) - 1;
+
+
+// Tag information for Failure.
+const int kFailureTag = 3;
+const int kFailureTagSize = 2;
+const int kFailureTagMask = (1 << kFailureTagSize) - 1;
+
+
+const int kBitsPerByte = 8;
+const int kBitsPerByteLog2 = 3;
+const int kBitsPerPointer = kPointerSize * kBitsPerByte;
+const int kBitsPerInt = kIntSize * kBitsPerByte;
+
+
+// Zap-value: The value used for zapping dead objects. Should be a recognizable
+// illegal heap object pointer.
+const Address kZapValue = reinterpret_cast<Address>(0xdeadbeed);
+const Address kHandleZapValue = reinterpret_cast<Address>(0xbaddead);
+const Address kFromSpaceZapValue = reinterpret_cast<Address>(0xbeefdad);
+
+// -----------------------------------------------------------------------------
+// Forward declarations for frequently used classes
+// (sorted alphabetically)
+
+class AccessorInfo;
+class Allocation;
+class Assembler;
+class BreakableStatement;
+class Code;
+class CodeGenerator;
+class CodeStub;
+class Context;
+class Debug;
+class Debugger;
+class DebugInfo;
+class Descriptor;
+class DescriptorArray;
+class Expression;
+class ExternalReference;
+class FixedArray;
+class FunctionEntry;
+class FunctionLiteral;
+class FunctionTemplateInfo;
+class Dictionary;
+class FreeStoreAllocationPolicy;
+template <typename T> class Handle;
+class Heap;
+class HeapObject;
+class IC;
+class InterceptorInfo;
+class IterationStatement;
+class JSArray;
+class JSFunction;
+class JSObject;
+class LabelCollector;
+class LargeObjectSpace;
+template <typename T, class P = FreeStoreAllocationPolicy> class List;
+class LookupResult;
+class MacroAssembler;
+class Map;
+class MapSpace;
+class MarkCompactCollector;
+class NewSpace;
+class Object;
+class OldSpace;
+class Property;
+class Proxy;
+class RegExpTree;
+class Scope;
+template<class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
+class Script;
+class Slot;
+class Smi;
+class Statement;
+class String;
+class Struct;
+class SwitchStatement;
+class Visitor;
+class Variable;
+class VariableProxy;
+class RelocInfo;
+class Deserializer;
+class MessageLocation;
+class ObjectGroup;
+class TickSample;
+class VirtualMemory;
+class Mutex;
+
+typedef bool (*WeakSlotCallback)(Object** pointer);
+
+// -----------------------------------------------------------------------------
+// Miscellaneous
+
+// NOTE: SpaceIterator depends on AllocationSpace enumeration values being
+// consecutive.
+enum AllocationSpace {
+  NEW_SPACE,          // Semispaces collected with copying collector.
+  OLD_POINTER_SPACE,  // Must be first of the paged spaces - see PagedSpaces.
+  OLD_DATA_SPACE,     // May not have pointers to new space.
+  CODE_SPACE,         // Also one of the old spaces.  Marked executable.
+  MAP_SPACE,          // Only map objects.
+  LO_SPACE,           // Large objects.
+  FIRST_SPACE = NEW_SPACE,
+  LAST_SPACE = LO_SPACE  // <= 5 (see kSpaceBits and kLOSpacePointer)
+};
+const int kSpaceTagSize = 3;
+const int kSpaceTagMask = (1 << kSpaceTagSize) - 1;
+
+
+// A flag that indicates whether objects should be pretenured when
+// allocated (allocated directly into the old generation) or not
+// (allocated in the young generation if the object size and type
+// allows).
+enum PretenureFlag { NOT_TENURED, TENURED };
+
+enum GarbageCollector { SCAVENGER, MARK_COMPACTOR };
+
+enum Executability { NOT_EXECUTABLE, EXECUTABLE };
+
+
+// A CodeDesc describes a buffer holding instructions and relocation
+// information. The instructions start at the beginning of the buffer
+// and grow forward, the relocation information starts at the end of
+// the buffer and grows backward.
+//
+//  |<--------------- buffer_size ---------------->|
+//  |<-- instr_size -->|        |<-- reloc_size -->|
+//  +==================+========+==================+
+//  |   instructions   |  free  |    reloc info    |
+//  +==================+========+==================+
+//  ^
+//  |
+//  buffer
+
+struct CodeDesc {
+  byte* buffer;
+  int buffer_size;
+  int instr_size;
+  int reloc_size;
+};
+
+
+// Callback function on object slots, used for iterating heap object slots in
+// HeapObjects, global pointers to heap objects, etc. The callback allows the
+// callback function to change the value of the slot.
+typedef void (*ObjectSlotCallback)(HeapObject** pointer);
+
+
+// Callback function used for iterating objects in heap spaces,
+// for example, scanning heap objects.
+typedef int (*HeapObjectCallback)(HeapObject* obj);
+
+
+// Callback function used for checking constraints when copying/relocating
+// objects. Returns true if an object can be copied/relocated from its
+// old_addr to a new_addr.
+typedef bool (*ConstraintCallback)(Address new_addr, Address old_addr);
+
+
+// Callback function on inline caches, used for iterating over inline caches
+// in compiled code.
+typedef void (*InlineCacheCallback)(Code* code, Address ic);
+
+
+// State for inline cache call sites. Aliased as IC::State.
+enum InlineCacheState {
+  // Has never been executed.
+  UNINITIALIZED,
+  // Has been executed but monomorhic state has been delayed.
+  PREMONOMORPHIC,
+  // Has been executed and only one receiver type has been seen.
+  MONOMORPHIC,
+  // Like MONOMORPHIC but check failed due to prototype.
+  MONOMORPHIC_PROTOTYPE_FAILURE,
+  // Multiple receiver types have been seen.
+  MEGAMORPHIC,
+  // Special states for debug break or step in prepare stubs.
+  DEBUG_BREAK,
+  DEBUG_PREPARE_STEP_IN
+};
+
+
+// Type of properties.
+// Order of properties is significant.
+// Must fit in the BitField PropertyDetails::TypeField.
+// A copy of this is in mirror-delay.js.
+enum PropertyType {
+  NORMAL              = 0,  // only in slow mode
+  FIELD               = 1,  // only in fast mode
+  CONSTANT_FUNCTION   = 2,  // only in fast mode
+  CALLBACKS           = 3,
+  INTERCEPTOR         = 4,  // only in lookup results, not in descriptors.
+  MAP_TRANSITION      = 5,  // only in fast mode
+  CONSTANT_TRANSITION = 6,  // only in fast mode
+  NULL_DESCRIPTOR     = 7,  // only in fast mode
+  // All properties before MAP_TRANSITION are real.
+  FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION
+};
+
+
+// Whether to remove map transitions and constant transitions from a
+// DescriptorArray.
+enum TransitionFlag {
+  REMOVE_TRANSITIONS,
+  KEEP_TRANSITIONS
+};
+
+
+// Union used for fast testing of specific double values.
+union DoubleRepresentation {
+  double  value;
+  int64_t bits;
+  DoubleRepresentation(double x) { value = x; }
+};
+
+
+// AccessorCallback
+struct AccessorDescriptor {
+  Object* (*getter)(Object* object, void* data);
+  Object* (*setter)(JSObject* object, Object* value, void* data);
+  void* data;
+};
+
+
+// Logging and profiling.
+// A StateTag represents a possible state of the VM.  When compiled with
+// ENABLE_LOGGING_AND_PROFILING, the logger maintains a stack of these.
+// Creating a VMState object enters a state by pushing on the stack, and
+// destroying a VMState object leaves a state by popping the current state
+// from the stack.
+
+#define STATE_TAG_LIST(V) \
+  V(JS)                   \
+  V(GC)                   \
+  V(COMPILER)             \
+  V(OTHER)
+
+enum StateTag {
+#define DEF_STATE_TAG(name) name,
+  STATE_TAG_LIST(DEF_STATE_TAG)
+#undef DEF_STATE_TAG
+  // Pseudo-types.
+  state_tag_count
+};
+
+
+// -----------------------------------------------------------------------------
+// Macros
+
+// Testers for test.
+
+#define HAS_SMI_TAG(value) \
+  ((reinterpret_cast<int>(value) & kSmiTagMask) == kSmiTag)
+
+#define HAS_FAILURE_TAG(value) \
+  ((reinterpret_cast<int>(value) & kFailureTagMask) == kFailureTag)
+
+#define HAS_HEAP_OBJECT_TAG(value) \
+  ((reinterpret_cast<int>(value) & kHeapObjectTagMask) == kHeapObjectTag)
+
+// OBJECT_SIZE_ALIGN returns the value aligned HeapObject size
+#define OBJECT_SIZE_ALIGN(value)                                \
+  ((value + kObjectAlignmentMask) & ~kObjectAlignmentMask)
+
+// The expression OFFSET_OF(type, field) computes the byte-offset
+// of the specified field relative to the containing type. This
+// corresponds to 'offsetof' (in stddef.h), except that it doesn't
+// use 0 or NULL, which causes a problem with the compiler warnings
+// we have enabled (which is also why 'offsetof' doesn't seem to work).
+// Here we simply use the non-zero value 4, which seems to work.
+#define OFFSET_OF(type, field)                                          \
+  (reinterpret_cast<intptr_t>(&(reinterpret_cast<type*>(4)->field)) - 4)
+
+
+// The expression ARRAY_SIZE(a) is a compile-time constant of type
+// size_t which represents the number of elements of the given
+// array. You should only use ARRAY_SIZE on statically allocated
+// arrays.
+#define ARRAY_SIZE(a)                                   \
+  ((sizeof(a) / sizeof(*(a))) /                         \
+  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+
+// The USE(x) template is used to silence C++ compiler warnings
+// issued for (yet) unused variables (typically parameters).
+template <typename T>
+static inline void USE(T) { }
+
+
+// FUNCTION_ADDR(f) gets the address of a C function f.
+#define FUNCTION_ADDR(f)                                        \
+  (reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(f)))
+
+
+// FUNCTION_CAST<F>(addr) casts an address into a function
+// of type F. Used to invoke generated code from within C.
+template <typename F>
+F FUNCTION_CAST(Address addr) {
+  return reinterpret_cast<F>(reinterpret_cast<intptr_t>(addr));
+}
+
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName)      \
+  TypeName(const TypeName&);                    \
+  void operator=(const TypeName&)
+
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+
+// Support for tracking C++ memory allocation.  Insert TRACK_MEMORY("Fisk")
+// inside a C++ class and new and delete will be overloaded so logging is
+// performed.
+// This file (globals.h) is included before log.h, so we use direct calls to
+// the Logger rather than the LOG macro.
+#ifdef DEBUG
+#define TRACK_MEMORY(name) \
+  void* operator new(size_t size) { \
+    void* result = ::operator new(size); \
+    Logger::NewEvent(name, result, size); \
+    return result; \
+  } \
+  void operator delete(void* object) { \
+    Logger::DeleteEvent(name, object); \
+    ::operator delete(object); \
+  }
+#else
+#define TRACK_MEMORY(name)
+#endif
+
+// define used for helping GCC to make better inlining.
+#ifdef __GNUC__
+#if (__GNUC__ >= 4)
+#define INLINE(header) inline header  __attribute__((always_inline))
+#else
+#define INLINE(header) inline __attribute__((always_inline)) header
+#endif
+#else
+#define INLINE(header) inline header
+#endif
+
+// The type-based aliasing rule allows the compiler to assume that pointers of
+// different types (for some definition of different) never alias each other.
+// Thus the following code does not work:
+//
+// float f = foo();
+// int fbits = *(int*)(&f);
+//
+// The compiler 'knows' that the int pointer can't refer to f since the types
+// don't match, so the compiler may cache f in a register, leaving random data
+// in fbits.  Using C++ style casts makes no difference, however a pointer to
+// char data is assumed to alias any other pointer.  This is the 'memcpy
+// exception'.
+//
+// Bit_cast uses the memcpy exception to move the bits from a variable of one
+// type o a variable of another type.  Of course the end result is likely to
+// be implementation dependent.  Most compilers (gcc-4.2 and MSVC 2005)
+// will completely optimize bit_cast away.
+//
+// There is an additional use for bit_cast.
+// Recent gccs will warn when they see casts that may result in breakage due to
+// the type-based aliasing rule.  If you have checked that there is no breakage
+// you can use bit_cast to cast one pointer type to another.  This confuses gcc
+// enough that it can no longer see that you have cast one pointer type to
+// another thus avoiding the warning.
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+  // Compile time assertion: sizeof(Dest) == sizeof(Source)
+  // A compile error here means your Dest and Source have different sizes.
+  typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_GLOBALS_H_
diff --git a/regexp2000/src/handles-inl.h b/regexp2000/src/handles-inl.h
new file mode 100644 (file)
index 0000000..502aeab
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef V8_HANDLES_INL_H_
+#define V8_HANDLES_INL_H_
+
+#include "handles.h"
+#include "api.h"
+
+namespace v8 { namespace internal {
+
+template<class T>
+Handle<T>::Handle(T* obj) {
+  location_ = reinterpret_cast<T**>(HandleScope::CreateHandle(obj));
+}
+
+
+template <class T>
+inline T* Handle<T>::operator*() const {
+  ASSERT(location_ != NULL);
+  ASSERT(reinterpret_cast<Address>(*location_) != kHandleZapValue);
+  return *location_;
+}
+
+
+#ifdef DEBUG
+inline NoHandleAllocation::NoHandleAllocation() {
+  ImplementationUtilities::HandleScopeData* current =
+      ImplementationUtilities::CurrentHandleScope();
+  extensions_ = current->extensions;
+  // Shrink the current handle scope to make it impossible to do
+  // handle allocations without an explicit handle scope.
+  current->limit = current->next;
+  current->extensions = -1;
+}
+
+
+inline NoHandleAllocation::~NoHandleAllocation() {
+  // Restore state in current handle scope to re-enable handle
+  // allocations.
+  ImplementationUtilities::CurrentHandleScope()->extensions = extensions_;
+}
+#endif
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_HANDLES_INL_H_
diff --git a/regexp2000/src/handles.cc b/regexp2000/src/handles.cc
new file mode 100644 (file)
index 0000000..1a600db
--- /dev/null
@@ -0,0 +1,549 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "accessors.h"
+#include "api.h"
+#include "bootstrapper.h"
+#include "compiler.h"
+#include "debug.h"
+#include "execution.h"
+#include "global-handles.h"
+#include "natives.h"
+#include "runtime.h"
+
+namespace v8 { namespace internal {
+
+#define CALL_GC(RESULT)                                             \
+  {                                                                 \
+    Failure* __failure__ = Failure::cast(RESULT);                   \
+    if (!Heap::CollectGarbage(__failure__->requested(),             \
+                              __failure__->allocation_space())) {   \
+       /* TODO(1181417): Fix this. */                               \
+       V8::FatalProcessOutOfMemory("Handles");                      \
+    }                                                               \
+  }
+
+
+Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
+                                      Handle<JSArray> array) {
+  CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray);
+}
+
+
+Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
+                               Handle<FixedArray> second) {
+  CALL_HEAP_FUNCTION(first->UnionOfKeys(*second), FixedArray);
+}
+
+
+Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
+    Handle<JSFunction> constructor,
+    Handle<JSGlobalProxy> global) {
+  CALL_HEAP_FUNCTION(Heap::ReinitializeJSGlobalProxy(*constructor, *global),
+                     JSGlobalProxy);
+}
+
+
+void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
+  func->shared()->set_expected_nof_properties(nof);
+  if (func->has_initial_map()) {
+    Handle<Map> new_initial_map =
+        Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map()));
+    new_initial_map->set_unused_property_fields(nof);
+    func->set_initial_map(*new_initial_map);
+  }
+}
+
+
+void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) {
+  CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value));
+}
+
+
+static int ExpectedNofPropertiesFromEstimate(int estimate) {
+  // TODO(1231235): We need dynamic feedback to estimate the number
+  // of expected properties in an object. The static hack below
+  // is barely a solution.
+  if (estimate == 0) return 4;
+  return estimate + 2;
+}
+
+
+void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
+                                          int estimate) {
+  shared->set_expected_nof_properties(
+      ExpectedNofPropertiesFromEstimate(estimate));
+}
+
+
+void SetExpectedNofPropertiesFromEstimate(Handle<JSFunction> func,
+                                          int estimate) {
+  SetExpectedNofProperties(
+      func, ExpectedNofPropertiesFromEstimate(estimate));
+}
+
+
+void NormalizeProperties(Handle<JSObject> object) {
+  CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties());
+}
+
+
+void NormalizeElements(Handle<JSObject> object) {
+  CALL_HEAP_FUNCTION_VOID(object->NormalizeElements());
+}
+
+
+void TransformToFastProperties(Handle<JSObject> object,
+                               int unused_property_fields) {
+  CALL_HEAP_FUNCTION_VOID(
+      object->TransformToFastProperties(unused_property_fields));
+}
+
+
+void FlattenString(Handle<String> string) {
+  if (string->IsFlat()) return;
+  CALL_HEAP_FUNCTION_VOID(string->Flatten());
+  ASSERT(string->IsFlat());
+}
+
+
+Handle<Object> SetPrototype(Handle<JSFunction> function,
+                            Handle<Object> prototype) {
+  CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function,
+                                                     *prototype,
+                                                     NULL),
+                     Object);
+}
+
+
+Handle<Object> SetProperty(Handle<JSObject> object,
+                           Handle<String> key,
+                           Handle<Object> value,
+                           PropertyAttributes attributes) {
+  CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object);
+}
+
+
+Handle<Object> SetProperty(Handle<Object> object,
+                           Handle<Object> key,
+                           Handle<Object> value,
+                           PropertyAttributes attributes) {
+  CALL_HEAP_FUNCTION(
+      Runtime::SetObjectProperty(object, key, value, attributes), Object);
+}
+
+
+Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
+                           Handle<String> key,
+                           Handle<Object> value,
+                           PropertyAttributes attributes) {
+  CALL_HEAP_FUNCTION(object->
+      IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object);
+}
+
+Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
+                                          Handle<String> key,
+                                          Handle<Object> value,
+                                          PropertyAttributes attributes) {
+  CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key,
+                                                        *value,
+                                                        attributes),
+                     Object);
+}
+
+
+Handle<Object> GetProperty(Handle<JSObject> obj,
+                           const char* name) {
+  Handle<String> str = Factory::LookupAsciiSymbol(name);
+  CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object);
+}
+
+
+Handle<Object> GetProperty(Handle<Object> obj,
+                           Handle<Object> key) {
+  CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object);
+}
+
+
+Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
+                                          Handle<JSObject> holder,
+                                          Handle<String> name,
+                                          PropertyAttributes* attributes) {
+  CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver,
+                                                        *name,
+                                                        attributes),
+                     Object);
+}
+
+
+Handle<Object> GetPrototype(Handle<Object> obj) {
+  Handle<Object> result(obj->GetPrototype());
+  return result;
+}
+
+
+Handle<Object> DeleteElement(Handle<JSObject> obj,
+                             uint32_t index) {
+  CALL_HEAP_FUNCTION(obj->DeleteElement(index), Object);
+}
+
+
+Handle<Object> DeleteProperty(Handle<JSObject> obj,
+                              Handle<String> prop) {
+  CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop), Object);
+}
+
+
+Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
+  CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object);
+}
+
+
+Handle<String> SubString(Handle<String> str, int start, int end) {
+  CALL_HEAP_FUNCTION(str->Slice(start, end), String);
+}
+
+
+Handle<Object> SetElement(Handle<JSObject> object,
+                          uint32_t index,
+                          Handle<Object> value) {
+  CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object);
+}
+
+
+Handle<JSObject> Copy(Handle<JSObject> obj) {
+  CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject);
+}
+
+
+// Wrappers for scripts are kept alive and cached in weak global
+// handles referred from proxy objects held by the scripts as long as
+// they are used. When they are not used anymore, the garbage
+// collector will call the weak callback on the global handle
+// associated with the wrapper and get rid of both the wrapper and the
+// handle.
+static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
+  Handle<Object> cache = Utils::OpenHandle(*handle);
+  JSValue* wrapper = JSValue::cast(*cache);
+  Proxy* proxy = Script::cast(wrapper->value())->wrapper();
+  ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
+  proxy->set_proxy(0);
+  GlobalHandles::Destroy(cache.location());
+  Counters::script_wrappers.Decrement();
+}
+
+
+Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
+  Handle<Object> cache(reinterpret_cast<Object**>(script->wrapper()->proxy()));
+  if (!cache.is_null()) {
+    // Return the script wrapper directly from the cache.
+    return Handle<JSValue>(JSValue::cast(*cache));
+  }
+
+  // Construct a new script wrapper.
+  Counters::script_wrappers.Increment();
+  Handle<JSFunction> constructor = Top::script_function();
+  Handle<JSValue> result =
+      Handle<JSValue>::cast(Factory::NewJSObject(constructor));
+  result->set_value(*script);
+
+  // Create a new weak global handle and use it to cache the wrapper
+  // for future use. The cache will automatically be cleared by the
+  // garbage collector when it is not used anymore.
+  Handle<Object> handle = GlobalHandles::Create(*result);
+  GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache);
+  script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
+  return result;
+}
+
+
+#undef CALL_HEAP_FUNCTION
+#undef CALL_GC
+
+
+// Compute the property keys from the interceptor.
+v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
+                                                 Handle<JSObject> object) {
+  Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
+  Handle<Object> data(interceptor->data());
+  v8::AccessorInfo info(
+    v8::Utils::ToLocal(receiver),
+    v8::Utils::ToLocal(data),
+    v8::Utils::ToLocal(object));
+  v8::Handle<v8::Array> result;
+  if (!interceptor->enumerator()->IsUndefined()) {
+    v8::NamedPropertyEnumerator enum_fun =
+        v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
+    LOG(ApiObjectAccess("interceptor-named-enum", *object));
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = enum_fun(info);
+    }
+  }
+  return result;
+}
+
+
+// Compute the element keys from the interceptor.
+v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
+                                                   Handle<JSObject> object) {
+  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
+  Handle<Object> data(interceptor->data());
+  v8::AccessorInfo info(
+    v8::Utils::ToLocal(receiver),
+    v8::Utils::ToLocal(data),
+    v8::Utils::ToLocal(object));
+  v8::Handle<v8::Array> result;
+  if (!interceptor->enumerator()->IsUndefined()) {
+    v8::IndexedPropertyEnumerator enum_fun =
+        v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
+    LOG(ApiObjectAccess("interceptor-indexed-enum", *object));
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = enum_fun(info);
+    }
+  }
+  return result;
+}
+
+
+Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object) {
+  Handle<FixedArray> content = Factory::empty_fixed_array();
+
+  JSObject* arguments_boilerplate =
+      Top::context()->global_context()->arguments_boilerplate();
+  JSFunction* arguments_function =
+      JSFunction::cast(arguments_boilerplate->map()->constructor());
+  bool allow_enumeration = (object->map()->constructor() != arguments_function);
+
+  // Only collect keys if access is permitted.
+  if (allow_enumeration) {
+    for (Handle<Object> p = object;
+         *p != Heap::null_value();
+         p = Handle<Object>(p->GetPrototype())) {
+      Handle<JSObject> current(JSObject::cast(*p));
+
+      // Check access rights if required.
+      if (current->IsAccessCheckNeeded() &&
+        !Top::MayNamedAccess(*current, Heap::undefined_value(),
+                             v8::ACCESS_KEYS)) {
+        Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
+        break;
+      }
+
+      // Compute the property keys.
+      content = UnionOfKeys(content, GetEnumPropertyKeys(current));
+
+      // Add the property keys from the interceptor.
+      if (current->HasNamedInterceptor()) {
+        v8::Handle<v8::Array> result =
+            GetKeysForNamedInterceptor(object, current);
+        if (!result.IsEmpty())
+          content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
+      }
+
+      // Compute the element keys.
+      Handle<FixedArray> element_keys =
+          Factory::NewFixedArray(current->NumberOfEnumElements());
+      current->GetEnumElementKeys(*element_keys);
+      content = UnionOfKeys(content, element_keys);
+
+      // Add the element keys from the interceptor.
+      if (current->HasIndexedInterceptor()) {
+        v8::Handle<v8::Array> result =
+            GetKeysForIndexedInterceptor(object, current);
+        if (!result.IsEmpty())
+          content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
+      }
+    }
+  }
+  return content;
+}
+
+
+Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
+  Counters::for_in.Increment();
+  Handle<FixedArray> elements = GetKeysInFixedArrayFor(object);
+  return Factory::NewJSArrayWithElements(elements);
+}
+
+
+Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) {
+  int index = 0;
+  if (object->HasFastProperties()) {
+    if (object->map()->instance_descriptors()->HasEnumCache()) {
+      Counters::enum_cache_hits.Increment();
+      DescriptorArray* desc = object->map()->instance_descriptors();
+      return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()));
+    }
+    Counters::enum_cache_misses.Increment();
+    int num_enum = object->NumberOfEnumProperties();
+    Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
+    Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
+    for (DescriptorReader r(object->map()->instance_descriptors());
+         !r.eos();
+         r.advance()) {
+      if (!r.IsTransition() && !r.IsDontEnum()) {
+        (*storage)->set(index, r.GetKey());
+        (*sort_array)->set(index, Smi::FromInt(r.GetDetails().index()));
+        index++;
+      }
+    }
+    (*storage)->SortPairs(*sort_array);
+    Handle<FixedArray> bridge_storage =
+        Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
+    DescriptorArray* desc = object->map()->instance_descriptors();
+    desc->SetEnumCache(*bridge_storage, *storage);
+    ASSERT(storage->length() == index);
+    return storage;
+  } else {
+    int num_enum = object->NumberOfEnumProperties();
+    Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
+    Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
+    object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
+    return storage;
+  }
+}
+
+
+bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
+                       ClearExceptionFlag flag) {
+  // Compile the source information to a code object.
+  ASSERT(!shared->is_compiled());
+  bool result = Compiler::CompileLazy(shared);
+  ASSERT(result != Top::has_pending_exception());
+  if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception();
+  return result;
+}
+
+
+bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
+  // Compile the source information to a code object.
+  Handle<SharedFunctionInfo> shared(function->shared());
+  return CompileLazyShared(shared, flag);
+}
+
+
+OptimizedObjectForAddingMultipleProperties::
+OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
+                                           bool condition) {
+  object_ = object;
+  if (condition && object_->HasFastProperties()) {
+    // Normalize the properties of object to avoid n^2 behavior
+    // when extending the object multiple properties.
+    unused_property_fields_ = object->map()->unused_property_fields();
+    NormalizeProperties(object_);
+    has_been_transformed_ = true;
+
+  } else {
+    has_been_transformed_ = false;
+  }
+}
+
+
+OptimizedObjectForAddingMultipleProperties::
+~OptimizedObjectForAddingMultipleProperties() {
+  // Reoptimize the object to allow fast property access.
+  if (has_been_transformed_) {
+    TransformToFastProperties(object_, unused_property_fields_);
+  }
+}
+
+
+void LoadLazy(Handle<JSFunction> fun, bool* pending_exception) {
+  HandleScope scope;
+  Handle<FixedArray> info(FixedArray::cast(fun->shared()->lazy_load_data()));
+  int index = Smi::cast(info->get(0))->value();
+  ASSERT(index >= 0);
+  Handle<Context> compile_context(Context::cast(info->get(1)));
+  Handle<Context> function_context(Context::cast(info->get(2)));
+  Handle<Object> receiver(compile_context->global()->builtins());
+
+  Vector<const char> name = Natives::GetScriptName(index);
+
+  Handle<JSFunction> boilerplate;
+
+  if (!Bootstrapper::NativesCacheLookup(name, &boilerplate)) {
+    Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
+    Handle<String> script_name = Factory::NewStringFromAscii(name);
+    bool allow_natives_syntax = FLAG_allow_natives_syntax;
+    FLAG_allow_natives_syntax = true;
+    boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL);
+    FLAG_allow_natives_syntax = allow_natives_syntax;
+    // If the compilation failed (possibly due to stack overflows), we
+    // should never enter the result in the natives cache. Instead we
+    // return from the function without marking the function as having
+    // been lazily loaded.
+    if (boilerplate.is_null()) {
+      *pending_exception = true;
+      return;
+    }
+    Bootstrapper::NativesCacheAdd(name, boilerplate);
+  }
+
+  // We shouldn't get here if compiling the script failed.
+  ASSERT(!boilerplate.is_null());
+
+  // When the debugger running in its own context touches lazy loaded
+  // functions loading can be triggered. In that case ensure that the
+  // execution of the boilerplate is in the correct context.
+  SaveContext save;
+  if (!Debug::debug_context().is_null() &&
+      Top::context() == *Debug::debug_context()) {
+    Top::set_context(*compile_context);
+  }
+
+  // Reset the lazy load data before running the script to make sure
+  // not to get recursive lazy loading.
+  fun->shared()->set_lazy_load_data(Heap::undefined_value());
+
+  // Run the script.
+  Handle<JSFunction> script_fun(
+      Factory::NewFunctionFromBoilerplate(boilerplate, function_context));
+  Execution::Call(script_fun, receiver, 0, NULL, pending_exception);
+
+  // If lazy loading failed, restore the unloaded state of fun.
+  if (*pending_exception) fun->shared()->set_lazy_load_data(*info);
+}
+
+
+void SetupLazy(Handle<JSFunction> fun,
+               int index,
+               Handle<Context> compile_context,
+               Handle<Context> function_context) {
+  Handle<FixedArray> arr = Factory::NewFixedArray(3);
+  arr->set(0, Smi::FromInt(index));
+  arr->set(1, *compile_context);  // Compile in this context
+  arr->set(2, *function_context);  // Set function context to this
+  fun->shared()->set_lazy_load_data(*arr);
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/handles.h b/regexp2000/src/handles.h
new file mode 100644 (file)
index 0000000..a9adf3d
--- /dev/null
@@ -0,0 +1,241 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HANDLES_H_
+#define V8_HANDLES_H_
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// A Handle provides a reference to an object that survives relocation by
+// the garbage collector.
+// Handles are only valid withing a HandleScope.
+// When a handle is created for an object a cell is allocated in the heap.
+
+template<class T>
+class Handle {
+ public:
+  INLINE(Handle(T** location))  { location_ = location; }
+  INLINE(explicit Handle(T* obj));
+
+  INLINE(Handle()) : location_(NULL) {}
+
+  // Constructor for handling automatic up casting.
+  // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
+  template <class S> Handle(Handle<S> handle) {
+#ifdef DEBUG
+    T* a = NULL;
+    S* b = NULL;
+    a = b;  // Fake assignment to enforce type checks.
+    USE(a);
+#endif
+    location_ = reinterpret_cast<T**>(handle.location());
+  }
+
+  INLINE(T* operator ->() const)  { return operator*(); }
+
+  // Check if this handle refers to the exact same object as the other handle.
+  bool is_identical_to(const Handle<T> other) const {
+    return operator*() == *other;
+  }
+
+  // Provides the C++ dereference operator.
+  INLINE(T* operator*() const);
+
+  // Returns the address to where the raw pointer is stored.
+  T** location() const {
+    ASSERT(location_ == NULL ||
+           reinterpret_cast<Address>(*location_) != kZapValue);
+    return location_;
+  }
+
+  template <class S> static Handle<T> cast(Handle<S> that) {
+    T::cast(*that);
+    return Handle<T>(reinterpret_cast<T**>(that.location()));
+  }
+
+  static Handle<T> null() { return Handle<T>(); }
+  bool is_null() {return location_ == NULL; }
+
+  // Closes the given scope, but lets this handle escape. See
+  // implementation in api.h.
+  inline Handle<T> EscapeFrom(HandleScope* scope);
+
+ private:
+  T** location_;
+};
+
+
+// ----------------------------------------------------------------------------
+// Handle operations.
+// They might invoke garbage collection. The result is an handle to
+// an object of expected type, or the handle is an error if running out
+// of space or encounting an internal error.
+
+void NormalizeProperties(Handle<JSObject> object);
+void NormalizeElements(Handle<JSObject> object);
+void TransformToFastProperties(Handle<JSObject> object,
+                               int unused_property_fields);
+void FlattenString(Handle<String> str);
+
+Handle<Object> SetProperty(Handle<JSObject> object,
+                           Handle<String> key,
+                           Handle<Object> value,
+                           PropertyAttributes attributes);
+
+Handle<Object> SetProperty(Handle<Object> object,
+                           Handle<Object> key,
+                           Handle<Object> value,
+                           PropertyAttributes attributes);
+
+Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
+                                                   Handle<String> key,
+                                                   Handle<Object> value,
+    PropertyAttributes attributes);
+
+Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
+                                          Handle<String> key,
+                                          Handle<Object> value,
+                                          PropertyAttributes attributes);
+
+Handle<Object> SetElement(Handle<JSObject> object,
+                          uint32_t index,
+                          Handle<Object> value);
+
+Handle<Object> GetProperty(Handle<JSObject> obj,
+                           const char* name);
+
+Handle<Object> GetProperty(Handle<Object> obj,
+                           Handle<Object> key);
+
+Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
+                                          Handle<JSObject> holder,
+                                          Handle<String> name,
+                                          PropertyAttributes* attributes);
+
+Handle<Object> GetPrototype(Handle<Object> obj);
+
+Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
+Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<String> prop);
+
+Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index);
+
+Handle<JSObject> Copy(Handle<JSObject> obj);
+
+// Get the JS object corresponding to the given script; create it
+// if none exists.
+Handle<JSValue> GetScriptWrapper(Handle<Script> script);
+
+// Computes the enumerable keys from interceptors. Used for debug mirrors and
+// by GetKeysInFixedArrayFor below.
+v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
+                                                 Handle<JSObject> object);
+v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
+                                                   Handle<JSObject> object);
+// Computes the enumerable keys for a JSObject. Used for implementing
+// "for (n in object) { }".
+Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object);
+Handle<JSArray> GetKeysFor(Handle<JSObject> object);
+Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object);
+
+// Computes the union of keys and return the result.
+// Used for implementing "for (n in object) { }"
+Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
+                               Handle<FixedArray> second);
+
+Handle<String> SubString(Handle<String> str, int start, int end);
+
+
+// Sets the expected number of properties for the function's instances.
+void SetExpectedNofProperties(Handle<JSFunction> func, int nof);
+
+// Sets the prototype property for a function instance.
+void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value);
+
+// Sets the expected number of properties based on estimate from compiler.
+void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
+                                          int estimate);
+void SetExpectedNofPropertiesFromEstimate(Handle<JSFunction> func,
+                                          int estimate);
+
+
+Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
+    Handle<JSFunction> constructor,
+    Handle<JSGlobalProxy> global);
+
+Handle<Object> SetPrototype(Handle<JSFunction> function,
+                            Handle<Object> prototype);
+
+
+// Do lazy compilation of the given function. Returns true on success
+// and false if the compilation resulted in a stack overflow.
+enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
+bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
+                       ClearExceptionFlag flag);
+bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
+
+// These deal with lazily loaded properties.
+void SetupLazy(Handle<JSFunction> fun,
+               int index,
+               Handle<Context> compile_context,
+               Handle<Context> function_context);
+void LoadLazy(Handle<JSFunction> fun, bool* pending_exception);
+
+class NoHandleAllocation BASE_EMBEDDED {
+ public:
+#ifndef DEBUG
+  NoHandleAllocation() {}
+  ~NoHandleAllocation() {}
+#else
+  inline NoHandleAllocation();
+  inline ~NoHandleAllocation();
+ private:
+  int extensions_;
+#endif
+};
+
+
+// ----------------------------------------------------------------------------
+
+
+// Stack allocated wrapper call for optimizing adding multiple
+// properties to an object.
+class OptimizedObjectForAddingMultipleProperties BASE_EMBEDDED {
+ public:
+  OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
+                                             bool condition = true);
+  ~OptimizedObjectForAddingMultipleProperties();
+ private:
+  bool has_been_transformed_;  // Tells whether the object has been transformed.
+  int unused_property_fields_;  // Captures the unused number of field.
+  Handle<JSObject> object_;    // The object being optimized.
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_HANDLES_H_
diff --git a/regexp2000/src/hashmap.cc b/regexp2000/src/hashmap.cc
new file mode 100644 (file)
index 0000000..126f739
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "hashmap.h"
+
+namespace v8 { namespace internal {
+
+
+static inline bool IsPowerOf2(uint32_t x) {
+  ASSERT(x != 0);
+  return (x & (x - 1)) == 0;
+}
+
+
+Allocator HashMap::DefaultAllocator;
+
+
+HashMap::HashMap() {
+  allocator_ = NULL;
+  match_ = NULL;
+}
+
+
+HashMap::HashMap(MatchFun match,
+                 Allocator* allocator,
+                 uint32_t initial_capacity) {
+  allocator_ = allocator;
+  match_ = match;
+  Initialize(initial_capacity);
+}
+
+
+HashMap::~HashMap() {
+  if (allocator_) {
+    allocator_->Delete(map_);
+  }
+}
+
+
+HashMap::Entry* HashMap::Lookup(void* key, uint32_t hash, bool insert) {
+  // Find a matching entry.
+  Entry* p = Probe(key, hash);
+    if (p->key != NULL) {
+    return p;
+  }
+
+  // No entry found; insert one if necessary.
+  if (insert) {
+    p->key = key;
+    p->value = NULL;
+    p->hash = hash;
+    occupancy_++;
+
+    // Grow the map if we reached >= 80% occupancy.
+    if (occupancy_ + occupancy_/4 >= capacity_) {
+      Resize();
+      p = Probe(key, hash);
+    }
+
+    return p;
+  }
+
+  // No entry found and none inserted.
+  return NULL;
+}
+
+
+void HashMap::Clear() {
+  // Mark all entries as empty.
+  const Entry* end = map_end();
+  for (Entry* p = map_; p < end; p++) {
+    p->key = NULL;
+  }
+  occupancy_ = 0;
+}
+
+
+HashMap::Entry* HashMap::Start() const {
+  return Next(map_ - 1);
+}
+
+
+HashMap::Entry* HashMap::Next(Entry* p) const {
+  const Entry* end = map_end();
+  ASSERT(map_ - 1 <= p && p < end);
+  for (p++; p < end; p++) {
+    if (p->key != NULL) {
+      return p;
+    }
+  }
+  return NULL;
+}
+
+
+HashMap::Entry* HashMap::Probe(void* key, uint32_t hash) {
+  ASSERT(key != NULL);
+
+  ASSERT(IsPowerOf2(capacity_));
+  Entry* p = map_ + (hash & (capacity_ - 1));
+  const Entry* end = map_end();
+  ASSERT(map_ <= p && p < end);
+
+  ASSERT(occupancy_ < capacity_);  // guarantees loop termination
+  while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) {
+    p++;
+    if (p >= end) {
+      p = map_;
+    }
+  }
+
+  return p;
+}
+
+
+void HashMap::Initialize(uint32_t capacity) {
+  ASSERT(IsPowerOf2(capacity));
+  map_ = reinterpret_cast<Entry*>(allocator_->New(capacity * sizeof(Entry)));
+  if (map_ == NULL) V8::FatalProcessOutOfMemory("HashMap::Initialize");
+  capacity_ = capacity;
+  Clear();
+}
+
+
+void HashMap::Resize() {
+  Entry* map = map_;
+  uint32_t n = occupancy_;
+
+  // Allocate larger map.
+  Initialize(capacity_ * 2);
+
+  // Rehash all current entries.
+  for (Entry* p = map; n > 0; p++) {
+    if (p->key != NULL) {
+      Lookup(p->key, p->hash, true)->value = p->value;
+      n--;
+    }
+  }
+
+  // Delete old map.
+  allocator_->Delete(map);
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/hashmap.h b/regexp2000/src/hashmap.h
new file mode 100644 (file)
index 0000000..7826311
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HASHMAP_H_
+#define V8_HASHMAP_H_
+
+namespace v8 { namespace internal {
+
+
+// Allocator defines the memory allocator interface
+// used by HashMap and implements a default allocator.
+class Allocator BASE_EMBEDDED {
+ public:
+  virtual ~Allocator()  {}
+  virtual void* New(size_t size)  { return Malloced::New(size); }
+  virtual void Delete(void* p)  { Malloced::Delete(p); }
+};
+
+
+class HashMap {
+ public:
+  static Allocator DefaultAllocator;
+
+  typedef bool (*MatchFun) (void* key1, void* key2);
+
+  // Dummy constructor.  This constructor doesn't set up the hash
+  // map properly so don't use it unless you have good reason.
+  HashMap();
+
+  // initial_capacity is the size of the initial hash map;
+  // it must be a power of 2 (and thus must not be 0).
+  HashMap(MatchFun match,
+          Allocator* allocator = &DefaultAllocator,
+          uint32_t initial_capacity = 8);
+
+  ~HashMap();
+
+  // HashMap entries are (key, value, hash) tripplets.
+  // Some clients may not need to use the value slot
+  // (e.g. implementers of sets, where the key is the value).
+  struct Entry {
+    void* key;
+    void* value;
+    uint32_t hash;  // the full hash value for key
+  };
+
+  // If an entry with matching key is found, Lookup()
+  // returns that entry. If no matching entry is found,
+  // but insert is set, a new entry is inserted with
+  // corresponding key, key hash, and NULL value.
+  // Otherwise, NULL is returned.
+  Entry* Lookup(void* key, uint32_t hash, bool insert);
+
+  // Empties the hash map (occupancy() == 0).
+  void Clear();
+
+  // The number of (non-empty) entries in the table.
+  uint32_t occupancy() const  { return occupancy_; }
+
+  // The capacity of the table. The implementation
+  // makes sure that occupancy is at most 80% of
+  // the table capacity.
+  uint32_t capacity() const  { return capacity_; }
+
+  // Iteration
+  //
+  // for (Entry* p = map.Start(); p != NULL; p = map.Next(p)) {
+  //   ...
+  // }
+  //
+  // If entries are inserted during iteration, the effect of
+  // calling Next() is undefined.
+  Entry* Start() const;
+  Entry* Next(Entry* p) const;
+
+ private:
+  Allocator* allocator_;
+  MatchFun match_;
+  Entry* map_;
+  uint32_t capacity_;
+  uint32_t occupancy_;
+
+  Entry* map_end() const  { return map_ + capacity_; }
+  Entry* Probe(void* key, uint32_t hash);
+  void Initialize(uint32_t capacity);
+  void Resize();
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_HASHMAP_H_
diff --git a/regexp2000/src/heap-inl.h b/regexp2000/src/heap-inl.h
new file mode 100644 (file)
index 0000000..bfa2b65
--- /dev/null
@@ -0,0 +1,274 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HEAP_INL_H_
+#define V8_HEAP_INL_H_
+
+#include "log.h"
+#include "v8-counters.h"
+
+namespace v8 { namespace internal {
+
+int Heap::MaxHeapObjectSize() {
+  return Page::kMaxHeapObjectSize;
+}
+
+
+Object* Heap::AllocateRaw(int size_in_bytes,
+                          AllocationSpace space) {
+  ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
+#ifdef DEBUG
+  if (FLAG_gc_interval >= 0 &&
+      !disallow_allocation_failure_ &&
+      Heap::allocation_timeout_-- <= 0) {
+    return Failure::RetryAfterGC(size_in_bytes, space);
+  }
+  Counters::objs_since_last_full.Increment();
+  Counters::objs_since_last_young.Increment();
+#endif
+  if (NEW_SPACE == space) {
+    return new_space_.AllocateRaw(size_in_bytes);
+  }
+
+  Object* result;
+  if (OLD_POINTER_SPACE == space) {
+    result = old_pointer_space_->AllocateRaw(size_in_bytes);
+  } else if (OLD_DATA_SPACE == space) {
+    result = old_data_space_->AllocateRaw(size_in_bytes);
+  } else if (CODE_SPACE == space) {
+    result = code_space_->AllocateRaw(size_in_bytes);
+  } else if (LO_SPACE == space) {
+    result = lo_space_->AllocateRaw(size_in_bytes);
+  } else {
+    ASSERT(MAP_SPACE == space);
+    result = map_space_->AllocateRaw(size_in_bytes);
+  }
+  if (result->IsFailure()) old_gen_exhausted_ = true;
+  return result;
+}
+
+
+Object* Heap::NumberFromInt32(int32_t value) {
+  if (Smi::IsValid(value)) return Smi::FromInt(value);
+  // Bypass NumberFromDouble to avoid various redundant checks.
+  return AllocateHeapNumber(FastI2D(value));
+}
+
+
+Object* Heap::NumberFromUint32(uint32_t value) {
+  if ((int32_t)value >= 0 && Smi::IsValid((int32_t)value)) {
+    return Smi::FromInt((int32_t)value);
+  }
+  // Bypass NumberFromDouble to avoid various redundant checks.
+  return AllocateHeapNumber(FastUI2D(value));
+}
+
+
+Object* Heap::AllocateRawMap(int size_in_bytes) {
+#ifdef DEBUG
+  Counters::objs_since_last_full.Increment();
+  Counters::objs_since_last_young.Increment();
+#endif
+  Object* result = map_space_->AllocateRaw(size_in_bytes);
+  if (result->IsFailure()) old_gen_exhausted_ = true;
+  return result;
+}
+
+
+bool Heap::InNewSpace(Object* object) {
+  return new_space_.Contains(object);
+}
+
+
+bool Heap::InFromSpace(Object* object) {
+  return new_space_.FromSpaceContains(object);
+}
+
+
+bool Heap::InToSpace(Object* object) {
+  return new_space_.ToSpaceContains(object);
+}
+
+
+bool Heap::ShouldBePromoted(Address old_address, int object_size) {
+  // An object should be promoted if:
+  // - the object has survived a scavenge operation or
+  // - to space is already 25% full.
+  return old_address < new_space_.age_mark()
+      || (new_space_.Size() + object_size) >= (new_space_.Capacity() >> 2);
+}
+
+
+void Heap::RecordWrite(Address address, int offset) {
+  if (new_space_.Contains(address)) return;
+  ASSERT(!new_space_.FromSpaceContains(address));
+  SLOW_ASSERT(Contains(address + offset));
+  Page::SetRSet(address, offset);
+}
+
+
+OldSpace* Heap::TargetSpace(HeapObject* object) {
+  // Heap numbers and sequential strings are promoted to old data space, all
+  // other object types are promoted to old pointer space.  We do not use
+  // object->IsHeapNumber() and object->IsSeqString() because we already
+  // know that object has the heap object tag.
+  InstanceType type = object->map()->instance_type();
+  ASSERT((type != CODE_TYPE) && (type != MAP_TYPE));
+  bool has_pointers =
+      type != HEAP_NUMBER_TYPE &&
+      (type >= FIRST_NONSTRING_TYPE ||
+       String::cast(object)->representation_tag() != kSeqStringTag);
+  return has_pointers ? old_pointer_space_ : old_data_space_;
+}
+
+
+void Heap::CopyBlock(Object** dst, Object** src, int byte_size) {
+  ASSERT(IsAligned(byte_size, kPointerSize));
+
+  // Use block copying memcpy if the segment we're copying is
+  // enough to justify the extra call/setup overhead.
+  static const int kBlockCopyLimit = 16 * kPointerSize;
+
+  if (byte_size >= kBlockCopyLimit) {
+    memcpy(dst, src, byte_size);
+  } else {
+    int remaining = byte_size / kPointerSize;
+    do {
+      remaining--;
+      *dst++ = *src++;
+    } while (remaining > 0);
+  }
+}
+
+
+Object* Heap::GetKeyedLookupCache() {
+  if (keyed_lookup_cache()->IsUndefined()) {
+    Object* obj = LookupCache::Allocate(4);
+    if (obj->IsFailure()) return obj;
+    keyed_lookup_cache_ = obj;
+  }
+  return keyed_lookup_cache();
+}
+
+
+void Heap::SetKeyedLookupCache(LookupCache* cache) {
+  keyed_lookup_cache_ = cache;
+}
+
+
+void Heap::ClearKeyedLookupCache() {
+  keyed_lookup_cache_ = undefined_value();
+}
+
+
+#define GC_GREEDY_CHECK() \
+  ASSERT(!FLAG_gc_greedy || v8::internal::Heap::GarbageCollectionGreedyCheck())
+
+// Do not use the identifier __object__ in a call to this macro.
+//
+// Call the function FUNCTION_CALL.  If it fails with a RetryAfterGC
+// failure, call the garbage collector and retry the function.  If the
+// garbage collector cannot reclaim the required space or the second
+// call fails with a RetryAfterGC failure, fail with out of memory.
+// If there is any other failure, return a null handle.  If either
+// call succeeds, return a handle to the functions return value.
+//
+// Note that this macro always returns or raises a fatal error.
+#define CALL_HEAP_FUNCTION(FUNCTION_CALL, TYPE)                              \
+  do {                                                                       \
+    GC_GREEDY_CHECK();                                                       \
+    Object* __object__ = FUNCTION_CALL;                                      \
+    if (__object__->IsFailure()) {                                           \
+      if (__object__->IsRetryAfterGC()) {                                    \
+        if (!Heap::CollectGarbage(                                           \
+                Failure::cast(__object__)->requested(),                      \
+                Failure::cast(__object__)->allocation_space())) {            \
+          /* TODO(1181417): Fix this. */                                     \
+          v8::internal::V8::FatalProcessOutOfMemory("CALL_HEAP_FUNCTION");   \
+        }                                                                    \
+        __object__ = FUNCTION_CALL;                                          \
+        if (__object__->IsFailure()) {                                       \
+          if (__object__->IsRetryAfterGC()) {                                \
+            /* TODO(1181417): Fix this. */                                   \
+            v8::internal::V8::FatalProcessOutOfMemory("CALL_HEAP_FUNCTION"); \
+          }                                                                  \
+          return Handle<TYPE>();                                             \
+        }                                                                    \
+      } else {                                                               \
+        if (__object__->IsOutOfMemoryFailure()) {                            \
+          v8::internal::V8::FatalProcessOutOfMemory("CALL_HEAP_FUNCTION");   \
+        }                                                                    \
+        return Handle<TYPE>();                                               \
+      }                                                                      \
+    }                                                                        \
+    return Handle<TYPE>(TYPE::cast(__object__));                             \
+  } while (false)
+
+
+// Don't use the following names: __object__, __failure__.
+#define CALL_HEAP_FUNCTION_VOID(FUNCTION_CALL)                      \
+  GC_GREEDY_CHECK();                                                \
+  Object* __object__ = FUNCTION_CALL;                               \
+  if (__object__->IsFailure()) {                                    \
+    if (__object__->IsRetryAfterGC()) {                             \
+      Failure* __failure__ = Failure::cast(__object__);             \
+      if (!Heap::CollectGarbage(__failure__->requested(),           \
+                                __failure__->allocation_space())) { \
+         /* TODO(1181417): Fix this. */                             \
+         V8::FatalProcessOutOfMemory("Handles");                    \
+      }                                                             \
+      __object__ = FUNCTION_CALL;                                   \
+      if (__object__->IsFailure()) {                                \
+        if (__object__->IsRetryAfterGC()) {                         \
+           /* TODO(1181417): Fix this. */                           \
+           V8::FatalProcessOutOfMemory("Handles");                  \
+        }                                                           \
+        return;                                                     \
+      }                                                             \
+    } else {                                                        \
+      if (__object__->IsOutOfMemoryFailure()) {                     \
+         V8::FatalProcessOutOfMemory("Handles");                    \
+      }                                                             \
+      UNREACHABLE();                                                \
+    }                                                               \
+  }
+
+
+#ifdef DEBUG
+
+inline bool Heap::allow_allocation(bool new_state) {
+  bool old = allocation_allowed_;
+  allocation_allowed_ = new_state;
+  return old;
+}
+
+#endif
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_HEAP_INL_H_
diff --git a/regexp2000/src/heap.cc b/regexp2000/src/heap.cc
new file mode 100644 (file)
index 0000000..14c1940
--- /dev/null
@@ -0,0 +1,3195 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "accessors.h"
+#include "api.h"
+#include "bootstrapper.h"
+#include "codegen-inl.h"
+#include "compilation-cache.h"
+#include "debug.h"
+#include "global-handles.h"
+#include "jsregexp.h"
+#include "mark-compact.h"
+#include "natives.h"
+#include "scanner.h"
+#include "scopeinfo.h"
+#include "v8threads.h"
+
+namespace v8 { namespace internal {
+
+#define ROOT_ALLOCATION(type, name) type* Heap::name##_;
+  ROOT_LIST(ROOT_ALLOCATION)
+#undef ROOT_ALLOCATION
+
+
+#define STRUCT_ALLOCATION(NAME, Name, name) Map* Heap::name##_map_;
+  STRUCT_LIST(STRUCT_ALLOCATION)
+#undef STRUCT_ALLOCATION
+
+
+#define SYMBOL_ALLOCATION(name, string) String* Heap::name##_;
+  SYMBOL_LIST(SYMBOL_ALLOCATION)
+#undef SYMBOL_ALLOCATION
+
+NewSpace Heap::new_space_;
+OldSpace* Heap::old_pointer_space_ = NULL;
+OldSpace* Heap::old_data_space_ = NULL;
+OldSpace* Heap::code_space_ = NULL;
+MapSpace* Heap::map_space_ = NULL;
+LargeObjectSpace* Heap::lo_space_ = NULL;
+
+int Heap::promoted_space_limit_ = 0;
+int Heap::old_gen_exhausted_ = false;
+
+int Heap::amount_of_external_allocated_memory_ = 0;
+int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
+
+// semispace_size_ should be a power of 2 and old_generation_size_ should be
+// a multiple of Page::kPageSize.
+int Heap::semispace_size_  = 2*MB;
+int Heap::old_generation_size_ = 512*MB;
+int Heap::initial_semispace_size_ = 256*KB;
+
+GCCallback Heap::global_gc_prologue_callback_ = NULL;
+GCCallback Heap::global_gc_epilogue_callback_ = NULL;
+
+// Variables set based on semispace_size_ and old_generation_size_ in
+// ConfigureHeap.
+int Heap::young_generation_size_ = 0;  // Will be 2 * semispace_size_.
+
+// Double the new space after this many scavenge collections.
+int Heap::new_space_growth_limit_ = 8;
+int Heap::scavenge_count_ = 0;
+Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
+
+int Heap::mc_count_ = 0;
+int Heap::gc_count_ = 0;
+
+#ifdef DEBUG
+bool Heap::allocation_allowed_ = true;
+
+int Heap::allocation_timeout_ = 0;
+bool Heap::disallow_allocation_failure_ = false;
+#endif  // DEBUG
+
+
+int Heap::Capacity() {
+  if (!HasBeenSetup()) return 0;
+
+  return new_space_.Capacity() +
+      old_pointer_space_->Capacity() +
+      old_data_space_->Capacity() +
+      code_space_->Capacity() +
+      map_space_->Capacity();
+}
+
+
+int Heap::Available() {
+  if (!HasBeenSetup()) return 0;
+
+  return new_space_.Available() +
+      old_pointer_space_->Available() +
+      old_data_space_->Available() +
+      code_space_->Available() +
+      map_space_->Available();
+}
+
+
+bool Heap::HasBeenSetup() {
+  return old_pointer_space_ != NULL &&
+         old_data_space_ != NULL &&
+         code_space_ != NULL &&
+         map_space_ != NULL &&
+         lo_space_ != NULL;
+}
+
+
+GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) {
+  // Is global GC requested?
+  if (space != NEW_SPACE || FLAG_gc_global) {
+    Counters::gc_compactor_caused_by_request.Increment();
+    return MARK_COMPACTOR;
+  }
+
+  // Is enough data promoted to justify a global GC?
+  if (PromotedSpaceSize() + PromotedExternalMemorySize()
+      > promoted_space_limit_) {
+    Counters::gc_compactor_caused_by_promoted_data.Increment();
+    return MARK_COMPACTOR;
+  }
+
+  // Have allocation in OLD and LO failed?
+  if (old_gen_exhausted_) {
+    Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
+    return MARK_COMPACTOR;
+  }
+
+  // Is there enough space left in OLD to guarantee that a scavenge can
+  // succeed?
+  //
+  // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
+  // for object promotion. It counts only the bytes that the memory
+  // allocator has not yet allocated from the OS and assigned to any space,
+  // and does not count available bytes already in the old space or code
+  // space.  Undercounting is safe---we may get an unrequested full GC when
+  // a scavenge would have succeeded.
+  if (MemoryAllocator::MaxAvailable() <= new_space_.Size()) {
+    Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
+    return MARK_COMPACTOR;
+  }
+
+  // Default
+  return SCAVENGER;
+}
+
+
+// TODO(1238405): Combine the infrastructure for --heap-stats and
+// --log-gc to avoid the complicated preprocessor and flag testing.
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+void Heap::ReportStatisticsBeforeGC() {
+  // Heap::ReportHeapStatistics will also log NewSpace statistics when
+  // compiled with ENABLE_LOGGING_AND_PROFILING and --log-gc is set.  The
+  // following logic is used to avoid double logging.
+#if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING)
+  if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
+  if (FLAG_heap_stats) {
+    ReportHeapStatistics("Before GC");
+  } else if (FLAG_log_gc) {
+    new_space_.ReportStatistics();
+  }
+  if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
+#elif defined(DEBUG)
+  if (FLAG_heap_stats) {
+    new_space_.CollectStatistics();
+    ReportHeapStatistics("Before GC");
+    new_space_.ClearHistograms();
+  }
+#elif defined(ENABLE_LOGGING_AND_PROFILING)
+  if (FLAG_log_gc) {
+    new_space_.CollectStatistics();
+    new_space_.ReportStatistics();
+    new_space_.ClearHistograms();
+  }
+#endif
+}
+
+
+// TODO(1238405): Combine the infrastructure for --heap-stats and
+// --log-gc to avoid the complicated preprocessor and flag testing.
+void Heap::ReportStatisticsAfterGC() {
+  // Similar to the before GC, we use some complicated logic to ensure that
+  // NewSpace statistics are logged exactly once when --log-gc is turned on.
+#if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING)
+  if (FLAG_heap_stats) {
+    ReportHeapStatistics("After GC");
+  } else if (FLAG_log_gc) {
+    new_space_.ReportStatistics();
+  }
+#elif defined(DEBUG)
+  if (FLAG_heap_stats) ReportHeapStatistics("After GC");
+#elif defined(ENABLE_LOGGING_AND_PROFILING)
+  if (FLAG_log_gc) new_space_.ReportStatistics();
+#endif
+}
+#endif  // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+
+
+void Heap::GarbageCollectionPrologue() {
+  RegExpImpl::NewSpaceCollectionPrologue();
+  gc_count_++;
+#ifdef DEBUG
+  ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
+  allow_allocation(false);
+
+  if (FLAG_verify_heap) {
+    Verify();
+  }
+
+  if (FLAG_gc_verbose) Print();
+
+  if (FLAG_print_rset) {
+    // Not all spaces have remembered set bits that we care about.
+    old_pointer_space_->PrintRSet();
+    map_space_->PrintRSet();
+    lo_space_->PrintRSet();
+  }
+#endif
+
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  ReportStatisticsBeforeGC();
+#endif
+}
+
+int Heap::SizeOfObjects() {
+  int total = 0;
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) total += space->Size();
+  return total;
+}
+
+void Heap::GarbageCollectionEpilogue() {
+#ifdef DEBUG
+  allow_allocation(true);
+  ZapFromSpace();
+
+  if (FLAG_verify_heap) {
+    Verify();
+  }
+
+  if (FLAG_print_global_handles) GlobalHandles::Print();
+  if (FLAG_print_handles) PrintHandles();
+  if (FLAG_gc_verbose) Print();
+  if (FLAG_code_stats) ReportCodeStatistics("After GC");
+#endif
+
+  Counters::alive_after_last_gc.Set(SizeOfObjects());
+
+  SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table_);
+  Counters::symbol_table_capacity.Set(symbol_table->Capacity());
+  Counters::number_of_symbols.Set(symbol_table->NumberOfElements());
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  ReportStatisticsAfterGC();
+#endif
+}
+
+
+void Heap::CollectAllGarbage() {
+  // Since we are ignoring the return value, the exact choice of space does
+  // not matter, so long as we do not specify NEW_SPACE, which would not
+  // cause a full GC.
+  CollectGarbage(0, OLD_POINTER_SPACE);
+}
+
+
+bool Heap::CollectGarbage(int requested_size, AllocationSpace space) {
+  // The VM is in the GC state until exiting this function.
+  VMState state(GC);
+
+#ifdef DEBUG
+  // Reset the allocation timeout to the GC interval, but make sure to
+  // allow at least a few allocations after a collection. The reason
+  // for this is that we have a lot of allocation sequences and we
+  // assume that a garbage collection will allow the subsequent
+  // allocation attempts to go through.
+  allocation_timeout_ = Max(6, FLAG_gc_interval);
+#endif
+
+  { GCTracer tracer;
+    GarbageCollectionPrologue();
+    // The GC count was incremented in the prologue.  Tell the tracer about
+    // it.
+    tracer.set_gc_count(gc_count_);
+
+    GarbageCollector collector = SelectGarbageCollector(space);
+    // Tell the tracer which collector we've selected.
+    tracer.set_collector(collector);
+
+    StatsRate* rate = (collector == SCAVENGER)
+        ? &Counters::gc_scavenger
+        : &Counters::gc_compactor;
+    rate->Start();
+    PerformGarbageCollection(space, collector, &tracer);
+    rate->Stop();
+
+    GarbageCollectionEpilogue();
+  }
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (FLAG_log_gc) HeapProfiler::WriteSample();
+#endif
+
+  switch (space) {
+    case NEW_SPACE:
+      return new_space_.Available() >= requested_size;
+    case OLD_POINTER_SPACE:
+      return old_pointer_space_->Available() >= requested_size;
+    case OLD_DATA_SPACE:
+      return old_data_space_->Available() >= requested_size;
+    case CODE_SPACE:
+      return code_space_->Available() >= requested_size;
+    case MAP_SPACE:
+      return map_space_->Available() >= requested_size;
+    case LO_SPACE:
+      return lo_space_->Available() >= requested_size;
+  }
+  return false;
+}
+
+
+void Heap::PerformScavenge() {
+  GCTracer tracer;
+  PerformGarbageCollection(NEW_SPACE, SCAVENGER, &tracer);
+}
+
+
+void Heap::PerformGarbageCollection(AllocationSpace space,
+                                    GarbageCollector collector,
+                                    GCTracer* tracer) {
+  if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
+    ASSERT(!allocation_allowed_);
+    global_gc_prologue_callback_();
+  }
+
+  if (collector == MARK_COMPACTOR) {
+    MarkCompact(tracer);
+
+    int promoted_space_size = PromotedSpaceSize();
+    promoted_space_limit_ =
+        promoted_space_size + Max(2 * MB, (promoted_space_size/100) * 35);
+    old_gen_exhausted_ = false;
+
+    // If we have used the mark-compact collector to collect the new
+    // space, and it has not compacted the new space, we force a
+    // separate scavenge collection.  This is a hack.  It covers the
+    // case where (1) a new space collection was requested, (2) the
+    // collector selection policy selected the mark-compact collector,
+    // and (3) the mark-compact collector policy selected not to
+    // compact the new space.  In that case, there is no more (usable)
+    // free space in the new space after the collection compared to
+    // before.
+    if (space == NEW_SPACE && !MarkCompactCollector::HasCompacted()) {
+      Scavenge();
+    }
+  } else {
+    Scavenge();
+  }
+  Counters::objs_since_last_young.Set(0);
+
+  // Process weak handles post gc.
+  GlobalHandles::PostGarbageCollectionProcessing();
+
+  if (collector == MARK_COMPACTOR) {
+    // Register the amount of external allocated memory.
+    amount_of_external_allocated_memory_at_last_global_gc_ =
+        amount_of_external_allocated_memory_;
+  }
+
+  if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
+    ASSERT(!allocation_allowed_);
+    global_gc_epilogue_callback_();
+  }
+}
+
+
+void Heap::MarkCompact(GCTracer* tracer) {
+  gc_state_ = MARK_COMPACT;
+  mc_count_++;
+  tracer->set_full_gc_count(mc_count_);
+  LOG(ResourceEvent("markcompact", "begin"));
+
+  MarkCompactPrologue();
+
+  MarkCompactCollector::CollectGarbage(tracer);
+
+  MarkCompactEpilogue();
+
+  LOG(ResourceEvent("markcompact", "end"));
+
+  gc_state_ = NOT_IN_GC;
+
+  Shrink();
+
+  Counters::objs_since_last_full.Set(0);
+}
+
+
+void Heap::MarkCompactPrologue() {
+  ClearKeyedLookupCache();
+  CompilationCache::MarkCompactPrologue();
+  RegExpImpl::OldSpaceCollectionPrologue();
+  Top::MarkCompactPrologue();
+  ThreadManager::MarkCompactPrologue();
+}
+
+
+void Heap::MarkCompactEpilogue() {
+  Top::MarkCompactEpilogue();
+  ThreadManager::MarkCompactEpilogue();
+}
+
+
+Object* Heap::FindCodeObject(Address a) {
+  Object* obj = code_space_->FindObject(a);
+  if (obj->IsFailure()) {
+    obj = lo_space_->FindObject(a);
+  }
+  ASSERT(!obj->IsFailure());
+  return obj;
+}
+
+
+// Helper class for copying HeapObjects
+class ScavengeVisitor: public ObjectVisitor {
+ public:
+
+  void VisitPointer(Object** p) { ScavengePointer(p); }
+
+  void VisitPointers(Object** start, Object** end) {
+    // Copy all HeapObject pointers in [start, end)
+    for (Object** p = start; p < end; p++) ScavengePointer(p);
+  }
+
+ private:
+  void ScavengePointer(Object** p) {
+    Object* object = *p;
+    if (!Heap::InNewSpace(object)) return;
+    Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
+                         reinterpret_cast<HeapObject*>(object));
+  }
+};
+
+
+// Shared state read by the scavenge collector and set by ScavengeObject.
+static Address promoted_top = NULL;
+
+
+#ifdef DEBUG
+// Visitor class to verify pointers in code or data space do not point into
+// new space.
+class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object**end) {
+    for (Object** current = start; current < end; current++) {
+      if ((*current)->IsHeapObject()) {
+        ASSERT(!Heap::InNewSpace(HeapObject::cast(*current)));
+      }
+    }
+  }
+};
+#endif
+
+void Heap::Scavenge() {
+#ifdef DEBUG
+  if (FLAG_enable_slow_asserts) {
+    VerifyNonPointerSpacePointersVisitor v;
+    HeapObjectIterator it(code_space_);
+    while (it.has_next()) {
+      HeapObject* object = it.next();
+      if (object->IsCode()) {
+        Code::cast(object)->ConvertICTargetsFromAddressToObject();
+      }
+      object->Iterate(&v);
+      if (object->IsCode()) {
+        Code::cast(object)->ConvertICTargetsFromObjectToAddress();
+      }
+    }
+  }
+#endif
+
+  gc_state_ = SCAVENGE;
+
+  // Implements Cheney's copying algorithm
+  LOG(ResourceEvent("scavenge", "begin"));
+
+  scavenge_count_++;
+  if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
+      scavenge_count_ > new_space_growth_limit_) {
+    // Double the size of the new space, and double the limit.  The next
+    // doubling attempt will occur after the current new_space_growth_limit_
+    // more collections.
+    // TODO(1240712): NewSpace::Double has a return value which is
+    // ignored here.
+    new_space_.Double();
+    new_space_growth_limit_ *= 2;
+  }
+
+  // Flip the semispaces.  After flipping, to space is empty, from space has
+  // live objects.
+  new_space_.Flip();
+  new_space_.ResetAllocationInfo();
+
+  // We need to sweep newly copied objects which can be in either the to space
+  // or the old space.  For to space objects, we use a mark.  Newly copied
+  // objects lie between the mark and the allocation top.  For objects
+  // promoted to old space, we write their addresses downward from the top of
+  // the new space.  Sweeping newly promoted objects requires an allocation
+  // pointer and a mark.  Note that the allocation pointer 'top' actually
+  // moves downward from the high address in the to space.
+  //
+  // There is guaranteed to be enough room at the top of the to space for the
+  // addresses of promoted objects: every object promoted frees up its size in
+  // bytes from the top of the new space, and objects are at least one pointer
+  // in size.  Using the new space to record promoted addresses makes the
+  // scavenge collector agnostic to the allocation strategy (eg, linear or
+  // free-list) used in old space.
+  Address new_mark = new_space_.ToSpaceLow();
+  Address promoted_mark = new_space_.ToSpaceHigh();
+  promoted_top = new_space_.ToSpaceHigh();
+
+  ScavengeVisitor scavenge_visitor;
+  // Copy roots.
+  IterateRoots(&scavenge_visitor);
+
+  // Copy objects reachable from the old generation.  By definition, there
+  // are no intergenerational pointers in code or data spaces.
+  IterateRSet(old_pointer_space_, &ScavengePointer);
+  IterateRSet(map_space_, &ScavengePointer);
+  lo_space_->IterateRSet(&ScavengePointer);
+
+  bool has_processed_weak_pointers = false;
+
+  while (true) {
+    ASSERT(new_mark <= new_space_.top());
+    ASSERT(promoted_mark >= promoted_top);
+
+    // Copy objects reachable from newly copied objects.
+    while (new_mark < new_space_.top() || promoted_mark > promoted_top) {
+      // Sweep newly copied objects in the to space.  The allocation pointer
+      // can change during sweeping.
+      Address previous_top = new_space_.top();
+      SemiSpaceIterator new_it(new_space(), new_mark);
+      while (new_it.has_next()) {
+        new_it.next()->Iterate(&scavenge_visitor);
+      }
+      new_mark = previous_top;
+
+      // Sweep newly copied objects in the old space.  The promotion 'top'
+      // pointer could change during sweeping.
+      previous_top = promoted_top;
+      for (Address current = promoted_mark - kPointerSize;
+           current >= previous_top;
+           current -= kPointerSize) {
+        HeapObject* object = HeapObject::cast(Memory::Object_at(current));
+        object->Iterate(&scavenge_visitor);
+        UpdateRSet(object);
+      }
+      promoted_mark = previous_top;
+    }
+
+    if (has_processed_weak_pointers) break;  // We are done.
+    // Copy objects reachable from weak pointers.
+    GlobalHandles::IterateWeakRoots(&scavenge_visitor);
+    has_processed_weak_pointers = true;
+  }
+
+  // Set age mark.
+  new_space_.set_age_mark(new_mark);
+
+  LOG(ResourceEvent("scavenge", "end"));
+
+  gc_state_ = NOT_IN_GC;
+}
+
+
+void Heap::ClearRSetRange(Address start, int size_in_bytes) {
+  uint32_t start_bit;
+  Address start_word_address =
+      Page::ComputeRSetBitPosition(start, 0, &start_bit);
+  uint32_t end_bit;
+  Address end_word_address =
+      Page::ComputeRSetBitPosition(start + size_in_bytes - kIntSize,
+                                   0,
+                                   &end_bit);
+
+  // We want to clear the bits in the starting word starting with the
+  // first bit, and in the ending word up to and including the last
+  // bit.  Build a pair of bitmasks to do that.
+  uint32_t start_bitmask = start_bit - 1;
+  uint32_t end_bitmask = ~((end_bit << 1) - 1);
+
+  // If the start address and end address are the same, we mask that
+  // word once, otherwise mask the starting and ending word
+  // separately and all the ones in between.
+  if (start_word_address == end_word_address) {
+    Memory::uint32_at(start_word_address) &= (start_bitmask | end_bitmask);
+  } else {
+    Memory::uint32_at(start_word_address) &= start_bitmask;
+    Memory::uint32_at(end_word_address) &= end_bitmask;
+    start_word_address += kIntSize;
+    memset(start_word_address, 0, end_word_address - start_word_address);
+  }
+}
+
+
+class UpdateRSetVisitor: public ObjectVisitor {
+ public:
+
+  void VisitPointer(Object** p) {
+    UpdateRSet(p);
+  }
+
+  void VisitPointers(Object** start, Object** end) {
+    // Update a store into slots [start, end), used (a) to update remembered
+    // set when promoting a young object to old space or (b) to rebuild
+    // remembered sets after a mark-compact collection.
+    for (Object** p = start; p < end; p++) UpdateRSet(p);
+  }
+ private:
+
+  void UpdateRSet(Object** p) {
+    // The remembered set should not be set.  It should be clear for objects
+    // newly copied to old space, and it is cleared before rebuilding in the
+    // mark-compact collector.
+    ASSERT(!Page::IsRSetSet(reinterpret_cast<Address>(p), 0));
+    if (Heap::InNewSpace(*p)) {
+      Page::SetRSet(reinterpret_cast<Address>(p), 0);
+    }
+  }
+};
+
+
+int Heap::UpdateRSet(HeapObject* obj) {
+  ASSERT(!InNewSpace(obj));
+  // Special handling of fixed arrays to iterate the body based on the start
+  // address and offset.  Just iterating the pointers as in UpdateRSetVisitor
+  // will not work because Page::SetRSet needs to have the start of the
+  // object.
+  if (obj->IsFixedArray()) {
+    FixedArray* array = FixedArray::cast(obj);
+    int length = array->length();
+    for (int i = 0; i < length; i++) {
+      int offset = FixedArray::kHeaderSize + i * kPointerSize;
+      ASSERT(!Page::IsRSetSet(obj->address(), offset));
+      if (Heap::InNewSpace(array->get(i))) {
+        Page::SetRSet(obj->address(), offset);
+      }
+    }
+  } else if (!obj->IsCode()) {
+    // Skip code object, we know it does not contain inter-generational
+    // pointers.
+    UpdateRSetVisitor v;
+    obj->Iterate(&v);
+  }
+  return obj->Size();
+}
+
+
+void Heap::RebuildRSets() {
+  // By definition, we do not care about remembered set bits in code or data
+  // spaces.
+  map_space_->ClearRSet();
+  RebuildRSets(map_space_);
+
+  old_pointer_space_->ClearRSet();
+  RebuildRSets(old_pointer_space_);
+
+  Heap::lo_space_->ClearRSet();
+  RebuildRSets(lo_space_);
+}
+
+
+void Heap::RebuildRSets(PagedSpace* space) {
+  HeapObjectIterator it(space);
+  while (it.has_next()) Heap::UpdateRSet(it.next());
+}
+
+
+void Heap::RebuildRSets(LargeObjectSpace* space) {
+  LargeObjectIterator it(space);
+  while (it.has_next()) Heap::UpdateRSet(it.next());
+}
+
+
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+void Heap::RecordCopiedObject(HeapObject* obj) {
+  bool should_record = false;
+#ifdef DEBUG
+  should_record = FLAG_heap_stats;
+#endif
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  should_record = should_record || FLAG_log_gc;
+#endif
+  if (should_record) {
+    if (new_space_.Contains(obj)) {
+      new_space_.RecordAllocation(obj);
+    } else {
+      new_space_.RecordPromotion(obj);
+    }
+  }
+}
+#endif  // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+
+
+
+HeapObject* Heap::MigrateObject(HeapObject* source,
+                                HeapObject* target,
+                                int size) {
+  // Copy the content of source to target.
+  CopyBlock(reinterpret_cast<Object**>(target->address()),
+            reinterpret_cast<Object**>(source->address()),
+            size);
+
+  // Set the forwarding address.
+  source->set_map_word(MapWord::FromForwardingAddress(target));
+
+  // Update NewSpace stats if necessary.
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  RecordCopiedObject(target);
+#endif
+
+  return target;
+}
+
+
+// Inlined function.
+void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
+  ASSERT(InFromSpace(object));
+
+  // We use the first word (where the map pointer usually is) of a heap
+  // object to record the forwarding pointer.  A forwarding pointer can
+  // point to an old space, the code space, or the to space of the new
+  // generation.
+  MapWord first_word = object->map_word();
+
+  // If the first word is a forwarding address, the object has already been
+  // copied.
+  if (first_word.IsForwardingAddress()) {
+    *p = first_word.ToForwardingAddress();
+    return;
+  }
+
+  // Call the slow part of scavenge object.
+  return ScavengeObjectSlow(p, object);
+}
+
+static inline bool IsShortcutCandidate(HeapObject* object, Map* map) {
+  // A ConString object with Heap::empty_string() as the right side
+  // is a candidate for being shortcut by the scavenger.
+  ASSERT(object->map() == map);
+  return (map->instance_type() < FIRST_NONSTRING_TYPE) &&
+      (String::cast(object)->map_representation_tag(map) == kConsStringTag) &&
+      (ConsString::cast(object)->second() == Heap::empty_string());
+}
+
+
+void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
+  ASSERT(InFromSpace(object));
+  MapWord first_word = object->map_word();
+  ASSERT(!first_word.IsForwardingAddress());
+
+  // Optimization: Bypass flattened ConsString objects.
+  if (IsShortcutCandidate(object, first_word.ToMap())) {
+    object = HeapObject::cast(ConsString::cast(object)->first());
+    *p = object;
+    // After patching *p we have to repeat the checks that object is in the
+    // active semispace of the young generation and not already copied.
+    if (!InNewSpace(object)) return;
+    first_word = object->map_word();
+    if (first_word.IsForwardingAddress()) {
+      *p = first_word.ToForwardingAddress();
+      return;
+    }
+  }
+
+  int object_size = object->SizeFromMap(first_word.ToMap());
+  // If the object should be promoted, we try to copy it to old space.
+  if (ShouldBePromoted(object->address(), object_size)) {
+    OldSpace* target_space = Heap::TargetSpace(object);
+    ASSERT(target_space == Heap::old_pointer_space_ ||
+           target_space == Heap::old_data_space_);
+    Object* result = target_space->AllocateRaw(object_size);
+    if (!result->IsFailure()) {
+      *p = MigrateObject(object, HeapObject::cast(result), object_size);
+      if (target_space == Heap::old_pointer_space_) {
+        // Record the object's address at the top of the to space, to allow
+        // it to be swept by the scavenger.
+        promoted_top -= kPointerSize;
+        Memory::Object_at(promoted_top) = *p;
+      } else {
+#ifdef DEBUG
+        // Objects promoted to the data space should not have pointers to
+        // new space.
+        VerifyNonPointerSpacePointersVisitor v;
+        (*p)->Iterate(&v);
+#endif
+      }
+      return;
+    }
+  }
+
+  // The object should remain in new space or the old space allocation failed.
+  Object* result = new_space_.AllocateRaw(object_size);
+  // Failed allocation at this point is utterly unexpected.
+  ASSERT(!result->IsFailure());
+  *p = MigrateObject(object, HeapObject::cast(result), object_size);
+}
+
+
+void Heap::ScavengePointer(HeapObject** p) {
+  ScavengeObject(p, *p);
+}
+
+
+Object* Heap::AllocatePartialMap(InstanceType instance_type,
+                                 int instance_size) {
+  Object* result = AllocateRawMap(Map::kSize);
+  if (result->IsFailure()) return result;
+
+  // Map::cast cannot be used due to uninitialized map field.
+  reinterpret_cast<Map*>(result)->set_map(meta_map());
+  reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
+  reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
+  reinterpret_cast<Map*>(result)->set_inobject_properties(0);
+  reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
+  return result;
+}
+
+
+Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
+  Object* result = AllocateRawMap(Map::kSize);
+  if (result->IsFailure()) return result;
+
+  Map* map = reinterpret_cast<Map*>(result);
+  map->set_map(meta_map());
+  map->set_instance_type(instance_type);
+  map->set_prototype(null_value());
+  map->set_constructor(null_value());
+  map->set_instance_size(instance_size);
+  map->set_inobject_properties(0);
+  map->set_instance_descriptors(empty_descriptor_array());
+  map->set_code_cache(empty_fixed_array());
+  map->set_unused_property_fields(0);
+  map->set_bit_field(0);
+  return map;
+}
+
+
+bool Heap::CreateInitialMaps() {
+  Object* obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
+  if (obj->IsFailure()) return false;
+
+  // Map::cast cannot be used due to uninitialized map field.
+  meta_map_ = reinterpret_cast<Map*>(obj);
+  meta_map()->set_map(meta_map());
+
+  obj = AllocatePartialMap(FIXED_ARRAY_TYPE, Array::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  fixed_array_map_ = Map::cast(obj);
+
+  obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
+  if (obj->IsFailure()) return false;
+  oddball_map_ = Map::cast(obj);
+
+  // Allocate the empty array
+  obj = AllocateEmptyFixedArray();
+  if (obj->IsFailure()) return false;
+  empty_fixed_array_ = FixedArray::cast(obj);
+
+  obj = Allocate(oddball_map(), OLD_DATA_SPACE);
+  if (obj->IsFailure()) return false;
+  null_value_ = obj;
+
+  // Allocate the empty descriptor array.  AllocateMap can now be used.
+  obj = AllocateEmptyFixedArray();
+  if (obj->IsFailure()) return false;
+  // There is a check against empty_descriptor_array() in cast().
+  empty_descriptor_array_ = reinterpret_cast<DescriptorArray*>(obj);
+
+  // Fix the instance_descriptors for the existing maps.
+  meta_map()->set_instance_descriptors(empty_descriptor_array());
+  meta_map()->set_code_cache(empty_fixed_array());
+
+  fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
+  fixed_array_map()->set_code_cache(empty_fixed_array());
+
+  oddball_map()->set_instance_descriptors(empty_descriptor_array());
+  oddball_map()->set_code_cache(empty_fixed_array());
+
+  // Fix prototype object for existing maps.
+  meta_map()->set_prototype(null_value());
+  meta_map()->set_constructor(null_value());
+
+  fixed_array_map()->set_prototype(null_value());
+  fixed_array_map()->set_constructor(null_value());
+  oddball_map()->set_prototype(null_value());
+  oddball_map()->set_constructor(null_value());
+
+  obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
+  if (obj->IsFailure()) return false;
+  heap_number_map_ = Map::cast(obj);
+
+  obj = AllocateMap(PROXY_TYPE, Proxy::kSize);
+  if (obj->IsFailure()) return false;
+  proxy_map_ = Map::cast(obj);
+
+#define ALLOCATE_STRING_MAP(type, size, name)   \
+    obj = AllocateMap(type, size);              \
+    if (obj->IsFailure()) return false;         \
+    name##_map_ = Map::cast(obj);
+  STRING_TYPE_LIST(ALLOCATE_STRING_MAP);
+#undef ALLOCATE_STRING_MAP
+
+  obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  undetectable_short_string_map_ = Map::cast(obj);
+  undetectable_short_string_map_->set_is_undetectable();
+
+  obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  undetectable_medium_string_map_ = Map::cast(obj);
+  undetectable_medium_string_map_->set_is_undetectable();
+
+  obj = AllocateMap(LONG_STRING_TYPE, SeqTwoByteString::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  undetectable_long_string_map_ = Map::cast(obj);
+  undetectable_long_string_map_->set_is_undetectable();
+
+  obj = AllocateMap(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  undetectable_short_ascii_string_map_ = Map::cast(obj);
+  undetectable_short_ascii_string_map_->set_is_undetectable();
+
+  obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  undetectable_medium_ascii_string_map_ = Map::cast(obj);
+  undetectable_medium_ascii_string_map_->set_is_undetectable();
+
+  obj = AllocateMap(LONG_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  undetectable_long_ascii_string_map_ = Map::cast(obj);
+  undetectable_long_ascii_string_map_->set_is_undetectable();
+
+  obj = AllocateMap(BYTE_ARRAY_TYPE, Array::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  byte_array_map_ = Map::cast(obj);
+
+  obj = AllocateMap(CODE_TYPE, Code::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  code_map_ = Map::cast(obj);
+
+  obj = AllocateMap(FILLER_TYPE, kPointerSize);
+  if (obj->IsFailure()) return false;
+  one_word_filler_map_ = Map::cast(obj);
+
+  obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
+  if (obj->IsFailure()) return false;
+  two_word_filler_map_ = Map::cast(obj);
+
+#define ALLOCATE_STRUCT_MAP(NAME, Name, name)      \
+  obj = AllocateMap(NAME##_TYPE, Name::kSize);     \
+  if (obj->IsFailure()) return false;              \
+  name##_map_ = Map::cast(obj);
+  STRUCT_LIST(ALLOCATE_STRUCT_MAP)
+#undef ALLOCATE_STRUCT_MAP
+
+  obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  hash_table_map_ = Map::cast(obj);
+
+  obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  context_map_ = Map::cast(obj);
+
+  obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  global_context_map_ = Map::cast(obj);
+
+  obj = AllocateMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+  if (obj->IsFailure()) return false;
+  boilerplate_function_map_ = Map::cast(obj);
+
+  obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE, SharedFunctionInfo::kSize);
+  if (obj->IsFailure()) return false;
+  shared_function_info_map_ = Map::cast(obj);
+
+  ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
+  return true;
+}
+
+
+Object* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
+  // Statically ensure that it is safe to allocate heap numbers in paged
+  // spaces.
+  STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
+  AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+  Object* result = AllocateRaw(HeapNumber::kSize, space);
+  if (result->IsFailure()) return result;
+
+  HeapObject::cast(result)->set_map(heap_number_map());
+  HeapNumber::cast(result)->set_value(value);
+  return result;
+}
+
+
+Object* Heap::AllocateHeapNumber(double value) {
+  // This version of AllocateHeapNumber is optimized for
+  // allocation in new space.
+  STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
+  ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
+  Object* result = new_space_.AllocateRaw(HeapNumber::kSize);
+  if (result->IsFailure()) return result;
+  HeapObject::cast(result)->set_map(heap_number_map());
+  HeapNumber::cast(result)->set_value(value);
+  return result;
+}
+
+
+Object* Heap::CreateOddball(Map* map,
+                            const char* to_string,
+                            Object* to_number) {
+  Object* result = Allocate(map, OLD_DATA_SPACE);
+  if (result->IsFailure()) return result;
+  return Oddball::cast(result)->Initialize(to_string, to_number);
+}
+
+
+bool Heap::CreateApiObjects() {
+  Object* obj;
+
+  obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+  if (obj->IsFailure()) return false;
+  neander_map_ = Map::cast(obj);
+
+  obj = Heap::AllocateJSObjectFromMap(neander_map_);
+  if (obj->IsFailure()) return false;
+  Object* elements = AllocateFixedArray(2);
+  if (elements->IsFailure()) return false;
+  FixedArray::cast(elements)->set(0, Smi::FromInt(0));
+  JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
+  message_listeners_ = JSObject::cast(obj);
+
+  obj = Heap::AllocateJSObjectFromMap(neander_map_);
+  if (obj->IsFailure()) return false;
+  elements = AllocateFixedArray(2);
+  if (elements->IsFailure()) return false;
+  FixedArray::cast(elements)->set(0, Smi::FromInt(0));
+  JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
+  debug_event_listeners_ = JSObject::cast(obj);
+
+  return true;
+}
+
+void Heap::CreateFixedStubs() {
+  // Here we create roots for fixed stubs. They are needed at GC
+  // for cooking and uncooking (check out frames.cc).
+  // The eliminates the need for doing dictionary lookup in the
+  // stub cache for these stubs.
+  HandleScope scope;
+  {
+    CEntryStub stub;
+    c_entry_code_ = *stub.GetCode();
+  }
+  {
+    CEntryDebugBreakStub stub;
+    c_entry_debug_break_code_ = *stub.GetCode();
+  }
+  {
+    JSEntryStub stub;
+    js_entry_code_ = *stub.GetCode();
+  }
+  {
+    JSConstructEntryStub stub;
+    js_construct_entry_code_ = *stub.GetCode();
+  }
+}
+
+
+bool Heap::CreateInitialObjects() {
+  Object* obj;
+
+  // The -0 value must be set before NumberFromDouble works.
+  obj = AllocateHeapNumber(-0.0, TENURED);
+  if (obj->IsFailure()) return false;
+  minus_zero_value_ = obj;
+  ASSERT(signbit(minus_zero_value_->Number()) != 0);
+
+  obj = AllocateHeapNumber(OS::nan_value(), TENURED);
+  if (obj->IsFailure()) return false;
+  nan_value_ = obj;
+
+  obj = Allocate(oddball_map(), OLD_DATA_SPACE);
+  if (obj->IsFailure()) return false;
+  undefined_value_ = obj;
+  ASSERT(!InNewSpace(undefined_value()));
+
+  // Allocate initial symbol table.
+  obj = SymbolTable::Allocate(kInitialSymbolTableSize);
+  if (obj->IsFailure()) return false;
+  symbol_table_ = obj;
+
+  // Assign the print strings for oddballs after creating symboltable.
+  Object* symbol = LookupAsciiSymbol("undefined");
+  if (symbol->IsFailure()) return false;
+  Oddball::cast(undefined_value_)->set_to_string(String::cast(symbol));
+  Oddball::cast(undefined_value_)->set_to_number(nan_value_);
+
+  // Assign the print strings for oddballs after creating symboltable.
+  symbol = LookupAsciiSymbol("null");
+  if (symbol->IsFailure()) return false;
+  Oddball::cast(null_value_)->set_to_string(String::cast(symbol));
+  Oddball::cast(null_value_)->set_to_number(Smi::FromInt(0));
+
+  // Allocate the null_value
+  obj = Oddball::cast(null_value())->Initialize("null", Smi::FromInt(0));
+  if (obj->IsFailure()) return false;
+
+  obj = CreateOddball(oddball_map(), "true", Smi::FromInt(1));
+  if (obj->IsFailure()) return false;
+  true_value_ = obj;
+
+  obj = CreateOddball(oddball_map(), "false", Smi::FromInt(0));
+  if (obj->IsFailure()) return false;
+  false_value_ = obj;
+
+  obj = CreateOddball(oddball_map(), "hole", Smi::FromInt(-1));
+  if (obj->IsFailure()) return false;
+  the_hole_value_ = obj;
+
+  // Allocate the empty string.
+  obj = AllocateRawAsciiString(0, TENURED);
+  if (obj->IsFailure()) return false;
+  empty_string_ = String::cast(obj);
+
+#define SYMBOL_INITIALIZE(name, string)                 \
+  obj = LookupAsciiSymbol(string);                      \
+  if (obj->IsFailure()) return false;                   \
+  (name##_) = String::cast(obj);
+  SYMBOL_LIST(SYMBOL_INITIALIZE)
+#undef SYMBOL_INITIALIZE
+
+  // Allocate the proxy for __proto__.
+  obj = AllocateProxy((Address) &Accessors::ObjectPrototype);
+  if (obj->IsFailure()) return false;
+  prototype_accessors_ = Proxy::cast(obj);
+
+  // Allocate the code_stubs dictionary.
+  obj = Dictionary::Allocate(4);
+  if (obj->IsFailure()) return false;
+  code_stubs_ = Dictionary::cast(obj);
+
+  // Allocate the non_monomorphic_cache used in stub-cache.cc
+  obj = Dictionary::Allocate(4);
+  if (obj->IsFailure()) return false;
+  non_monomorphic_cache_ =  Dictionary::cast(obj);
+
+  CreateFixedStubs();
+
+  // Allocate the number->string conversion cache
+  obj = AllocateFixedArray(kNumberStringCacheSize * 2);
+  if (obj->IsFailure()) return false;
+  number_string_cache_ = FixedArray::cast(obj);
+
+  // Allocate cache for single character strings.
+  obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
+  if (obj->IsFailure()) return false;
+  single_character_string_cache_ = FixedArray::cast(obj);
+
+  // Allocate cache for external strings pointing to native source code.
+  obj = AllocateFixedArray(Natives::GetBuiltinsCount());
+  if (obj->IsFailure()) return false;
+  natives_source_cache_ = FixedArray::cast(obj);
+
+  // Initialize keyed lookup cache.
+  ClearKeyedLookupCache();
+
+  // Initialize compilation cache.
+  CompilationCache::Clear();
+
+  return true;
+}
+
+
+static inline int double_get_hash(double d) {
+  DoubleRepresentation rep(d);
+  return ((static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32)) &
+          (Heap::kNumberStringCacheSize - 1));
+}
+
+
+static inline int smi_get_hash(Smi* smi) {
+  return (smi->value() & (Heap::kNumberStringCacheSize - 1));
+}
+
+
+
+Object* Heap::GetNumberStringCache(Object* number) {
+  int hash;
+  if (number->IsSmi()) {
+    hash = smi_get_hash(Smi::cast(number));
+  } else {
+    hash = double_get_hash(number->Number());
+  }
+  Object* key = number_string_cache_->get(hash * 2);
+  if (key == number) {
+    return String::cast(number_string_cache_->get(hash * 2 + 1));
+  } else if (key->IsHeapNumber() &&
+             number->IsHeapNumber() &&
+             key->Number() == number->Number()) {
+    return String::cast(number_string_cache_->get(hash * 2 + 1));
+  }
+  return undefined_value();
+}
+
+
+void Heap::SetNumberStringCache(Object* number, String* string) {
+  int hash;
+  if (number->IsSmi()) {
+    hash = smi_get_hash(Smi::cast(number));
+    number_string_cache_->set(hash * 2, number, SKIP_WRITE_BARRIER);
+  } else {
+    hash = double_get_hash(number->Number());
+    number_string_cache_->set(hash * 2, number);
+  }
+  number_string_cache_->set(hash * 2 + 1, string);
+}
+
+
+Object* Heap::SmiOrNumberFromDouble(double value,
+                                    bool new_object,
+                                    PretenureFlag pretenure) {
+  // We need to distinguish the minus zero value and this cannot be
+  // done after conversion to int. Doing this by comparing bit
+  // patterns is faster than using fpclassify() et al.
+  static const DoubleRepresentation plus_zero(0.0);
+  static const DoubleRepresentation minus_zero(-0.0);
+  static const DoubleRepresentation nan(OS::nan_value());
+  ASSERT(minus_zero_value_ != NULL);
+  ASSERT(sizeof(plus_zero.value) == sizeof(plus_zero.bits));
+
+  DoubleRepresentation rep(value);
+  if (rep.bits == plus_zero.bits) return Smi::FromInt(0);  // not uncommon
+  if (rep.bits == minus_zero.bits) {
+    return new_object ? AllocateHeapNumber(-0.0, pretenure)
+                      : minus_zero_value_;
+  }
+  if (rep.bits == nan.bits) {
+    return new_object
+        ? AllocateHeapNumber(OS::nan_value(), pretenure)
+        : nan_value_;
+  }
+
+  // Try to represent the value as a tagged small integer.
+  int int_value = FastD2I(value);
+  if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
+    return Smi::FromInt(int_value);
+  }
+
+  // Materialize the value in the heap.
+  return AllocateHeapNumber(value, pretenure);
+}
+
+
+Object* Heap::NewNumberFromDouble(double value, PretenureFlag pretenure) {
+  return SmiOrNumberFromDouble(value,
+                               true /* number object must be new */,
+                               pretenure);
+}
+
+
+Object* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
+  return SmiOrNumberFromDouble(value,
+                               false /* use preallocated NaN, -0.0 */,
+                               pretenure);
+}
+
+
+Object* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) {
+  // Statically ensure that it is safe to allocate proxies in paged spaces.
+  STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize);
+  AllocationSpace space =
+      (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+  Object* result = Allocate(proxy_map(), space);
+  if (result->IsFailure()) return result;
+
+  Proxy::cast(result)->set_proxy(proxy);
+  return result;
+}
+
+
+Object* Heap::AllocateSharedFunctionInfo(Object* name) {
+  Object* result = Allocate(shared_function_info_map(), NEW_SPACE);
+  if (result->IsFailure()) return result;
+
+  SharedFunctionInfo* share = SharedFunctionInfo::cast(result);
+  share->set_name(name);
+  Code* illegal = Builtins::builtin(Builtins::Illegal);
+  share->set_code(illegal);
+  share->set_expected_nof_properties(0);
+  share->set_length(0);
+  share->set_formal_parameter_count(0);
+  share->set_instance_class_name(Object_symbol());
+  share->set_function_data(undefined_value());
+  share->set_lazy_load_data(undefined_value());
+  share->set_script(undefined_value());
+  share->set_start_position_and_type(0);
+  share->set_debug_info(undefined_value());
+  return result;
+}
+
+
+Object* Heap::AllocateConsString(String* first, String* second) {
+  int first_length = first->length();
+  int second_length = second->length();
+  int length = first_length + second_length;
+  bool is_ascii = first->is_ascii_representation()
+      && second->is_ascii_representation();
+
+  // If the resulting string is small make a flat string.
+  if (length < String::kMinNonFlatLength) {
+    ASSERT(first->IsFlat());
+    ASSERT(second->IsFlat());
+    if (is_ascii) {
+      Object* result = AllocateRawAsciiString(length);
+      if (result->IsFailure()) return result;
+      // Copy the characters into the new object.
+      char* dest = SeqAsciiString::cast(result)->GetChars();
+      String::WriteToFlat(first, dest, 0, first_length);
+      String::WriteToFlat(second, dest + first_length, 0, second_length);
+      return result;
+    } else {
+      Object* result = AllocateRawTwoByteString(length);
+      if (result->IsFailure()) return result;
+      // Copy the characters into the new object.
+      uc16* dest = SeqTwoByteString::cast(result)->GetChars();
+      String::WriteToFlat(first, dest, 0, first_length);
+      String::WriteToFlat(second, dest + first_length, 0, second_length);
+      return result;
+    }
+  }
+
+  Map* map;
+  if (length <= String::kMaxShortStringSize) {
+    map = is_ascii ? short_cons_ascii_string_map()
+      : short_cons_string_map();
+  } else if (length <= String::kMaxMediumStringSize) {
+    map = is_ascii ? medium_cons_ascii_string_map()
+      : medium_cons_string_map();
+  } else {
+    map = is_ascii ? long_cons_ascii_string_map()
+      : long_cons_string_map();
+  }
+
+  Object* result = Allocate(map, NEW_SPACE);
+  if (result->IsFailure()) return result;
+  ASSERT(InNewSpace(result));
+  ConsString* cons_string = ConsString::cast(result);
+  cons_string->set_first(first, SKIP_WRITE_BARRIER);
+  cons_string->set_second(second, SKIP_WRITE_BARRIER);
+  cons_string->set_length(length);
+  return result;
+}
+
+
+Object* Heap::AllocateSlicedString(String* buffer, int start, int end) {
+  int length = end - start;
+
+  // If the resulting string is small make a sub string.
+  if (end - start <= String::kMinNonFlatLength) {
+    return Heap::AllocateSubString(buffer, start, end);
+  }
+
+  Map* map;
+  if (length <= String::kMaxShortStringSize) {
+    map = buffer->is_ascii_representation() ? short_sliced_ascii_string_map()
+      : short_sliced_string_map();
+  } else if (length <= String::kMaxMediumStringSize) {
+    map = buffer->is_ascii_representation() ? medium_sliced_ascii_string_map()
+      : medium_sliced_string_map();
+  } else {
+    map = buffer->is_ascii_representation() ? long_sliced_ascii_string_map()
+      : long_sliced_string_map();
+  }
+
+  Object* result = Allocate(map, NEW_SPACE);
+  if (result->IsFailure()) return result;
+
+  SlicedString* sliced_string = SlicedString::cast(result);
+  sliced_string->set_buffer(buffer);
+  sliced_string->set_start(start);
+  sliced_string->set_length(length);
+
+  return result;
+}
+
+
+Object* Heap::AllocateSubString(String* buffer, int start, int end) {
+  int length = end - start;
+
+  if (length == 1) {
+    return Heap::LookupSingleCharacterStringFromCode(buffer->Get(start));
+  }
+
+  // Make an attempt to flatten the buffer to reduce access time.
+  buffer->TryFlatten();
+
+  Object* result = buffer->is_ascii_representation()
+      ? AllocateRawAsciiString(length)
+      : AllocateRawTwoByteString(length);
+  if (result->IsFailure()) return result;
+
+  // Copy the characters into the new object.
+  String* string_result = String::cast(result);
+  StringHasher hasher(length);
+  int i = 0;
+  for (; i < length && hasher.is_array_index(); i++) {
+    uc32 c = buffer->Get(start + i);
+    hasher.AddCharacter(c);
+    string_result->Set(i, c);
+  }
+  for (; i < length; i++) {
+    uc32 c = buffer->Get(start + i);
+    hasher.AddCharacterNoIndex(c);
+    string_result->Set(i, c);
+  }
+  string_result->set_length_field(hasher.GetHashField());
+  return result;
+}
+
+
+Object* Heap::AllocateExternalStringFromAscii(
+    ExternalAsciiString::Resource* resource) {
+  Map* map;
+  int length = resource->length();
+  if (length <= String::kMaxShortStringSize) {
+    map = short_external_ascii_string_map();
+  } else if (length <= String::kMaxMediumStringSize) {
+    map = medium_external_ascii_string_map();
+  } else {
+    map = long_external_ascii_string_map();
+  }
+
+  Object* result = Allocate(map, NEW_SPACE);
+  if (result->IsFailure()) return result;
+
+  ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
+  external_string->set_length(length);
+  external_string->set_resource(resource);
+
+  return result;
+}
+
+
+Object* Heap::AllocateExternalStringFromTwoByte(
+    ExternalTwoByteString::Resource* resource) {
+  Map* map;
+  int length = resource->length();
+  if (length <= String::kMaxShortStringSize) {
+    map = short_external_string_map();
+  } else if (length <= String::kMaxMediumStringSize) {
+    map = medium_external_string_map();
+  } else {
+    map = long_external_string_map();
+  }
+
+  Object* result = Allocate(map, NEW_SPACE);
+  if (result->IsFailure()) return result;
+
+  ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
+  external_string->set_length(length);
+  external_string->set_resource(resource);
+
+  return result;
+}
+
+
+Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
+  if (code <= String::kMaxAsciiCharCode) {
+    Object* value = Heap::single_character_string_cache()->get(code);
+    if (value != Heap::undefined_value()) return value;
+
+    char buffer[1];
+    buffer[0] = static_cast<char>(code);
+    Object* result = LookupSymbol(Vector<const char>(buffer, 1));
+
+    if (result->IsFailure()) return result;
+    Heap::single_character_string_cache()->set(code, result);
+    return result;
+  }
+
+  Object* result = Heap::AllocateRawTwoByteString(1);
+  if (result->IsFailure()) return result;
+  String::cast(result)->Set(0, code);
+  return result;
+}
+
+
+Object* Heap::AllocateByteArray(int length) {
+  int size = ByteArray::SizeFor(length);
+  AllocationSpace space =
+      size > MaxHeapObjectSize() ? LO_SPACE : NEW_SPACE;
+
+  Object* result = AllocateRaw(size, space);
+
+  if (result->IsFailure()) return result;
+
+  reinterpret_cast<Array*>(result)->set_map(byte_array_map());
+  reinterpret_cast<Array*>(result)->set_length(length);
+  return result;
+}
+
+
+Object* Heap::CreateCode(const CodeDesc& desc,
+                         ScopeInfo<>* sinfo,
+                         Code::Flags flags) {
+  // Compute size
+  int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment);
+  int sinfo_size = 0;
+  if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL);
+  int obj_size = Code::SizeFor(body_size, sinfo_size);
+  Object* result;
+  if (obj_size > MaxHeapObjectSize()) {
+    result = lo_space_->AllocateRawCode(obj_size);
+  } else {
+    result = code_space_->AllocateRaw(obj_size);
+  }
+
+  if (result->IsFailure()) return result;
+
+  // Initialize the object
+  HeapObject::cast(result)->set_map(code_map());
+  Code* code = Code::cast(result);
+  code->set_instruction_size(desc.instr_size);
+  code->set_relocation_size(desc.reloc_size);
+  code->set_sinfo_size(sinfo_size);
+  code->set_flags(flags);
+  code->set_ic_flag(Code::IC_TARGET_IS_ADDRESS);
+  code->CopyFrom(desc);  // migrate generated code
+  if (sinfo != NULL) sinfo->Serialize(code);  // write scope info
+
+#ifdef DEBUG
+  code->Verify();
+#endif
+  return code;
+}
+
+
+Object* Heap::CopyCode(Code* code) {
+  // Allocate an object the same size as the code object.
+  int obj_size = code->Size();
+  Object* result;
+  if (obj_size > MaxHeapObjectSize()) {
+    result = lo_space_->AllocateRawCode(obj_size);
+  } else {
+    result = code_space_->AllocateRaw(obj_size);
+  }
+
+  if (result->IsFailure()) return result;
+
+  // Copy code object.
+  Address old_addr = code->address();
+  Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
+  CopyBlock(reinterpret_cast<Object**>(new_addr),
+            reinterpret_cast<Object**>(old_addr),
+            obj_size);
+  // Relocate the copy.
+  Code* new_code = Code::cast(result);
+  new_code->Relocate(new_addr - old_addr);
+  return new_code;
+}
+
+
+Object* Heap::Allocate(Map* map, AllocationSpace space) {
+  ASSERT(gc_state_ == NOT_IN_GC);
+  ASSERT(map->instance_type() != MAP_TYPE);
+  Object* result = AllocateRaw(map->instance_size(), space);
+  if (result->IsFailure()) return result;
+  HeapObject::cast(result)->set_map(map);
+  return result;
+}
+
+
+Object* Heap::InitializeFunction(JSFunction* function,
+                                 SharedFunctionInfo* shared,
+                                 Object* prototype) {
+  ASSERT(!prototype->IsMap());
+  function->initialize_properties();
+  function->initialize_elements();
+  function->set_shared(shared);
+  function->set_prototype_or_initial_map(prototype);
+  function->set_context(undefined_value());
+  function->set_literals(empty_fixed_array(), SKIP_WRITE_BARRIER);
+  return function;
+}
+
+
+Object* Heap::AllocateFunctionPrototype(JSFunction* function) {
+  // Allocate the prototype.
+  Object* prototype =
+      AllocateJSObject(Top::context()->global_context()->object_function());
+  if (prototype->IsFailure()) return prototype;
+  // When creating the prototype for the function we must set its
+  // constructor to the function.
+  Object* result =
+      JSObject::cast(prototype)->SetProperty(constructor_symbol(),
+                                             function,
+                                             DONT_ENUM);
+  if (result->IsFailure()) return result;
+  return prototype;
+}
+
+
+Object* Heap::AllocateFunction(Map* function_map,
+                               SharedFunctionInfo* shared,
+                               Object* prototype) {
+  Object* result = Allocate(function_map, OLD_POINTER_SPACE);
+  if (result->IsFailure()) return result;
+  return InitializeFunction(JSFunction::cast(result), shared, prototype);
+}
+
+
+Object* Heap::AllocateArgumentsObject(Object* callee, int length) {
+  // To get fast allocation and map sharing for arguments objects we
+  // allocate them based on an arguments boilerplate.
+
+  // This calls Copy directly rather than using Heap::AllocateRaw so we
+  // duplicate the check here.
+  ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
+
+  JSObject* boilerplate =
+      Top::context()->global_context()->arguments_boilerplate();
+
+  // Make the clone.
+  Map* map = boilerplate->map();
+  int object_size = map->instance_size();
+  Object* result = new_space_.AllocateRaw(object_size);
+  if (result->IsFailure()) return result;
+  ASSERT(Heap::InNewSpace(result));
+
+  // Copy the content.
+  CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(result)->address()),
+            reinterpret_cast<Object**>(boilerplate->address()),
+            object_size);
+
+  // Set the two properties.
+  JSObject::cast(result)->InObjectPropertyAtPut(arguments_callee_index,
+                                                callee,
+                                                SKIP_WRITE_BARRIER);
+  JSObject::cast(result)->InObjectPropertyAtPut(arguments_length_index,
+                                                Smi::FromInt(length),
+                                                SKIP_WRITE_BARRIER);
+
+  // Check the state of the object
+  ASSERT(JSObject::cast(result)->HasFastProperties());
+  ASSERT(JSObject::cast(result)->HasFastElements());
+
+  return result;
+}
+
+
+Object* Heap::AllocateInitialMap(JSFunction* fun) {
+  ASSERT(!fun->has_initial_map());
+
+  // First create a new map with the expected number of properties being
+  // allocated in-object.
+  int expected_nof_properties = fun->shared()->expected_nof_properties();
+  int instance_size = JSObject::kHeaderSize +
+                      expected_nof_properties * kPointerSize;
+  if (instance_size > JSObject::kMaxInstanceSize) {
+    instance_size = JSObject::kMaxInstanceSize;
+    expected_nof_properties = (instance_size - JSObject::kHeaderSize) /
+                              kPointerSize;
+  }
+  Object* map_obj = Heap::AllocateMap(JS_OBJECT_TYPE, instance_size);
+  if (map_obj->IsFailure()) return map_obj;
+
+  // Fetch or allocate prototype.
+  Object* prototype;
+  if (fun->has_instance_prototype()) {
+    prototype = fun->instance_prototype();
+  } else {
+    prototype = AllocateFunctionPrototype(fun);
+    if (prototype->IsFailure()) return prototype;
+  }
+  Map* map = Map::cast(map_obj);
+  map->set_inobject_properties(expected_nof_properties);
+  map->set_unused_property_fields(expected_nof_properties);
+  map->set_prototype(prototype);
+  return map;
+}
+
+
+void Heap::InitializeJSObjectFromMap(JSObject* obj,
+                                     FixedArray* properties,
+                                     Map* map) {
+  obj->set_properties(properties);
+  obj->initialize_elements();
+  // TODO(1240798): Initialize the object's body using valid initial values
+  // according to the object's initial map.  For example, if the map's
+  // instance type is JS_ARRAY_TYPE, the length field should be initialized
+  // to a number (eg, Smi::FromInt(0)) and the elements initialized to a
+  // fixed array (eg, Heap::empty_fixed_array()).  Currently, the object
+  // verification code has to cope with (temporarily) invalid objects.  See
+  // for example, JSArray::JSArrayVerify).
+  obj->InitializeBody(map->instance_size());
+}
+
+
+Object* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
+  // JSFunctions should be allocated using AllocateFunction to be
+  // properly initialized.
+  ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
+
+  // Allocate the backing storage for the properties.
+  int prop_size = map->unused_property_fields() - map->inobject_properties();
+  Object* properties = AllocateFixedArray(prop_size);
+  if (properties->IsFailure()) return properties;
+
+  // Allocate the JSObject.
+  AllocationSpace space =
+      (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
+  if (map->instance_size() > MaxHeapObjectSize()) space = LO_SPACE;
+  Object* obj = Allocate(map, space);
+  if (obj->IsFailure()) return obj;
+
+  // Initialize the JSObject.
+  InitializeJSObjectFromMap(JSObject::cast(obj),
+                            FixedArray::cast(properties),
+                            map);
+  return obj;
+}
+
+
+Object* Heap::AllocateJSObject(JSFunction* constructor,
+                               PretenureFlag pretenure) {
+  // Allocate the initial map if absent.
+  if (!constructor->has_initial_map()) {
+    Object* initial_map = AllocateInitialMap(constructor);
+    if (initial_map->IsFailure()) return initial_map;
+    constructor->set_initial_map(Map::cast(initial_map));
+    Map::cast(initial_map)->set_constructor(constructor);
+  }
+  // Allocate the object based on the constructors initial map.
+  return AllocateJSObjectFromMap(constructor->initial_map(), pretenure);
+}
+
+
+Object* Heap::CopyJSObject(JSObject* source) {
+  // Never used to copy functions.  If functions need to be copied we
+  // have to be careful to clear the literals array.
+  ASSERT(!source->IsJSFunction());
+
+  // Make the clone.
+  Map* map = source->map();
+  int object_size = map->instance_size();
+  Object* clone = new_space_.AllocateRaw(object_size);
+  if (clone->IsFailure()) return clone;
+  ASSERT(Heap::InNewSpace(clone));
+
+  // Copy the content.
+  CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(clone)->address()),
+            reinterpret_cast<Object**>(source->address()),
+            object_size);
+
+  FixedArray* elements = FixedArray::cast(source->elements());
+  FixedArray* properties = FixedArray::cast(source->properties());
+  // Update elements if necessary.
+  if (elements->length()> 0) {
+    Object* elem = CopyFixedArray(elements);
+    if (elem->IsFailure()) return elem;
+    JSObject::cast(clone)->set_elements(FixedArray::cast(elem));
+  }
+  // Update properties if necessary.
+  if (properties->length() > 0) {
+    Object* prop = CopyFixedArray(properties);
+    if (prop->IsFailure()) return prop;
+    JSObject::cast(clone)->set_properties(FixedArray::cast(prop));
+  }
+  // Return the new clone.
+  return clone;
+}
+
+
+Object* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
+                                        JSGlobalProxy* object) {
+  // Allocate initial map if absent.
+  if (!constructor->has_initial_map()) {
+    Object* initial_map = AllocateInitialMap(constructor);
+    if (initial_map->IsFailure()) return initial_map;
+    constructor->set_initial_map(Map::cast(initial_map));
+    Map::cast(initial_map)->set_constructor(constructor);
+  }
+
+  Map* map = constructor->initial_map();
+
+  // Check that the already allocated object has the same size as
+  // objects allocated using the constructor.
+  ASSERT(map->instance_size() == object->map()->instance_size());
+
+  // Allocate the backing storage for the properties.
+  int prop_size = map->unused_property_fields() - map->inobject_properties();
+  Object* properties = AllocateFixedArray(prop_size);
+  if (properties->IsFailure()) return properties;
+
+  // Reset the map for the object.
+  object->set_map(constructor->initial_map());
+
+  // Reinitialize the object from the constructor map.
+  InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
+  return object;
+}
+
+
+Object* Heap::AllocateStringFromAscii(Vector<const char> string,
+                                      PretenureFlag pretenure) {
+  Object* result = AllocateRawAsciiString(string.length(), pretenure);
+  if (result->IsFailure()) return result;
+
+  // Copy the characters into the new object.
+  SeqAsciiString* string_result = SeqAsciiString::cast(result);
+  for (int i = 0; i < string.length(); i++) {
+    string_result->SeqAsciiStringSet(i, string[i]);
+  }
+  return result;
+}
+
+
+Object* Heap::AllocateStringFromUtf8(Vector<const char> string,
+                                     PretenureFlag pretenure) {
+  // Count the number of characters in the UTF-8 string and check if
+  // it is an ASCII string.
+  Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
+  decoder->Reset(string.start(), string.length());
+  int chars = 0;
+  bool is_ascii = true;
+  while (decoder->has_more()) {
+    uc32 r = decoder->GetNext();
+    if (r > String::kMaxAsciiCharCode) is_ascii = false;
+    chars++;
+  }
+
+  // If the string is ascii, we do not need to convert the characters
+  // since UTF8 is backwards compatible with ascii.
+  if (is_ascii) return AllocateStringFromAscii(string, pretenure);
+
+  Object* result = AllocateRawTwoByteString(chars, pretenure);
+  if (result->IsFailure()) return result;
+
+  // Convert and copy the characters into the new object.
+  String* string_result = String::cast(result);
+  decoder->Reset(string.start(), string.length());
+  for (int i = 0; i < chars; i++) {
+    uc32 r = decoder->GetNext();
+    string_result->Set(i, r);
+  }
+  return result;
+}
+
+
+Object* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
+                                        PretenureFlag pretenure) {
+  // Check if the string is an ASCII string.
+  int i = 0;
+  while (i < string.length() && string[i] <= String::kMaxAsciiCharCode) i++;
+
+  Object* result;
+  if (i == string.length()) {  // It's an ASCII string.
+    result = AllocateRawAsciiString(string.length(), pretenure);
+  } else {  // It's not an ASCII string.
+    result = AllocateRawTwoByteString(string.length(), pretenure);
+  }
+  if (result->IsFailure()) return result;
+
+  // Copy the characters into the new object, which may be either ASCII or
+  // UTF-16.
+  String* string_result = String::cast(result);
+  for (int i = 0; i < string.length(); i++) {
+    string_result->Set(i, string[i]);
+  }
+  return result;
+}
+
+
+Map* Heap::SymbolMapForString(String* string) {
+  // If the string is in new space it cannot be used as a symbol.
+  if (InNewSpace(string)) return NULL;
+
+  // Find the corresponding symbol map for strings.
+  Map* map = string->map();
+
+  if (map == short_ascii_string_map()) return short_ascii_symbol_map();
+  if (map == medium_ascii_string_map()) return medium_ascii_symbol_map();
+  if (map == long_ascii_string_map()) return long_ascii_symbol_map();
+
+  if (map == short_string_map()) return short_symbol_map();
+  if (map == medium_string_map()) return medium_symbol_map();
+  if (map == long_string_map()) return long_symbol_map();
+
+  if (map == short_cons_string_map()) return short_cons_symbol_map();
+  if (map == medium_cons_string_map()) return medium_cons_symbol_map();
+  if (map == long_cons_string_map()) return long_cons_symbol_map();
+
+  if (map == short_cons_ascii_string_map()) {
+    return short_cons_ascii_symbol_map();
+  }
+  if (map == medium_cons_ascii_string_map()) {
+    return medium_cons_ascii_symbol_map();
+  }
+  if (map == long_cons_ascii_string_map()) {
+    return long_cons_ascii_symbol_map();
+  }
+
+  if (map == short_sliced_string_map()) return short_sliced_symbol_map();
+  if (map == medium_sliced_string_map()) return medium_sliced_symbol_map();
+  if (map == long_sliced_string_map()) return long_sliced_symbol_map();
+
+  if (map == short_sliced_ascii_string_map()) {
+    return short_sliced_ascii_symbol_map();
+  }
+  if (map == medium_sliced_ascii_string_map()) {
+    return medium_sliced_ascii_symbol_map();
+  }
+  if (map == long_sliced_ascii_string_map()) {
+    return long_sliced_ascii_symbol_map();
+  }
+
+  if (map == short_external_string_map()) return short_external_string_map();
+  if (map == medium_external_string_map()) return medium_external_string_map();
+  if (map == long_external_string_map()) return long_external_string_map();
+
+  if (map == short_external_ascii_string_map()) {
+    return short_external_ascii_string_map();
+  }
+  if (map == medium_external_ascii_string_map()) {
+    return medium_external_ascii_string_map();
+  }
+  if (map == long_external_ascii_string_map()) {
+    return long_external_ascii_string_map();
+  }
+
+  // No match found.
+  return NULL;
+}
+
+
+Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
+                             int chars,
+                             uint32_t length_field) {
+  // Ensure the chars matches the number of characters in the buffer.
+  ASSERT(static_cast<unsigned>(chars) == buffer->Length());
+  // Determine whether the string is ascii.
+  bool is_ascii = true;
+  while (buffer->has_more()) {
+    if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) is_ascii = false;
+  }
+  buffer->Rewind();
+
+  // Compute map and object size.
+  int size;
+  Map* map;
+
+  if (is_ascii) {
+    if (chars <= String::kMaxShortStringSize) {
+      map = short_ascii_symbol_map();
+    } else if (chars <= String::kMaxMediumStringSize) {
+      map = medium_ascii_symbol_map();
+    } else {
+      map = long_ascii_symbol_map();
+    }
+    size = SeqAsciiString::SizeFor(chars);
+  } else {
+    if (chars <= String::kMaxShortStringSize) {
+      map = short_symbol_map();
+    } else if (chars <= String::kMaxMediumStringSize) {
+      map = medium_symbol_map();
+    } else {
+      map = long_symbol_map();
+    }
+    size = SeqTwoByteString::SizeFor(chars);
+  }
+
+  // Allocate string.
+  AllocationSpace space =
+      (size > MaxHeapObjectSize()) ? LO_SPACE : OLD_DATA_SPACE;
+  Object* result = AllocateRaw(size, space);
+  if (result->IsFailure()) return result;
+
+  reinterpret_cast<HeapObject*>(result)->set_map(map);
+  // The hash value contains the length of the string.
+  String::cast(result)->set_length_field(length_field);
+
+  ASSERT_EQ(size, String::cast(result)->Size());
+
+  // Fill in the characters.
+  for (int i = 0; i < chars; i++) {
+    String::cast(result)->Set(i, buffer->GetNext());
+  }
+  return result;
+}
+
+
+Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
+  AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+  int size = SeqAsciiString::SizeFor(length);
+  if (size > MaxHeapObjectSize()) {
+    space = LO_SPACE;
+  }
+
+  // Use AllocateRaw rather than Allocate because the object's size cannot be
+  // determined from the map.
+  Object* result = AllocateRaw(size, space);
+  if (result->IsFailure()) return result;
+
+  // Determine the map based on the string's length.
+  Map* map;
+  if (length <= String::kMaxShortStringSize) {
+    map = short_ascii_string_map();
+  } else if (length <= String::kMaxMediumStringSize) {
+    map = medium_ascii_string_map();
+  } else {
+    map = long_ascii_string_map();
+  }
+
+  // Partially initialize the object.
+  HeapObject::cast(result)->set_map(map);
+  String::cast(result)->set_length(length);
+  ASSERT_EQ(size, HeapObject::cast(result)->Size());
+  return result;
+}
+
+
+Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
+  AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+  int size = SeqTwoByteString::SizeFor(length);
+  if (size > MaxHeapObjectSize()) {
+    space = LO_SPACE;
+  }
+
+  // Use AllocateRaw rather than Allocate because the object's size cannot be
+  // determined from the map.
+  Object* result = AllocateRaw(size, space);
+  if (result->IsFailure()) return result;
+
+  // Determine the map based on the string's length.
+  Map* map;
+  if (length <= String::kMaxShortStringSize) {
+    map = short_string_map();
+  } else if (length <= String::kMaxMediumStringSize) {
+    map = medium_string_map();
+  } else {
+    map = long_string_map();
+  }
+
+  // Partially initialize the object.
+  HeapObject::cast(result)->set_map(map);
+  String::cast(result)->set_length(length);
+  ASSERT_EQ(size, HeapObject::cast(result)->Size());
+  return result;
+}
+
+
+Object* Heap::AllocateEmptyFixedArray() {
+  int size = FixedArray::SizeFor(0);
+  Object* result = AllocateRaw(size, OLD_DATA_SPACE);
+  if (result->IsFailure()) return result;
+  // Initialize the object.
+  reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
+  reinterpret_cast<Array*>(result)->set_length(0);
+  return result;
+}
+
+
+Object* Heap::AllocateRawFixedArray(int length) {
+  // Allocate the raw data for a fixed array.
+  int size = FixedArray::SizeFor(length);
+  return (size > MaxHeapObjectSize())
+      ? lo_space_->AllocateRawFixedArray(size)
+      : new_space_.AllocateRaw(size);
+}
+
+
+Object* Heap::CopyFixedArray(FixedArray* src) {
+  int len = src->length();
+  Object* obj = AllocateRawFixedArray(len);
+  if (obj->IsFailure()) return obj;
+  if (Heap::InNewSpace(obj)) {
+    HeapObject* dst = HeapObject::cast(obj);
+    CopyBlock(reinterpret_cast<Object**>(dst->address()),
+              reinterpret_cast<Object**>(src->address()),
+              FixedArray::SizeFor(len));
+    return obj;
+  }
+  HeapObject::cast(obj)->set_map(src->map());
+  FixedArray* result = FixedArray::cast(obj);
+  result->set_length(len);
+  // Copy the content
+  WriteBarrierMode mode = result->GetWriteBarrierMode();
+  for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
+  return result;
+}
+
+
+Object* Heap::AllocateFixedArray(int length) {
+  Object* result = AllocateRawFixedArray(length);
+  if (!result->IsFailure()) {
+    // Initialize header.
+    reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
+    FixedArray* array = FixedArray::cast(result);
+    array->set_length(length);
+    Object* value = undefined_value();
+    // Initialize body.
+    for (int index = 0; index < length; index++) {
+      array->set(index, value, SKIP_WRITE_BARRIER);
+    }
+  }
+  return result;
+}
+
+
+Object* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
+  ASSERT(empty_fixed_array()->IsFixedArray());
+  if (length == 0) return empty_fixed_array();
+
+  int size = FixedArray::SizeFor(length);
+  Object* result;
+  if (size > MaxHeapObjectSize()) {
+    result = lo_space_->AllocateRawFixedArray(size);
+  } else {
+    AllocationSpace space =
+        (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
+    result = AllocateRaw(size, space);
+  }
+  if (result->IsFailure()) return result;
+
+  // Initialize the object.
+  reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
+  FixedArray* array = FixedArray::cast(result);
+  array->set_length(length);
+  Object* value = undefined_value();
+  for (int index = 0; index < length; index++) {
+    array->set(index, value, SKIP_WRITE_BARRIER);
+  }
+  return array;
+}
+
+
+Object* Heap::AllocateFixedArrayWithHoles(int length) {
+  if (length == 0) return empty_fixed_array();
+  Object* result = AllocateRawFixedArray(length);
+  if (!result->IsFailure()) {
+    // Initialize header.
+    reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
+    FixedArray* array = FixedArray::cast(result);
+    array->set_length(length);
+    // Initialize body.
+    Object* value = the_hole_value();
+    for (int index = 0; index < length; index++)  {
+      array->set(index, value, SKIP_WRITE_BARRIER);
+    }
+  }
+  return result;
+}
+
+
+Object* Heap::AllocateHashTable(int length) {
+  Object* result = Heap::AllocateFixedArray(length);
+  if (result->IsFailure()) return result;
+  reinterpret_cast<Array*>(result)->set_map(hash_table_map());
+  ASSERT(result->IsDictionary());
+  return result;
+}
+
+
+Object* Heap::AllocateGlobalContext() {
+  Object* result = Heap::AllocateFixedArray(Context::GLOBAL_CONTEXT_SLOTS);
+  if (result->IsFailure()) return result;
+  Context* context = reinterpret_cast<Context*>(result);
+  context->set_map(global_context_map());
+  ASSERT(context->IsGlobalContext());
+  ASSERT(result->IsContext());
+  return result;
+}
+
+
+Object* Heap::AllocateFunctionContext(int length, JSFunction* function) {
+  ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
+  Object* result = Heap::AllocateFixedArray(length);
+  if (result->IsFailure()) return result;
+  Context* context = reinterpret_cast<Context*>(result);
+  context->set_map(context_map());
+  context->set_closure(function);
+  context->set_fcontext(context);
+  context->set_previous(NULL);
+  context->set_extension(NULL);
+  context->set_global(function->context()->global());
+  ASSERT(!context->IsGlobalContext());
+  ASSERT(context->is_function_context());
+  ASSERT(result->IsContext());
+  return result;
+}
+
+
+Object* Heap::AllocateWithContext(Context* previous, JSObject* extension) {
+  Object* result = Heap::AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
+  if (result->IsFailure()) return result;
+  Context* context = reinterpret_cast<Context*>(result);
+  context->set_map(context_map());
+  context->set_closure(previous->closure());
+  context->set_fcontext(previous->fcontext());
+  context->set_previous(previous);
+  context->set_extension(extension);
+  context->set_global(previous->global());
+  ASSERT(!context->IsGlobalContext());
+  ASSERT(!context->is_function_context());
+  ASSERT(result->IsContext());
+  return result;
+}
+
+
+Object* Heap::AllocateStruct(InstanceType type) {
+  Map* map;
+  switch (type) {
+#define MAKE_CASE(NAME, Name, name) case NAME##_TYPE: map = name##_map(); break;
+STRUCT_LIST(MAKE_CASE)
+#undef MAKE_CASE
+    default:
+      UNREACHABLE();
+      return Failure::InternalError();
+  }
+  int size = map->instance_size();
+  AllocationSpace space =
+      (size > MaxHeapObjectSize()) ? LO_SPACE : OLD_POINTER_SPACE;
+  Object* result = Heap::Allocate(map, space);
+  if (result->IsFailure()) return result;
+  Struct::cast(result)->InitializeBody(size);
+  return result;
+}
+
+
+#ifdef DEBUG
+
+void Heap::Print() {
+  if (!HasBeenSetup()) return;
+  Top::PrintStack();
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) space->Print();
+}
+
+
+void Heap::ReportCodeStatistics(const char* title) {
+  PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
+  PagedSpace::ResetCodeStatistics();
+  // We do not look for code in new space, map space, or old space.  If code
+  // somehow ends up in those spaces, we would miss it here.
+  code_space_->CollectCodeStatistics();
+  lo_space_->CollectCodeStatistics();
+  PagedSpace::ReportCodeStatistics();
+}
+
+
+// This function expects that NewSpace's allocated objects histogram is
+// populated (via a call to CollectStatistics or else as a side effect of a
+// just-completed scavenge collection).
+void Heap::ReportHeapStatistics(const char* title) {
+  USE(title);
+  PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
+         title, gc_count_);
+  PrintF("mark-compact GC : %d\n", mc_count_);
+  PrintF("promoted_space_limit_ %d\n", promoted_space_limit_);
+
+  PrintF("\n");
+  PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
+  GlobalHandles::PrintStats();
+  PrintF("\n");
+
+  PrintF("Heap statistics : ");
+  MemoryAllocator::ReportStatistics();
+  PrintF("To space : ");
+  new_space_.ReportStatistics();
+  PrintF("Old pointer space : ");
+  old_pointer_space_->ReportStatistics();
+  PrintF("Old data space : ");
+  old_data_space_->ReportStatistics();
+  PrintF("Code space : ");
+  code_space_->ReportStatistics();
+  PrintF("Map space : ");
+  map_space_->ReportStatistics();
+  PrintF("Large object space : ");
+  lo_space_->ReportStatistics();
+  PrintF(">>>>>> ========================================= >>>>>>\n");
+}
+
+#endif  // DEBUG
+
+bool Heap::Contains(HeapObject* value) {
+  return Contains(value->address());
+}
+
+
+bool Heap::Contains(Address addr) {
+  if (OS::IsOutsideAllocatedSpace(addr)) return false;
+  return HasBeenSetup() &&
+    (new_space_.ToSpaceContains(addr) ||
+     old_pointer_space_->Contains(addr) ||
+     old_data_space_->Contains(addr) ||
+     code_space_->Contains(addr) ||
+     map_space_->Contains(addr) ||
+     lo_space_->SlowContains(addr));
+}
+
+
+bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
+  return InSpace(value->address(), space);
+}
+
+
+bool Heap::InSpace(Address addr, AllocationSpace space) {
+  if (OS::IsOutsideAllocatedSpace(addr)) return false;
+  if (!HasBeenSetup()) return false;
+
+  switch (space) {
+    case NEW_SPACE:
+      return new_space_.ToSpaceContains(addr);
+    case OLD_POINTER_SPACE:
+      return old_pointer_space_->Contains(addr);
+    case OLD_DATA_SPACE:
+      return old_data_space_->Contains(addr);
+    case CODE_SPACE:
+      return code_space_->Contains(addr);
+    case MAP_SPACE:
+      return map_space_->Contains(addr);
+    case LO_SPACE:
+      return lo_space_->SlowContains(addr);
+  }
+
+  return false;
+}
+
+
+#ifdef DEBUG
+void Heap::Verify() {
+  ASSERT(HasBeenSetup());
+
+  VerifyPointersVisitor visitor;
+  Heap::IterateRoots(&visitor);
+
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) {
+    space->Verify();
+  }
+}
+#endif  // DEBUG
+
+
+Object* Heap::LookupSymbol(Vector<const char> string) {
+  Object* symbol = NULL;
+  Object* new_table =
+      SymbolTable::cast(symbol_table_)->LookupSymbol(string, &symbol);
+  if (new_table->IsFailure()) return new_table;
+  symbol_table_ = new_table;
+  ASSERT(symbol != NULL);
+  return symbol;
+}
+
+
+Object* Heap::LookupSymbol(String* string) {
+  if (string->IsSymbol()) return string;
+  Object* symbol = NULL;
+  Object* new_table =
+      SymbolTable::cast(symbol_table_)->LookupString(string, &symbol);
+  if (new_table->IsFailure()) return new_table;
+  symbol_table_ = new_table;
+  ASSERT(symbol != NULL);
+  return symbol;
+}
+
+
+bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
+  if (string->IsSymbol()) {
+    *symbol = string;
+    return true;
+  }
+  SymbolTable* table = SymbolTable::cast(symbol_table_);
+  return table->LookupSymbolIfExists(string, symbol);
+}
+
+
+#ifdef DEBUG
+void Heap::ZapFromSpace() {
+  ASSERT(HAS_HEAP_OBJECT_TAG(kFromSpaceZapValue));
+  for (Address a = new_space_.FromSpaceLow();
+       a < new_space_.FromSpaceHigh();
+       a += kPointerSize) {
+    Memory::Address_at(a) = kFromSpaceZapValue;
+  }
+}
+#endif  // DEBUG
+
+
+void Heap::IterateRSetRange(Address object_start,
+                            Address object_end,
+                            Address rset_start,
+                            ObjectSlotCallback copy_object_func) {
+  Address object_address = object_start;
+  Address rset_address = rset_start;
+
+  // Loop over all the pointers in [object_start, object_end).
+  while (object_address < object_end) {
+    uint32_t rset_word = Memory::uint32_at(rset_address);
+    if (rset_word != 0) {
+      uint32_t result_rset = rset_word;
+      for (uint32_t bitmask = 1; bitmask != 0; bitmask = bitmask << 1) {
+        // Do not dereference pointers at or past object_end.
+        if ((rset_word & bitmask) != 0 && object_address < object_end) {
+          Object** object_p = reinterpret_cast<Object**>(object_address);
+          if (Heap::InNewSpace(*object_p)) {
+            copy_object_func(reinterpret_cast<HeapObject**>(object_p));
+          }
+          // If this pointer does not need to be remembered anymore, clear
+          // the remembered set bit.
+          if (!Heap::InNewSpace(*object_p)) result_rset &= ~bitmask;
+        }
+        object_address += kPointerSize;
+      }
+      // Update the remembered set if it has changed.
+      if (result_rset != rset_word) {
+        Memory::uint32_at(rset_address) = result_rset;
+      }
+    } else {
+      // No bits in the word were set.  This is the common case.
+      object_address += kPointerSize * kBitsPerInt;
+    }
+    rset_address += kIntSize;
+  }
+}
+
+
+void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) {
+  ASSERT(Page::is_rset_in_use());
+  ASSERT(space == old_pointer_space_ || space == map_space_);
+
+  PageIterator it(space, PageIterator::PAGES_IN_USE);
+  while (it.has_next()) {
+    Page* page = it.next();
+    IterateRSetRange(page->ObjectAreaStart(), page->AllocationTop(),
+                     page->RSetStart(), copy_object_func);
+  }
+}
+
+
+#ifdef DEBUG
+#define SYNCHRONIZE_TAG(tag) v->Synchronize(tag)
+#else
+#define SYNCHRONIZE_TAG(tag)
+#endif
+
+void Heap::IterateRoots(ObjectVisitor* v) {
+  IterateStrongRoots(v);
+  v->VisitPointer(reinterpret_cast<Object**>(&symbol_table_));
+  SYNCHRONIZE_TAG("symbol_table");
+}
+
+
+void Heap::IterateStrongRoots(ObjectVisitor* v) {
+#define ROOT_ITERATE(type, name) \
+  v->VisitPointer(bit_cast<Object**, type**>(&name##_));
+  STRONG_ROOT_LIST(ROOT_ITERATE);
+#undef ROOT_ITERATE
+  SYNCHRONIZE_TAG("strong_root_list");
+
+#define STRUCT_MAP_ITERATE(NAME, Name, name) \
+  v->VisitPointer(bit_cast<Object**, Map**>(&name##_map_));
+  STRUCT_LIST(STRUCT_MAP_ITERATE);
+#undef STRUCT_MAP_ITERATE
+  SYNCHRONIZE_TAG("struct_map");
+
+#define SYMBOL_ITERATE(name, string) \
+  v->VisitPointer(bit_cast<Object**, String**>(&name##_));
+  SYMBOL_LIST(SYMBOL_ITERATE)
+#undef SYMBOL_ITERATE
+  SYNCHRONIZE_TAG("symbol");
+
+  Bootstrapper::Iterate(v);
+  SYNCHRONIZE_TAG("bootstrapper");
+  Top::Iterate(v);
+  SYNCHRONIZE_TAG("top");
+  Debug::Iterate(v);
+  SYNCHRONIZE_TAG("debug");
+  CompilationCache::Iterate(v);
+  SYNCHRONIZE_TAG("compilationcache");
+
+  // Iterate over local handles in handle scopes.
+  HandleScopeImplementer::Iterate(v);
+  SYNCHRONIZE_TAG("handlescope");
+
+  // Iterate over the builtin code objects and code stubs in the heap. Note
+  // that it is not strictly necessary to iterate over code objects on
+  // scavenge collections.  We still do it here because this same function
+  // is used by the mark-sweep collector and the deserializer.
+  Builtins::IterateBuiltins(v);
+  SYNCHRONIZE_TAG("builtins");
+
+  // Iterate over global handles.
+  GlobalHandles::IterateRoots(v);
+  SYNCHRONIZE_TAG("globalhandles");
+
+  // Iterate over pointers being held by inactive threads.
+  ThreadManager::Iterate(v);
+  SYNCHRONIZE_TAG("threadmanager");
+}
+#undef SYNCHRONIZE_TAG
+
+
+// Flag is set when the heap has been configured.  The heap can be repeatedly
+// configured through the API until it is setup.
+static bool heap_configured = false;
+
+// TODO(1236194): Since the heap size is configurable on the command line
+// and through the API, we should gracefully handle the case that the heap
+// size is not big enough to fit all the initial objects.
+bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
+  if (HasBeenSetup()) return false;
+
+  if (semispace_size > 0) semispace_size_ = semispace_size;
+  if (old_gen_size > 0) old_generation_size_ = old_gen_size;
+
+  // The new space size must be a power of two to support single-bit testing
+  // for containment.
+  semispace_size_ = RoundUpToPowerOf2(semispace_size_);
+  initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
+  young_generation_size_ = 2 * semispace_size_;
+
+  // The old generation is paged.
+  old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize);
+
+  heap_configured = true;
+  return true;
+}
+
+
+bool Heap::ConfigureHeapDefault() {
+  return ConfigureHeap(FLAG_new_space_size, FLAG_old_space_size);
+}
+
+
+int Heap::PromotedSpaceSize() {
+  return old_pointer_space_->Size()
+      + old_data_space_->Size()
+      + code_space_->Size()
+      + map_space_->Size()
+      + lo_space_->Size();
+}
+
+
+int Heap::PromotedExternalMemorySize() {
+  if (amount_of_external_allocated_memory_
+      <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
+  return amount_of_external_allocated_memory_
+      - amount_of_external_allocated_memory_at_last_global_gc_;
+}
+
+
+bool Heap::Setup(bool create_heap_objects) {
+  // Initialize heap spaces and initial maps and objects. Whenever something
+  // goes wrong, just return false. The caller should check the results and
+  // call Heap::TearDown() to release allocated memory.
+  //
+  // If the heap is not yet configured (eg, through the API), configure it.
+  // Configuration is based on the flags new-space-size (really the semispace
+  // size) and old-space-size if set or the initial values of semispace_size_
+  // and old_generation_size_ otherwise.
+  if (!heap_configured) {
+    if (!ConfigureHeapDefault()) return false;
+  }
+
+  // Setup memory allocator and allocate an initial chunk of memory.  The
+  // initial chunk is double the size of the new space to ensure that we can
+  // find a pair of semispaces that are contiguous and aligned to their size.
+  if (!MemoryAllocator::Setup(MaxCapacity())) return false;
+  void* chunk
+      = MemoryAllocator::ReserveInitialChunk(2 * young_generation_size_);
+  if (chunk == NULL) return false;
+
+  // Put the initial chunk of the old space at the start of the initial
+  // chunk, then the two new space semispaces, then the initial chunk of
+  // code space.  Align the pair of semispaces to their size, which must be
+  // a power of 2.
+  ASSERT(IsPowerOf2(young_generation_size_));
+  Address code_space_start = reinterpret_cast<Address>(chunk);
+  Address new_space_start = RoundUp(code_space_start, young_generation_size_);
+  Address old_space_start = new_space_start + young_generation_size_;
+  int code_space_size = new_space_start - code_space_start;
+  int old_space_size = young_generation_size_ - code_space_size;
+
+  // Initialize new space.
+  if (!new_space_.Setup(new_space_start, young_generation_size_)) return false;
+
+  // Initialize old space, set the maximum capacity to the old generation
+  // size. It will not contain code.
+  old_pointer_space_ =
+      new OldSpace(old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE);
+  if (old_pointer_space_ == NULL) return false;
+  if (!old_pointer_space_->Setup(old_space_start, old_space_size >> 1)) {
+    return false;
+  }
+  old_data_space_ =
+      new OldSpace(old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE);
+  if (old_data_space_ == NULL) return false;
+  if (!old_data_space_->Setup(old_space_start + (old_space_size >> 1),
+                              old_space_size >> 1)) {
+    return false;
+  }
+
+  // Initialize the code space, set its maximum capacity to the old
+  // generation size. It needs executable memory.
+  code_space_ =
+      new OldSpace(old_generation_size_, CODE_SPACE, EXECUTABLE);
+  if (code_space_ == NULL) return false;
+  if (!code_space_->Setup(code_space_start, code_space_size)) return false;
+
+  // Initialize map space.
+  map_space_ = new MapSpace(kMaxMapSpaceSize, MAP_SPACE);
+  if (map_space_ == NULL) return false;
+  // Setting up a paged space without giving it a virtual memory range big
+  // enough to hold at least a page will cause it to allocate.
+  if (!map_space_->Setup(NULL, 0)) return false;
+
+  // The large object code space may contain code or data.  We set the memory
+  // to be non-executable here for safety, but this means we need to enable it
+  // explicitly when allocating large code objects.
+  lo_space_ = new LargeObjectSpace(LO_SPACE);
+  if (lo_space_ == NULL) return false;
+  if (!lo_space_->Setup()) return false;
+
+  if (create_heap_objects) {
+    // Create initial maps.
+    if (!CreateInitialMaps()) return false;
+    if (!CreateApiObjects()) return false;
+
+    // Create initial objects
+    if (!CreateInitialObjects()) return false;
+  }
+
+  LOG(IntEvent("heap-capacity", Capacity()));
+  LOG(IntEvent("heap-available", Available()));
+
+  return true;
+}
+
+
+void Heap::TearDown() {
+  GlobalHandles::TearDown();
+
+  new_space_.TearDown();
+
+  if (old_pointer_space_ != NULL) {
+    old_pointer_space_->TearDown();
+    delete old_pointer_space_;
+    old_pointer_space_ = NULL;
+  }
+
+  if (old_data_space_ != NULL) {
+    old_data_space_->TearDown();
+    delete old_data_space_;
+    old_data_space_ = NULL;
+  }
+
+  if (code_space_ != NULL) {
+    code_space_->TearDown();
+    delete code_space_;
+    code_space_ = NULL;
+  }
+
+  if (map_space_ != NULL) {
+    map_space_->TearDown();
+    delete map_space_;
+    map_space_ = NULL;
+  }
+
+  if (lo_space_ != NULL) {
+    lo_space_->TearDown();
+    delete lo_space_;
+    lo_space_ = NULL;
+  }
+
+  MemoryAllocator::TearDown();
+}
+
+
+void Heap::Shrink() {
+  // Try to shrink map, old, and code spaces.
+  map_space_->Shrink();
+  old_pointer_space_->Shrink();
+  old_data_space_->Shrink();
+  code_space_->Shrink();
+}
+
+
+#ifdef DEBUG
+
+class PrintHandleVisitor: public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object** end) {
+    for (Object** p = start; p < end; p++)
+      PrintF("  handle %p to %p\n", p, *p);
+  }
+};
+
+void Heap::PrintHandles() {
+  PrintF("Handles:\n");
+  PrintHandleVisitor v;
+  HandleScopeImplementer::Iterate(&v);
+}
+
+#endif
+
+
+Space* AllSpaces::next() {
+  switch (counter_++) {
+    case NEW_SPACE:
+      return Heap::new_space();
+    case OLD_POINTER_SPACE:
+      return Heap::old_pointer_space();
+    case OLD_DATA_SPACE:
+      return Heap::old_data_space();
+    case CODE_SPACE:
+      return Heap::code_space();
+    case MAP_SPACE:
+      return Heap::map_space();
+    case LO_SPACE:
+      return Heap::lo_space();
+    default:
+      return NULL;
+  }
+}
+
+
+PagedSpace* PagedSpaces::next() {
+  switch (counter_++) {
+    case OLD_POINTER_SPACE:
+      return Heap::old_pointer_space();
+    case OLD_DATA_SPACE:
+      return Heap::old_data_space();
+    case CODE_SPACE:
+      return Heap::code_space();
+    case MAP_SPACE:
+      return Heap::map_space();
+    default:
+      return NULL;
+  }
+}
+
+
+
+OldSpace* OldSpaces::next() {
+  switch (counter_++) {
+    case OLD_POINTER_SPACE:
+      return Heap::old_pointer_space();
+    case OLD_DATA_SPACE:
+      return Heap::old_data_space();
+    case CODE_SPACE:
+      return Heap::code_space();
+    default:
+      return NULL;
+  }
+}
+
+
+SpaceIterator::SpaceIterator() : current_space_(FIRST_SPACE), iterator_(NULL) {
+}
+
+
+SpaceIterator::~SpaceIterator() {
+  // Delete active iterator if any.
+  delete iterator_;
+}
+
+
+bool SpaceIterator::has_next() {
+  // Iterate until no more spaces.
+  return current_space_ != LAST_SPACE;
+}
+
+
+ObjectIterator* SpaceIterator::next() {
+  if (iterator_ != NULL) {
+    delete iterator_;
+    iterator_ = NULL;
+    // Move to the next space
+    current_space_++;
+    if (current_space_ > LAST_SPACE) {
+      return NULL;
+    }
+  }
+
+  // Return iterator for the new current space.
+  return CreateIterator();
+}
+
+
+// Create an iterator for the space to iterate.
+ObjectIterator* SpaceIterator::CreateIterator() {
+  ASSERT(iterator_ == NULL);
+
+  switch (current_space_) {
+    case NEW_SPACE:
+      iterator_ = new SemiSpaceIterator(Heap::new_space());
+      break;
+    case OLD_POINTER_SPACE:
+      iterator_ = new HeapObjectIterator(Heap::old_pointer_space());
+      break;
+    case OLD_DATA_SPACE:
+      iterator_ = new HeapObjectIterator(Heap::old_data_space());
+      break;
+    case CODE_SPACE:
+      iterator_ = new HeapObjectIterator(Heap::code_space());
+      break;
+    case MAP_SPACE:
+      iterator_ = new HeapObjectIterator(Heap::map_space());
+      break;
+    case LO_SPACE:
+      iterator_ = new LargeObjectIterator(Heap::lo_space());
+      break;
+  }
+
+  // Return the newly allocated iterator;
+  ASSERT(iterator_ != NULL);
+  return iterator_;
+}
+
+
+HeapIterator::HeapIterator() {
+  Init();
+}
+
+
+HeapIterator::~HeapIterator() {
+  Shutdown();
+}
+
+
+void HeapIterator::Init() {
+  // Start the iteration.
+  space_iterator_ = new SpaceIterator();
+  object_iterator_ = space_iterator_->next();
+}
+
+
+void HeapIterator::Shutdown() {
+  // Make sure the last iterator is deallocated.
+  delete space_iterator_;
+  space_iterator_ = NULL;
+  object_iterator_ = NULL;
+}
+
+
+bool HeapIterator::has_next() {
+  // No iterator means we are done.
+  if (object_iterator_ == NULL) return false;
+
+  if (object_iterator_->has_next_object()) {
+    // If the current iterator has more objects we are fine.
+    return true;
+  } else {
+    // Go though the spaces looking for one that has objects.
+    while (space_iterator_->has_next()) {
+      object_iterator_ = space_iterator_->next();
+      if (object_iterator_->has_next_object()) {
+        return true;
+      }
+    }
+  }
+  // Done with the last space.
+  object_iterator_ = NULL;
+  return false;
+}
+
+
+HeapObject* HeapIterator::next() {
+  if (has_next()) {
+    return object_iterator_->next_object();
+  } else {
+    return NULL;
+  }
+}
+
+
+void HeapIterator::reset() {
+  // Restart the iterator.
+  Shutdown();
+  Init();
+}
+
+
+//
+// HeapProfiler class implementation.
+//
+#ifdef ENABLE_LOGGING_AND_PROFILING
+void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
+  InstanceType type = obj->map()->instance_type();
+  ASSERT(0 <= type && type <= LAST_TYPE);
+  info[type].increment_number(1);
+  info[type].increment_bytes(obj->Size());
+}
+#endif
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+void HeapProfiler::WriteSample() {
+  LOG(HeapSampleBeginEvent("Heap", "allocated"));
+
+  HistogramInfo info[LAST_TYPE+1];
+#define DEF_TYPE_NAME(name) info[name].set_name(#name);
+  INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
+#undef DEF_TYPE_NAME
+
+  HeapIterator iterator;
+  while (iterator.has_next()) {
+    CollectStats(iterator.next(), info);
+  }
+
+  // Lump all the string types together.
+  int string_number = 0;
+  int string_bytes = 0;
+#define INCREMENT_SIZE(type, size, name)   \
+    string_number += info[type].number();  \
+    string_bytes += info[type].bytes();
+  STRING_TYPE_LIST(INCREMENT_SIZE)
+#undef INCREMENT_SIZE
+  if (string_bytes > 0) {
+    LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
+  }
+
+  for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
+    if (info[i].bytes() > 0) {
+      LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
+                              info[i].bytes()));
+    }
+  }
+
+  LOG(HeapSampleEndEvent("Heap", "allocated"));
+}
+
+
+#endif
+
+
+
+#ifdef DEBUG
+
+static bool search_for_any_global;
+static Object* search_target;
+static bool found_target;
+static List<Object*> object_stack(20);
+
+
+// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
+static const int kMarkTag = 2;
+
+static void MarkObjectRecursively(Object** p);
+class MarkObjectVisitor : public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object** end) {
+    // Copy all HeapObject pointers in [start, end)
+    for (Object** p = start; p < end; p++) {
+      if ((*p)->IsHeapObject())
+        MarkObjectRecursively(p);
+    }
+  }
+};
+
+static MarkObjectVisitor mark_visitor;
+
+static void MarkObjectRecursively(Object** p) {
+  if (!(*p)->IsHeapObject()) return;
+
+  HeapObject* obj = HeapObject::cast(*p);
+
+  Object* map = obj->map();
+
+  if (!map->IsHeapObject()) return;  // visited before
+
+  if (found_target) return;  // stop if target found
+  object_stack.Add(obj);
+  if ((search_for_any_global && obj->IsJSGlobalObject()) ||
+      (!search_for_any_global && (obj == search_target))) {
+    found_target = true;
+    return;
+  }
+
+  if (obj->IsCode()) {
+    Code::cast(obj)->ConvertICTargetsFromAddressToObject();
+  }
+
+  // not visited yet
+  Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
+
+  Address map_addr = map_p->address();
+
+  obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag));
+
+  MarkObjectRecursively(&map);
+
+  obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
+                   &mark_visitor);
+
+  if (!found_target)  // don't pop if found the target
+    object_stack.RemoveLast();
+}
+
+
+static void UnmarkObjectRecursively(Object** p);
+class UnmarkObjectVisitor : public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object** end) {
+    // Copy all HeapObject pointers in [start, end)
+    for (Object** p = start; p < end; p++) {
+      if ((*p)->IsHeapObject())
+        UnmarkObjectRecursively(p);
+    }
+  }
+};
+
+static UnmarkObjectVisitor unmark_visitor;
+
+static void UnmarkObjectRecursively(Object** p) {
+  if (!(*p)->IsHeapObject()) return;
+
+  HeapObject* obj = HeapObject::cast(*p);
+
+  Object* map = obj->map();
+
+  if (map->IsHeapObject()) return;  // unmarked already
+
+  Address map_addr = reinterpret_cast<Address>(map);
+
+  map_addr -= kMarkTag;
+
+  ASSERT_TAG_ALIGNED(map_addr);
+
+  HeapObject* map_p = HeapObject::FromAddress(map_addr);
+
+  obj->set_map(reinterpret_cast<Map*>(map_p));
+
+  UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
+
+  obj->IterateBody(Map::cast(map_p)->instance_type(),
+                   obj->SizeFromMap(Map::cast(map_p)),
+                   &unmark_visitor);
+
+  if (obj->IsCode()) {
+    Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
+  }
+}
+
+
+static void MarkRootObjectRecursively(Object** root) {
+  if (search_for_any_global) {
+    ASSERT(search_target == NULL);
+  } else {
+    ASSERT(search_target->IsHeapObject());
+  }
+  found_target = false;
+  object_stack.Clear();
+
+  MarkObjectRecursively(root);
+  UnmarkObjectRecursively(root);
+
+  if (found_target) {
+    PrintF("=====================================\n");
+    PrintF("====        Path to object       ====\n");
+    PrintF("=====================================\n\n");
+
+    ASSERT(!object_stack.is_empty());
+    for (int i = 0; i < object_stack.length(); i++) {
+      if (i > 0) PrintF("\n     |\n     |\n     V\n\n");
+      Object* obj = object_stack[i];
+      obj->Print();
+    }
+    PrintF("=====================================\n");
+  }
+}
+
+
+// Helper class for visiting HeapObjects recursively.
+class MarkRootVisitor: public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object** end) {
+    // Visit all HeapObject pointers in [start, end)
+    for (Object** p = start; p < end; p++) {
+      if ((*p)->IsHeapObject())
+        MarkRootObjectRecursively(p);
+    }
+  }
+};
+
+
+// Triggers a depth-first traversal of reachable objects from roots
+// and finds a path to a specific heap object and prints it.
+void Heap::TracePathToObject() {
+  search_target = NULL;
+  search_for_any_global = false;
+
+  MarkRootVisitor root_visitor;
+  IterateRoots(&root_visitor);
+}
+
+
+// Triggers a depth-first traversal of reachable objects from roots
+// and finds a path to any global object and prints it. Useful for
+// determining the source for leaks of global objects.
+void Heap::TracePathToGlobal() {
+  search_target = NULL;
+  search_for_any_global = true;
+
+  MarkRootVisitor root_visitor;
+  IterateRoots(&root_visitor);
+}
+#endif
+
+
+GCTracer::GCTracer()
+    : start_time_(0.0),
+      start_size_(0.0),
+      gc_count_(0),
+      full_gc_count_(0),
+      is_compacting_(false),
+      marked_count_(0) {
+  // These two fields reflect the state of the previous full collection.
+  // Set them before they are changed by the collector.
+  previous_has_compacted_ = MarkCompactCollector::HasCompacted();
+  previous_marked_count_ = MarkCompactCollector::previous_marked_count();
+  if (!FLAG_trace_gc) return;
+  start_time_ = OS::TimeCurrentMillis();
+  start_size_ = SizeOfHeapObjects();
+}
+
+
+GCTracer::~GCTracer() {
+  if (!FLAG_trace_gc) return;
+  // Printf ONE line iff flag is set.
+  PrintF("%s %.1f -> %.1f MB, %d ms.\n",
+         CollectorString(),
+         start_size_, SizeOfHeapObjects(),
+         static_cast<int>(OS::TimeCurrentMillis() - start_time_));
+}
+
+
+const char* GCTracer::CollectorString() {
+  switch (collector_) {
+    case SCAVENGER:
+      return "Scavenge";
+    case MARK_COMPACTOR:
+      return MarkCompactCollector::HasCompacted() ? "Mark-compact"
+                                                  : "Mark-sweep";
+  }
+  return "Unknown GC";
+}
+
+
+#ifdef DEBUG
+bool Heap::GarbageCollectionGreedyCheck() {
+  ASSERT(FLAG_gc_greedy);
+  if (Bootstrapper::IsActive()) return true;
+  if (disallow_allocation_failure()) return true;
+  return CollectGarbage(0, NEW_SPACE);
+}
+#endif
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/heap.h b/regexp2000/src/heap.h
new file mode 100644 (file)
index 0000000..87b972d
--- /dev/null
@@ -0,0 +1,1207 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HEAP_H_
+#define V8_HEAP_H_
+
+namespace v8 { namespace internal {
+
+// Defines all the roots in Heap.
+#define STRONG_ROOT_LIST(V)                             \
+  V(Map, meta_map)                                      \
+  V(Map, heap_number_map)                               \
+  V(Map, short_string_map)                              \
+  V(Map, medium_string_map)                             \
+  V(Map, long_string_map)                               \
+  V(Map, short_ascii_string_map)                        \
+  V(Map, medium_ascii_string_map)                       \
+  V(Map, long_ascii_string_map)                         \
+  V(Map, short_symbol_map)                              \
+  V(Map, medium_symbol_map)                             \
+  V(Map, long_symbol_map)                               \
+  V(Map, short_ascii_symbol_map)                        \
+  V(Map, medium_ascii_symbol_map)                       \
+  V(Map, long_ascii_symbol_map)                         \
+  V(Map, short_cons_symbol_map)                         \
+  V(Map, medium_cons_symbol_map)                        \
+  V(Map, long_cons_symbol_map)                          \
+  V(Map, short_cons_ascii_symbol_map)                   \
+  V(Map, medium_cons_ascii_symbol_map)                  \
+  V(Map, long_cons_ascii_symbol_map)                    \
+  V(Map, short_sliced_symbol_map)                       \
+  V(Map, medium_sliced_symbol_map)                      \
+  V(Map, long_sliced_symbol_map)                        \
+  V(Map, short_sliced_ascii_symbol_map)                 \
+  V(Map, medium_sliced_ascii_symbol_map)                \
+  V(Map, long_sliced_ascii_symbol_map)                  \
+  V(Map, short_external_symbol_map)                     \
+  V(Map, medium_external_symbol_map)                    \
+  V(Map, long_external_symbol_map)                      \
+  V(Map, short_external_ascii_symbol_map)               \
+  V(Map, medium_external_ascii_symbol_map)              \
+  V(Map, long_external_ascii_symbol_map)                \
+  V(Map, short_cons_string_map)                         \
+  V(Map, medium_cons_string_map)                        \
+  V(Map, long_cons_string_map)                          \
+  V(Map, short_cons_ascii_string_map)                   \
+  V(Map, medium_cons_ascii_string_map)                  \
+  V(Map, long_cons_ascii_string_map)                    \
+  V(Map, short_sliced_string_map)                       \
+  V(Map, medium_sliced_string_map)                      \
+  V(Map, long_sliced_string_map)                        \
+  V(Map, short_sliced_ascii_string_map)                 \
+  V(Map, medium_sliced_ascii_string_map)                \
+  V(Map, long_sliced_ascii_string_map)                  \
+  V(Map, short_external_string_map)                     \
+  V(Map, medium_external_string_map)                    \
+  V(Map, long_external_string_map)                      \
+  V(Map, short_external_ascii_string_map)               \
+  V(Map, medium_external_ascii_string_map)              \
+  V(Map, long_external_ascii_string_map)                \
+  V(Map, undetectable_short_string_map)                 \
+  V(Map, undetectable_medium_string_map)                \
+  V(Map, undetectable_long_string_map)                  \
+  V(Map, undetectable_short_ascii_string_map)           \
+  V(Map, undetectable_medium_ascii_string_map)          \
+  V(Map, undetectable_long_ascii_string_map)            \
+  V(Map, byte_array_map)                                \
+  V(Map, fixed_array_map)                               \
+  V(Map, hash_table_map)                                \
+  V(Map, context_map)                                   \
+  V(Map, global_context_map)                            \
+  V(Map, code_map)                                      \
+  V(Map, oddball_map)                                   \
+  V(Map, boilerplate_function_map)                      \
+  V(Map, shared_function_info_map)                      \
+  V(Map, proxy_map)                                     \
+  V(Map, one_word_filler_map)                           \
+  V(Map, two_word_filler_map)                           \
+  V(Object, nan_value)                                  \
+  V(Object, undefined_value)                            \
+  V(Object, minus_zero_value)                           \
+  V(Object, null_value)                                 \
+  V(Object, true_value)                                 \
+  V(Object, false_value)                                \
+  V(String, empty_string)                               \
+  V(FixedArray, empty_fixed_array)                      \
+  V(DescriptorArray, empty_descriptor_array)            \
+  V(Object, the_hole_value)                             \
+  V(Map, neander_map)                                   \
+  V(JSObject, message_listeners)                        \
+  V(Proxy, prototype_accessors)                         \
+  V(JSObject, debug_event_listeners)                    \
+  V(Dictionary, code_stubs)                             \
+  V(Dictionary, non_monomorphic_cache)                  \
+  V(Code, js_entry_code)                                \
+  V(Code, js_construct_entry_code)                      \
+  V(Code, c_entry_code)                                 \
+  V(Code, c_entry_debug_break_code)                     \
+  V(FixedArray, number_string_cache)                    \
+  V(FixedArray, single_character_string_cache)          \
+  V(FixedArray, natives_source_cache)                   \
+  V(Object, keyed_lookup_cache)
+
+
+#define ROOT_LIST(V)                                  \
+  STRONG_ROOT_LIST(V)                                 \
+  V(Object, symbol_table)
+
+#define SYMBOL_LIST(V)                                                   \
+  V(Array_symbol, "Array")                                               \
+  V(Object_symbol, "Object")                                             \
+  V(Proto_symbol, "__proto__")                                           \
+  V(StringImpl_symbol, "StringImpl")                                     \
+  V(arguments_symbol, "arguments")                                       \
+  V(Arguments_symbol, "Arguments")                                       \
+  V(arguments_shadow_symbol, ".arguments")                               \
+  V(call_symbol, "call")                                                 \
+  V(apply_symbol, "apply")                                               \
+  V(caller_symbol, "caller")                                             \
+  V(boolean_symbol, "boolean")                                           \
+  V(Boolean_symbol, "Boolean")                                           \
+  V(callee_symbol, "callee")                                             \
+  V(constructor_symbol, "constructor")                                   \
+  V(code_symbol, ".code")                                                \
+  V(result_symbol, ".result")                                            \
+  V(catch_var_symbol, ".catch-var")                                      \
+  V(empty_symbol, "")                                                    \
+  V(eval_symbol, "eval")                                                 \
+  V(function_symbol, "function")                                         \
+  V(length_symbol, "length")                                             \
+  V(name_symbol, "name")                                                 \
+  V(number_symbol, "number")                                             \
+  V(Number_symbol, "Number")                                             \
+  V(RegExp_symbol, "RegExp")                                             \
+  V(object_symbol, "object")                                             \
+  V(prototype_symbol, "prototype")                                       \
+  V(string_symbol, "string")                                             \
+  V(String_symbol, "String")                                             \
+  V(Date_symbol, "Date")                                                 \
+  V(this_symbol, "this")                                                 \
+  V(to_string_symbol, "toString")                                        \
+  V(char_at_symbol, "CharAt")                                            \
+  V(undefined_symbol, "undefined")                                       \
+  V(value_of_symbol, "valueOf")                                          \
+  V(CreateObjectLiteralBoilerplate_symbol, "CreateObjectLiteralBoilerplate") \
+  V(CreateArrayLiteral_symbol, "CreateArrayLiteral")                     \
+  V(InitializeVarGlobal_symbol, "InitializeVarGlobal")                   \
+  V(InitializeConstGlobal_symbol, "InitializeConstGlobal")               \
+  V(stack_overflow_symbol, "kStackOverflowBoilerplate")                  \
+  V(illegal_access_symbol, "illegal access")                             \
+  V(out_of_memory_symbol, "out-of-memory")                               \
+  V(illegal_execution_state_symbol, "illegal execution state")           \
+  V(get_symbol, "get")                                                   \
+  V(set_symbol, "set")                                                   \
+  V(function_class_symbol, "Function")                                   \
+  V(illegal_argument_symbol, "illegal argument")                         \
+  V(MakeReferenceError_symbol, "MakeReferenceError")                     \
+  V(MakeSyntaxError_symbol, "MakeSyntaxError")                           \
+  V(MakeTypeError_symbol, "MakeTypeError")                               \
+  V(invalid_lhs_in_assignment_symbol, "invalid_lhs_in_assignment")       \
+  V(invalid_lhs_in_for_in_symbol, "invalid_lhs_in_for_in")               \
+  V(invalid_lhs_in_postfix_op_symbol, "invalid_lhs_in_postfix_op")       \
+  V(invalid_lhs_in_prefix_op_symbol, "invalid_lhs_in_prefix_op")         \
+  V(illegal_return_symbol, "illegal_return")                             \
+  V(illegal_break_symbol, "illegal_break")                               \
+  V(illegal_continue_symbol, "illegal_continue")                         \
+  V(unknown_label_symbol, "unknown_label")                               \
+  V(redeclaration_symbol, "redeclaration")                               \
+  V(failure_symbol, "<failure>")                                         \
+  V(space_symbol, " ")                                                   \
+  V(exec_symbol, "exec")                                                 \
+  V(zero_symbol, "0")
+
+
+// Forward declaration of the GCTracer class.
+class GCTracer;
+
+
+// The all static Heap captures the interface to the global object heap.
+// All JavaScript contexts by this process share the same object heap.
+
+class Heap : public AllStatic {
+ public:
+  // Configure heap size before setup. Return false if the heap has been
+  // setup already.
+  static bool ConfigureHeap(int semispace_size, int old_gen_size);
+  static bool ConfigureHeapDefault();
+
+  // Initializes the global object heap. If create_heap_objects is true,
+  // also creates the basic non-mutable objects.
+  // Returns whether it succeeded.
+  static bool Setup(bool create_heap_objects);
+
+  // Destroys all memory allocated by the heap.
+  static void TearDown();
+
+  // Returns whether Setup has been called.
+  static bool HasBeenSetup();
+
+  // Returns the maximum heap capacity.
+  static int MaxCapacity() {
+    return young_generation_size_ + old_generation_size_;
+  }
+  static int SemiSpaceSize() { return semispace_size_; }
+  static int InitialSemiSpaceSize() { return initial_semispace_size_; }
+  static int YoungGenerationSize() { return young_generation_size_; }
+  static int OldGenerationSize() { return old_generation_size_; }
+
+  // Returns the capacity of the heap in bytes w/o growing. Heap grows when
+  // more spaces are needed until it reaches the limit.
+  static int Capacity();
+
+  // Returns the available bytes in space w/o growing.
+  // Heap doesn't guarantee that it can allocate an object that requires
+  // all available bytes. Check MaxHeapObjectSize() instead.
+  static int Available();
+
+  // Returns the maximum object size that heap supports. Objects larger than
+  // the maximum heap object size are allocated in a large object space.
+  static inline int MaxHeapObjectSize();
+
+  // Returns of size of all objects residing in the heap.
+  static int SizeOfObjects();
+
+  // Return the starting address and a mask for the new space.  And-masking an
+  // address with the mask will result in the start address of the new space
+  // for all addresses in either semispace.
+  static Address NewSpaceStart() { return new_space_.start(); }
+  static uint32_t NewSpaceMask() { return new_space_.mask(); }
+  static Address NewSpaceTop() { return new_space_.top(); }
+
+  static NewSpace* new_space() { return &new_space_; }
+  static OldSpace* old_pointer_space() { return old_pointer_space_; }
+  static OldSpace* old_data_space() { return old_data_space_; }
+  static OldSpace* code_space() { return code_space_; }
+  static MapSpace* map_space() { return map_space_; }
+  static LargeObjectSpace* lo_space() { return lo_space_; }
+
+  static Address* NewSpaceAllocationTopAddress() {
+    return new_space_.allocation_top_address();
+  }
+  static Address* NewSpaceAllocationLimitAddress() {
+    return new_space_.allocation_limit_address();
+  }
+
+  // Allocates and initializes a new JavaScript object based on a
+  // constructor.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateJSObject(JSFunction* constructor,
+                                  PretenureFlag pretenure = NOT_TENURED);
+
+  // Returns a deep copy of the JavaScript object.
+  // Properties and elements are copied too.
+  // Returns failure if allocation failed.
+  static Object* CopyJSObject(JSObject* source);
+
+  // Allocates the function prototype.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateFunctionPrototype(JSFunction* function);
+
+  // Reinitialize an JSGlobalProxy based on a constructor.  The object
+  // must have the same size as objects allocated using the
+  // constructor.  The object is reinitialized and behaves as an
+  // object that has been freshly allocated using the constructor.
+  static Object* ReinitializeJSGlobalProxy(JSFunction* constructor,
+                                           JSGlobalProxy* global);
+
+  // Allocates and initializes a new JavaScript object based on a map.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateJSObjectFromMap(Map* map,
+                                         PretenureFlag pretenure = NOT_TENURED);
+
+  // Allocates a heap object based on the map.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this function does not perform a garbage collection.
+  static Object* Allocate(Map* map, AllocationSpace space);
+
+  // Allocates a JS Map in the heap.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this function does not perform a garbage collection.
+  static Object* AllocateMap(InstanceType instance_type, int instance_size);
+
+  // Allocates a partial map for bootstrapping.
+  static Object* AllocatePartialMap(InstanceType instance_type,
+                                    int instance_size);
+
+  // Allocate a map for the specified function
+  static Object* AllocateInitialMap(JSFunction* fun);
+
+  // Allocates and fully initializes a String.  There are two String
+  // encodings: ASCII and two byte. One should choose between the three string
+  // allocation functions based on the encoding of the string buffer used to
+  // initialized the string.
+  //   - ...FromAscii initializes the string from a buffer that is ASCII
+  //     encoded (it does not check that the buffer is ASCII encoded) and the
+  //     result will be ASCII encoded.
+  //   - ...FromUTF8 initializes the string from a buffer that is UTF-8
+  //     encoded.  If the characters are all single-byte characters, the
+  //     result will be ASCII encoded, otherwise it will converted to two
+  //     byte.
+  //   - ...FromTwoByte initializes the string from a buffer that is two-byte
+  //     encoded.  If the characters are all single-byte characters, the
+  //     result will be converted to ASCII, otherwise it will be left as
+  //     two-byte.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateStringFromAscii(
+      Vector<const char> str,
+      PretenureFlag pretenure = NOT_TENURED);
+  static Object* AllocateStringFromUtf8(
+      Vector<const char> str,
+      PretenureFlag pretenure = NOT_TENURED);
+  static Object* AllocateStringFromTwoByte(
+      Vector<const uc16> str,
+      PretenureFlag pretenure = NOT_TENURED);
+
+  // Allocates a symbol in old space based on the character stream.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this function does not perform a garbage collection.
+  static Object* AllocateSymbol(unibrow::CharacterStream* buffer,
+                                int chars,
+                                uint32_t length_field);
+
+  // Allocates and partially initializes a String.  There are two String
+  // encodings: ASCII and two byte.  These functions allocate a string of the
+  // given length and set its map and length fields.  The characters of the
+  // string are uninitialized.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateRawAsciiString(
+      int length,
+      PretenureFlag pretenure = NOT_TENURED);
+  static Object* AllocateRawTwoByteString(
+      int length,
+      PretenureFlag pretenure = NOT_TENURED);
+
+  // Computes a single character string where the character has code.
+  // A cache is used for ascii codes.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed. Please note this does not perform a garbage collection.
+  static Object* LookupSingleCharacterStringFromCode(uint16_t code);
+
+  // Allocate a byte array of the specified length
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please not this does not perform a garbage collection.
+  static Object* AllocateByteArray(int length);
+
+  // Allocates a fixed array initialized with undefined values
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateFixedArray(int length, PretenureFlag pretenure);
+  // Allocate uninitialized, non-tenured fixed array with length elements.
+  static Object* AllocateFixedArray(int length);
+
+  // Make a copy of src and return it. Returns
+  // Failure::RetryAfterGC(requested_bytes, space) if the allocation failed.
+  static Object* CopyFixedArray(FixedArray* src);
+
+  // Allocates a fixed array initialized with the hole values.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateFixedArrayWithHoles(int length);
+
+  // AllocateHashTable is identical to AllocateFixedArray except
+  // that the resulting object has hash_table_map as map.
+  static Object* AllocateHashTable(int length);
+
+  // Allocate a global (but otherwise uninitialized) context.
+  static Object* AllocateGlobalContext();
+
+  // Allocate a function context.
+  static Object* AllocateFunctionContext(int length, JSFunction* closure);
+
+  // Allocate a 'with' context.
+  static Object* AllocateWithContext(Context* previous, JSObject* extension);
+
+  // Allocates a new utility object in the old generation.
+  static Object* AllocateStruct(InstanceType type);
+
+
+  // Initializes a function with a shared part and prototype.
+  // Returns the function.
+  // Note: this code was factored out of AllocateFunction such that
+  // other parts of the VM could use it. Specifically, a function that creates
+  // instances of type JS_FUNCTION_TYPE benefit from the use of this function.
+  // Please note this does not perform a garbage collection.
+  static Object* InitializeFunction(JSFunction* function,
+                                    SharedFunctionInfo* shared,
+                                    Object* prototype);
+
+  // Allocates a function initialized with a shared part.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateFunction(Map* function_map,
+                                  SharedFunctionInfo* shared,
+                                  Object* prototype);
+
+  // Indicies for direct access into argument objects.
+  static const int arguments_callee_index = 0;
+  static const int arguments_length_index = 1;
+
+  // Allocates an arguments object - optionally with an elements array.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateArgumentsObject(Object* callee, int length);
+
+  // Converts a double into either a Smi or a HeapNumber object.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* NewNumberFromDouble(double value,
+                                     PretenureFlag pretenure = NOT_TENURED);
+
+  // Same as NewNumberFromDouble, but may return a preallocated/immutable
+  // number object (e.g., minus_zero_value_, nan_value_)
+  static Object* NumberFromDouble(double value,
+                                  PretenureFlag pretenure = NOT_TENURED);
+
+  // Allocated a HeapNumber from value.
+  static Object* AllocateHeapNumber(double value, PretenureFlag pretenure);
+  static Object* AllocateHeapNumber(double value);  // pretenure = NOT_TENURED
+
+  // Converts an int into either a Smi or a HeapNumber object.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static inline Object* NumberFromInt32(int32_t value);
+
+  // Converts an int into either a Smi or a HeapNumber object.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static inline Object* NumberFromUint32(uint32_t value);
+
+  // Allocates a new proxy object.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateProxy(Address proxy,
+                               PretenureFlag pretenure = NOT_TENURED);
+
+  // Allocates a new SharedFunctionInfo object.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateSharedFunctionInfo(Object* name);
+
+  // Allocates a new cons string object.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateConsString(String* first, String* second);
+
+  // Allocates a new sliced string object which is a slice of an underlying
+  // string buffer stretching from the index start (inclusive) to the index
+  // end (exclusive).
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateSlicedString(String* buffer, int start, int end);
+
+  // Allocates a new sub string object which is a substring of an underlying
+  // string buffer stretching from the index start (inclusive) to the index
+  // end (exclusive).
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateSubString(String* buffer, int start, int end);
+
+  // Allocate a new external string object, which is backed by a string
+  // resource that resides outside the V8 heap.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this does not perform a garbage collection.
+  static Object* AllocateExternalStringFromAscii(
+      ExternalAsciiString::Resource* resource);
+  static Object* AllocateExternalStringFromTwoByte(
+      ExternalTwoByteString::Resource* resource);
+
+  // Allocates an uninitialized object.  The memory is non-executable if the
+  // hardware and OS allow.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this function does not perform a garbage collection.
+  static inline Object* AllocateRaw(int size_in_bytes,
+                                    AllocationSpace space);
+
+  // Makes a new native code object
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this function does not perform a garbage collection.
+  static Object* CreateCode(const CodeDesc& desc,
+                            ScopeInfo<>* sinfo,
+                            Code::Flags flags);
+
+  static Object* CopyCode(Code* code);
+  // Finds the symbol for string in the symbol table.
+  // If not found, a new symbol is added to the table and returned.
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if allocation
+  // failed.
+  // Please note this function does not perform a garbage collection.
+  static Object* LookupSymbol(Vector<const char> str);
+  static Object* LookupAsciiSymbol(const char* str) {
+    return LookupSymbol(CStrVector(str));
+  }
+  static Object* LookupSymbol(String* str);
+  static bool LookupSymbolIfExists(String* str, String** symbol);
+
+  // Compute the matching symbol map for a string if possible.
+  // NULL is returned if string is in new space or not flattened.
+  static Map* SymbolMapForString(String* str);
+
+  // Converts the given boolean condition to JavaScript boolean value.
+  static Object* ToBoolean(bool condition) {
+    return condition ? true_value() : false_value();
+  }
+
+  // Code that should be run before and after each GC.  Includes some
+  // reporting/verification activities when compiled with DEBUG set.
+  static void GarbageCollectionPrologue();
+  static void GarbageCollectionEpilogue();
+
+  // Performs garbage collection operation.
+  // Returns whether required_space bytes are available after the collection.
+  static bool CollectGarbage(int required_space, AllocationSpace space);
+
+  // Performs a full garbage collection.
+  static void CollectAllGarbage();
+
+  // Utility to invoke the scavenger. This is needed in test code to
+  // ensure correct callback for weak global handles.
+  static void PerformScavenge();
+
+#ifdef DEBUG
+  // Utility used with flag gc-greedy.
+  static bool GarbageCollectionGreedyCheck();
+#endif
+
+  static void SetGlobalGCPrologueCallback(GCCallback callback) {
+    global_gc_prologue_callback_ = callback;
+  }
+  static void SetGlobalGCEpilogueCallback(GCCallback callback) {
+    global_gc_epilogue_callback_ = callback;
+  }
+
+  // Heap roots
+#define ROOT_ACCESSOR(type, name) static type* name() { return name##_; }
+  ROOT_LIST(ROOT_ACCESSOR)
+#undef ROOT_ACCESSOR
+
+// Utility type maps
+#define STRUCT_MAP_ACCESSOR(NAME, Name, name) \
+    static Map* name##_map() { return name##_map_; }
+  STRUCT_LIST(STRUCT_MAP_ACCESSOR)
+#undef STRUCT_MAP_ACCESSOR
+
+#define SYMBOL_ACCESSOR(name, str) static String* name() { return name##_; }
+  SYMBOL_LIST(SYMBOL_ACCESSOR)
+#undef SYMBOL_ACCESSOR
+
+  // Iterates over all roots in the heap.
+  static void IterateRoots(ObjectVisitor* v);
+  // Iterates over all strong roots in the heap.
+  static void IterateStrongRoots(ObjectVisitor* v);
+
+  // Iterates remembered set of an old space.
+  static void IterateRSet(PagedSpace* space, ObjectSlotCallback callback);
+
+  // Iterates a range of remembered set addresses starting with rset_start
+  // corresponding to the range of allocated pointers
+  // [object_start, object_end).
+  static void IterateRSetRange(Address object_start,
+                               Address object_end,
+                               Address rset_start,
+                               ObjectSlotCallback copy_object_func);
+
+  // Returns whether the object resides in new space.
+  static inline bool InNewSpace(Object* object);
+  static inline bool InFromSpace(Object* object);
+  static inline bool InToSpace(Object* object);
+
+  // Checks whether an address/object in the heap (including auxiliary
+  // area and unused area).
+  static bool Contains(Address addr);
+  static bool Contains(HeapObject* value);
+
+  // Checks whether an address/object in a space.
+  // Currently used by tests and heap verification only.
+  static bool InSpace(Address addr, AllocationSpace space);
+  static bool InSpace(HeapObject* value, AllocationSpace space);
+
+  // Finds out which space an object should get promoted to based on its type.
+  static inline OldSpace* TargetSpace(HeapObject* object);
+
+  // Sets the stub_cache_ (only used when expanding the dictionary).
+  static void set_code_stubs(Dictionary* value) { code_stubs_ = value; }
+
+  // Sets the non_monomorphic_cache_ (only used when expanding the dictionary).
+  static void set_non_monomorphic_cache(Dictionary* value) {
+    non_monomorphic_cache_ = value;
+  }
+
+  // Gets, sets and clears the lookup cache used for keyed access.
+  static inline Object* GetKeyedLookupCache();
+  static inline void SetKeyedLookupCache(LookupCache* cache);
+  static inline void ClearKeyedLookupCache();
+
+#ifdef DEBUG
+  static void Print();
+  static void PrintHandles();
+
+  // Verify the heap is in its normal state before or after a GC.
+  static void Verify();
+
+  // Report heap statistics.
+  static void ReportHeapStatistics(const char* title);
+  static void ReportCodeStatistics(const char* title);
+
+  // Fill in bogus values in from space
+  static void ZapFromSpace();
+#endif
+
+  // Makes a new symbol object
+  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+  // failed.
+  // Please note this function does not perform a garbage collection.
+  static Object* CreateSymbol(const char* str, int length, int hash);
+  static Object* CreateSymbol(String* str);
+
+  // Write barrier support for address[offset] = o.
+  inline static void RecordWrite(Address address, int offset);
+
+  // Given an address occupied by a live code object, return that object.
+  static Object* FindCodeObject(Address a);
+
+  // Invoke Shrink on shrinkable spaces.
+  static void Shrink();
+
+  enum HeapState { NOT_IN_GC, SCAVENGE, MARK_COMPACT };
+  static inline HeapState gc_state() { return gc_state_; }
+
+#ifdef DEBUG
+  static bool IsAllocationAllowed() { return allocation_allowed_; }
+  static inline bool allow_allocation(bool enable);
+
+  static bool disallow_allocation_failure() {
+    return disallow_allocation_failure_;
+  }
+
+  static void TracePathToObject();
+  static void TracePathToGlobal();
+#endif
+
+  // Callback function pased to Heap::Iterate etc.  Copies an object if
+  // necessary, the object might be promoted to an old space.  The caller must
+  // ensure the precondition that the object is (a) a heap object and (b) in
+  // the heap's from space.
+  static void ScavengePointer(HeapObject** p);
+  static inline void ScavengeObject(HeapObject** p, HeapObject* object);
+
+  // Clear a range of remembered set addresses corresponding to the object
+  // area address 'start' with size 'size_in_bytes', eg, when adding blocks
+  // to the free list.
+  static void ClearRSetRange(Address start, int size_in_bytes);
+
+  // Rebuild remembered set in old and map spaces.
+  static void RebuildRSets();
+
+  //
+  // Support for the API.
+  //
+
+  static bool CreateApiObjects();
+
+  // Attempt to find the number in a small cache.  If we finds it, return
+  // the string representation of the number.  Otherwise return undefined.
+  static Object* GetNumberStringCache(Object* number);
+
+  // Update the cache with a new number-string pair.
+  static void SetNumberStringCache(Object* number, String* str);
+
+  // Entries in the cache.  Must be a power of 2.
+  static const int kNumberStringCacheSize = 64;
+
+  // Adjusts the amount of registered external memory.
+  // Returns the adjusted value.
+  static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
+    int amount = amount_of_external_allocated_memory_ + change_in_bytes;
+    if (change_in_bytes >= 0) {
+      // Avoid overflow.
+      if (amount > amount_of_external_allocated_memory_) {
+        amount_of_external_allocated_memory_ = amount;
+      }
+    } else {
+      // Avoid underflow.
+      if (amount >= 0) {
+        amount_of_external_allocated_memory_ = amount;
+      }
+    }
+    ASSERT(amount_of_external_allocated_memory_ >= 0);
+    return amount_of_external_allocated_memory_;
+  }
+
+  // Allocate unitialized fixed array (pretenure == NON_TENURE).
+  static Object* AllocateRawFixedArray(int length);
+
+ private:
+  static int semispace_size_;
+  static int initial_semispace_size_;
+  static int young_generation_size_;
+  static int old_generation_size_;
+
+  static int new_space_growth_limit_;
+  static int scavenge_count_;
+
+  static const int kMaxMapSpaceSize = 8*MB;
+
+  static NewSpace new_space_;
+  static OldSpace* old_pointer_space_;
+  static OldSpace* old_data_space_;
+  static OldSpace* code_space_;
+  static MapSpace* map_space_;
+  static LargeObjectSpace* lo_space_;
+  static HeapState gc_state_;
+
+  // Returns the size of object residing in non new spaces.
+  static int PromotedSpaceSize();
+
+  // Returns the amount of external memory registered since last global gc.
+  static int PromotedExternalMemorySize();
+
+  static int mc_count_;  // how many mark-compact collections happened
+  static int gc_count_;  // how many gc happened
+
+#ifdef DEBUG
+  static bool allocation_allowed_;
+
+  // If the --gc-interval flag is set to a positive value, this
+  // variable holds the value indicating the number of allocations
+  // remain until the next failure and garbage collection.
+  static int allocation_timeout_;
+
+  // Do we expect to be able to handle allocation failure at this
+  // time?
+  static bool disallow_allocation_failure_;
+#endif  // DEBUG
+
+  // Promotion limit that trigger a global GC
+  static int promoted_space_limit_;
+
+  // The amount of external memory registered through the API kept alive
+  // by global handles
+  static int amount_of_external_allocated_memory_;
+
+  // Caches the amount of external memory registered at the last global gc.
+  static int amount_of_external_allocated_memory_at_last_global_gc_;
+
+  // Indicates that an allocation has failed in the old generation since the
+  // last GC.
+  static int old_gen_exhausted_;
+
+  // Declare all the roots
+#define ROOT_DECLARATION(type, name) static type* name##_;
+  ROOT_LIST(ROOT_DECLARATION)
+#undef ROOT_DECLARATION
+
+// Utility type maps
+#define DECLARE_STRUCT_MAP(NAME, Name, name) static Map* name##_map_;
+  STRUCT_LIST(DECLARE_STRUCT_MAP)
+#undef DECLARE_STRUCT_MAP
+
+#define SYMBOL_DECLARATION(name, str) static String* name##_;
+  SYMBOL_LIST(SYMBOL_DECLARATION)
+#undef SYMBOL_DECLARATION
+
+  // GC callback function, called before and after mark-compact GC.
+  // Allocations in the callback function are disallowed.
+  static GCCallback global_gc_prologue_callback_;
+  static GCCallback global_gc_epilogue_callback_;
+
+  // Checks whether a global GC is necessary
+  static GarbageCollector SelectGarbageCollector(AllocationSpace space);
+
+  // Performs garbage collection
+  static void PerformGarbageCollection(AllocationSpace space,
+                                       GarbageCollector collector,
+                                       GCTracer* tracer);
+
+  // Returns either a Smi or a Number object from 'value'. If 'new_object'
+  // is false, it may return a preallocated immutable object.
+  static Object* SmiOrNumberFromDouble(double value,
+                                       bool new_object,
+                                       PretenureFlag pretenure = NOT_TENURED);
+
+  // Allocate an uninitialized object in map space.  The behavior is identical
+  // to Heap::AllocateRaw(size_in_bytes, MAP_SPACE), except that (a) it doesn't
+  // have to test the allocation space argument and (b) can reduce code size
+  // (since both AllocateRaw and AllocateRawMap are inlined).
+  static inline Object* AllocateRawMap(int size_in_bytes);
+
+  // Initializes a JSObject based on its map.
+  static void InitializeJSObjectFromMap(JSObject* obj,
+                                        FixedArray* properties,
+                                        Map* map);
+
+  static bool CreateInitialMaps();
+  static bool CreateInitialObjects();
+  static void CreateFixedStubs();
+  static Object* CreateOddball(Map* map,
+                               const char* to_string,
+                               Object* to_number);
+
+  // Allocate empty fixed array.
+  static Object* AllocateEmptyFixedArray();
+
+  // Performs a minor collection in new generation.
+  static void Scavenge();
+
+  // Performs a major collection in the whole heap.
+  static void MarkCompact(GCTracer* tracer);
+
+  // Code to be run before and after mark-compact.
+  static void MarkCompactPrologue();
+  static void MarkCompactEpilogue();
+
+  // Helper function used by CopyObject to copy a source object to an
+  // allocated target object and update the forwarding pointer in the source
+  // object.  Returns the target object.
+  static HeapObject* MigrateObject(HeapObject* source,
+                                   HeapObject* target,
+                                   int size);
+
+  // Helper function that governs the promotion policy from new space to
+  // old.  If the object's old address lies below the new space's age
+  // mark or if we've already filled the bottom 1/16th of the to space,
+  // we try to promote this object.
+  static inline bool ShouldBePromoted(Address old_address, int object_size);
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  // Record the copy of an object in the NewSpace's statistics.
+  static void RecordCopiedObject(HeapObject* obj);
+
+  // Record statistics before and after garbage collection.
+  static void ReportStatisticsBeforeGC();
+  static void ReportStatisticsAfterGC();
+#endif
+
+  // Update an old object's remembered set
+  static int UpdateRSet(HeapObject* obj);
+
+  // Rebuild remembered set in an old space.
+  static void RebuildRSets(PagedSpace* space);
+
+  // Rebuild remembered set in the large object space.
+  static void RebuildRSets(LargeObjectSpace* space);
+
+  // Slow part of scavenge object.
+  static void ScavengeObjectSlow(HeapObject** p, HeapObject* object);
+
+  // Copy memory from src to dst.
+  inline static void CopyBlock(Object** dst, Object** src, int byte_size);
+
+  static const int kInitialSymbolTableSize = 2048;
+  static const int kInitialEvalCacheSize = 64;
+
+  friend class Factory;
+  friend class DisallowAllocationFailure;
+};
+
+
+#ifdef DEBUG
+// Visitor class to verify interior pointers that do not have remembered set
+// bits.  All heap object pointers have to point into the heap to a location
+// that has a map pointer at its first word.  Caveat: Heap::Contains is an
+// approximation because it can return true for objects in a heap space but
+// above the allocation pointer.
+class VerifyPointersVisitor: public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object** end) {
+    for (Object** current = start; current < end; current++) {
+      if ((*current)->IsHeapObject()) {
+        HeapObject* object = HeapObject::cast(*current);
+        ASSERT(Heap::Contains(object));
+        ASSERT(object->map()->IsMap());
+      }
+    }
+  }
+};
+
+
+// Visitor class to verify interior pointers that have remembered set bits.
+// As VerifyPointersVisitor but also checks that remembered set bits are
+// always set for pointers into new space.
+class VerifyPointersAndRSetVisitor: public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object** end) {
+    for (Object** current = start; current < end; current++) {
+      if ((*current)->IsHeapObject()) {
+        HeapObject* object = HeapObject::cast(*current);
+        ASSERT(Heap::Contains(object));
+        ASSERT(object->map()->IsMap());
+        if (Heap::InNewSpace(object)) {
+          ASSERT(Page::IsRSetSet(reinterpret_cast<Address>(current), 0));
+        }
+      }
+    }
+  }
+};
+#endif
+
+
+// Space iterator for iterating over all spaces of the heap.
+// Returns each space in turn, and null when it is done.
+class AllSpaces BASE_EMBEDDED {
+ public:
+  Space* next();
+  AllSpaces() { counter_ = FIRST_SPACE; }
+ private:
+  int counter_;
+};
+
+
+// Space iterator for iterating over all old spaces of the heap: Old pointer
+// space, old data space and code space.
+// Returns each space in turn, and null when it is done.
+class OldSpaces BASE_EMBEDDED {
+ public:
+  OldSpace* next();
+  OldSpaces() { counter_ = OLD_POINTER_SPACE; }
+ private:
+  int counter_;
+};
+
+
+// Space iterator for iterating over all the paged spaces of the heap:
+// Map space, old pointer space, old data space and code space.
+// Returns each space in turn, and null when it is done.
+class PagedSpaces BASE_EMBEDDED {
+ public:
+  PagedSpace* next();
+  PagedSpaces() { counter_ = OLD_POINTER_SPACE; }
+ private:
+  int counter_;
+};
+
+
+// Space iterator for iterating over all spaces of the heap.
+// For each space an object iterator is provided. The deallocation of the
+// returned object iterators is handled by the space iterator.
+class SpaceIterator : public Malloced {
+ public:
+  SpaceIterator();
+  virtual ~SpaceIterator();
+
+  bool has_next();
+  ObjectIterator* next();
+
+ private:
+  ObjectIterator* CreateIterator();
+
+  int current_space_;  // from enum AllocationSpace.
+  ObjectIterator* iterator_;  // object iterator for the current space.
+};
+
+
+// A HeapIterator provides iteration over the whole heap It aggregates a the
+// specific iterators for the different spaces as these can only iterate over
+// one space only.
+
+class HeapIterator BASE_EMBEDDED {
+ public:
+  explicit HeapIterator();
+  virtual ~HeapIterator();
+
+  bool has_next();
+  HeapObject* next();
+  void reset();
+
+ private:
+  // Perform the initialization.
+  void Init();
+
+  // Perform all necessary shutdown (destruction) work.
+  void Shutdown();
+
+  // Space iterator for iterating all the spaces.
+  SpaceIterator* space_iterator_;
+  // Object iterator for the space currently being iterated.
+  ObjectIterator* object_iterator_;
+};
+
+
+// ----------------------------------------------------------------------------
+// Marking stack for tracing live objects.
+
+class MarkingStack {
+ public:
+  void Initialize(Address low, Address high) {
+    top_ = low_ = reinterpret_cast<HeapObject**>(low);
+    high_ = reinterpret_cast<HeapObject**>(high);
+    overflowed_ = false;
+  }
+
+  bool is_full() { return top_ >= high_; }
+
+  bool is_empty() { return top_ <= low_; }
+
+  bool overflowed() { return overflowed_; }
+
+  void clear_overflowed() { overflowed_ = false; }
+
+  // Push the (marked) object on the marking stack if there is room,
+  // otherwise mark the object as overflowed and wait for a rescan of the
+  // heap.
+  void Push(HeapObject* object) {
+    CHECK(object->IsHeapObject());
+    if (is_full()) {
+      object->SetOverflow();
+      overflowed_ = true;
+    } else {
+      *(top_++) = object;
+    }
+  }
+
+  HeapObject* Pop() {
+    ASSERT(!is_empty());
+    HeapObject* object = *(--top_);
+    CHECK(object->IsHeapObject());
+    return object;
+  }
+
+ private:
+  HeapObject** low_;
+  HeapObject** top_;
+  HeapObject** high_;
+  bool overflowed_;
+};
+
+
+// A helper class to document/test C++ scopes where we do not
+// expect a GC. Usage:
+//
+// /* Allocation not allowed: we cannot handle a GC in this scope. */
+// { AssertNoAllocation nogc;
+//   ...
+// }
+
+#ifdef DEBUG
+
+class DisallowAllocationFailure {
+ public:
+  DisallowAllocationFailure() {
+    old_state_ = Heap::disallow_allocation_failure_;
+    Heap::disallow_allocation_failure_ = true;
+  }
+  ~DisallowAllocationFailure() {
+    Heap::disallow_allocation_failure_ = old_state_;
+  }
+ private:
+  bool old_state_;
+};
+
+class AssertNoAllocation {
+ public:
+  AssertNoAllocation() {
+    old_state_ = Heap::allow_allocation(false);
+  }
+
+  ~AssertNoAllocation() {
+    Heap::allow_allocation(old_state_);
+  }
+
+ private:
+  bool old_state_;
+};
+
+#else  // ndef DEBUG
+
+class AssertNoAllocation {
+ public:
+  AssertNoAllocation() { }
+  ~AssertNoAllocation() { }
+};
+
+#endif
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+// The HeapProfiler writes data to the log files, which can be postprocessed
+// to generate .hp files for use by the GHC/Valgrind tool hp2ps.
+class HeapProfiler {
+ public:
+  // Write a single heap sample to the log file.
+  static void WriteSample();
+
+ private:
+  // Update the array info with stats from obj.
+  static void CollectStats(HeapObject* obj, HistogramInfo* info);
+};
+#endif
+
+// GCTracer collects and prints ONE line after each garbage collector
+// invocation IFF --trace_gc is used.
+
+class GCTracer BASE_EMBEDDED {
+ public:
+  GCTracer();
+
+  ~GCTracer();
+
+  // Sets the collector.
+  void set_collector(GarbageCollector collector) { collector_ = collector; }
+
+  // Sets the GC count.
+  void set_gc_count(int count) { gc_count_ = count; }
+
+  // Sets the full GC count.
+  void set_full_gc_count(int count) { full_gc_count_ = count; }
+
+  // Sets the flag that this is a compacting full GC.
+  void set_is_compacting() { is_compacting_ = true; }
+
+  // Increment and decrement the count of marked objects.
+  void increment_marked_count() { ++marked_count_; }
+  void decrement_marked_count() { --marked_count_; }
+
+  int marked_count() { return marked_count_; }
+
+ private:
+  // Returns a string matching the collector.
+  const char* CollectorString();
+
+  // Returns size of object in heap (in MB).
+  double SizeOfHeapObjects() {
+    return (static_cast<double>(Heap::SizeOfObjects())) / MB;
+  }
+
+  double start_time_;  // Timestamp set in the constructor.
+  double start_size_;  // Size of objects in heap set in constructor.
+  GarbageCollector collector_;  // Type of collector.
+
+  // A count (including this one, eg, the first collection is 1) of the
+  // number of garbage collections.
+  int gc_count_;
+
+  // A count (including this one) of the number of full garbage collections.
+  int full_gc_count_;
+
+  // True if the current GC is a compacting full collection, false
+  // otherwise.
+  bool is_compacting_;
+
+  // True if the *previous* full GC cwas a compacting collection (will be
+  // false if there has not been a previous full GC).
+  bool previous_has_compacted_;
+
+  // On a full GC, a count of the number of marked objects.  Incremented
+  // when an object is marked and decremented when an object's mark bit is
+  // cleared.  Will be zero on a scavenge collection.
+  int marked_count_;
+
+  // The count from the end of the previous full GC.  Will be zero if there
+  // was no previous full GC.
+  int previous_marked_count_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_HEAP_H_
diff --git a/regexp2000/src/ic-arm.cc b/regexp2000/src/ic-arm.cc
new file mode 100644 (file)
index 0000000..7624319
--- /dev/null
@@ -0,0 +1,598 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "ic-inl.h"
+#include "runtime.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+
+// ----------------------------------------------------------------------------
+// Static IC stub generators.
+//
+
+#define __ masm->
+
+
+// Helper function used from LoadIC/CallIC GenerateNormal.
+static void GenerateDictionaryLoad(MacroAssembler* masm,
+                                   Label* done_label,
+                                   Label* miss_label,
+                                   Register t0,
+                                   Register t1) {
+  // Register use:
+  //
+  // t0 - used to hold the property dictionary.
+  //
+  // t1 - initially the receiver
+  //    - used for the index into the property dictionary
+  //    - holds the result on exit.
+  //
+  // r3 - used as temporary and to hold the capacity of the property
+  //      dictionary.
+  //
+  // r2 - holds the name of the property and is unchanges.
+
+  // Check for the absence of an interceptor.
+  // Load the map into t0.
+  __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
+  // Test the has_named_interceptor bit in the map.
+  __ ldr(t0, FieldMemOperand(t1, Map::kInstanceAttributesOffset));
+  __ tst(t0, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8))));
+  // Jump to miss if the interceptor bit is set.
+  __ b(ne, miss_label);
+
+
+  // Check that the properties array is a dictionary.
+  __ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset));
+  __ ldr(r3, FieldMemOperand(t0, HeapObject::kMapOffset));
+  __ cmp(r3, Operand(Factory::hash_table_map()));
+  __ b(ne, miss_label);
+
+  // Compute the capacity mask.
+  const int kCapacityOffset =
+      Array::kHeaderSize + Dictionary::kCapacityIndex * kPointerSize;
+  __ ldr(r3, FieldMemOperand(t0, kCapacityOffset));
+  __ mov(r3, Operand(r3, ASR, kSmiTagSize));  // convert smi to int
+  __ sub(r3, r3, Operand(1));
+
+  const int kElementsStartOffset =
+      Array::kHeaderSize + Dictionary::kElementsStartIndex * kPointerSize;
+
+  // Generate an unrolled loop that performs a few probes before
+  // giving up. Measurements done on Gmail indicate that 2 probes
+  // cover ~93% of loads from dictionaries.
+  static const int kProbes = 4;
+  for (int i = 0; i < kProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ ldr(t1, FieldMemOperand(r2, String::kLengthOffset));
+    __ mov(t1, Operand(t1, LSR, String::kHashShift));
+    if (i > 0) __ add(t1, t1, Operand(Dictionary::GetProbeOffset(i)));
+    __ and_(t1, t1, Operand(r3));
+
+    // Scale the index by multiplying by the element size.
+    ASSERT(Dictionary::kElementSize == 3);
+    __ add(t1, t1, Operand(t1, LSL, 1));  // t1 = t1 * 3
+
+    // Check if the key is identical to the name.
+    __ add(t1, t0, Operand(t1, LSL, 2));
+    __ ldr(ip, FieldMemOperand(t1, kElementsStartOffset));
+    __ cmp(r2, Operand(ip));
+    if (i != kProbes - 1) {
+      __ b(eq, done_label);
+    } else {
+      __ b(ne, miss_label);
+    }
+  }
+
+  // Check that the value is a normal property.
+  __ bind(done_label);  // t1 == t0 + 4*index
+  __ ldr(r3, FieldMemOperand(t1, kElementsStartOffset + 2 * kPointerSize));
+  __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
+  __ b(ne, miss_label);
+
+  // Get the value at the masked, scaled index and return.
+  __ ldr(t1, FieldMemOperand(t1, kElementsStartOffset + 1 * kPointerSize));
+}
+
+
+void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the object is a JS array.
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ cmp(r1, Operand(JS_ARRAY_TYPE));
+  __ b(ne, &miss);
+
+  // Load length directly from the JS array.
+  __ ldr(r0, FieldMemOperand(r0, JSArray::kLengthOffset));
+  __ Ret();
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void LoadIC::GenerateShortStringLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the object is a short string.
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ and_(r1, r1, Operand(kIsNotStringMask | kStringSizeMask));
+  // The cast is to resolve the overload for the argument of 0x0.
+  __ cmp(r1, Operand(static_cast<int32_t>(kStringTag | kShortStringTag)));
+  __ b(ne, &miss);
+
+  // Load length directly from the string.
+  __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset));
+  __ mov(r0, Operand(r0, LSR, String::kShortLengthShift));
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+  __ Ret();
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void LoadIC::GenerateMediumStringLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the object is a medium string.
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ and_(r1, r1, Operand(kIsNotStringMask | kStringSizeMask));
+  __ cmp(r1, Operand(kStringTag | kMediumStringTag));
+  __ b(ne, &miss);
+
+  // Load length directly from the string.
+  __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset));
+  __ mov(r0, Operand(r0, LSR, String::kMediumLengthShift));
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+  __ Ret();
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void LoadIC::GenerateLongStringLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the object is a long string.
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ and_(r1, r1, Operand(kIsNotStringMask | kStringSizeMask));
+  __ cmp(r1, Operand(kStringTag | kLongStringTag));
+  __ b(ne, &miss);
+
+  // Load length directly from the string.
+  __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset));
+  __ mov(r0, Operand(r0, LSR, String::kLongLengthShift));
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+  __ Ret();
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  // NOTE: Right now, this code always misses on ARM which is
+  // sub-optimal. We should port the fast case code from IA-32.
+
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+// Defined in ic.cc.
+Object* CallIC_Miss(Arguments args);
+
+void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
+  // ----------- S t a t e -------------
+  //  -- lr: return address
+  // -----------------------------------
+  Label number, non_number, non_string, boolean, probe, miss;
+
+  // Get the receiver of the function from the stack into r1.
+  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+  // Get the name of the function from the stack; 1 ~ receiver.
+  __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));
+
+  // Probe the stub cache.
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc);
+  StubCache::GenerateProbe(masm, flags, r1, r2, r3);
+
+  // If the stub cache probing failed, the receiver might be a value.
+  // For value objects, we use the map of the prototype objects for
+  // the corresponding JSValue for the cache and that is what we need
+  // to probe.
+  //
+  // Check for number.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &number);
+  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+  __ cmp(r3, Operand(HEAP_NUMBER_TYPE));
+  __ b(ne, &non_number);
+  __ bind(&number);
+  StubCompiler::GenerateLoadGlobalFunctionPrototype(
+      masm, Context::NUMBER_FUNCTION_INDEX, r1);
+  __ b(&probe);
+
+  // Check for string.
+  __ bind(&non_number);
+  __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
+  __ b(hs, &non_string);
+  StubCompiler::GenerateLoadGlobalFunctionPrototype(
+      masm, Context::STRING_FUNCTION_INDEX, r1);
+  __ b(&probe);
+
+  // Check for boolean.
+  __ bind(&non_string);
+  __ cmp(r1, Operand(Factory::true_value()));
+  __ b(eq, &boolean);
+  __ cmp(r1, Operand(Factory::false_value()));
+  __ b(ne, &miss);
+  __ bind(&boolean);
+  StubCompiler::GenerateLoadGlobalFunctionPrototype(
+      masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
+
+  // Probe the stub cache for the value object.
+  __ bind(&probe);
+  StubCache::GenerateProbe(masm, flags, r1, r2, r3);
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
+}
+
+
+void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
+  // ----------- S t a t e -------------
+  //  -- lr: return address
+  // -----------------------------------
+
+  Label miss, probe, done, global;
+
+  // Get the receiver of the function from the stack into r1.
+  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+  // Get the name of the function from the stack; 1 ~ receiver.
+  __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the receiver is a valid JS object.
+  __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
+  __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE));
+  __ b(lt, &miss);
+
+  // If this assert fails, we have to check upper bound too.
+  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+
+  // Check for access to global proxy.
+  __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
+  __ b(eq, &global);
+
+  // Search the dictionary placing the result in r1.
+  __ bind(&probe);
+  GenerateDictionaryLoad(masm, &done, &miss, r0, r1);
+
+  // Check that the value isn't a smi.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the value is a JSFunction.
+  __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
+  __ cmp(r0, Operand(JS_FUNCTION_TYPE));
+  __ b(ne, &miss);
+
+  // TODO(120): Check for access to global object. Needs patching of
+  // receiver but no security check.
+
+  // Invoke the function.
+  ParameterCount actual(argc);
+  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
+
+  // Global object access: Check access rights.
+  __ bind(&global);
+  __ CheckAccessGlobalProxy(r1, r0, &miss);
+  __ b(&probe);
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
+}
+
+
+void CallIC::Generate(MacroAssembler* masm,
+                      int argc,
+                      const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  //  -- lr: return address
+  // -----------------------------------
+
+  // Get the receiver of the function from the stack.
+  __ ldr(r2, MemOperand(sp, argc * kPointerSize));
+  // Get the name of the function to call from the stack.
+  __ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize));
+
+  __ EnterInternalFrame();
+
+  // Push the receiver and the name of the function.
+  __ stm(db_w, sp, r1.bit() | r2.bit());
+
+  // Call the entry.
+  __ mov(r0, Operand(2));
+  __ mov(r1, Operand(f));
+
+  CEntryStub stub;
+  __ CallStub(&stub);
+
+  // Move result to r1 and leave the internal frame.
+  __ mov(r1, Operand(r0));
+  __ LeaveInternalFrame();
+
+  // TODO(120): Check for access to to global object. Needs patching
+  // of receiver but no security check.
+
+  // Invoke the function.
+  ParameterCount actual(argc);
+  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
+}
+
+
+// Defined in ic.cc.
+Object* LoadIC_Miss(Arguments args);
+
+void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  __ ldr(r0, MemOperand(sp, 0));
+  // Probe the stub cache.
+  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
+  StubCache::GenerateProbe(masm, flags, r0, r2, r3);
+
+  // Cache miss: Jump to runtime.
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+void LoadIC::GenerateNormal(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  Label miss, probe, done, global;
+
+  __ ldr(r0, MemOperand(sp, 0));
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the receiver is a valid JS object.
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
+  __ b(lt, &miss);
+  // If this assert fails, we have to check upper bound too.
+  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+
+  // Check for access to global object (unlikely).
+  __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
+  __ b(eq, &global);
+
+  __ bind(&probe);
+  GenerateDictionaryLoad(masm, &done, &miss, r1, r0);
+  __ Ret();
+
+  // Global object access: Check access rights.
+  __ bind(&global);
+  __ CheckAccessGlobalProxy(r0, r1, &miss);
+  __ b(&probe);
+
+  // Cache miss: Restore receiver from stack and jump to runtime.
+  __ bind(&miss);
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+void LoadIC::GenerateMiss(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  __ ldr(r0, MemOperand(sp, 0));
+  __ push(r0);
+  __ push(r2);
+
+  // Perform tail call to the entry.
+  __ TailCallRuntime(f, 2);
+}
+
+
+// TODO(1224671): ICs for keyed load/store is not implemented on ARM.
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+}
+
+void KeyedLoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+}
+
+void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
+}
+
+void KeyedStoreIC::Generate(MacroAssembler* masm,
+                            const ExternalReference& f) {
+}
+
+void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
+}
+
+void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+}
+
+
+void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  // Get the receiver from the stack and probe the stub cache.
+  __ ldr(r1, MemOperand(sp));
+  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC);
+  StubCache::GenerateProbe(masm, flags, r1, r2, r3);
+
+  // Cache miss: Jump to runtime.
+  Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
+}
+
+
+void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  __ ldr(r3, MemOperand(sp));  // copy receiver
+  __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit());
+
+  // Perform tail call to the entry.
+  __ TailCallRuntime(
+      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
+}
+
+
+void StoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  __ ldr(r3, MemOperand(sp));  // copy receiver
+  __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit());
+
+  // Perform tail call to the entry.
+  __ TailCallRuntime(f, 3);
+}
+
+
+#undef __
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/ic-ia32.cc b/regexp2000/src/ic-ia32.cc
new file mode 100644 (file)
index 0000000..31e3370
--- /dev/null
@@ -0,0 +1,812 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen-inl.h"
+#include "ic-inl.h"
+#include "runtime.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// Static IC stub generators.
+//
+
+#define __ masm->
+
+
+// Helper function used from LoadIC/CallIC GenerateNormal.
+static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
+                                   Register r0, Register r1, Register r2,
+                                   Register name) {
+  // Register use:
+  //
+  // r0   - used to hold the property dictionary.
+  //
+  // r1   - initially the receiver
+  //      - used for the index into the property dictionary
+  //      - holds the result on exit.
+  //
+  // r2   - used to hold the capacity of the property dictionary.
+  //
+  // name - holds the name of the property and is unchanges.
+
+  Label done;
+
+  // Check for the absence of an interceptor.
+  // Load the map into r0.
+  __ mov(r0, FieldOperand(r1, JSObject::kMapOffset));
+  // Test the has_named_interceptor bit in the map.
+  __ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
+          Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
+  // Jump to miss if the interceptor bit is set.
+  __ j(not_zero, miss_label, not_taken);
+
+  // Check that the properties array is a dictionary.
+  __ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
+  __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
+         Immediate(Factory::hash_table_map()));
+  __ j(not_equal, miss_label);
+
+  // Compute the capacity mask.
+  const int kCapacityOffset =
+      Array::kHeaderSize + Dictionary::kCapacityIndex * kPointerSize;
+  __ mov(r2, FieldOperand(r0, kCapacityOffset));
+  __ shr(r2, kSmiTagSize);  // convert smi to int
+  __ dec(r2);
+
+  // Generate an unrolled loop that performs a few probes before
+  // giving up. Measurements done on Gmail indicate that 2 probes
+  // cover ~93% of loads from dictionaries.
+  static const int kProbes = 4;
+  const int kElementsStartOffset =
+      Array::kHeaderSize + Dictionary::kElementsStartIndex * kPointerSize;
+  for (int i = 0; i < kProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ mov(r1, FieldOperand(name, String::kLengthOffset));
+    __ shr(r1, String::kHashShift);
+    if (i > 0) __ add(Operand(r1), Immediate(Dictionary::GetProbeOffset(i)));
+    __ and_(r1, Operand(r2));
+
+    // Scale the index by multiplying by the element size.
+    ASSERT(Dictionary::kElementSize == 3);
+    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
+
+    // Check if the key is identical to the name.
+    __ cmp(name,
+           Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
+    if (i != kProbes - 1) {
+      __ j(equal, &done, taken);
+    } else {
+      __ j(not_equal, miss_label, not_taken);
+    }
+  }
+
+  // Check that the value is a normal property.
+  __ bind(&done);
+  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
+  __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
+          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
+  __ j(not_zero, miss_label, not_taken);
+
+  // Get the value at the masked, scaled index.
+  const int kValueOffset = kElementsStartOffset + kPointerSize;
+  __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
+}
+
+
+void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
+  __ bind(&miss);
+  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+}
+
+
+void LoadIC::GenerateShortStringLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  StubCompiler::GenerateLoadShortStringLength(masm, eax, edx, &miss);
+  __ bind(&miss);
+  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+}
+
+
+void LoadIC::GenerateMediumStringLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  StubCompiler::GenerateLoadMediumStringLength(masm, eax, edx, &miss);
+  __ bind(&miss);
+  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+}
+
+
+void LoadIC::GenerateLongStringLength(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  StubCompiler::GenerateLoadLongStringLength(masm, eax, edx, &miss);
+  __ bind(&miss);
+  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+}
+
+
+void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  Label miss;
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
+  __ bind(&miss);
+  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
+}
+
+
+#ifdef DEBUG
+// For use in assert below.
+static int TenToThe(int exponent) {
+  ASSERT(exponent <= 9);
+  ASSERT(exponent >= 1);
+  int answer = 10;
+  for (int i = 1; i < exponent; i++) answer *= 10;
+  return answer;
+}
+#endif
+
+
+void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  Label slow, fast, check_string, index_int, index_string;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+
+  // Check that the object isn't a smi.
+  __ test(ecx, Immediate(kSmiTagMask));
+  __ j(zero, &slow, not_taken);
+  // Check that the object is some kind of JS object EXCEPT JS Value type.
+  // In the case that the object is a value-wrapper object,
+  // we enter the runtime system to make sure that indexing
+  // into string objects work as intended.
+  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
+  __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset));
+  __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
+  __ cmp(edx, JS_OBJECT_TYPE);
+  __ j(less, &slow, not_taken);
+  // Check that the key is a smi.
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(not_zero, &check_string, not_taken);
+  __ sar(eax, kSmiTagSize);
+  // Get the elements array of the object.
+  __ bind(&index_int);
+  __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
+  // Check that the object is in fast mode (not dictionary).
+  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
+         Immediate(Factory::hash_table_map()));
+  __ j(equal, &slow, not_taken);
+  // Check that the key (index) is within bounds.
+  __ cmp(eax, FieldOperand(ecx, Array::kLengthOffset));
+  __ j(below, &fast, taken);
+  // Slow case: Load name and receiver from stack and jump to runtime.
+  __ bind(&slow);
+  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
+  KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
+  // Check if the key is a symbol that is not an array index.
+  __ bind(&check_string);
+  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
+  __ test(ebx, Immediate(String::kIsArrayIndexMask));
+  __ j(not_zero, &index_string, not_taken);
+  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ test(ebx, Immediate(kIsSymbolMask));
+  __ j(not_zero, &slow, not_taken);
+  // Probe the dictionary leaving result in ecx.
+  GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
+  __ mov(eax, Operand(ecx));
+  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
+  __ ret(0);
+  // Array index string: If short enough use cache in length/hash field (ebx).
+  // We assert that there are enough bits in an int32_t after the hash shift
+  // bits have been subtracted to allow space for the length and the cached
+  // array index.
+  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
+             (1 << (String::kShortLengthShift - String::kHashShift)));
+  __ bind(&index_string);
+  const int kLengthFieldLimit =
+      (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
+  __ cmp(ebx, kLengthFieldLimit);
+  __ j(above_equal, &slow);
+  __ mov(eax, Operand(ebx));
+  __ and_(eax, (1 << String::kShortLengthShift) - 1);
+  __ shr(eax, String::kLongLengthShift);
+  __ jmp(&index_int);
+  // Fast case: Do the load.
+  __ bind(&fast);
+  __ mov(eax, Operand(ecx, eax, times_4, Array::kHeaderSize - kHeapObjectTag));
+  __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
+  // In case the loaded value is the_hole we have to consult GetProperty
+  // to ensure the prototype chain is searched.
+  __ j(equal, &slow, not_taken);
+  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
+  __ ret(0);
+}
+
+
+void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- esp[0] : return address
+  //  -- esp[4] : key
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  Label slow, fast, array, extra;
+  // Get the key and the object from the stack.
+  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
+  __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
+  // Check that the key is a smi.
+  __ test(ebx, Immediate(kSmiTagMask));
+  __ j(not_zero, &slow, not_taken);
+  // Check that the object isn't a smi.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &slow, not_taken);
+  // Get the type of the object from its map.
+  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  // Check if the object is a JS array or not.
+  __ cmp(ecx, JS_ARRAY_TYPE);
+  __ j(equal, &array);
+  // Check that the object is some kind of JS object.
+  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
+  __ j(less, &slow, not_taken);
+
+
+  // Object case: Check key against length in the elements array.
+  // eax: value
+  // edx: JSObject
+  // ebx: index (as a smi)
+  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+  // Check that the object is in fast mode (not dictionary).
+  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
+         Immediate(Factory::hash_table_map()));
+  __ j(equal, &slow, not_taken);
+  // Untag the key (for checking against untagged length in the fixed array).
+  __ mov(edx, Operand(ebx));
+  __ sar(edx, kSmiTagSize);  // untag the index and use it for the comparison
+  __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset));
+  // eax: value
+  // ecx: FixedArray
+  // ebx: index (as a smi)
+  __ j(below, &fast, taken);
+
+
+  // Slow case: Push extra copies of the arguments (3).
+  __ bind(&slow);
+  __ pop(ecx);
+  __ push(Operand(esp, 1 * kPointerSize));
+  __ push(Operand(esp, 1 * kPointerSize));
+  __ push(eax);
+  __ push(ecx);
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
+
+
+  // Extra capacity case: Check if there is extra capacity to
+  // perform the store and update the length. Used for adding one
+  // element to the array by writing to array[array.length].
+  __ bind(&extra);
+  // eax: value
+  // edx: JSArray
+  // ecx: FixedArray
+  // ebx: index (as a smi)
+  // flags: compare (ebx, edx.length())
+  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
+  __ sar(ebx, kSmiTagSize);  // untag
+  __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset));
+  __ j(above_equal, &slow, not_taken);
+  // Restore tag and increment.
+  __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize));
+  __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx);
+  __ sub(Operand(ebx), Immediate(1 << kSmiTagSize));  // decrement ebx again
+  __ jmp(&fast);
+
+
+  // Array case: Get the length and the elements array from the JS
+  // array. Check that the array is in fast mode; if it is the
+  // length is always a smi.
+  __ bind(&array);
+  // eax: value
+  // edx: JSArray
+  // ebx: index (as a smi)
+  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
+         Immediate(Factory::hash_table_map()));
+  __ j(equal, &slow, not_taken);
+
+  // Check the key against the length in the array, compute the
+  // address to store into and fall through to fast case.
+  __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
+  __ j(above_equal, &extra, not_taken);
+
+
+  // Fast case: Do the store.
+  __ bind(&fast);
+  // eax: value
+  // ecx: FixedArray
+  // ebx: index (as a smi)
+  __ mov(Operand(ecx, ebx, times_2, Array::kHeaderSize - kHeapObjectTag), eax);
+  // Update write barrier for the elements array address.
+  __ mov(edx, Operand(eax));
+  __ RecordWrite(ecx, 0, edx, ebx);
+  __ ret(0);
+}
+
+
+// Defined in ic.cc.
+Object* CallIC_Miss(Arguments args);
+
+void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+  Label number, non_number, non_string, boolean, probe, miss;
+
+  // Get the receiver of the function from the stack; 1 ~ return address.
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+  // Get the name of the function from the stack; 2 ~ return address, receiver
+  __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize));
+
+  // Probe the stub cache.
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc);
+  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx);
+
+  // If the stub cache probing failed, the receiver might be a value.
+  // For value objects, we use the map of the prototype objects for
+  // the corresponding JSValue for the cache and that is what we need
+  // to probe.
+  //
+  // Check for number.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &number, not_taken);
+  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ cmp(ebx, HEAP_NUMBER_TYPE);
+  __ j(not_equal, &non_number, taken);
+  __ bind(&number);
+  StubCompiler::GenerateLoadGlobalFunctionPrototype(
+      masm, Context::NUMBER_FUNCTION_INDEX, edx);
+  __ jmp(&probe);
+
+  // Check for string.
+  __ bind(&non_number);
+  __ cmp(ebx, FIRST_NONSTRING_TYPE);
+  __ j(above_equal, &non_string, taken);
+  StubCompiler::GenerateLoadGlobalFunctionPrototype(
+      masm, Context::STRING_FUNCTION_INDEX, edx);
+  __ jmp(&probe);
+
+  // Check for boolean.
+  __ bind(&non_string);
+  __ cmp(edx, Factory::true_value());
+  __ j(equal, &boolean, not_taken);
+  __ cmp(edx, Factory::false_value());
+  __ j(not_equal, &miss, taken);
+  __ bind(&boolean);
+  StubCompiler::GenerateLoadGlobalFunctionPrototype(
+      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
+
+  // Probe the stub cache for the value object.
+  __ bind(&probe);
+  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx);
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
+}
+
+
+void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+
+  Label miss, probe, global;
+
+  // Get the receiver of the function from the stack; 1 ~ return address.
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+  // Get the name of the function from the stack; 2 ~ return address, receiver.
+  __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Check that the receiver is a valid JS object.
+  __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
+  __ cmp(eax, FIRST_JS_OBJECT_TYPE);
+  __ j(less, &miss, not_taken);
+
+  // If this assert fails, we have to check upper bound too.
+  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+
+  // Check for access to global proxy.
+  __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
+  __ j(equal, &global, not_taken);
+
+  // Search the dictionary placing the result in edx.
+  __ bind(&probe);
+  GenerateDictionaryLoad(masm, &miss, eax, edx, ebx, ecx);
+
+  // Move the result to register edi and check that it isn't a smi.
+  __ mov(edi, Operand(edx));
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Check that the value is a JavaScript function.
+  __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
+  __ cmp(edx, JS_FUNCTION_TYPE);
+  __ j(not_equal, &miss, not_taken);
+
+  // TODO(120): Check for access to global object. Needs patching of
+  // receiver but no security check.
+
+  // Invoke the function.
+  ParameterCount actual(argc);
+  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
+
+  // Global object proxy access: Check access rights.
+  __ bind(&global);
+  __ CheckAccessGlobalProxy(edx, eax, &miss);
+  __ jmp(&probe);
+
+  // Cache miss: Jump to runtime.
+  __ bind(&miss);
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
+}
+
+
+void CallIC::Generate(MacroAssembler* masm,
+                      int argc,
+                      const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+
+  // Get the receiver of the function from the stack; 1 ~ return address.
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+  // Get the name of the function to call from the stack.
+  // 2 ~ receiver, return address.
+  __ mov(ebx, Operand(esp, (argc + 2) * kPointerSize));
+
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Push the receiver and the name of the function.
+  __ push(Operand(edx));
+  __ push(Operand(ebx));
+
+  // Call the entry.
+  CEntryStub stub;
+  __ mov(Operand(eax), Immediate(2));
+  __ mov(Operand(ebx), Immediate(f));
+  __ CallStub(&stub);
+
+  // Move result to edi and exit the internal frame.
+  __ mov(Operand(edi), eax);
+  __ LeaveInternalFrame();
+
+  // TODO(120): Check for access to to global object. Needs patching
+  // of receiver but no security check.
+
+  // Invoke the function.
+  ParameterCount actual(argc);
+  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
+}
+
+
+// Defined in ic.cc.
+Object* LoadIC_Miss(Arguments args);
+
+void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  // Probe the stub cache.
+  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
+  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx);
+
+  // Cache miss: Jump to runtime.
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+void LoadIC::GenerateNormal(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  Label miss, probe, global;
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Check that the receiver is a valid JS object.
+  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
+  __ cmp(edx, FIRST_JS_OBJECT_TYPE);
+  __ j(less, &miss, not_taken);
+
+  // If this assert fails, we have to check upper bound too.
+  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+
+  // Check for access to global object (unlikely).
+  __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
+  __ j(equal, &global, not_taken);
+
+  // Search the dictionary placing the result in eax.
+  __ bind(&probe);
+  GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx);
+  __ ret(0);
+
+  // Global object access: Check access rights.
+  __ bind(&global);
+  __ CheckAccessGlobalProxy(eax, edx, &miss);
+  __ jmp(&probe);
+
+  // Cache miss: Restore receiver from stack and jump to runtime.
+  __ bind(&miss);
+  __ mov(eax, Operand(esp, 1 * kPointerSize));
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+void LoadIC::GenerateMiss(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  __ mov(eax, Operand(esp, kPointerSize));
+
+  // Move the return address below the arguments.
+  __ pop(ebx);
+  __ push(eax);
+  __ push(ecx);
+  __ push(ebx);
+
+  // Perform tail call to the entry.
+  __ TailCallRuntime(f, 2);
+}
+
+
+// Defined in ic.cc.
+Object* KeyedLoadIC_Miss(Arguments args);
+
+
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+
+  Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
+}
+
+
+void KeyedLoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+
+  __ mov(eax, Operand(esp, kPointerSize));
+  __ mov(ecx, Operand(esp, 2 * kPointerSize));
+
+  // Move the return address below the arguments.
+  __ pop(ebx);
+  __ push(ecx);
+  __ push(eax);
+  __ push(ebx);
+
+  // Perform tail call to the entry.
+  __ TailCallRuntime(f, 2);
+}
+
+
+void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  // Get the receiver from the stack and probe the stub cache.
+  __ mov(edx, Operand(esp, 4));
+  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC);
+  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx);
+
+  // Cache miss: Jump to runtime.
+  Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
+}
+
+
+void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : transition map
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  // Move the return address below the arguments.
+  __ pop(ebx);
+  __ push(Operand(esp, 0));
+  __ push(ecx);
+  __ push(eax);
+  __ push(ebx);
+  // Perform tail call to the entry.
+  __ TailCallRuntime(
+      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
+}
+
+
+void StoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  // Move the return address below the arguments.
+  __ pop(ebx);
+  __ push(Operand(esp, 0));
+  __ push(ecx);
+  __ push(eax);
+  __ push(ebx);
+
+  // Perform tail call to the entry.
+  __ TailCallRuntime(f, 3);
+}
+
+
+// Defined in ic.cc.
+Object* KeyedStoreIC_Miss(Arguments args);
+
+void KeyedStoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- esp[0] : return address
+  //  -- esp[4] : key
+  //  -- esp[8] : receiver
+  // -----------------------------------
+
+  // Move the return address below the arguments.
+  __ pop(ecx);
+  __ push(Operand(esp, 1 * kPointerSize));
+  __ push(Operand(esp, 1 * kPointerSize));
+  __ push(eax);
+  __ push(ecx);
+
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(f, 3);
+}
+
+
+void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : transition map
+  //  -- esp[0] : return address
+  //  -- esp[4] : key
+  //  -- esp[8] : receiver
+  // -----------------------------------
+
+  // Move the return address below the arguments.
+  __ pop(ebx);
+  __ push(Operand(esp, 1 * kPointerSize));
+  __ push(ecx);
+  __ push(eax);
+  __ push(ebx);
+
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(
+      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
+}
+
+#undef __
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/ic-inl.h b/regexp2000/src/ic-inl.h
new file mode 100644 (file)
index 0000000..201048a
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_IC_INL_H_
+#define V8_IC_INL_H_
+
+#include "ic.h"
+#include "debug.h"
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+
+Address IC::address() {
+  // Get the address of the call.
+  Address result = pc() - Assembler::kTargetAddrToReturnAddrDist;
+
+  // First check if any break points are active if not just return the address
+  // of the call.
+  if (!Debug::has_break_points()) return result;
+
+  // At least one break point is active perform additional test to ensure that
+  // break point locations are updated correctly.
+  if (Debug::IsDebugBreak(Assembler::target_address_at(result))) {
+    // If the call site is a call to debug break then return the address in
+    // the original code instead of the address in the running code. This will
+    // cause the original code to be updated and keeps the breakpoint active in
+    // the running code.
+    return OriginalCodeAddress();
+  } else {
+    // No break point here just return the address of the call.
+    return result;
+  }
+}
+
+
+Code* IC::GetTargetAtAddress(Address address) {
+  Address target = Assembler::target_address_at(address);
+  HeapObject* code = HeapObject::FromAddress(target - Code::kHeaderSize);
+  // GetTargetAtAddress is called from IC::Clear which in turn is
+  // called when marking objects during mark sweep. reinterpret_cast
+  // is therefore used instead of the more appropriate
+  // Code::cast. Code::cast does not work when the object's map is
+  // marked.
+  Code* result = reinterpret_cast<Code*>(code);
+  ASSERT(result->is_inline_cache_stub());
+  return result;
+}
+
+
+void IC::SetTargetAtAddress(Address address, Code* target) {
+  ASSERT(target->is_inline_cache_stub());
+  Assembler::set_target_address_at(address, target->instruction_start());
+}
+
+
+Map* IC::GetCodeCacheMapForObject(Object* object) {
+  if (object->IsJSObject()) return JSObject::cast(object)->map();
+  // If the object is a value, we use the prototype map for the cache.
+  ASSERT(object->IsString() || object->IsNumber() || object->IsBoolean());
+  return JSObject::cast(object->GetPrototype())->map();
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_IC_INL_H_
diff --git a/regexp2000/src/ic.cc b/regexp2000/src/ic.cc
new file mode 100644 (file)
index 0000000..9d954bb
--- /dev/null
@@ -0,0 +1,1201 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "accessors.h"
+#include "api.h"
+#include "arguments.h"
+#include "execution.h"
+#include "ic-inl.h"
+#include "runtime.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+#ifdef DEBUG
+static char TransitionMarkFromState(IC::State state) {
+  switch (state) {
+    case UNINITIALIZED: return '0';
+    case PREMONOMORPHIC: return '0';
+    case MONOMORPHIC: return '1';
+    case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
+    case MEGAMORPHIC: return 'N';
+
+    // We never see the debugger states here, because the state is
+    // computed from the original code - not the patched code. Let
+    // these cases fall through to the unreachable code below.
+    case DEBUG_BREAK: break;
+    case DEBUG_PREPARE_STEP_IN: break;
+  }
+  UNREACHABLE();
+  return 0;
+}
+
+void IC::TraceIC(const char* type,
+                 Handle<String> name,
+                 State old_state,
+                 Code* new_target) {
+  if (FLAG_trace_ic) {
+    State new_state = StateFrom(new_target, Heap::undefined_value());
+    PrintF("[%s (%c->%c) ", type,
+           TransitionMarkFromState(old_state),
+           TransitionMarkFromState(new_state));
+    name->Print();
+    PrintF("]\n");
+  }
+}
+#endif
+
+
+IC::IC(FrameDepth depth) {
+  // To improve the performance of the (much used) IC code, we unfold
+  // a few levels of the stack frame iteration code. This yields a
+  // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.
+  const Address entry = Top::c_entry_fp(Top::GetCurrentThread());
+  Address* pc_address =
+      reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
+  Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
+  // If there's another JavaScript frame on the stack, we need to look
+  // one frame further down the stack to find the frame pointer and
+  // the return address stack slot.
+  if (depth == EXTRA_CALL_FRAME) {
+    const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
+    pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
+    fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
+  }
+#ifdef DEBUG
+  StackFrameIterator it;
+  for (int i = 0; i < depth + 1; i++) it.Advance();
+  StackFrame* frame = it.frame();
+  ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
+#endif
+  fp_ = fp;
+  pc_address_ = pc_address;
+}
+
+
+Address IC::OriginalCodeAddress() {
+  HandleScope scope;
+  // Compute the JavaScript frame for the frame pointer of this IC
+  // structure. We need this to be able to find the function
+  // corresponding to the frame.
+  StackFrameIterator it;
+  while (it.frame()->fp() != this->fp()) it.Advance();
+  JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
+  // Find the function on the stack and both the active code for the
+  // function and the original code.
+  JSFunction* function = JSFunction::cast(frame->function());
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Code* code = shared->code();
+  ASSERT(Debug::HasDebugInfo(shared));
+  Code* original_code = Debug::GetDebugInfo(shared)->original_code();
+  ASSERT(original_code->IsCode());
+  // Get the address of the call site in the active code. This is the
+  // place where the call to DebugBreakXXX is and where the IC
+  // normally would be.
+  Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist;
+  // Return the address in the original code. This is the place where
+  // the call which has been overwriten by the DebugBreakXXX resides
+  // and the place where the inline cache system should look.
+  int delta = original_code->instruction_start() - code->instruction_start();
+  return addr + delta;
+}
+
+
+IC::State IC::StateFrom(Code* target, Object* receiver) {
+  IC::State state = target->ic_state();
+
+  if (state != MONOMORPHIC) return state;
+  if (receiver->IsUndefined() || receiver->IsNull()) return state;
+
+  Map* map = GetCodeCacheMapForObject(receiver);
+
+  // Decide whether the inline cache failed because of changes to the
+  // receiver itself or changes to one of its prototypes.
+  //
+  // If there are changes to the receiver itself, the map of the
+  // receiver will have changed and the current target will not be in
+  // the receiver map's code cache.  Therefore, if the current target
+  // is in the receiver map's code cache, the inline cache failed due
+  // to prototype check failure.
+  int index = map->IndexInCodeCache(target);
+  if (index >= 0) {
+    // For keyed load/store, the most likely cause of cache failure is
+    // that the key has changed.  We do not distinguish between
+    // prototype and non-prototype failures for keyed access.
+    Code::Kind kind = target->kind();
+    if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) {
+      return MONOMORPHIC;
+    }
+
+    // Remove the target from the code cache to avoid hitting the same
+    // invalid stub again.
+    map->RemoveFromCodeCache(index);
+
+    return MONOMORPHIC_PROTOTYPE_FAILURE;
+  }
+
+  // The builtins object is special.  It only changes when JavaScript
+  // builtins are loaded lazily.  It is important to keep inline
+  // caches for the builtins object monomorphic.  Therefore, if we get
+  // an inline cache miss for the builtins object after lazily loading
+  // JavaScript builtins, we return uninitialized as the state to
+  // force the inline cache back to monomorphic state.
+  if (receiver->IsJSBuiltinsObject()) {
+    return UNINITIALIZED;
+  }
+
+  return MONOMORPHIC;
+}
+
+
+RelocInfo::Mode IC::ComputeMode() {
+  Address addr = address();
+  Code* code = Code::cast(Heap::FindCodeObject(addr));
+  for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
+       !it.done(); it.next()) {
+    RelocInfo* info = it.rinfo();
+    if (info->pc() == addr) return info->rmode();
+  }
+  UNREACHABLE();
+  return RelocInfo::NONE;
+}
+
+
+Failure* IC::TypeError(const char* type,
+                       Handle<Object> object,
+                       Handle<String> name) {
+  HandleScope scope;
+  Handle<Object> args[2] = { name, object };
+  Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2));
+  return Top::Throw(*error);
+}
+
+
+Failure* IC::ReferenceError(const char* type, Handle<String> name) {
+  HandleScope scope;
+  Handle<Object> error =
+      Factory::NewReferenceError(type, HandleVector(&name, 1));
+  return Top::Throw(*error);
+}
+
+
+void IC::Clear(Address address) {
+  Code* target = GetTargetAtAddress(address);
+
+  // Don't clear debug break inline cache as it will remove the break point.
+  if (target->ic_state() == DEBUG_BREAK) return;
+
+  switch (target->kind()) {
+    case Code::LOAD_IC: return LoadIC::Clear(address, target);
+    case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
+    case Code::STORE_IC: return StoreIC::Clear(address, target);
+    case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
+    case Code::CALL_IC: return CallIC::Clear(address, target);
+    default: UNREACHABLE();
+  }
+}
+
+
+void CallIC::Clear(Address address, Code* target) {
+  if (target->ic_state() == UNINITIALIZED) return;
+  Code* code = StubCache::FindCallInitialize(target->arguments_count());
+  SetTargetAtAddress(address, code);
+}
+
+
+void KeyedLoadIC::Clear(Address address, Code* target) {
+  if (target->ic_state() == UNINITIALIZED) return;
+  SetTargetAtAddress(address, initialize_stub());
+}
+
+
+void LoadIC::Clear(Address address, Code* target) {
+  if (target->ic_state() == UNINITIALIZED) return;
+  SetTargetAtAddress(address, initialize_stub());
+}
+
+
+void StoreIC::Clear(Address address, Code* target) {
+  if (target->ic_state() == UNINITIALIZED) return;
+  SetTargetAtAddress(address, initialize_stub());
+}
+
+
+void KeyedStoreIC::Clear(Address address, Code* target) {
+  if (target->ic_state() == UNINITIALIZED) return;
+  SetTargetAtAddress(address, initialize_stub());
+}
+
+
+Object* CallIC::TryCallAsFunction(Object* object) {
+  HandleScope scope;
+  Handle<Object> target(object);
+  Handle<Object> delegate = Execution::GetFunctionDelegate(target);
+
+  if (delegate->IsJSFunction()) {
+    // Patch the receiver and use the delegate as the function to
+    // invoke. This is used for invoking objects as if they were
+    // functions.
+    const int argc = this->target()->arguments_count();
+    StackFrameLocator locator;
+    JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
+    int index = frame->ComputeExpressionsCount() - (argc + 1);
+    frame->SetExpression(index, *target);
+  }
+
+  return *delegate;
+}
+
+
+Object* CallIC::LoadFunction(State state,
+                             Handle<Object> object,
+                             Handle<String> name) {
+  // If the object is undefined or null it's illegal to try to get any
+  // of its properties; throw a TypeError in that case.
+  if (object->IsUndefined() || object->IsNull()) {
+    return TypeError("non_object_property_call", object, name);
+  }
+
+  Object* result = Heap::the_hole_value();
+
+  // Check if the name is trivially convertible to an index and get
+  // the element if so.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) {
+    result = object->GetElement(index);
+    if (result->IsJSFunction()) return result;
+
+    // Try to find a suitable function delegate for the object at hand.
+    result = TryCallAsFunction(result);
+    if (result->IsJSFunction()) return result;
+
+    // Otherwise, it will fail in the lookup step.
+  }
+
+  // Lookup the property in the object.
+  LookupResult lookup;
+  object->Lookup(*name, &lookup);
+
+  if (!lookup.IsValid()) {
+    // If the object does not have the requested property, check which
+    // exception we need to throw.
+    if (is_contextual()) {
+      return ReferenceError("not_defined", name);
+    }
+    return TypeError("undefined_method", object, name);
+  }
+
+  // Lookup is valid: Update inline cache and stub cache.
+  if (FLAG_use_ic && lookup.IsLoaded()) {
+    UpdateCaches(&lookup, state, object, name);
+  }
+
+  if (lookup.type() == INTERCEPTOR) {
+    // Get the property.
+    PropertyAttributes attr;
+    result = object->GetProperty(*name, &attr);
+    if (result->IsFailure()) return result;
+    // If the object does not have the requested property, check which
+    // exception we need to throw.
+    if (attr == ABSENT) {
+      if (is_contextual()) {
+        return ReferenceError("not_defined", name);
+      }
+      return TypeError("undefined_method", object, name);
+    }
+  } else {
+    // Lookup is valid and no interceptors are involved. Get the
+    // property.
+    result = object->GetProperty(*name);
+    if (result->IsFailure()) return result;
+  }
+
+  ASSERT(result != Heap::the_hole_value());
+
+  if (result->IsJSFunction()) {
+    // Check if there is an optimized (builtin) version of the function.
+    // Ignored this will degrade performance for Array.prototype.{push,pop}.
+    // Please note we only return the optimized function iff
+    // the JSObject has FastElements.
+    if (object->IsJSObject() && JSObject::cast(*object)->HasFastElements()) {
+      Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object),
+                                               lookup.holder(),
+                                               JSFunction::cast(result));
+      if (opt->IsJSFunction()) return opt;
+    }
+
+    // If performing debug step into then flood this function with one-shot
+    // break points if it is called from where step into was requested.
+    if (Debug::StepInActive() && fp() == Debug::step_in_fp()) {
+      // Don't allow step into functions in the native context.
+      if (JSFunction::cast(result)->context()->global() !=
+          Top::context()->builtins()) {
+        HandleScope scope;
+        Handle<SharedFunctionInfo> shared(JSFunction::cast(result)->shared());
+        Debug::FloodWithOneShot(shared);
+      }
+    }
+    return result;
+  }
+
+  // Try to find a suitable function delegate for the object at hand.
+  result = TryCallAsFunction(result);
+  return result->IsJSFunction() ?
+      result : TypeError("property_not_function", object, name);
+}
+
+
+void CallIC::UpdateCaches(LookupResult* lookup,
+                          State state,
+                          Handle<Object> object,
+                          Handle<String> name) {
+  ASSERT(lookup->IsLoaded());
+  // Bail out if we didn't find a result.
+  if (!lookup->IsValid() || !lookup->IsCacheable()) return;
+
+  // Compute the number of arguments.
+  int argc = target()->arguments_count();
+  Object* code = NULL;
+
+  if (state == UNINITIALIZED) {
+    // This is the first time we execute this inline cache.
+    // Set the target to the pre monomorphic stub to delay
+    // setting the monomorphic state.
+    code = StubCache::ComputeCallPreMonomorphic(argc);
+  } else if (state == MONOMORPHIC) {
+    code = StubCache::ComputeCallMegamorphic(argc);
+  } else {
+    // Compute monomorphic stub.
+    switch (lookup->type()) {
+      case FIELD: {
+        int index = lookup->GetFieldIndex();
+        code = StubCache::ComputeCallField(argc, *name, *object,
+                                           lookup->holder(), index);
+        break;
+      }
+      case CONSTANT_FUNCTION: {
+        // Get the constant function and compute the code stub for this
+        // call; used for rewriting to monomorphic state and making sure
+        // that the code stub is in the stub cache.
+        JSFunction* function = lookup->GetConstantFunction();
+        code = StubCache::ComputeCallConstant(argc, *name, *object,
+                                              lookup->holder(), function);
+        break;
+      }
+      case NORMAL: {
+        // There is only one shared stub for calling normalized
+        // properties. It does not traverse the prototype chain, so the
+        // property must be found in the receiver for the stub to be
+        // applicable.
+        if (!object->IsJSObject()) return;
+        Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+        if (lookup->holder() != *receiver) return;
+        code = StubCache::ComputeCallNormal(argc, *name, *receiver);
+        break;
+      }
+      case INTERCEPTOR: {
+        code = StubCache::ComputeCallInterceptor(argc, *name, *object,
+                                                 lookup->holder());
+        break;
+      }
+      default:
+        return;
+    }
+  }
+
+  // If we're unable to compute the stub (not enough memory left), we
+  // simply avoid updating the caches.
+  if (code->IsFailure()) return;
+
+  // Patch the call site depending on the state of the cache.
+  if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
+      state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
+    set_target(Code::cast(code));
+  }
+
+#ifdef DEBUG
+  TraceIC("CallIC", name, state, target());
+#endif
+}
+
+
+Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
+  // If the object is undefined or null it's illegal to try to get any
+  // of its properties; throw a TypeError in that case.
+  if (object->IsUndefined() || object->IsNull()) {
+    return TypeError("non_object_property_load", object, name);
+  }
+
+  if (FLAG_use_ic) {
+    // Use specialized code for getting the length of strings.
+    if (object->IsString() && name->Equals(Heap::length_symbol())) {
+#ifdef DEBUG
+      if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
+#endif
+      Code* target = NULL;
+      if (object->IsShortString()) {
+        target = Builtins::builtin(Builtins::LoadIC_ShortStringLength);
+      } else if (object->IsMediumString()) {
+        target = Builtins::builtin(Builtins::LoadIC_MediumStringLength);
+      } else {
+        ASSERT(object->IsLongString());
+        target  = Builtins::builtin(Builtins::LoadIC_LongStringLength);
+      }
+      set_target(target);
+      StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
+      return Smi::FromInt(String::cast(*object)->length());
+    }
+
+    // Use specialized code for getting the length of arrays.
+    if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
+#ifdef DEBUG
+      if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
+#endif
+      Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength);
+      set_target(target);
+      StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
+      return JSArray::cast(*object)->length();
+    }
+
+    // Use specialized code for getting prototype of functions.
+    if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
+#ifdef DEBUG
+      if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
+#endif
+      Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype);
+      set_target(target);
+      StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
+      return Accessors::FunctionGetPrototype(*object, 0);
+    }
+  }
+
+  // Check if the name is trivially convertible to an index and get
+  // the element if so.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) return object->GetElement(index);
+
+  // Named lookup in the object.
+  LookupResult lookup;
+  object->Lookup(*name, &lookup);
+
+  // If lookup is invalid, check if we need to throw an exception.
+  if (!lookup.IsValid()) {
+    if (FLAG_strict || is_contextual()) {
+      return ReferenceError("not_defined", name);
+    }
+    String* class_name = object->IsJSObject()
+                         ? Handle<JSObject>::cast(object)->class_name()
+                         : Heap::empty_string();
+    LOG(SuspectReadEvent(*name, class_name));
+    USE(class_name);
+  }
+
+  // Update inline cache and stub cache.
+  if (FLAG_use_ic && lookup.IsLoaded()) {
+    UpdateCaches(&lookup, state, object, name);
+  }
+
+  PropertyAttributes attr;
+  if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
+    // Get the property.
+    Object* result = object->GetProperty(*object, &lookup, *name, &attr);
+    if (result->IsFailure()) return result;
+    // If the property is not present, check if we need to throw an
+    // exception.
+    if (attr == ABSENT && is_contextual()) {
+      return ReferenceError("not_defined", name);
+    }
+    return result;
+  }
+
+  // Get the property.
+  return object->GetProperty(*object, &lookup, *name, &attr);
+}
+
+
+void LoadIC::UpdateCaches(LookupResult* lookup,
+                          State state,
+                          Handle<Object> object,
+                          Handle<String> name) {
+  ASSERT(lookup->IsLoaded());
+  // Bail out if we didn't find a result.
+  if (!lookup->IsValid() || !lookup->IsCacheable()) return;
+
+  // Loading properties from values is not common, so don't try to
+  // deal with non-JS objects here.
+  if (!object->IsJSObject()) return;
+  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
+  // Compute the code stub for this load.
+  Object* code = NULL;
+  if (state == UNINITIALIZED) {
+    // This is the first time we execute this inline cache.
+    // Set the target to the pre monomorphic stub to delay
+    // setting the monomorphic state.
+    code = pre_monomorphic_stub();
+  } else {
+    // Compute monomorphic stub.
+    switch (lookup->type()) {
+      case FIELD: {
+        code = StubCache::ComputeLoadField(*name, *receiver,
+                                           lookup->holder(),
+                                           lookup->GetFieldIndex());
+        break;
+      }
+      case CONSTANT_FUNCTION: {
+        Object* constant = lookup->GetConstantFunction();
+        code = StubCache::ComputeLoadConstant(*name, *receiver,
+                                              lookup->holder(), constant);
+        break;
+      }
+      case NORMAL: {
+        // There is only one shared stub for loading normalized
+        // properties. It does not traverse the prototype chain, so the
+        // property must be found in the receiver for the stub to be
+        // applicable.
+        if (lookup->holder() != *receiver) return;
+        code = StubCache::ComputeLoadNormal(*name, *receiver);
+        break;
+      }
+      case CALLBACKS: {
+        if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
+        AccessorInfo* callback =
+            AccessorInfo::cast(lookup->GetCallbackObject());
+        if (v8::ToCData<Address>(callback->getter()) == 0) return;
+        code = StubCache::ComputeLoadCallback(*name, *receiver,
+                                              lookup->holder(), callback);
+        break;
+      }
+      case INTERCEPTOR: {
+        code = StubCache::ComputeLoadInterceptor(*name, *receiver,
+                                                 lookup->holder());
+        break;
+      }
+      default:
+        return;
+    }
+  }
+
+  // If we're unable to compute the stub (not enough memory left), we
+  // simply avoid updating the caches.
+  if (code->IsFailure()) return;
+
+  // Patch the call site depending on the state of the cache.
+  if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
+      state == MONOMORPHIC_PROTOTYPE_FAILURE) {
+    set_target(Code::cast(code));
+  } else if (state == MONOMORPHIC) {
+    set_target(megamorphic_stub());
+  }
+
+#ifdef DEBUG
+  TraceIC("LoadIC", name, state, target());
+#endif
+}
+
+
+Object* KeyedLoadIC::Load(State state,
+                          Handle<Object> object,
+                          Handle<Object> key) {
+  if (key->IsSymbol()) {
+    Handle<String> name = Handle<String>::cast(key);
+
+    // If the object is undefined or null it's illegal to try to get any
+    // of its properties; throw a TypeError in that case.
+    if (object->IsUndefined() || object->IsNull()) {
+      return TypeError("non_object_property_load", object, name);
+    }
+
+    if (FLAG_use_ic) {
+      // Use specialized code for getting the length of strings.
+      if (object->IsString() && name->Equals(Heap::length_symbol())) {
+        Handle<String> string = Handle<String>::cast(object);
+        Object* code = NULL;
+        if (string->IsShortString()) {
+          code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string);
+        } else if (string->IsMediumString()) {
+          code =
+              StubCache::ComputeKeyedLoadMediumStringLength(*name, *string);
+        } else {
+          ASSERT(string->IsLongString());
+          code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string);
+        }
+        if (code->IsFailure()) return code;
+        set_target(Code::cast(code));
+#ifdef DEBUG
+        TraceIC("KeyedLoadIC", name, state, target());
+#endif
+        return Smi::FromInt(string->length());
+      }
+
+      // Use specialized code for getting the length of arrays.
+      if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
+        Handle<JSArray> array = Handle<JSArray>::cast(object);
+        Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array);
+        if (code->IsFailure()) return code;
+        set_target(Code::cast(code));
+#ifdef DEBUG
+        TraceIC("KeyedLoadIC", name, state, target());
+#endif
+        return JSArray::cast(*object)->length();
+      }
+
+      // Use specialized code for getting prototype of functions.
+      if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
+        Handle<JSFunction> function = Handle<JSFunction>::cast(object);
+        Object* code =
+            StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function);
+        if (code->IsFailure()) return code;
+        set_target(Code::cast(code));
+#ifdef DEBUG
+        TraceIC("KeyedLoadIC", name, state, target());
+#endif
+        return Accessors::FunctionGetPrototype(*object, 0);
+      }
+    }
+
+    // Check if the name is trivially convertible to an index and get
+    // the element or char if so.
+    uint32_t index = 0;
+    if (name->AsArrayIndex(&index)) {
+      HandleScope scope;
+      // Rewrite to the generic keyed load stub.
+      if (FLAG_use_ic) set_target(generic_stub());
+      return Runtime::GetElementOrCharAt(object, index);
+    }
+
+    // Named lookup.
+    LookupResult lookup;
+    object->Lookup(*name, &lookup);
+
+    // If lookup is invalid, check if we need to throw an exception.
+    if (!lookup.IsValid()) {
+      if (FLAG_strict || is_contextual()) {
+        return ReferenceError("not_defined", name);
+      }
+    }
+
+    // Update the inline cache.
+    if (FLAG_use_ic && lookup.IsLoaded()) {
+      UpdateCaches(&lookup, state, object, name);
+    }
+
+    PropertyAttributes attr;
+    if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
+      // Get the property.
+      Object* result = object->GetProperty(*object, &lookup, *name, &attr);
+      if (result->IsFailure()) return result;
+      // If the property is not present, check if we need to throw an
+      // exception.
+      if (attr == ABSENT && is_contextual()) {
+        return ReferenceError("not_defined", name);
+      }
+      return result;
+    }
+
+    return object->GetProperty(*object, &lookup, *name, &attr);
+  }
+
+  // Do not use ICs for objects that require access checks (including
+  // the global object).
+  bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
+
+  if (use_ic) set_target(generic_stub());
+
+  // Get the property.
+  return Runtime::GetObjectProperty(object, key);
+}
+
+
+void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
+                               Handle<Object> object, Handle<String> name) {
+  ASSERT(lookup->IsLoaded());
+  // Bail out if we didn't find a result.
+  if (!lookup->IsValid() || !lookup->IsCacheable()) return;
+
+  if (!object->IsJSObject()) return;
+  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
+  // Compute the code stub for this load.
+  Object* code = NULL;
+
+  if (state == UNINITIALIZED) {
+    // This is the first time we execute this inline cache.
+    // Set the target to the pre monomorphic stub to delay
+    // setting the monomorphic state.
+    code = pre_monomorphic_stub();
+  } else {
+    // Compute a monomorphic stub.
+    switch (lookup->type()) {
+      case FIELD: {
+        code = StubCache::ComputeKeyedLoadField(*name, *receiver,
+                                                lookup->holder(),
+                                                lookup->GetFieldIndex());
+        break;
+      }
+      case CONSTANT_FUNCTION: {
+        Object* constant = lookup->GetConstantFunction();
+        code = StubCache::ComputeKeyedLoadConstant(*name, *receiver,
+                                                   lookup->holder(), constant);
+        break;
+      }
+      case CALLBACKS: {
+        if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
+        AccessorInfo* callback =
+            AccessorInfo::cast(lookup->GetCallbackObject());
+        if (v8::ToCData<Address>(callback->getter()) == 0) return;
+        code = StubCache::ComputeKeyedLoadCallback(*name, *receiver,
+                                                   lookup->holder(), callback);
+        break;
+      }
+      case INTERCEPTOR: {
+        code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver,
+                                                      lookup->holder());
+        break;
+      }
+      default: {
+        // Always rewrite to the generic case so that we do not
+        // repeatedly try to rewrite.
+        code = generic_stub();
+        break;
+      }
+    }
+  }
+
+  // If we're unable to compute the stub (not enough memory left), we
+  // simply avoid updating the caches.
+  if (code->IsFailure()) return;
+
+  // Patch the call site depending on the state of the cache.  Make
+  // sure to always rewrite from monomorphic to megamorphic.
+  ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
+  if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
+    set_target(Code::cast(code));
+  } else if (state == MONOMORPHIC) {
+    set_target(megamorphic_stub());
+  }
+
+#ifdef DEBUG
+  TraceIC("KeyedLoadIC", name, state, target());
+#endif
+}
+
+
+Object* StoreIC::Store(State state,
+                       Handle<Object> object,
+                       Handle<String> name,
+                       Handle<Object> value) {
+  // If the object is undefined or null it's illegal to try to set any
+  // properties on it; throw a TypeError in that case.
+  if (object->IsUndefined() || object->IsNull()) {
+    return TypeError("non_object_property_store", object, name);
+  }
+
+  // Ignore stores where the receiver is not a JSObject.
+  if (!object->IsJSObject()) return *value;
+  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
+  // Check if the given name is an array index.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) {
+    HandleScope scope;
+    Handle<Object> result = SetElement(receiver, index, value);
+    if (result.is_null()) return Failure::Exception();
+    return *value;
+  }
+
+  // Lookup the property locally in the receiver.
+  LookupResult lookup;
+  receiver->LocalLookup(*name, &lookup);
+
+  // Update inline cache and stub cache.
+  if (FLAG_use_ic && lookup.IsLoaded()) {
+    UpdateCaches(&lookup, state, receiver, name, value);
+  }
+
+  // Set the property.
+  return receiver->SetProperty(*name, *value, NONE);
+}
+
+
+void StoreIC::UpdateCaches(LookupResult* lookup,
+                           State state,
+                           Handle<JSObject> receiver,
+                           Handle<String> name,
+                           Handle<Object> value) {
+  ASSERT(lookup->IsLoaded());
+  // Skip JSGlobalProxy.
+  if (receiver->IsJSGlobalProxy()) return;
+
+  // Bail out if we didn't find a result.
+  if (!lookup->IsValid() || !lookup->IsCacheable()) return;
+
+  // If the property is read-only, we leave the IC in its current
+  // state.
+  if (lookup->IsReadOnly()) return;
+
+  // If the property has a non-field type allowing map transitions
+  // where there is extra room in the object, we leave the IC in its
+  // current state.
+  PropertyType type = lookup->type();
+
+  // Compute the code stub for this store; used for rewriting to
+  // monomorphic state and making sure that the code stub is in the
+  // stub cache.
+  Object* code = NULL;
+  switch (type) {
+    case FIELD: {
+      code = StubCache::ComputeStoreField(*name, *receiver,
+                                          lookup->GetFieldIndex());
+      break;
+    }
+    case MAP_TRANSITION: {
+      if (lookup->GetAttributes() != NONE) return;
+      HandleScope scope;
+      ASSERT(type == MAP_TRANSITION);
+      Handle<Map> transition(lookup->GetTransitionMap());
+      int index = transition->PropertyIndexFor(*name);
+      code = StubCache::ComputeStoreField(*name, *receiver, index, *transition);
+      break;
+    }
+    case CALLBACKS: {
+      if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
+      AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
+      if (v8::ToCData<Address>(callback->setter()) == 0) return;
+      code = StubCache::ComputeStoreCallback(*name, *receiver, callback);
+      break;
+    }
+    case INTERCEPTOR: {
+      code = StubCache::ComputeStoreInterceptor(*name, *receiver);
+      break;
+    }
+    default:
+      return;
+  }
+
+  // If we're unable to compute the stub (not enough memory left), we
+  // simply avoid updating the caches.
+  if (code->IsFailure()) return;
+
+  // Patch the call site depending on the state of the cache.
+  if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
+    set_target(Code::cast(code));
+  } else if (state == MONOMORPHIC) {
+    // Only move to mega morphic if the target changes.
+    if (target() != Code::cast(code)) set_target(megamorphic_stub());
+  }
+
+#ifdef DEBUG
+  TraceIC("StoreIC", name, state, target());
+#endif
+}
+
+
+Object* KeyedStoreIC::Store(State state,
+                            Handle<Object> object,
+                            Handle<Object> key,
+                            Handle<Object> value) {
+  if (key->IsSymbol()) {
+    Handle<String> name = Handle<String>::cast(key);
+
+    // If the object is undefined or null it's illegal to try to set any
+    // properties on it; throw a TypeError in that case.
+    if (object->IsUndefined() || object->IsNull()) {
+      return TypeError("non_object_property_store", object, name);
+    }
+
+    // Ignore stores where the receiver is not a JSObject.
+    if (!object->IsJSObject()) return *value;
+    Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
+    // Check if the given name is an array index.
+    uint32_t index;
+    if (name->AsArrayIndex(&index)) {
+      HandleScope scope;
+      Handle<Object> result = SetElement(receiver, index, value);
+      if (result.is_null()) return Failure::Exception();
+      return *value;
+    }
+
+    // Lookup the property locally in the receiver.
+    LookupResult lookup;
+    receiver->LocalLookup(*name, &lookup);
+
+    // Update inline cache and stub cache.
+    if (FLAG_use_ic && lookup.IsLoaded()) {
+      UpdateCaches(&lookup, state, receiver, name, value);
+    }
+
+    // Set the property.
+    return receiver->SetProperty(*name, *value, NONE);
+  }
+
+  // Do not use ICs for objects that require access checks (including
+  // the global object).
+  bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
+  ASSERT(!(use_ic && object->IsJSGlobalProxy()));
+
+  if (use_ic) set_target(generic_stub());
+
+  // Set the property.
+  return Runtime::SetObjectProperty(object, key, value, NONE);
+}
+
+
+void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
+                                State state,
+                                Handle<JSObject> receiver,
+                                Handle<String> name,
+                                Handle<Object> value) {
+  ASSERT(lookup->IsLoaded());
+
+  // Skip JSGlobalProxy.
+  if (receiver->IsJSGlobalProxy()) return;
+
+  // Bail out if we didn't find a result.
+  if (!lookup->IsValid() || !lookup->IsCacheable()) return;
+
+  // If the property is read-only, we leave the IC in its current
+  // state.
+  if (lookup->IsReadOnly()) return;
+
+  // If the property has a non-field type allowing map transitions
+  // where there is extra room in the object, we leave the IC in its
+  // current state.
+  PropertyType type = lookup->type();
+
+  // Compute the code stub for this store; used for rewriting to
+  // monomorphic state and making sure that the code stub is in the
+  // stub cache.
+  Object* code = NULL;
+
+  switch (type) {
+    case FIELD: {
+      code = StubCache::ComputeKeyedStoreField(*name, *receiver,
+                                               lookup->GetFieldIndex());
+      break;
+    }
+    case MAP_TRANSITION: {
+      if (lookup->GetAttributes() == NONE) {
+        HandleScope scope;
+        ASSERT(type == MAP_TRANSITION);
+        Handle<Map> transition(lookup->GetTransitionMap());
+        int index = transition->PropertyIndexFor(*name);
+        code = StubCache::ComputeKeyedStoreField(*name, *receiver,
+                                                 index, *transition);
+        break;
+      }
+      // fall through.
+    }
+    default: {
+      // Always rewrite to the generic case so that we do not
+      // repeatedly try to rewrite.
+      code = generic_stub();
+      break;
+    }
+  }
+
+  // If we're unable to compute the stub (not enough memory left), we
+  // simply avoid updating the caches.
+  if (code->IsFailure()) return;
+
+  // Patch the call site depending on the state of the cache.  Make
+  // sure to always rewrite from monomorphic to megamorphic.
+  ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
+  if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
+    set_target(Code::cast(code));
+  } else if (state == MONOMORPHIC) {
+    set_target(megamorphic_stub());
+  }
+
+#ifdef DEBUG
+  TraceIC("KeyedStoreIC", name, state, target());
+#endif
+}
+
+
+// ----------------------------------------------------------------------------
+// Static IC stub generators.
+//
+
+// Used from ic_<arch>.cc.
+Object* CallIC_Miss(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 2);
+  CallIC ic;
+  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  return ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
+}
+
+
+void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) {
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
+}
+
+
+void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) {
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
+}
+
+
+void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
+  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
+}
+
+
+// Used from ic_<arch>.cc.
+Object* LoadIC_Miss(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 2);
+  LoadIC ic;
+  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  return ic.Load(state, args.at<Object>(0), args.at<String>(1));
+}
+
+
+void LoadIC::GenerateInitialize(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
+}
+
+
+// Used from ic_<arch>.cc
+Object* KeyedLoadIC_Miss(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 2);
+  KeyedLoadIC ic;
+  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
+}
+
+
+void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
+}
+
+
+void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
+}
+
+
+// Used from ic_<arch>.cc.
+Object* StoreIC_Miss(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 3);
+  StoreIC ic;
+  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  return ic.Store(state, args.at<Object>(0), args.at<String>(1),
+                  args.at<Object>(2));
+}
+
+
+// Extend storage is called in a store inline cache when
+// it is necessary to extend the properties array of a
+// JSObject.
+Object* SharedStoreIC_ExtendStorage(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 3);
+
+  // Convert the parameters
+  JSObject* object = JSObject::cast(args[0]);
+  Map* transition = Map::cast(args[1]);
+  Object* value = args[2];
+
+  // Check the object has run out out property space.
+  ASSERT(object->HasFastProperties());
+  ASSERT(object->map()->unused_property_fields() == 0);
+
+  // Expand the properties array.
+  FixedArray* old_storage = object->properties();
+  int new_unused = transition->unused_property_fields();
+  int new_size = old_storage->length() + new_unused + 1;
+  Object* result = old_storage->CopySize(new_size);
+  if (result->IsFailure()) return result;
+  FixedArray* new_storage = FixedArray::cast(result);
+  new_storage->set(old_storage->length(), value);
+
+  // Set the new property value and do the map tranistion.
+  object->set_properties(new_storage);
+  object->set_map(transition);
+
+  // Return the stored value.
+  return value;
+}
+
+
+void StoreIC::GenerateInitialize(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
+}
+
+
+void StoreIC::GenerateMiss(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
+}
+
+
+// Used from ic_<arch>.cc.
+Object* KeyedStoreIC_Miss(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 3);
+  KeyedStoreIC ic;
+  IC::State state = IC::StateFrom(ic.target(), args[0]);
+  return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
+                  args.at<Object>(2));
+}
+
+
+void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
+}
+
+
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
+  Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
+}
+
+
+static Address IC_utilities[] = {
+#define ADDR(name) FUNCTION_ADDR(name),
+    IC_UTIL_LIST(ADDR)
+    NULL
+#undef ADDR
+};
+
+
+Address IC::AddressFromUtilityId(IC::UtilityId id) {
+  return IC_utilities[id];
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/ic.h b/regexp2000/src/ic.h
new file mode 100644 (file)
index 0000000..fd5c72b
--- /dev/null
@@ -0,0 +1,366 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_IC_H_
+#define V8_IC_H_
+
+#include "assembler.h"
+
+namespace v8 { namespace internal {
+
+// IC_UTIL_LIST defines all utility functions called from generated
+// inline caching code. The argument for the macro, ICU, is the function name.
+#define IC_UTIL_LIST(ICU)          \
+  ICU(LoadIC_Miss)                 \
+  ICU(KeyedLoadIC_Miss)            \
+  ICU(CallIC_Miss)                 \
+  ICU(StoreIC_Miss)                \
+  ICU(SharedStoreIC_ExtendStorage) \
+  ICU(KeyedStoreIC_Miss)           \
+  /* Utilities for IC stubs. */    \
+  ICU(LoadCallbackProperty)        \
+  ICU(StoreCallbackProperty)       \
+  ICU(LoadInterceptorProperty)     \
+  ICU(StoreInterceptorProperty)
+
+//
+// IC is the base class for LoadIC, StoreIC and CallIC.
+//
+class IC {
+ public:
+
+  // The ids for utility called from the generated code.
+  enum UtilityId {
+  #define CONST_NAME(name) k##name,
+    IC_UTIL_LIST(CONST_NAME)
+  #undef CONST_NAME
+    kUtilityCount
+  };
+
+  // Looks up the address of the named utility.
+  static Address AddressFromUtilityId(UtilityId id);
+
+  // Alias the inline cache state type to make the IC code more readable.
+  typedef InlineCacheState State;
+
+  // The IC code is either invoked with no extra frames on the stack
+  // or with a single extra frame for supporting calls.
+  enum FrameDepth {
+    NO_EXTRA_FRAME = 0,
+    EXTRA_CALL_FRAME = 1
+  };
+
+  // Construct the IC structure with the given number of extra
+  // JavaScript frames on the stack.
+  explicit IC(FrameDepth depth);
+
+  // Get the call-site target; used for determining the state.
+  Code* target() { return GetTargetAtAddress(address()); }
+  inline Address address();
+
+  // Compute the current IC state based on the target stub and the receiver.
+  static State StateFrom(Code* target, Object* receiver);
+
+  // Clear the inline cache to initial state.
+  static void Clear(Address address);
+
+  // Computes the reloc info for this IC. This is a fairly expensive
+  // operation as it has to search through the heap to find the code
+  // object that contains this IC site.
+  RelocInfo::Mode ComputeMode();
+
+  // Returns if this IC is for contextual (no explicit receiver)
+  // access to properties.
+  bool is_contextual() {
+    return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
+  }
+
+  // Returns the map to use for caching stubs for a given object.
+  // This method should not be called with undefined or null.
+  static inline Map* GetCodeCacheMapForObject(Object* object);
+
+ protected:
+  Address fp() const { return fp_; }
+  Address pc() const { return *pc_address_; }
+
+  // Computes the address in the original code when the code running is
+  // containing break points (calls to DebugBreakXXX builtins).
+  Address OriginalCodeAddress();
+
+  // Set the call-site target.
+  void set_target(Code* code) { SetTargetAtAddress(address(), code); }
+
+#ifdef DEBUG
+  static void TraceIC(const char* type,
+                      Handle<String> name,
+                      State old_state,
+                      Code* new_target);
+#endif
+
+  static Failure* TypeError(const char* type,
+                            Handle<Object> object,
+                            Handle<String> name);
+  static Failure* ReferenceError(const char* type, Handle<String> name);
+
+  // Access the target code for the given IC address.
+  static inline Code* GetTargetAtAddress(Address address);
+  static inline void SetTargetAtAddress(Address address, Code* target);
+
+ private:
+  // Frame pointer for the frame that uses (calls) the IC.
+  Address fp_;
+
+  // All access to the program counter of an IC structure is indirect
+  // to make the code GC safe. This feature is crucial since
+  // GetProperty and SetProperty are called and they in turn might
+  // invoke the garbage collector.
+  Address* pc_address_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
+};
+
+
+// An IC_Utility encapsulates IC::UtilityId. It exists mainly because you
+// cannot make forward declarations to an enum.
+class IC_Utility {
+ public:
+  explicit IC_Utility(IC::UtilityId id)
+    : address_(IC::AddressFromUtilityId(id)), id_(id) {}
+
+  Address address() const { return address_; }
+
+  IC::UtilityId id() const { return id_; }
+ private:
+  Address address_;
+  IC::UtilityId id_;
+};
+
+
+class CallIC: public IC {
+ public:
+  CallIC() : IC(EXTRA_CALL_FRAME) { ASSERT(target()->is_call_stub()); }
+
+  Object* LoadFunction(State state, Handle<Object> object, Handle<String> name);
+
+
+  // Code generator routines.
+  static void GenerateInitialize(MacroAssembler* masm, int argc);
+  static void GeneratePreMonomorphic(MacroAssembler* masm, int argc);
+  static void GenerateMiss(MacroAssembler* masm, int argc);
+  static void GenerateMegamorphic(MacroAssembler* masm, int argc);
+  static void GenerateNormal(MacroAssembler* masm, int argc);
+
+ private:
+  static void Generate(MacroAssembler* masm,
+                       int argc,
+                       const ExternalReference& f);
+
+  // Update the inline cache and the global stub cache based on the
+  // lookup result.
+  void UpdateCaches(LookupResult* lookup,
+                    State state,
+                    Handle<Object> object,
+                    Handle<String> name);
+
+  // Returns a JSFunction if the object can be called as a function,
+  // and patches the stack to be ready for the call.
+  // Otherwise, it returns the undefined value.
+  Object* TryCallAsFunction(Object* object);
+
+  static void Clear(Address address, Code* target);
+  friend class IC;
+};
+
+
+class LoadIC: public IC {
+ public:
+  LoadIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_load_stub()); }
+
+  Object* Load(State state, Handle<Object> object, Handle<String> name);
+
+  // Code generator routines.
+  static void GenerateInitialize(MacroAssembler* masm);
+  static void GeneratePreMonomorphic(MacroAssembler* masm);
+  static void GenerateMiss(MacroAssembler* masm);
+  static void GenerateMegamorphic(MacroAssembler* masm);
+  static void GenerateNormal(MacroAssembler* masm);
+
+  // Specialized code generator routines.
+  static void GenerateArrayLength(MacroAssembler* masm);
+  static void GenerateShortStringLength(MacroAssembler* masm);
+  static void GenerateMediumStringLength(MacroAssembler* masm);
+  static void GenerateLongStringLength(MacroAssembler* masm);
+  static void GenerateFunctionPrototype(MacroAssembler* masm);
+
+ private:
+  static void Generate(MacroAssembler* masm, const ExternalReference& f);
+
+  // Update the inline cache and the global stub cache based on the
+  // lookup result.
+  void UpdateCaches(LookupResult* lookup,
+                    State state,
+                    Handle<Object> object,
+                    Handle<String> name);
+
+  // Stub accessors.
+  static Code* megamorphic_stub() {
+    return Builtins::builtin(Builtins::LoadIC_Megamorphic);
+  }
+  static Code* initialize_stub() {
+    return Builtins::builtin(Builtins::LoadIC_Initialize);
+  }
+  static Code* pre_monomorphic_stub() {
+    return Builtins::builtin(Builtins::LoadIC_PreMonomorphic);
+  }
+
+  static void Clear(Address address, Code* target);
+  friend class IC;
+};
+
+
+class KeyedLoadIC: public IC {
+ public:
+  KeyedLoadIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_keyed_load_stub()); }
+
+  Object* Load(State state, Handle<Object> object, Handle<Object> key);
+
+  // Code generator routines.
+  static void GenerateMiss(MacroAssembler* masm);
+  static void GenerateInitialize(MacroAssembler* masm);
+  static void GeneratePreMonomorphic(MacroAssembler* masm);
+  static void GenerateGeneric(MacroAssembler* masm);
+
+ private:
+  static void Generate(MacroAssembler* masm, const ExternalReference& f);
+
+  // Update the inline cache.
+  void UpdateCaches(LookupResult* lookup,
+                    State state,
+                    Handle<Object> object,
+                    Handle<String> name);
+
+  // Stub accessors.
+  static Code* initialize_stub() {
+    return Builtins::builtin(Builtins::KeyedLoadIC_Initialize);
+  }
+  static Code* megamorphic_stub() {
+    return Builtins::builtin(Builtins::KeyedLoadIC_Generic);
+  }
+  static Code* generic_stub() {
+    return Builtins::builtin(Builtins::KeyedLoadIC_Generic);
+  }
+  static Code* pre_monomorphic_stub() {
+    return Builtins::builtin(Builtins::KeyedLoadIC_PreMonomorphic);
+  }
+
+  static void Clear(Address address, Code* target);
+  friend class IC;
+};
+
+
+class StoreIC: public IC {
+ public:
+  StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); }
+
+  Object* Store(State state,
+                Handle<Object> object,
+                Handle<String> name,
+                Handle<Object> value);
+
+  // Code generators for stub routines. Only called once at startup.
+  static void GenerateInitialize(MacroAssembler* masm);
+  static void GenerateMiss(MacroAssembler* masm);
+  static void GenerateMegamorphic(MacroAssembler* masm);
+  static void GenerateExtendStorage(MacroAssembler* masm);
+
+ private:
+  static void Generate(MacroAssembler* masm, const ExternalReference& f);
+
+  // Update the inline cache and the global stub cache based on the
+  // lookup result.
+  void UpdateCaches(LookupResult* lookup,
+                    State state, Handle<JSObject> receiver,
+                    Handle<String> name,
+                    Handle<Object> value);
+
+  // Stub accessors.
+  static Code* megamorphic_stub() {
+    return Builtins::builtin(Builtins::StoreIC_Megamorphic);
+  }
+  static Code* initialize_stub() {
+    return Builtins::builtin(Builtins::StoreIC_Initialize);
+  }
+
+  static void Clear(Address address, Code* target);
+  friend class IC;
+};
+
+
+class KeyedStoreIC: public IC {
+ public:
+  KeyedStoreIC() : IC(NO_EXTRA_FRAME) { }
+
+  Object* Store(State state,
+                Handle<Object> object,
+                Handle<Object> name,
+                Handle<Object> value);
+
+  // Code generators for stub routines.  Only called once at startup.
+  static void GenerateInitialize(MacroAssembler* masm);
+  static void GenerateMiss(MacroAssembler* masm);
+  static void GenerateGeneric(MacroAssembler* masm);
+  static void GenerateExtendStorage(MacroAssembler* masm);
+
+ private:
+  static void Generate(MacroAssembler* masm, const ExternalReference& f);
+
+  // Update the inline cache.
+  void UpdateCaches(LookupResult* lookup,
+                    State state,
+                    Handle<JSObject> receiver,
+                    Handle<String> name,
+                    Handle<Object> value);
+
+  // Stub accessors.
+  static Code* initialize_stub() {
+    return Builtins::builtin(Builtins::KeyedStoreIC_Initialize);
+  }
+  static Code* megamorphic_stub() {
+    return Builtins::builtin(Builtins::KeyedStoreIC_Generic);
+  }
+  static Code* generic_stub() {
+    return Builtins::builtin(Builtins::KeyedStoreIC_Generic);
+  }
+
+  static void Clear(Address address, Code* target);
+  friend class IC;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_IC_H_
diff --git a/regexp2000/src/jsregexp.cc b/regexp2000/src/jsregexp.cc
new file mode 100644 (file)
index 0000000..5f3df57
--- /dev/null
@@ -0,0 +1,1051 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <set>
+
+#include "v8.h"
+
+#include "ast.h"
+#include "execution.h"
+#include "factory.h"
+#include "jsregexp.h"
+#include "third_party/jscre/pcre.h"
+#include "platform.h"
+#include "runtime.h"
+#include "top.h"
+#include "compilation-cache.h"
+#include "string-stream.h"
+#include "parser.h"
+
+namespace v8 { namespace internal {
+
+
+#define CAPTURE_INDEX 0
+#define INTERNAL_INDEX 1
+
+static Failure* malloc_failure;
+
+static void* JSREMalloc(size_t size) {
+  Object* obj = Heap::AllocateByteArray(size);
+
+  // If allocation failed, return a NULL pointer to JSRE, and jsRegExpCompile
+  // will return NULL to the caller, performs GC there.
+  // Also pass failure information to the caller.
+  if (obj->IsFailure()) {
+    malloc_failure = Failure::cast(obj);
+    return NULL;
+  }
+
+  // Note: object is unrooted, the caller of jsRegExpCompile must
+  // create a handle for the return value before doing heap allocation.
+  return reinterpret_cast<void*>(ByteArray::cast(obj)->GetDataStartAddress());
+}
+
+
+static void JSREFree(void* p) {
+  USE(p);  // Do nothing, memory is garbage collected.
+}
+
+
+String* RegExpImpl::last_ascii_string_ = NULL;
+String* RegExpImpl::two_byte_cached_string_ = NULL;
+
+
+void RegExpImpl::NewSpaceCollectionPrologue() {
+  // The two byte string is always in the old space.  The Ascii string may be
+  // in either place.  If it is in the old space we don't need to do anything.
+  if (Heap::InNewSpace(last_ascii_string_)) {
+    // Invalidate the cache.
+    last_ascii_string_ = NULL;
+    two_byte_cached_string_ = NULL;
+  }
+}
+
+
+void RegExpImpl::OldSpaceCollectionPrologue() {
+  last_ascii_string_ = NULL;
+  two_byte_cached_string_ = NULL;
+}
+
+
+Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
+                                               Handle<String> pattern,
+                                               Handle<String> flags,
+                                               bool* has_pending_exception) {
+  // Ensure that the constructor function has been loaded.
+  if (!constructor->IsLoaded()) {
+    LoadLazy(constructor, has_pending_exception);
+    if (*has_pending_exception) return Handle<Object>(Failure::Exception());
+  }
+  // Call the construct code with 2 arguments.
+  Object** argv[2] = { Handle<Object>::cast(pattern).location(),
+                       Handle<Object>::cast(flags).location() };
+  return Execution::New(constructor, 2, argv, has_pending_exception);
+}
+
+
+// Converts a source string to a 16 bit flat string or a SlicedString containing
+// a 16 bit flat string).
+Handle<String> RegExpImpl::CachedStringToTwoByte(Handle<String> subject) {
+  if (*subject == last_ascii_string_) {
+    ASSERT(two_byte_cached_string_ != NULL);
+    return Handle<String>(String::cast(two_byte_cached_string_));
+  }
+  Handle<String> two_byte_string = StringToTwoByte(subject);
+  last_ascii_string_ = *subject;
+  two_byte_cached_string_ = *two_byte_string;
+  return two_byte_string;
+}
+
+
+// Converts a source string to a 16 bit flat string or a SlicedString containing
+// a 16 bit flat string).
+Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
+  if (!pattern->IsFlat()) {
+    FlattenString(pattern);
+  }
+  Handle<String> flat_string(pattern->IsConsString() ?
+    String::cast(ConsString::cast(*pattern)->first()) :
+    *pattern);
+  ASSERT(!flat_string->IsConsString());
+  ASSERT(flat_string->IsSeqString() || flat_string->IsSlicedString() ||
+         flat_string->IsExternalString());
+  if (!flat_string->IsAsciiRepresentation()) {
+    return flat_string;
+  }
+
+  Handle<String> two_byte_string =
+    Factory::NewRawTwoByteString(flat_string->length(), TENURED);
+  static StringInputBuffer convert_to_two_byte_buffer;
+  convert_to_two_byte_buffer.Reset(*flat_string);
+  for (int i = 0; convert_to_two_byte_buffer.has_more(); i++) {
+    two_byte_string->Set(i, convert_to_two_byte_buffer.GetNext());
+  }
+  return two_byte_string;
+}
+
+
+static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
+  int flags = JSRegExp::NONE;
+  for (int i = 0; i < str->length(); i++) {
+    switch (str->Get(i)) {
+      case 'i':
+        flags |= JSRegExp::IGNORE_CASE;
+        break;
+      case 'g':
+        flags |= JSRegExp::GLOBAL;
+        break;
+      case 'm':
+        flags |= JSRegExp::MULTILINE;
+        break;
+    }
+  }
+  return JSRegExp::Flags(flags);
+}
+
+
+static inline Handle<Object> CreateRegExpException(Handle<JSRegExp> re,
+                                                   Handle<String> pattern,
+                                                   Handle<String> error_text,
+                                                   const char* message) {
+  Handle<JSArray> array = Factory::NewJSArray(2);
+  SetElement(array, 0, pattern);
+  SetElement(array, 1, error_text);
+  Handle<Object> regexp_err = Factory::NewSyntaxError(message, array);
+  return Handle<Object>(Top::Throw(*regexp_err));
+}
+
+
+unibrow::Predicate<unibrow::RegExpSpecialChar, 128> is_reg_exp_special_char;
+
+Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
+                                   Handle<String> pattern,
+                                   Handle<String> flag_str) {
+  JSRegExp::Flags flags = RegExpFlagsFromString(flag_str);
+  Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
+  bool in_cache = !cached.is_null();
+  Handle<Object> result;
+  if (in_cache) {
+    re->set_data(*cached);
+    result = re;
+  } else {
+    SafeStringInputBuffer buffer(pattern.location());
+    Handle<String> error_text;
+    RegExpTree* ast = ParseRegExp(&buffer, &error_text);
+    if (!error_text.is_null()) {
+      // Throw an exception if we fail to parse the pattern.
+      return CreateRegExpException(re, pattern, error_text, "malformed_regexp");
+    }
+
+    RegExpAtom* atom = ast->AsAtom();
+    if (atom != NULL && !flags.is_ignore_case()) {
+      Vector<const uc16> atom_pattern = atom->data();
+      // Test if pattern equals atom_pattern and reuse pattern if it does.
+      Handle<String> atom_string = Factory::NewStringFromTwoByte(atom_pattern);
+      result = AtomCompile(re, atom_string, flags);
+    } else {
+      result = JsreCompile(re, pattern, flags);
+    }
+    Object* data = re->data();
+    if (data->IsFixedArray()) {
+      // If compilation succeeded then the data is set on the regexp
+      // and we can store it in the cache.
+      Handle<FixedArray> data(FixedArray::cast(re->data()));
+      CompilationCache::PutRegExp(pattern, flags, data);
+    }
+  }
+
+  LOG(RegExpCompileEvent(re, in_cache));
+  return result;
+}
+
+
+Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp,
+                                Handle<String> subject,
+                                Handle<Object> index) {
+  switch (regexp->TypeTag()) {
+    case JSRegExp::JSCRE:
+      return JsreExec(regexp, subject, index);
+    case JSRegExp::ATOM:
+      return AtomExec(regexp, subject, index);
+    default:
+      UNREACHABLE();
+      return Handle<Object>();
+  }
+}
+
+
+Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
+                                Handle<String> subject) {
+  switch (regexp->TypeTag()) {
+    case JSRegExp::JSCRE:
+      return JsreExecGlobal(regexp, subject);
+    case JSRegExp::ATOM:
+      return AtomExecGlobal(regexp, subject);
+    default:
+      UNREACHABLE();
+      return Handle<Object>();
+  }
+}
+
+
+Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re,
+                                       Handle<String> pattern,
+                                       JSRegExp::Flags flags) {
+  ASSERT(!flags.is_ignore_case());
+  Factory::SetRegExpData(re, JSRegExp::ATOM, pattern, flags, pattern);
+  return re;
+}
+
+
+Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
+                                    Handle<String> subject,
+                                    Handle<Object> index) {
+  Handle<String> needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));
+
+  uint32_t start_index;
+  if (!Array::IndexFromObject(*index, &start_index)) {
+    return Handle<Smi>(Smi::FromInt(-1));
+  }
+
+  LOG(RegExpExecEvent(re, start_index, subject));
+  int value = Runtime::StringMatch(subject, needle, start_index);
+  if (value == -1) return Factory::null_value();
+
+  Handle<FixedArray> array = Factory::NewFixedArray(2);
+  array->set(0,
+             Smi::FromInt(value),
+             SKIP_WRITE_BARRIER);
+  array->set(1,
+             Smi::FromInt(value + needle->length()),
+             SKIP_WRITE_BARRIER);
+  return Factory::NewJSArrayWithElements(array);
+}
+
+
+Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
+                                          Handle<String> subject) {
+  Handle<String> needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));
+  Handle<JSArray> result = Factory::NewJSArray(1);
+  int index = 0;
+  int match_count = 0;
+  int subject_length = subject->length();
+  int needle_length = needle->length();
+  while (true) {
+    LOG(RegExpExecEvent(re, index, subject));
+    int value = -1;
+    if (index + needle_length <= subject_length) {
+      value = Runtime::StringMatch(subject, needle, index);
+    }
+    if (value == -1) break;
+    HandleScope scope;
+    int end = value + needle_length;
+
+    Handle<FixedArray> array = Factory::NewFixedArray(2);
+    array->set(0,
+               Smi::FromInt(value),
+               SKIP_WRITE_BARRIER);
+    array->set(1,
+               Smi::FromInt(end),
+               SKIP_WRITE_BARRIER);
+    Handle<JSArray> pair = Factory::NewJSArrayWithElements(array);
+    SetElement(result, match_count, pair);
+    match_count++;
+    index = end;
+    if (needle_length == 0) index++;
+  }
+  return result;
+}
+
+
+Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
+                                       Handle<String> pattern,
+                                       JSRegExp::Flags flags) {
+  // Change this to not compile immediately, but defer the compilation
+  // until the first execution.
+  JSRegExpIgnoreCaseOption case_option = flags.is_ignore_case()
+    ? JSRegExpIgnoreCase
+    : JSRegExpDoNotIgnoreCase;
+  JSRegExpMultilineOption multiline_option = flags.is_multiline()
+    ? JSRegExpMultiline
+    : JSRegExpSingleLine;
+
+  Handle<String> two_byte_pattern = StringToTwoByte(pattern);
+
+  unsigned number_of_captures;
+  const char* error_message = NULL;
+
+  JscreRegExp* code = NULL;
+  FlattenString(pattern);
+
+  bool first_time = true;
+
+  while (true) {
+    malloc_failure = Failure::Exception();
+    code = jsRegExpCompile(two_byte_pattern->GetTwoByteData(),
+                           pattern->length(), case_option,
+                           multiline_option, &number_of_captures,
+                           &error_message, &JSREMalloc, &JSREFree);
+    if (code == NULL) {
+      if (first_time && malloc_failure->IsRetryAfterGC()) {
+        first_time = false;
+        if (!Heap::CollectGarbage(malloc_failure->requested(),
+                                  malloc_failure->allocation_space())) {
+          // TODO(1181417): Fix this.
+          V8::FatalProcessOutOfMemory("RegExpImpl::JsreCompile");
+        }
+        continue;
+      }
+      if (malloc_failure->IsRetryAfterGC() ||
+          malloc_failure->IsOutOfMemoryFailure()) {
+        // TODO(1181417): Fix this.
+        V8::FatalProcessOutOfMemory("RegExpImpl::JsreCompile");
+      } else {
+        // Throw an exception.
+        Handle<JSArray> array = Factory::NewJSArray(2);
+        SetElement(array, 0, pattern);
+        SetElement(array, 1, Factory::NewStringFromUtf8(CStrVector(
+            (error_message == NULL) ? "Unknown regexp error" : error_message)));
+        Handle<Object> regexp_err =
+            Factory::NewSyntaxError("malformed_regexp", array);
+        return Handle<Object>(Top::Throw(*regexp_err));
+      }
+    }
+
+    ASSERT(code != NULL);
+    // Convert the return address to a ByteArray pointer.
+    Handle<ByteArray> internal(
+        ByteArray::FromDataStartAddress(reinterpret_cast<Address>(code)));
+
+    Handle<FixedArray> value = Factory::NewFixedArray(2);
+    value->set(CAPTURE_INDEX, Smi::FromInt(number_of_captures));
+    value->set(INTERNAL_INDEX, *internal);
+    Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value);
+
+    return re;
+  }
+}
+
+
+Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
+                                        int num_captures,
+                                        Handle<String> subject,
+                                        int previous_index,
+                                        const uc16* two_byte_subject,
+                                        int* offsets_vector,
+                                        int offsets_vector_length) {
+  int rc;
+  {
+    AssertNoAllocation a;
+    ByteArray* internal = JsreInternal(regexp);
+    const JscreRegExp* js_regexp =
+        reinterpret_cast<JscreRegExp*>(internal->GetDataStartAddress());
+
+    LOG(RegExpExecEvent(regexp, previous_index, subject));
+
+    rc = jsRegExpExecute(js_regexp,
+                         two_byte_subject,
+                         subject->length(),
+                         previous_index,
+                         offsets_vector,
+                         offsets_vector_length);
+  }
+
+  // The KJS JavaScript engine returns null (ie, a failed match) when
+  // JSRE's internal match limit is exceeded.  We duplicate that behavior here.
+  if (rc == JSRegExpErrorNoMatch
+      || rc == JSRegExpErrorHitLimit) {
+    return Factory::null_value();
+  }
+
+  // Other JSRE errors:
+  if (rc < 0) {
+    // Throw an exception.
+    Handle<Object> code(Smi::FromInt(rc));
+    Handle<Object> args[2] = { Factory::LookupAsciiSymbol("jsre_exec"), code };
+    Handle<Object> regexp_err(
+        Factory::NewTypeError("jsre_error", HandleVector(args, 2)));
+    return Handle<Object>(Top::Throw(*regexp_err));
+  }
+
+  Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1));
+  // The captures come in (start, end+1) pairs.
+  for (int i = 0; i < 2 * (num_captures+1); i += 2) {
+    array->set(i,
+               Smi::FromInt(offsets_vector[i]),
+               SKIP_WRITE_BARRIER);
+    array->set(i+1,
+               Smi::FromInt(offsets_vector[i+1]),
+               SKIP_WRITE_BARRIER);
+  }
+  return Factory::NewJSArrayWithElements(array);
+}
+
+
+class OffsetsVector {
+ public:
+  inline OffsetsVector(int num_captures) {
+    offsets_vector_length_ = (num_captures + 1) * 3;
+    if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
+      vector_ = NewArray<int>(offsets_vector_length_);
+    } else {
+      vector_ = static_offsets_vector_;
+    }
+  }
+
+
+  inline ~OffsetsVector() {
+    if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
+      DeleteArray(vector_);
+      vector_ = NULL;
+    }
+  }
+
+
+  inline int* vector() {
+    return vector_;
+  }
+
+
+  inline int length() {
+    return offsets_vector_length_;
+  }
+
+ private:
+  int* vector_;
+  int offsets_vector_length_;
+  static const int kStaticOffsetsVectorSize = 30;
+  static int static_offsets_vector_[kStaticOffsetsVectorSize];
+};
+
+
+int OffsetsVector::static_offsets_vector_[
+    OffsetsVector::kStaticOffsetsVectorSize];
+
+
+Handle<Object> RegExpImpl::JsreExec(Handle<JSRegExp> regexp,
+                                    Handle<String> subject,
+                                    Handle<Object> index) {
+  // Prepare space for the return values.
+  int num_captures = JsreCapture(regexp);
+
+  OffsetsVector offsets(num_captures);
+
+  int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
+
+  Handle<String> subject16 = CachedStringToTwoByte(subject);
+
+  Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
+                                     previous_index,
+                                     subject16->GetTwoByteData(),
+                                     offsets.vector(), offsets.length()));
+
+  return result;
+}
+
+
+Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
+                                          Handle<String> subject) {
+  // Prepare space for the return values.
+  int num_captures = JsreCapture(regexp);
+
+  OffsetsVector offsets(num_captures);
+
+  int previous_index = 0;
+
+  Handle<JSArray> result = Factory::NewJSArray(0);
+  int i = 0;
+  Handle<Object> matches;
+
+  Handle<String> subject16 = CachedStringToTwoByte(subject);
+
+  do {
+    if (previous_index > subject->length() || previous_index < 0) {
+      // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+      // string length, there is no match.
+      matches = Factory::null_value();
+    } else {
+      matches = JsreExecOnce(regexp, num_captures, subject, previous_index,
+                             subject16->GetTwoByteData(),
+                             offsets.vector(), offsets.length());
+
+      if (matches->IsJSArray()) {
+        SetElement(result, i, matches);
+        i++;
+        previous_index = offsets.vector()[1];
+        if (offsets.vector()[0] == offsets.vector()[1]) {
+          previous_index++;
+        }
+      }
+    }
+  } while (matches->IsJSArray());
+
+  // If we exited the loop with an exception, throw it.
+  if (matches->IsNull()) {  // Exited loop normally.
+    return result;
+  } else {  // Exited loop with the exception in matches.
+    return matches;
+  }
+}
+
+
+int RegExpImpl::JsreCapture(Handle<JSRegExp> re) {
+  FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
+  return Smi::cast(value->get(CAPTURE_INDEX))->value();
+}
+
+
+ByteArray* RegExpImpl::JsreInternal(Handle<JSRegExp> re) {
+  FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
+  return ByteArray::cast(value->get(INTERNAL_INDEX));
+}
+
+
+// -------------------------------------------------------------------
+// New regular expression engine
+
+
+template <typename Char> class ExecutionState;
+
+
+template <typename Char>
+class DotPrinter {
+ public:
+  DotPrinter() : stream_(&alloc_) { }
+  void PrintNode(RegExpNode<Char>* node);
+  void Visit(RegExpNode<Char>* node);
+  StringStream* stream() { return &stream_; }
+ private:
+  HeapStringAllocator alloc_;
+  StringStream stream_;
+  std::set<RegExpNode<Char>*> seen_;
+};
+
+
+template <typename Char>
+class RegExpCompiler: public RegExpVisitor {
+ public:
+  RegExpCompiler() { }
+  RegExpNode<Char>* Compile(RegExpTree* tree, RegExpNode<Char>* rest) {
+    return static_cast<RegExpNode<Char>*>(tree->Accept(this, rest));
+  }
+#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void*);
+  FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CASE)
+#undef MAKE_CASE
+};
+
+
+template <typename Char>
+class RegExpNode: public ZoneObject {
+ public:
+  virtual ~RegExpNode() { }
+  virtual void EmitDot(DotPrinter<Char>* out);
+  virtual bool Step(ExecutionState<Char>* state) = 0;
+};
+
+
+template <typename Char>
+class SeqRegExpNode: public RegExpNode<Char> {
+ public:
+  explicit SeqRegExpNode(RegExpNode<Char>* next) : next_(next) { }
+  RegExpNode<Char>* next() { return next_; }
+ private:
+  RegExpNode<Char>* next_;
+};
+
+
+template <typename Char>
+class EndNode: public RegExpNode<Char> {
+ public:
+  virtual void EmitDot(DotPrinter<Char>* out);
+  virtual bool Step(ExecutionState<Char>* state);
+};
+
+
+template <typename Char>
+class AtomNode: public SeqRegExpNode<Char> {
+ public:
+  AtomNode(Vector<const uc16> data, RegExpNode<Char>* next)
+    : SeqRegExpNode<Char>(next),
+      data_(data) { }
+  virtual void EmitDot(DotPrinter<Char>* out);
+  virtual bool Step(ExecutionState<Char>* state);
+  Vector<const uc16> data() { return data_; }
+ private:
+  Vector<const uc16> data_;
+};
+
+
+template <typename Char>
+class CharacterClassNode: public SeqRegExpNode<Char> {
+ public:
+  CharacterClassNode(ZoneList<CharacterRange>* ranges, RegExpNode<Char>* next)
+    : SeqRegExpNode<Char>(next),
+      ranges_(ranges) { }
+  virtual void EmitDot(DotPrinter<Char>* out);
+  virtual bool Step(ExecutionState<Char>* state);
+  ZoneList<CharacterRange>* ranges() { return ranges_; }
+ private:
+  ZoneList<CharacterRange>* ranges_;
+};
+
+
+template <typename Char>
+class ChoiceNode: public RegExpNode<Char> {
+ public:
+  explicit ChoiceNode(ZoneList<RegExpNode<Char>*>* choices)
+    : choices_(choices) { }
+  virtual void EmitDot(DotPrinter<Char>* out);
+  virtual bool Step(ExecutionState<Char>* state);
+  ZoneList<RegExpNode<Char>*>* choices() { return choices_; }
+ private:
+  ZoneList<RegExpNode<Char>*>* choices_;
+};
+
+
+// -------------------------------------------------------------------
+// Dot/dotty output
+
+
+template <typename Char>
+void DotPrinter<Char>::PrintNode(RegExpNode<Char>* node) {
+  stream()->Add("digraph G {\n");
+  Visit(node);
+  stream()->Add("}\n");
+  printf("%s", *(stream()->ToCString()));
+}
+
+
+template <typename Char>
+void DotPrinter<Char>::Visit(RegExpNode<Char>* node) {
+  if (seen_.find(node) != seen_.end())
+    return;
+  seen_.insert(node);
+  node->EmitDot(this);
+}
+
+
+template <typename Char>
+void RegExpNode<Char>::EmitDot(DotPrinter<Char>* out) {
+  UNIMPLEMENTED();
+}
+
+
+template <typename Char>
+void ChoiceNode<Char>::EmitDot(DotPrinter<Char>* out) {
+  out->stream()->Add("n%p [label=\"?\"];\n", this);
+  for (int i = 0; i < choices()->length(); i++) {
+    out->stream()->Add("n%p -> n%p [label=\"%i\"];\n",
+                       this,
+                       choices()->at(i),
+                       i);
+    out->Visit(choices()->at(i));
+  }
+}
+
+
+template <typename Char>
+void AtomNode<Char>::EmitDot(DotPrinter<Char>* out) {
+  out->stream()->Add("n%p [label=\"'%w'\"];\n", this, data());
+  out->stream()->Add("n%p -> n%p;\n", this, this->next());
+  out->Visit(this->next());
+}
+
+
+template <typename Char>
+void EndNode<Char>::EmitDot(DotPrinter<Char>* out) {
+  out->stream()->Add("n%p [style=bold, label=\"done\"];\n", this);
+}
+
+
+template <typename Char>
+void CharacterClassNode<Char>::EmitDot(DotPrinter<Char>* out) {
+  out->stream()->Add("n%p [label=\"[...]\"];\n", this);
+  out->stream()->Add("n%p -> n%p;\n", this, this->next());
+  out->Visit(this->next());
+}
+
+
+// -------------------------------------------------------------------
+// Tree to graph conversion
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitAtom(RegExpAtom* that, void* rest) {
+  return new AtomNode<Char>(that->data(),
+                            static_cast<RegExpNode<Char>*>(rest));
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitCharacterClass(RegExpCharacterClass* that,
+                                                void* rest) {
+  return new CharacterClassNode<Char>(that->ranges(),
+                                      static_cast<RegExpNode<Char>*>(rest));
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitDisjunction(RegExpDisjunction* that,
+                                             void* rest_ptr) {
+  RegExpNode<Char>* rest = static_cast<RegExpNode<Char>*>(rest_ptr);
+  ZoneList<RegExpTree*>* children = that->nodes();
+  int length = children->length();
+  ZoneList<RegExpNode<Char>*>* choices
+      = new ZoneList<RegExpNode<Char>*>(length);
+  for (int i = 0; i < length; i++)
+    choices->Add(Compile(children->at(i), rest));
+  return new ChoiceNode<Char>(choices);
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitQuantifier(RegExpQuantifier* that,
+                                            void* rest_ptr) {
+  RegExpNode<Char>* rest = static_cast<RegExpNode<Char>*>(rest_ptr);
+  if (that->max() >= RegExpQuantifier::kInfinity) {
+    // Don't try to count the number of iterations if the max it too
+    // large.
+    if (that->min() != 0) {
+      UNIMPLEMENTED();
+    }
+    ZoneList<RegExpNode<Char>*>* loop_choices
+        = new ZoneList<RegExpNode<Char>*>(2);
+    RegExpNode<Char>* loop_node = new ChoiceNode<Char>(loop_choices);
+    RegExpNode<Char>* body_node = Compile(that->body(), loop_node);
+    if (that->is_greedy()) {
+      loop_choices->Add(body_node);
+      loop_choices->Add(rest);
+    } else {
+      loop_choices->Add(rest);
+      loop_choices->Add(body_node);
+    }
+    return loop_node;
+  } else {
+    UNIMPLEMENTED();
+    return NULL;
+  }
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitAssertion(RegExpAssertion* that,
+                                           void* rest) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitCapture(RegExpCapture* that, void* rest) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitLookahead(RegExpLookahead* that,
+                                           void* rest) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitBackreference(RegExpBackreference* that,
+                                               void* rest) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitEmpty(RegExpEmpty* that, void* rest) {
+  return rest;
+}
+
+
+template <typename Char>
+void* RegExpCompiler<Char>::VisitAlternative(RegExpAlternative* that,
+                                             void* rest) {
+  ZoneList<RegExpTree*>* children = that->nodes();
+  RegExpNode<Char>* current = static_cast<RegExpNode<Char>*>(rest);
+  for (int i = children->length() - 1; i >= 0; i--) {
+    current = Compile(children->at(i), current);
+  }
+  return current;
+}
+
+
+// -------------------------------------------------------------------
+// Execution
+
+
+template <typename Char>
+class ExecutionState {
+ public:
+  ExecutionState(RegExpNode<Char>* start, Vector<Char> input)
+    : current_(start),
+      input_(input),
+      pos_(0),
+      backtrack_stack_(8),
+      is_done_(false) { }
+
+  class BacktrackState {
+   public:
+    BacktrackState(ChoiceNode<Char>* choice, int next, int pos)
+      : choice_(choice),
+        next_(next),
+        pos_(pos) { }
+    ChoiceNode<Char>* choice() { return choice_; }
+    int next() { return next_; }
+    void set_next(int value) { next_ = value; }
+    int pos() { return pos_; }
+   private:
+    ChoiceNode<Char>* choice_;
+    int next_;
+    int pos_;
+  };
+
+  // Execute a single step, returning true if it succeeded
+  inline bool Step() { return current()->Step(this); }
+
+  // Stores the given choice node and the execution state on the
+  // backtrack stack.
+  void SaveBacktrack(ChoiceNode<Char>* choice);
+
+  // Reverts to the next unused backtrack if there is one.  Returns
+  // false exactly if there was no backtrack to restore.
+  bool Backtrack();
+
+  Char current_char() { return input()[pos()]; }
+
+  void Advance(int delta, RegExpNode<Char>* next) {
+    pos_ += delta;
+    current_ = next;
+  }
+
+  bool AtEnd() { return pos_ >= input_.length(); }
+
+  bool is_done() { return is_done_; }
+  void set_done() { is_done_ = true; }
+
+  List<BacktrackState>* backtrack_stack() { return &backtrack_stack_; }
+  RegExpNode<Char>* current() { return current_; }
+  void set_current(RegExpNode<Char>* value) { current_ = value; }
+  Vector<Char> input() { return input_; }
+  int pos() { return pos_; }
+ private:
+  RegExpNode<Char>* current_;
+  Vector<Char> input_;
+  int pos_;
+  List<BacktrackState> backtrack_stack_;
+  bool is_done_;
+};
+
+
+template <typename Char>
+void ExecutionState<Char>::SaveBacktrack(ChoiceNode<Char>* choice) {
+  ASSERT(choice->choices()->length() > 1);
+  if (FLAG_trace_regexps) {
+    PrintF("Setting up backtrack on level %i for choice %p\n",
+           backtrack_stack()->length(),
+           choice);
+  }
+  backtrack_stack()->Add(BacktrackState(choice, 1, pos_));
+}
+
+
+template <typename Char>
+bool ExecutionState<Char>::Backtrack() {
+  if (backtrack_stack()->is_empty()) return false;
+  BacktrackState& top = backtrack_stack()->at(backtrack_stack()->length() - 1);
+  ZoneList<RegExpNode<Char>*>* choices = top.choice()->choices();
+  int next_index = top.next();
+  current_ = choices->at(next_index);
+  pos_ = top.pos();
+  if (FLAG_trace_regexps) {
+    PrintF("Backtracking to %p[%i] on level %i\n",
+           top.choice(),
+           next_index,
+           backtrack_stack()->length() - 1);
+  }
+  if (next_index == choices->length() - 1) {
+    if (FLAG_trace_regexps)
+      PrintF("Popping backtrack on level %i\n",
+             backtrack_stack()->length() - 1);
+    // If this was the last alternative we're done with this backtrack
+    // state and can pop it off the stack.
+    backtrack_stack()->RemoveLast();
+  } else {
+    if (FLAG_trace_regexps)
+      PrintF("Advancing backtrack on level %i\n",
+             backtrack_stack()->length() - 1);
+    // Otherwise we set the next choice to visit if this one fails.
+    top.set_next(next_index + 1);
+  }
+  return true;
+}
+
+
+template <typename Char>
+bool ChoiceNode<Char>::Step(ExecutionState<Char>* state) {
+  state->SaveBacktrack(this);
+  state->set_current(this->choices()->at(0));
+  return true;
+}
+
+
+template <typename Char>
+bool AtomNode<Char>::Step(ExecutionState<Char>* state) {
+  Vector<const uc16> data = this->data();
+  int length = data.length();
+  Vector<Char> input = state->input();
+  int p = state->pos();
+  if (p + length > input.length())
+    return false;
+  for (int i = 0; i < length; i++, p++) {
+    if (data[i] != input[p])
+      return false;
+  }
+  state->Advance(length, this->next());
+  return true;
+}
+
+
+template <typename Char>
+bool CharacterClassNode<Char>::Step(ExecutionState<Char>* state) {
+  if (state->AtEnd()) return false;
+  ZoneList<CharacterRange>* ranges = this->ranges();
+  unsigned current = state->current_char();
+  for (int i = 0; i < ranges->length(); i++) {
+    CharacterRange& range = ranges->at(i);
+    if (range.is_character_class()) {
+      switch (range.from()) {
+        case '.':
+          state->Advance(1, this->next());
+          return true;
+        default:
+          UNIMPLEMENTED();
+      }
+    } else {
+      if (range.from() <= current && current <= range.to()) {
+        state->Advance(1, this->next());
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+template <typename Char>
+bool EndNode<Char>::Step(ExecutionState<Char>* state) {
+  state->set_done();
+  return false;
+}
+
+
+template <typename Char>
+bool RegExpEngine::Execute(RegExpNode<Char>* start, Vector<Char> input) {
+  ExecutionState<Char> state(start, input);
+  if (FLAG_trace_regexps) {
+    PrintF("Beginning regexp execution\n");
+  }
+  while (state.Step() || (!state.is_done() && state.Backtrack()))
+    ;
+  if (FLAG_trace_regexps) {
+    PrintF("Matching %s\n", state.is_done() ? "succeeded" : "failed");
+  }
+  return state.is_done();
+}
+
+
+template <typename Char>
+RegExpNode<Char>* RegExpEngine::Compile(RegExpTree* regexp) {
+  RegExpNode<Char>* end = new EndNode<Char>();
+  RegExpCompiler<Char> compiler;
+  return compiler.Compile(regexp, end);
+}
+
+
+template
+RegExpNode<const char>* RegExpEngine::Compile<const char>(RegExpTree* regexp);
+
+template
+RegExpNode<const uc16>* RegExpEngine::Compile<const uc16>(RegExpTree* regexp);
+
+template
+bool RegExpEngine::Execute<const char>(RegExpNode<const char>* start,
+                                       Vector<const char> input);
+
+template
+bool RegExpEngine::Execute<const uc16>(RegExpNode<const uc16>* start,
+                                       Vector<const uc16> input);
+
+
+}}  // namespace v8::internal
diff --git a/regexp2000/src/jsregexp.h b/regexp2000/src/jsregexp.h
new file mode 100644 (file)
index 0000000..7138316
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_JSREGEXP_H_
+#define V8_JSREGEXP_H_
+
+namespace v8 { namespace internal {
+
+class RegExpImpl {
+ public:
+  // Creates a regular expression literal in the old space.
+  // This function calls the garbage collector if necessary.
+  static Handle<Object> CreateRegExpLiteral(Handle<JSFunction> constructor,
+                                            Handle<String> pattern,
+                                            Handle<String> flags,
+                                            bool* has_pending_exception);
+
+  // Returns a string representation of a regular expression.
+  // Implements RegExp.prototype.toString, see ECMA-262 section 15.10.6.4.
+  // This function calls the garbage collector if necessary.
+  static Handle<String> ToString(Handle<Object> value);
+
+  static Handle<Object> Compile(Handle<JSRegExp> re,
+                                Handle<String> pattern,
+                                Handle<String> flags);
+
+  // Implements RegExp.prototype.exec(string) function.
+  // See ECMA-262 section 15.10.6.2.
+  // This function calls the garbage collector if necessary.
+  static Handle<Object> Exec(Handle<JSRegExp> regexp,
+                             Handle<String> subject,
+                             Handle<Object> index);
+
+  // Call RegExp.prototyp.exec(string) in a loop.
+  // Used by String.prototype.match and String.prototype.replace.
+  // This function calls the garbage collector if necessary.
+  static Handle<Object> ExecGlobal(Handle<JSRegExp> regexp,
+                                   Handle<String> subject);
+
+  static Handle<Object> AtomCompile(Handle<JSRegExp> re,
+                                    Handle<String> pattern,
+                                    JSRegExp::Flags flags);
+
+  static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
+                                 Handle<String> subject,
+                                 Handle<Object> index);
+
+  static Handle<Object> AtomExecGlobal(Handle<JSRegExp> regexp,
+                                       Handle<String> subject);
+
+  static Handle<Object> JsreCompile(Handle<JSRegExp> re,
+                                    Handle<String> pattern,
+                                    JSRegExp::Flags flags);
+
+  static Handle<Object> JsreExec(Handle<JSRegExp> regexp,
+                                 Handle<String> subject,
+                                 Handle<Object> index);
+
+  static Handle<Object> JsreExecGlobal(Handle<JSRegExp> regexp,
+                                       Handle<String> subject);
+
+  static void NewSpaceCollectionPrologue();
+  static void OldSpaceCollectionPrologue();
+
+ private:
+  // Converts a source string to a 16 bit flat string.  The string
+  // will be either sequential or it will be a SlicedString backed
+  // by a flat string.
+  static Handle<String> StringToTwoByte(Handle<String> pattern);
+  static Handle<String> CachedStringToTwoByte(Handle<String> pattern);
+
+  static String* last_ascii_string_;
+  static String* two_byte_cached_string_;
+
+  // Returns the caputure from the re.
+  static int JsreCapture(Handle<JSRegExp> re);
+  static ByteArray* JsreInternal(Handle<JSRegExp> re);
+
+  // Call jsRegExpExecute once
+  static Handle<Object> JsreExecOnce(Handle<JSRegExp> regexp,
+                                     int num_captures,
+                                     Handle<String> subject,
+                                     int previous_index,
+                                     const uc16* utf8_subject,
+                                     int* ovector,
+                                     int ovector_length);
+
+  // Set the subject cache.  The previous string buffer is not deleted, so the
+  // caller should ensure that it doesn't leak.
+  static void SetSubjectCache(String* subject, char* utf8_subject,
+                              int uft8_length, int character_position,
+                              int utf8_position);
+
+  // A one element cache of the last utf8_subject string and its length.  The
+  // subject JS String object is cached in the heap.  We also cache a
+  // translation between position and utf8 position.
+  static char* utf8_subject_cache_;
+  static int utf8_length_cache_;
+  static int utf8_position_;
+  static int character_position_;
+};
+
+
+template <typename Char> class RegExpNode;
+
+
+class RegExpEngine: public AllStatic {
+ public:
+  template <typename Char>
+  static RegExpNode<Char>* Compile(RegExpTree* regexp);
+
+  template <typename Char>
+  static bool Execute(RegExpNode<Char>* start, Vector<Char> input);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_JSREGEXP_H_
diff --git a/regexp2000/src/list-inl.h b/regexp2000/src/list-inl.h
new file mode 100644 (file)
index 0000000..a185af3
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_LIST_INL_H_
+#define V8_LIST_INL_H_
+
+#include "list.h"
+
+namespace v8 { namespace internal {
+
+
+template<typename T, class P>
+T& List<T, P>::Add(const T& element) {
+  if (length_ >= capacity_) {
+    // Grow the list capacity by 50%, but make sure to let it grow
+    // even when the capacity is zero (possible initial case).
+    int new_capacity = 1 + capacity_ + (capacity_ >> 1);
+    T* new_data = NewData(new_capacity);
+    memcpy(new_data, data_, capacity_ * sizeof(T));
+    DeleteData(data_);
+    data_ = new_data;
+    capacity_ = new_capacity;
+  }
+  return data_[length_++] = element;
+}
+
+
+template<typename T, class P>
+Vector<T> List<T, P>::AddBlock(const T& element, int count) {
+  int start = length_;
+  for (int i = 0; i < count; i++)
+    Add(element);
+  return Vector<T>(&data_[start], count);
+}
+
+
+template<typename T, class P>
+T List<T, P>::Remove(int i) {
+  T element = at(i);
+  length_--;
+  while (i < length_) {
+    data_[i] = data_[i + 1];
+    i++;
+  }
+  return element;
+}
+
+
+template<typename T, class P>
+void List<T, P>::Clear() {
+  DeleteData(data_);
+  Initialize(0);
+}
+
+
+template<typename T, class P>
+void List<T, P>::Rewind(int pos) {
+  length_ = pos;
+}
+
+
+template<typename T, class P>
+void List<T, P>::Iterate(void (*callback)(T* x)) {
+  for (int i = 0; i < length_; i++) callback(&data_[i]);
+}
+
+
+template<typename T, class P>
+void List<T, P>::Sort(int (*cmp)(const T* x, const T* y)) {
+  qsort(data_,
+        length_,
+        sizeof(T),
+        reinterpret_cast<int (*)(const void*, const void*)>(cmp));
+#ifdef DEBUG
+  for (int i = 1; i < length_; i++)
+    ASSERT(cmp(&data_[i - 1], &data_[i]) <= 0);
+#endif
+}
+
+
+template<typename T, class P>
+void List<T, P>::Initialize(int capacity) {
+  ASSERT(capacity >= 0);
+  data_ = (capacity > 0) ? NewData(capacity) : NULL;
+  capacity_ = capacity;
+  length_ = 0;
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_LIST_INL_H_
diff --git a/regexp2000/src/list.h b/regexp2000/src/list.h
new file mode 100644 (file)
index 0000000..1fe9067
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_LIST_H_
+#define V8_LIST_H_
+
+namespace v8 { namespace internal {
+
+
+// ----------------------------------------------------------------------------
+// The list is a template for very light-weight lists. We are not
+// using the STL because we want full control over space and speed of
+// the code. This implementation is based on code by Robert Griesemer
+// and Rob Pike.
+//
+// The list is parameterized by the type of its elements (T) and by an
+// allocation policy (P). The policy is used for allocating lists in
+// the C free store or the zone; see zone.h.
+
+// Forward defined as
+// template <typename T, class P = FreeStoreAllocationPolicy> class List;
+template <typename T, class P>
+class List {
+ public:
+
+  INLINE(explicit List(int capacity)) { Initialize(capacity); }
+  INLINE(~List()) { DeleteData(data_); }
+
+  INLINE(void* operator new(size_t size)) { return P::New(size); }
+  INLINE(void operator delete(void* p, size_t)) { return P::Delete(p); }
+
+  inline T& operator[](int i) const  {
+    ASSERT(0 <= i && i < length_);
+    return data_[i];
+  }
+  inline T& at(int i) const  { return this->operator[](i); }
+  INLINE(const T& last() const)  {
+    ASSERT(!is_empty());
+    return this->at(length_ - 1);
+  }
+
+  INLINE(bool is_empty() const) { return length_ == 0; }
+  INLINE(int length() const) { return length_; }
+
+  Vector<T> ToVector() { return Vector<T>(data_, length_); }
+
+  Vector<const T> ToConstVector() { return Vector<const T>(data_, length_); }
+
+  // Adds a copy of the given 'element' to the end of the list,
+  // expanding the list if necessary.
+  T& Add(const T& element);
+
+  // Added 'count' elements with the value 'value' and returns a
+  // vector that allows access to the elements.  The vector is valid
+  // until the next change is made to this list.
+  Vector<T> AddBlock(const T& value, int count);
+
+  // Removes the i'th element without deleting it even if T is a
+  // pointer type; moves all elements above i "down". Returns the
+  // removed element.
+  T Remove(int i);
+
+  // Removes the last element without deleting it even if T is a
+  // pointer type. Returns the removed element.
+  INLINE(T RemoveLast()) { return Remove(length_ - 1); }
+
+  // Clears the list by setting the length to zero. Even if T is a
+  // pointer type, clearing the list doesn't delete the entries.
+  INLINE(void Clear());
+
+  // Drops all but the first 'pos' elements from the list.
+  INLINE(void Rewind(int pos));
+
+  // Iterate through all list entries, starting at index 0.
+  void Iterate(void (*callback)(T* x));
+
+  // Sort all list entries (using QuickSort)
+  void Sort(int (*cmp)(const T* x, const T* y));
+
+  INLINE(void Initialize(int capacity));
+
+ private:
+  T* data_;
+  int capacity_;
+  int length_;
+
+  INLINE(T* NewData(int n))  { return static_cast<T*>(P::New(n * sizeof(T))); }
+  INLINE(void DeleteData(T* data))  { P::Delete(data); }
+
+  DISALLOW_COPY_AND_ASSIGN(List);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_LIST_H_
diff --git a/regexp2000/src/log.cc b/regexp2000/src/log.cc
new file mode 100644 (file)
index 0000000..796b98e
--- /dev/null
@@ -0,0 +1,849 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdarg.h>
+
+#include "v8.h"
+
+#include "log.h"
+#include "platform.h"
+#include "string-stream.h"
+
+namespace v8 { namespace internal {
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+//
+// Sliding state window.  Updates counters to keep track of the last
+// window of kBufferSize states.  This is useful to track where we
+// spent our time.
+//
+class SlidingStateWindow {
+ public:
+  SlidingStateWindow();
+  ~SlidingStateWindow();
+  void AddState(StateTag state);
+
+ private:
+  static const int kBufferSize = 256;
+  int current_index_;
+  bool is_full_;
+  byte buffer_[kBufferSize];
+
+
+  void IncrementStateCounter(StateTag state) {
+    Counters::state_counters[state].Increment();
+  }
+
+
+  void DecrementStateCounter(StateTag state) {
+    Counters::state_counters[state].Decrement();
+  }
+};
+
+
+//
+// The Profiler samples pc and sp values for the main thread.
+// Each sample is appended to a circular buffer.
+// An independent thread removes data and writes it to the log.
+// This design minimizes the time spent in the sampler.
+//
+class Profiler: public Thread {
+ public:
+  Profiler();
+  void Engage();
+  void Disengage();
+
+  // Inserts collected profiling data into buffer.
+  void Insert(TickSample* sample) {
+    if (Succ(head_) == tail_) {
+      overflow_ = true;
+    } else {
+      buffer_[head_] = *sample;
+      head_ = Succ(head_);
+      buffer_semaphore_->Signal();  // Tell we have an element.
+    }
+  }
+
+  // Waits for a signal and removes profiling data.
+  bool Remove(TickSample* sample) {
+    buffer_semaphore_->Wait();  // Wait for an element.
+    *sample = buffer_[tail_];
+    bool result = overflow_;
+    tail_ = Succ(tail_);
+    overflow_ = false;
+    return result;
+  }
+
+  void Run();
+
+ private:
+  // Returns the next index in the cyclic buffer.
+  int Succ(int index) { return (index + 1) % kBufferSize; }
+
+  // Cyclic buffer for communicating profiling samples
+  // between the signal handler and the worker thread.
+  static const int kBufferSize = 128;
+  TickSample buffer_[kBufferSize];  // Buffer storage.
+  int head_;  // Index to the buffer head.
+  int tail_;  // Index to the buffer tail.
+  bool overflow_;  // Tell whether a buffer overflow has occurred.
+  Semaphore* buffer_semaphore_;  // Sempahore used for buffer synchronization.
+
+  // Tells whether worker thread should continue running.
+  bool running_;
+};
+
+
+//
+// Ticker used to provide ticks to the profiler and the sliding state
+// window.
+//
+class Ticker: public Sampler {
+ public:
+  explicit Ticker(int interval):
+      Sampler(interval, FLAG_prof), window_(NULL), profiler_(NULL) {}
+
+  ~Ticker() { if (IsActive()) Stop(); }
+
+  void Tick(TickSample* sample) {
+    if (profiler_) profiler_->Insert(sample);
+    if (window_) window_->AddState(sample->state);
+  }
+
+  void SetWindow(SlidingStateWindow* window) {
+    window_ = window;
+    if (!IsActive()) Start();
+  }
+
+  void ClearWindow() {
+    window_ = NULL;
+    if (!profiler_ && IsActive()) Stop();
+  }
+
+  void SetProfiler(Profiler* profiler) {
+    profiler_ = profiler;
+    if (!IsActive()) Start();
+  }
+
+  void ClearProfiler() {
+    profiler_ = NULL;
+    if (!window_ && IsActive()) Stop();
+  }
+
+ private:
+  SlidingStateWindow* window_;
+  Profiler* profiler_;
+};
+
+
+//
+// SlidingStateWindow implementation.
+//
+SlidingStateWindow::SlidingStateWindow(): current_index_(0), is_full_(false) {
+  for (int i = 0; i < kBufferSize; i++) {
+    buffer_[i] = static_cast<byte>(OTHER);
+  }
+  Logger::ticker_->SetWindow(this);
+}
+
+
+SlidingStateWindow::~SlidingStateWindow() {
+  Logger::ticker_->ClearWindow();
+}
+
+
+void SlidingStateWindow::AddState(StateTag state) {
+  if (is_full_) {
+    DecrementStateCounter(static_cast<StateTag>(buffer_[current_index_]));
+  } else if (current_index_ == kBufferSize - 1) {
+    is_full_ = true;
+  }
+  buffer_[current_index_] = static_cast<byte>(state);
+  IncrementStateCounter(state);
+  ASSERT(IsPowerOf2(kBufferSize));
+  current_index_ = (current_index_ + 1) & (kBufferSize - 1);
+}
+
+
+//
+// Profiler implementation.
+//
+Profiler::Profiler() {
+  buffer_semaphore_ = OS::CreateSemaphore(0);
+  head_ = 0;
+  tail_ = 0;
+  overflow_ = false;
+  running_ = false;
+}
+
+
+void Profiler::Engage() {
+  OS::LogSharedLibraryAddresses();
+
+  // Start thread processing the profiler buffer.
+  running_ = true;
+  Start();
+
+  // Register to get ticks.
+  Logger::ticker_->SetProfiler(this);
+
+  LOG(StringEvent("profiler", "begin"));
+}
+
+
+void Profiler::Disengage() {
+  // Stop receiving ticks.
+  Logger::ticker_->ClearProfiler();
+
+  // Terminate the worker thread by setting running_ to false,
+  // inserting a fake element in the queue and then wait for
+  // the thread to terminate.
+  running_ = false;
+  TickSample sample;
+  sample.pc = 0;
+  sample.sp = 0;
+  sample.state = OTHER;
+  Insert(&sample);
+  Join();
+
+  LOG(StringEvent("profiler", "end"));
+}
+
+
+void Profiler::Run() {
+  TickSample sample;
+  bool overflow = Logger::profiler_->Remove(&sample);
+  while (running_) {
+    LOG(TickEvent(&sample, overflow));
+    overflow = Logger::profiler_->Remove(&sample);
+  }
+}
+
+
+//
+// Logger class implementation.
+//
+Ticker* Logger::ticker_ = NULL;
+FILE* Logger::logfile_ = NULL;
+Profiler* Logger::profiler_ = NULL;
+Mutex* Logger::mutex_ = NULL;
+VMState* Logger::current_state_ = NULL;
+SlidingStateWindow* Logger::sliding_state_window_ = NULL;
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+void Logger::Preamble(const char* content) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "%s", content);
+#endif
+}
+
+
+void Logger::StringEvent(const char* name, const char* value) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "%s,\"%s\"\n", name, value);
+#endif
+}
+
+
+void Logger::IntEvent(const char* name, int value) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "%s,%d\n", name, value);
+#endif
+}
+
+
+void Logger::HandleEvent(const char* name, Object** location) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_handles) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "%s,0x%x\n", name,
+          reinterpret_cast<unsigned int>(location));
+#endif
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+// ApiEvent is private so all the calls come from the Logger class.  It is the
+// caller's responsibility to ensure that logfile_ is not NULL and that
+// FLAG_log_api is true.
+void Logger::ApiEvent(const char* format, ...) {
+  ASSERT(logfile_ != NULL && FLAG_log_api);
+  ScopedLock sl(mutex_);
+  va_list ap;
+  va_start(ap, format);
+  vfprintf(logfile_, format, ap);
+}
+#endif
+
+
+void Logger::ApiNamedSecurityCheck(Object* key) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_api) return;
+  if (key->IsString()) {
+    SmartPointer<char> str =
+        String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+    ApiEvent("api,check-security,\"%s\"\n", *str);
+  } else if (key->IsUndefined()) {
+    ApiEvent("api,check-security,undefined\n");
+  } else {
+    ApiEvent("api,check-security,['no-name']\n");
+  }
+#endif
+}
+
+
+void Logger::SharedLibraryEvent(const char* library_path,
+                                unsigned start,
+                                unsigned end) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_prof) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "shared-library,\"%s\",0x%08x,0x%08x\n", library_path,
+          start, end);
+#endif
+}
+
+
+void Logger::SharedLibraryEvent(const wchar_t* library_path,
+                                unsigned start,
+                                unsigned end) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_prof) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "shared-library,\"%ls\",0x%08x,0x%08x\n", library_path,
+          start, end);
+#endif
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+void Logger::LogString(Handle<String> str) {
+  int len = str->length();
+  if (len > 256)
+    len = 256;
+  for (int i = 0; i < len; i++) {
+    uc32 c = str->Get(i);
+    if (c < 32 || (c > 126 && c <= 255)) {
+      fprintf(logfile_, "\\x%02x", c);
+    } else if (c > 255) {
+      fprintf(logfile_, "\\u%04x", c);
+    } else if (c == ',') {
+      fprintf(logfile_, "\\,");
+    } else {
+      fprintf(logfile_, "%lc", c);
+    }
+  }
+}
+
+void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
+  // Prints "/" + re.source + "/" +
+  //      (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
+
+  Handle<Object> source = GetProperty(regexp, "source");
+  if (!source->IsString()) {
+    fprintf(logfile_, "no source");
+    return;
+  }
+
+  switch (regexp->TypeTag()) {
+    case JSRegExp::ATOM:
+      fprintf(logfile_, "a");
+      break;
+    default:
+      break;
+  }
+  fprintf(logfile_, "/");
+  LogString(Handle<String>::cast(source));
+  fprintf(logfile_, "/");
+
+  // global flag
+  Handle<Object> global = GetProperty(regexp, "global");
+  if (global->IsTrue()) {
+    fprintf(logfile_, "g");
+  }
+  // ignorecase flag
+  Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
+  if (ignorecase->IsTrue()) {
+    fprintf(logfile_, "i");
+  }
+  // multiline flag
+  Handle<Object> multiline = GetProperty(regexp, "multiline");
+  if (multiline->IsTrue()) {
+    fprintf(logfile_, "m");
+  }
+}
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+
+void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_regexp) return;
+  ScopedLock sl(mutex_);
+
+  fprintf(logfile_, "regexp-compile,");
+  LogRegExpSource(regexp);
+  fprintf(logfile_, in_cache ? ",hit\n" : ",miss\n");
+#endif
+}
+
+
+void Logger::RegExpExecEvent(Handle<JSRegExp> regexp,
+                             int start_index,
+                             Handle<String> input_string) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_regexp) return;
+  ScopedLock sl(mutex_);
+
+  fprintf(logfile_, "regexp-run,");
+  LogRegExpSource(regexp);
+  fprintf(logfile_, ",");
+  LogString(input_string);
+  fprintf(logfile_, ",%d..%d\n", start_index, input_string->length());
+#endif
+}
+
+
+void Logger::ApiIndexedSecurityCheck(uint32_t index) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_api) return;
+  ApiEvent("api,check-security,%u\n", index);
+#endif
+}
+
+
+void Logger::ApiNamedPropertyAccess(const char* tag,
+                                    JSObject* holder,
+                                    Object* name) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  ASSERT(name->IsString());
+  if (logfile_ == NULL || !FLAG_log_api) return;
+  String* class_name_obj = holder->class_name();
+  SmartPointer<char> class_name =
+      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  SmartPointer<char> property_name =
+      String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  Logger::ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
+#endif
+}
+
+void Logger::ApiIndexedPropertyAccess(const char* tag,
+                                      JSObject* holder,
+                                      uint32_t index) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_api) return;
+  String* class_name_obj = holder->class_name();
+  SmartPointer<char> class_name =
+      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  Logger::ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
+#endif
+}
+
+void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_api) return;
+  String* class_name_obj = object->class_name();
+  SmartPointer<char> class_name =
+      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  Logger::ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
+#endif
+}
+
+
+void Logger::ApiEntryCall(const char* name) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_api) return;
+  Logger::ApiEvent("api,%s\n", name);
+#endif
+}
+
+
+void Logger::NewEvent(const char* name, void* object, size_t size) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "new,%s,0x%x,%u\n", name,
+          reinterpret_cast<unsigned int>(object),
+          static_cast<unsigned int>(size));
+#endif
+}
+
+
+void Logger::DeleteEvent(const char* name, void* object) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "delete,%s,0x%x\n", name,
+          reinterpret_cast<unsigned int>(object));
+#endif
+}
+
+
+void Logger::CodeCreateEvent(const char* tag, Code* code, const char* comment) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_code) return;
+  ScopedLock sl(mutex_);
+
+  fprintf(logfile_, "code-creation,%s,0x%x,%d,\"", tag,
+          reinterpret_cast<unsigned int>(code->address()),
+          code->instruction_size());
+  for (const char* p = comment; *p != '\0'; p++) {
+    if (*p == '\"') fprintf(logfile_, "\\");
+    fprintf(logfile_, "%c", *p);
+  }
+  fprintf(logfile_, "\"\n");
+#endif
+}
+
+
+void Logger::CodeCreateEvent(const char* tag, Code* code, String* name) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_code) return;
+  ScopedLock sl(mutex_);
+  SmartPointer<char> str =
+      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  fprintf(logfile_, "code-creation,%s,0x%x,%d,\"%s\"\n", tag,
+          reinterpret_cast<unsigned int>(code->address()),
+          code->instruction_size(), *str);
+#endif
+}
+
+
+void Logger::CodeCreateEvent(const char* tag, Code* code, int args_count) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_code) return;
+  ScopedLock sl(mutex_);
+
+  fprintf(logfile_, "code-creation,%s,0x%x,%d,\"args_count: %d\"\n", tag,
+          reinterpret_cast<unsigned int>(code->address()),
+          code->instruction_size(),
+          args_count);
+#endif
+}
+
+
+void Logger::CodeMoveEvent(Address from, Address to) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_code) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "code-move,0x%x,0x%x\n",
+          reinterpret_cast<unsigned int>(from),
+          reinterpret_cast<unsigned int>(to));
+#endif
+}
+
+
+void Logger::CodeDeleteEvent(Address from) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_code) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "code-delete,0x%x\n", reinterpret_cast<unsigned int>(from));
+#endif
+}
+
+
+void Logger::ResourceEvent(const char* name, const char* tag) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "%s,%s,", name, tag);
+
+  uint32_t sec, usec;
+  if (OS::GetUserTime(&sec, &usec) != -1) {
+    fprintf(logfile_, "%d,%d,", sec, usec);
+  }
+  fprintf(logfile_, "%.0f", OS::TimeCurrentMillis());
+
+  fprintf(logfile_, "\n");
+#endif
+}
+
+
+void Logger::SuspectReadEvent(String* name, String* obj) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_suspect) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "suspect-read,");
+  obj->PrintOn(logfile_);
+  fprintf(logfile_, ",\"");
+  name->PrintOn(logfile_);
+  fprintf(logfile_, "\"\n");
+#endif
+}
+
+
+void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_gc) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "heap-sample-begin,\"%s\",\"%s\"\n", space, kind);
+#endif
+}
+
+
+void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_gc) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "heap-sample-end,\"%s\",\"%s\"\n", space, kind);
+#endif
+}
+
+
+void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log_gc) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "heap-sample-item,%s,%d,%d\n", type, number, bytes);
+#endif
+}
+
+
+void Logger::DebugTag(const char* call_site_tag) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "debug-tag,%s\n", call_site_tag);
+#endif
+}
+
+
+void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (logfile_ == NULL || !FLAG_log) return;
+  StringBuilder s(parameter.length() + 1);
+  for (int i = 0; i < parameter.length(); ++i) {
+    s.AddCharacter(static_cast<char>(parameter[i]));
+  }
+  char* parameter_string = s.Finalize();
+  ScopedLock sl(mutex_);
+  fprintf(logfile_,
+          "debug-queue-event,%s,%15.3f,%s\n",
+          event_type,
+          OS::TimeCurrentMillis(),
+          parameter_string);
+  DeleteArray(parameter_string);
+#endif
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+void Logger::TickEvent(TickSample* sample, bool overflow) {
+  if (logfile_ == NULL || !FLAG_prof) return;
+  ScopedLock sl(mutex_);
+  fprintf(logfile_, "tick,0x%x,0x%x,%d", sample->pc, sample->sp,
+          static_cast<int>(sample->state));
+  if (overflow) fprintf(logfile_, ",overflow");
+  fprintf(logfile_, "\n");
+}
+#endif
+
+
+bool Logger::Setup() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  // --log-all enables all the log flags.
+  if (FLAG_log_all) {
+    FLAG_log_api = true;
+    FLAG_log_code = true;
+    FLAG_log_gc = true;
+    FLAG_log_suspect = true;
+    FLAG_log_handles = true;
+    FLAG_log_regexp = true;
+  }
+
+  // --prof implies --log-code.
+  if (FLAG_prof) FLAG_log_code = true;
+
+  bool open_log_file = FLAG_log || FLAG_log_api || FLAG_log_code
+      || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
+      || FLAG_log_regexp;
+
+  // If we're logging anything, we need to open the log file.
+  if (open_log_file) {
+    if (strcmp(FLAG_logfile, "-") == 0) {
+      logfile_ = stdout;
+    } else if (strchr(FLAG_logfile, '%') != NULL) {
+      // If there's a '%' in the log file name we have to expand
+      // placeholders.
+      HeapStringAllocator allocator;
+      StringStream stream(&allocator);
+      for (const char* p = FLAG_logfile; *p; p++) {
+        if (*p == '%') {
+          p++;
+          switch (*p) {
+            case '\0':
+              // If there's a % at the end of the string we back up
+              // one character so we can escape the loop properly.
+              p--;
+              break;
+            case 't': {
+              // %t expands to the current time in milliseconds.
+              uint32_t time = static_cast<uint32_t>(OS::TimeCurrentMillis());
+              stream.Add("%u", time);
+              break;
+            }
+            case '%':
+              // %% expands (contracts really) to %.
+              stream.Put('%');
+              break;
+            default:
+              // All other %'s expand to themselves.
+              stream.Put('%');
+              stream.Put(*p);
+              break;
+          }
+        } else {
+          stream.Put(*p);
+        }
+      }
+      SmartPointer<char> expanded = stream.ToCString();
+      logfile_ = OS::FOpen(*expanded, "w");
+    } else {
+      logfile_ = OS::FOpen(FLAG_logfile, "w");
+    }
+    mutex_ = OS::CreateMutex();
+  }
+
+  current_state_ = new VMState(OTHER);
+
+  ticker_ = new Ticker(10);
+
+  if (FLAG_sliding_state_window && sliding_state_window_ == NULL) {
+    sliding_state_window_ = new SlidingStateWindow();
+  }
+
+  if (FLAG_prof) {
+    profiler_ = new Profiler();
+    profiler_->Engage();
+  }
+
+  return true;
+
+#else
+  return false;
+#endif
+}
+
+
+void Logger::TearDown() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  // Stop the profiler before closing the file.
+  if (profiler_ != NULL) {
+    profiler_->Disengage();
+    delete profiler_;
+    profiler_ = NULL;
+  }
+
+  // Deleting the current_state_ has the side effect of assigning to it(!).
+  while (current_state_) delete current_state_;
+  delete sliding_state_window_;
+
+  delete ticker_;
+
+  if (logfile_ != NULL) {
+    fclose(logfile_);
+    logfile_ = NULL;
+    delete mutex_;
+    mutex_ = NULL;
+  }
+#endif
+}
+
+
+void Logger::EnableSlidingStateWindow() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  // If the ticker is NULL, Logger::Setup has not been called yet.  In
+  // that case, we set the sliding_state_window flag so that the
+  // sliding window computation will be started when Logger::Setup is
+  // called.
+  if (ticker_ == NULL) {
+    FLAG_sliding_state_window = true;
+    return;
+  }
+  // Otherwise, if the sliding state window computation has not been
+  // started we do it now.
+  if (sliding_state_window_ == NULL) {
+    sliding_state_window_ = new SlidingStateWindow();
+  }
+#endif
+}
+
+
+//
+// VMState class implementation.  A simple stack of VM states held by the
+// logger and partially threaded through the call stack.  States are pushed by
+// VMState construction and popped by destruction.
+//
+#ifdef ENABLE_LOGGING_AND_PROFILING
+static const char* StateToString(StateTag state) {
+  switch (state) {
+    case GC:
+      return "GC";
+    case COMPILER:
+      return "COMPILER";
+    case OTHER:
+      return "OTHER";
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+VMState::VMState(StateTag state) {
+  state_ = state;
+  previous_ = Logger::current_state_;
+  Logger::current_state_ = this;
+
+  if (FLAG_log_state_changes) {
+    LOG(StringEvent("Entering", StateToString(state_)));
+    if (previous_) {
+      LOG(StringEvent("From", StateToString(previous_->state_)));
+    }
+  }
+}
+
+
+VMState::~VMState() {
+  Logger::current_state_ = previous_;
+
+  if (FLAG_log_state_changes) {
+    LOG(StringEvent("Leaving", StateToString(state_)));
+    if (previous_) {
+      LOG(StringEvent("To", StateToString(previous_->state_)));
+    }
+  }
+}
+#endif
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/log.h b/regexp2000/src/log.h
new file mode 100644 (file)
index 0000000..c950b86
--- /dev/null
@@ -0,0 +1,245 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_LOG_H_
+#define V8_LOG_H_
+
+namespace v8 { namespace internal {
+
+// Logger is used for collecting logging information from V8 during
+// execution. The result is dumped to a file.
+//
+// Available command line flags:
+//
+//  --log
+// Minimal logging (no API, code, or GC sample events), default is off.
+//
+// --log-all
+// Log all events to the file, default is off.  This is the same as combining
+// --log-api, --log-code, --log-gc, and --log-regexp.
+//
+// --log-api
+// Log API events to the logfile, default is off.  --log-api implies --log.
+//
+// --log-code
+// Log code (create, move, and delete) events to the logfile, default is off.
+// --log-code implies --log.
+//
+// --log-gc
+// Log GC heap samples after each GC that can be processed by hp2ps, default
+// is off.  --log-gc implies --log.
+//
+// --log-regexp
+// Log creation and use of regular expressions, Default is off.
+// --log-regexp implies --log.
+//
+// --logfile <filename>
+// Specify the name of the logfile, default is "v8.log".
+//
+// --prof
+// Collect statistical profiling information (ticks), default is off.  The
+// tick profiler requires code events, so --prof implies --log-code.
+
+// Forward declarations.
+class Ticker;
+class Profiler;
+class Semaphore;
+class SlidingStateWindow;
+
+#undef LOG
+#ifdef ENABLE_LOGGING_AND_PROFILING
+#define LOG(Call) v8::internal::Logger::Call
+#else
+#define LOG(Call) ((void) 0)
+#endif
+
+
+class VMState {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ public:
+  explicit VMState(StateTag state);
+  ~VMState();
+
+  StateTag state() { return state_; }
+
+ private:
+  StateTag state_;
+  VMState* previous_;
+#else
+ public:
+  explicit VMState(StateTag state) {}
+#endif
+};
+
+
+class Logger {
+ public:
+  // Opens the file for logging if the right flags are set.
+  static bool Setup();
+
+  // Closes file opened in Setup.
+  static void TearDown();
+
+  // Enable the computation of a sliding window of states.
+  static void EnableSlidingStateWindow();
+
+  // Write a raw string to the log to be used as a preamble.
+  // No check is made that the 'preamble' is actually at the beginning
+  // of the log.
+  static void Preamble(const char* content);
+
+  // ==== Events that are always logged. ====
+  // Emits an event with a string value -> (name, value).
+  static void StringEvent(const char* name, const char* value);
+
+  // Emits an event with an int value -> (name, value).
+  static void IntEvent(const char* name, int value);
+
+  // Emits an event with an handle value -> (name, location).
+  static void HandleEvent(const char* name, Object** location);
+
+  // Emits memory management events for C allocated structures.
+  static void NewEvent(const char* name, void* object, size_t size);
+  static void DeleteEvent(const char* name, void* object);
+
+  // Emits an event with a tag, and some resource usage information.
+  // -> (name, tag, <rusage information>).
+  // Currently, the resource usage information is a process time stamp
+  // and a real time timestamp.
+  static void ResourceEvent(const char* name, const char* tag);
+
+  // Emits an event that an undefined property was read from an
+  // object.
+  static void SuspectReadEvent(String* name, String* obj);
+
+  // Emits an event when a message is put on or read from a debugging queue.
+  // DebugTag lets us put a call-site specific label on the event.
+  static void DebugTag(const char* call_site_tag);
+  static void DebugEvent(const char* event_type, Vector<uint16_t> parameter);
+
+
+  // ==== Events logged by --log-api. ====
+  static void ApiNamedSecurityCheck(Object* key);
+  static void ApiIndexedSecurityCheck(uint32_t index);
+  static void ApiNamedPropertyAccess(const char* tag,
+                                     JSObject* holder,
+                                     Object* name);
+  static void ApiIndexedPropertyAccess(const char* tag,
+                                       JSObject* holder,
+                                       uint32_t index);
+  static void ApiObjectAccess(const char* tag, JSObject* obj);
+  static void ApiEntryCall(const char* name);
+
+
+  // ==== Events logged by --log-code. ====
+  // Emits a code create event.
+  static void CodeCreateEvent(const char* tag, Code* code, const char* source);
+  static void CodeCreateEvent(const char* tag, Code* code, String* name);
+  static void CodeCreateEvent(const char* tag, Code* code, int args_count);
+  // Emits a code move event.
+  static void CodeMoveEvent(Address from, Address to);
+  // Emits a code delete event.
+  static void CodeDeleteEvent(Address from);
+
+  // ==== Events logged by --log-gc. ====
+  // Heap sampling events: start, end, and individual types.
+  static void HeapSampleBeginEvent(const char* space, const char* kind);
+  static void HeapSampleEndEvent(const char* space, const char* kind);
+  static void HeapSampleItemEvent(const char* type, int number, int bytes);
+
+  static void SharedLibraryEvent(const char* library_path,
+                                 unsigned start,
+                                 unsigned end);
+  static void SharedLibraryEvent(const wchar_t* library_path,
+                                 unsigned start,
+                                 unsigned end);
+
+  // ==== Events logged by --log-regexp ====
+  // Regexp compilation and execution events.
+
+  static void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
+
+  static void RegExpExecEvent(Handle<JSRegExp> regexp,
+                              int start_index,
+                              Handle<String> input_string);
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  static StateTag state() {
+    return current_state_ ? current_state_->state() : OTHER;
+  }
+#endif
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ private:
+
+  // Emits the source code of a regexp. Used by regexp events.
+  static void LogRegExpSource(Handle<JSRegExp> regexp);
+
+  static void LogString(Handle<String> str);
+
+  // Emits a profiler tick event. Used by the profiler thread.
+  static void TickEvent(TickSample* sample, bool overflow);
+
+  static void ApiEvent(const char* name, ...);
+
+  // When logging is active, logfile_ refers the file
+  // events are written to.
+  static FILE* logfile_;
+
+  // The sampler used by the profiler and the sliding state window.
+  static Ticker* ticker_;
+
+  // When the statistical profile is active, profiler_
+  // points to a Profiler, that handles collection
+  // of samples.
+  static Profiler* profiler_;
+
+  // mutex_ is a Mutex used for enforcing exclusive
+  // access to the log file.
+  static Mutex* mutex_;
+
+  // A stack of VM states.
+  static VMState* current_state_;
+
+  // SlidingStateWindow instance keeping a sliding window of the most
+  // recent VM states.
+  static SlidingStateWindow* sliding_state_window_;
+
+  // Internal implementation classes with access to
+  // private members.
+  friend class EventLog;
+  friend class TimeLog;
+  friend class Profiler;
+  friend class SlidingStateWindow;
+  friend class VMState;
+#endif
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_LOG_H_
diff --git a/regexp2000/src/macro-assembler-arm.cc b/regexp2000/src/macro-assembler-arm.cc
new file mode 100644 (file)
index 0000000..2e957e4
--- /dev/null
@@ -0,0 +1,883 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "codegen-inl.h"
+#include "debug.h"
+#include "runtime.h"
+
+namespace v8 { namespace internal {
+
+// Give alias names to registers
+Register cp = {  8 };  // JavaScript context pointer
+Register pp = { 10 };  // parameter pointer
+
+
+MacroAssembler::MacroAssembler(void* buffer, int size)
+    : Assembler(buffer, size),
+      unresolved_(0),
+      generating_stub_(false),
+      allow_stub_calls_(true) {
+}
+
+
+// We always generate arm code, never thumb code, even if V8 is compiled to
+// thumb, so we require inter-working support
+#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
+#error "flag -mthumb-interwork missing"
+#endif
+
+
+// We do not support thumb inter-working with an arm architecture not supporting
+// the blx instruction (below v5t)
+#if defined(__THUMB_INTERWORK__)
+#if !defined(__ARM_ARCH_5T__) && !defined(__ARM_ARCH_5TE__)
+// add tests for other versions above v5t as required
+#error "for thumb inter-working we require architecture v5t or above"
+#endif
+#endif
+
+
+// Using blx may yield better code, so use it when required or when available
+#if defined(__THUMB_INTERWORK__) || defined(__ARM_ARCH_5__)
+#define USE_BLX 1
+#endif
+
+// Using bx does not yield better code, so use it only when required
+#if defined(__THUMB_INTERWORK__)
+#define USE_BX 1
+#endif
+
+
+void MacroAssembler::Jump(Register target, Condition cond) {
+#if USE_BX
+  bx(target, cond);
+#else
+  mov(pc, Operand(target), LeaveCC, cond);
+#endif
+}
+
+
+void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
+                          Condition cond) {
+#if USE_BX
+  mov(ip, Operand(target, rmode), LeaveCC, cond);
+  bx(ip, cond);
+#else
+  mov(pc, Operand(target, rmode), LeaveCC, cond);
+#endif
+}
+
+
+void MacroAssembler::Jump(byte* target, RelocInfo::Mode rmode,
+                          Condition cond) {
+  ASSERT(!RelocInfo::IsCodeTarget(rmode));
+  Jump(reinterpret_cast<intptr_t>(target), rmode, cond);
+}
+
+
+void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
+                          Condition cond) {
+  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  // 'code' is always generated ARM code, never THUMB code
+  Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
+}
+
+
+void MacroAssembler::Call(Register target, Condition cond) {
+#if USE_BLX
+  blx(target, cond);
+#else
+  // set lr for return at current pc + 8
+  mov(lr, Operand(pc), LeaveCC, cond);
+  mov(pc, Operand(target), LeaveCC, cond);
+#endif
+}
+
+
+void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
+                          Condition cond) {
+#if !defined(__arm__)
+  if (rmode == RelocInfo::RUNTIME_ENTRY) {
+    mov(r2, Operand(target, rmode), LeaveCC, cond);
+    // Set lr for return at current pc + 8.
+    mov(lr, Operand(pc), LeaveCC, cond);
+    // Emit a ldr<cond> pc, [pc + offset of target in constant pool].
+    // Notify the simulator of the transition to C code.
+    swi(assembler::arm::call_rt_r2);
+  } else {
+    // set lr for return at current pc + 8
+    mov(lr, Operand(pc), LeaveCC, cond);
+    // emit a ldr<cond> pc, [pc + offset of target in constant pool]
+    mov(pc, Operand(target, rmode), LeaveCC, cond);
+  }
+#else
+  // Set lr for return at current pc + 8.
+  mov(lr, Operand(pc), LeaveCC, cond);
+  // Emit a ldr<cond> pc, [pc + offset of target in constant pool].
+  mov(pc, Operand(target, rmode), LeaveCC, cond);
+#endif  // !defined(__arm__)
+  // If USE_BLX is defined, we could emit a 'mov ip, target', followed by a
+  // 'blx ip'; however, the code would not be shorter than the above sequence
+  // and the target address of the call would be referenced by the first
+  // instruction rather than the second one, which would make it harder to patch
+  // (two instructions before the return address, instead of one).
+  ASSERT(kTargetAddrToReturnAddrDist == sizeof(Instr));
+}
+
+
+void MacroAssembler::Call(byte* target, RelocInfo::Mode rmode,
+                          Condition cond) {
+  ASSERT(!RelocInfo::IsCodeTarget(rmode));
+  Call(reinterpret_cast<intptr_t>(target), rmode, cond);
+}
+
+
+void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
+                          Condition cond) {
+  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  // 'code' is always generated ARM code, never THUMB code
+  Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
+}
+
+
+void MacroAssembler::Ret() {
+#if USE_BX
+  bx(lr);
+#else
+  mov(pc, Operand(lr));
+#endif
+}
+
+
+// Will clobber 4 registers: object, offset, scratch, ip.  The
+// register 'object' contains a heap object pointer.  The heap object
+// tag is shifted away.
+void MacroAssembler::RecordWrite(Register object, Register offset,
+                                 Register scratch) {
+  // This is how much we shift the remembered set bit offset to get the
+  // offset of the word in the remembered set.  We divide by kBitsPerInt (32,
+  // shift right 5) and then multiply by kIntSize (4, shift left 2).
+  const int kRSetWordShift = 3;
+
+  Label fast, done;
+
+  // First, test that the object is not in the new space.  We cannot set
+  // remembered set bits in the new space.
+  // object: heap object pointer (with tag)
+  // offset: offset to store location from the object
+  and_(scratch, object, Operand(Heap::NewSpaceMask()));
+  cmp(scratch, Operand(ExternalReference::new_space_start()));
+  b(eq, &done);
+
+  // Compute the bit offset in the remembered set.
+  // object: heap object pointer (with tag)
+  // offset: offset to store location from the object
+  mov(ip, Operand(Page::kPageAlignmentMask));  // load mask only once
+  and_(scratch, object, Operand(ip));  // offset into page of the object
+  add(offset, scratch, Operand(offset));  // add offset into the object
+  mov(offset, Operand(offset, LSR, kObjectAlignmentBits));
+
+  // Compute the page address from the heap object pointer.
+  // object: heap object pointer (with tag)
+  // offset: bit offset of store position in the remembered set
+  bic(object, object, Operand(ip));
+
+  // If the bit offset lies beyond the normal remembered set range, it is in
+  // the extra remembered set area of a large object.
+  // object: page start
+  // offset: bit offset of store position in the remembered set
+  cmp(offset, Operand(Page::kPageSize / kPointerSize));
+  b(lt, &fast);
+
+  // Adjust the bit offset to be relative to the start of the extra
+  // remembered set and the start address to be the address of the extra
+  // remembered set.
+  sub(offset, offset, Operand(Page::kPageSize / kPointerSize));
+  // Load the array length into 'scratch' and multiply by four to get the
+  // size in bytes of the elements.
+  ldr(scratch, MemOperand(object, Page::kObjectStartOffset
+                                  + FixedArray::kLengthOffset));
+  mov(scratch, Operand(scratch, LSL, kObjectAlignmentBits));
+  // Add the page header (including remembered set), array header, and array
+  // body size to the page address.
+  add(object, object, Operand(Page::kObjectStartOffset
+                              + Array::kHeaderSize));
+  add(object, object, Operand(scratch));
+
+  bind(&fast);
+  // Get address of the rset word.
+  // object: start of the remembered set (page start for the fast case)
+  // offset: bit offset of store position in the remembered set
+  bic(scratch, offset, Operand(kBitsPerInt - 1));  // clear the bit offset
+  add(object, object, Operand(scratch, LSR, kRSetWordShift));
+  // Get bit offset in the rset word.
+  // object: address of remembered set word
+  // offset: bit offset of store position
+  and_(offset, offset, Operand(kBitsPerInt - 1));
+
+  ldr(scratch, MemOperand(object));
+  mov(ip, Operand(1));
+  orr(scratch, scratch, Operand(ip, LSL, offset));
+  str(scratch, MemOperand(object));
+
+  bind(&done);
+}
+
+
+void MacroAssembler::EnterFrame(StackFrame::Type type) {
+  // r0-r3: preserved
+  stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());
+  mov(ip, Operand(Smi::FromInt(type)));
+  push(ip);
+  mov(ip, Operand(0));
+  push(ip);  // Push an empty code cache slot.
+  add(fp, sp, Operand(3 * kPointerSize));  // Adjust FP to point to saved FP.
+}
+
+
+void MacroAssembler::LeaveFrame(StackFrame::Type type) {
+  // r0: preserved
+  // r1: preserved
+  // r2: preserved
+
+  // Drop the execution stack down to the frame pointer and restore
+  // the caller frame pointer and return address.
+  mov(sp, fp);
+  ldm(ia_w, sp, fp.bit() | lr.bit());
+}
+
+
+void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
+  ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
+  // Compute parameter pointer before making changes and save it as ip
+  // register so that it is restored as sp register on exit, thereby
+  // popping the args.
+
+  // ip = sp + kPointerSize * #args;
+  add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
+
+  // Push in reverse order: caller_fp, sp_on_exit, and caller_pc.
+  stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
+  mov(fp, Operand(sp));  // setup new frame pointer
+
+  // Push debug marker.
+  mov(ip, Operand(type == StackFrame::EXIT_DEBUG ? 1 : 0));
+  push(ip);
+
+  // Save the frame pointer and the context in top.
+  mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+  str(fp, MemOperand(ip));
+  mov(ip, Operand(ExternalReference(Top::k_context_address)));
+  str(cp, MemOperand(ip));
+
+  // Setup argc and the builtin function in callee-saved registers.
+  mov(r4, Operand(r0));
+  mov(r5, Operand(r1));
+
+  // Compute the argv pointer and keep it in a callee-saved register.
+  add(r6, fp, Operand(r4, LSL, kPointerSizeLog2));
+  add(r6, r6, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize));
+
+  // Save the state of all registers to the stack from the memory
+  // location. This is needed to allow nested break points.
+  if (type == StackFrame::EXIT_DEBUG) {
+    // Use sp as base to push.
+    CopyRegistersFromMemoryToStack(sp, kJSCallerSaved);
+  }
+}
+
+
+void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
+  // Restore the memory copy of the registers by digging them out from
+  // the stack. This is needed to allow nested break points.
+  if (type == StackFrame::EXIT_DEBUG) {
+    // This code intentionally clobbers r2 and r3.
+    const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
+    const int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
+    add(r3, fp, Operand(kOffset));
+    CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved);
+  }
+
+  // Clear top frame.
+  mov(r3, Operand(0));
+  mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+  str(r3, MemOperand(ip));
+
+  // Restore current context from top and clear it in debug mode.
+  mov(ip, Operand(ExternalReference(Top::k_context_address)));
+  ldr(cp, MemOperand(ip));
+  if (kDebug) {
+    str(r3, MemOperand(ip));
+  }
+
+  // Pop the arguments, restore registers, and return.
+  mov(sp, Operand(fp));  // respect ABI stack constraint
+  ldm(ia, sp, fp.bit() | sp.bit() | pc.bit());
+}
+
+
+void MacroAssembler::InvokePrologue(const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    Handle<Code> code_constant,
+                                    Register code_reg,
+                                    Label* done,
+                                    InvokeFlag flag) {
+  bool definitely_matches = false;
+  Label regular_invoke;
+
+  // Check whether the expected and actual arguments count match. If not,
+  // setup registers according to contract with ArgumentsAdaptorTrampoline:
+  //  r0: actual arguments count
+  //  r1: function (passed through to callee)
+  //  r2: expected arguments count
+  //  r3: callee code entry
+
+  // The code below is made a lot easier because the calling code already sets
+  // up actual and expected registers according to the contract if values are
+  // passed in registers.
+  ASSERT(actual.is_immediate() || actual.reg().is(r0));
+  ASSERT(expected.is_immediate() || expected.reg().is(r2));
+  ASSERT((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(r3));
+
+  if (expected.is_immediate()) {
+    ASSERT(actual.is_immediate());
+    if (expected.immediate() == actual.immediate()) {
+      definitely_matches = true;
+    } else {
+      mov(r0, Operand(actual.immediate()));
+      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+      if (expected.immediate() == sentinel) {
+        // Don't worry about adapting arguments for builtins that
+        // don't want that done. Skip adaption code by making it look
+        // like we have a match between expected and actual number of
+        // arguments.
+        definitely_matches = true;
+      } else {
+        mov(r2, Operand(expected.immediate()));
+      }
+    }
+  } else {
+    if (actual.is_immediate()) {
+      cmp(expected.reg(), Operand(actual.immediate()));
+      b(eq, &regular_invoke);
+      mov(r0, Operand(actual.immediate()));
+    } else {
+      cmp(expected.reg(), Operand(actual.reg()));
+      b(eq, &regular_invoke);
+    }
+  }
+
+  if (!definitely_matches) {
+    if (!code_constant.is_null()) {
+      mov(r3, Operand(code_constant));
+      add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
+    }
+
+    Handle<Code> adaptor =
+        Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+    if (flag == CALL_FUNCTION) {
+      Call(adaptor, RelocInfo::CODE_TARGET);
+      b(done);
+    } else {
+      Jump(adaptor, RelocInfo::CODE_TARGET);
+    }
+    bind(&regular_invoke);
+  }
+}
+
+
+void MacroAssembler::InvokeCode(Register code,
+                                const ParameterCount& expected,
+                                const ParameterCount& actual,
+                                InvokeFlag flag) {
+  Label done;
+
+  InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
+  if (flag == CALL_FUNCTION) {
+    Call(code);
+  } else {
+    ASSERT(flag == JUMP_FUNCTION);
+    Jump(code);
+  }
+
+  // Continue here if InvokePrologue does handle the invocation due to
+  // mismatched parameter counts.
+  bind(&done);
+}
+
+
+void MacroAssembler::InvokeCode(Handle<Code> code,
+                                const ParameterCount& expected,
+                                const ParameterCount& actual,
+                                RelocInfo::Mode rmode,
+                                InvokeFlag flag) {
+  Label done;
+
+  InvokePrologue(expected, actual, code, no_reg, &done, flag);
+  if (flag == CALL_FUNCTION) {
+    Call(code, rmode);
+  } else {
+    Jump(code, rmode);
+  }
+
+  // Continue here if InvokePrologue does handle the invocation due to
+  // mismatched parameter counts.
+  bind(&done);
+}
+
+
+void MacroAssembler::InvokeFunction(Register fun,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag) {
+  // Contract with called JS functions requires that function is passed in r1.
+  ASSERT(fun.is(r1));
+
+  Register expected_reg = r2;
+  Register code_reg = r3;
+
+  ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+  ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+  ldr(expected_reg,
+      FieldMemOperand(code_reg,
+                      SharedFunctionInfo::kFormalParameterCountOffset));
+  ldr(code_reg,
+      MemOperand(code_reg, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
+  add(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  ParameterCount expected(expected_reg);
+  InvokeCode(code_reg, expected, actual, flag);
+}
+
+
+void MacroAssembler::SaveRegistersToMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of registers to memory location.
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      Register reg = { r };
+      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
+      str(reg, MemOperand(ip));
+    }
+  }
+}
+
+
+void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of memory location to registers.
+  for (int i = kNumJSCallerSaved; --i >= 0;) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      Register reg = { r };
+      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
+      ldr(reg, MemOperand(ip));
+    }
+  }
+}
+
+
+void MacroAssembler::CopyRegistersFromMemoryToStack(Register base,
+                                                    RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of the memory location to the stack and adjust base.
+  for (int i = kNumJSCallerSaved; --i >= 0;) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
+      ldr(ip, MemOperand(ip));
+      str(ip, MemOperand(base, 4, NegPreIndex));
+    }
+  }
+}
+
+
+void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
+                                                    Register scratch,
+                                                    RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of the stack to the memory location and adjust base.
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      mov(ip, Operand(ExternalReference(Debug_Address::Register(i))));
+      ldr(scratch, MemOperand(base, 4, PostIndex));
+      str(scratch, MemOperand(ip));
+    }
+  }
+}
+
+
+void MacroAssembler::PushTryHandler(CodeLocation try_location,
+                                    HandlerType type) {
+  ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize);  // adjust this code
+  // The pc (return address) is passed in register lr.
+  if (try_location == IN_JAVASCRIPT) {
+    stm(db_w, sp, pp.bit() | fp.bit() | lr.bit());
+    if (type == TRY_CATCH_HANDLER) {
+      mov(r3, Operand(StackHandler::TRY_CATCH));
+    } else {
+      mov(r3, Operand(StackHandler::TRY_FINALLY));
+    }
+    push(r3);  // state
+    mov(r3, Operand(ExternalReference(Top::k_handler_address)));
+    ldr(r1, MemOperand(r3));
+    push(r1);  // next sp
+    str(sp, MemOperand(r3));  // chain handler
+    mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent)));  // new TOS
+    push(r0);
+  } else {
+    // Must preserve r0-r4, r5-r7 are available.
+    ASSERT(try_location == IN_JS_ENTRY);
+    // The parameter pointer is meaningless here and fp does not point to a JS
+    // frame. So we save NULL for both pp and fp. We expect the code throwing an
+    // exception to check fp before dereferencing it to restore the context.
+    mov(pp, Operand(0));  // set pp to NULL
+    mov(ip, Operand(0));  // to save a NULL fp
+    stm(db_w, sp, pp.bit() | ip.bit() | lr.bit());
+    mov(r6, Operand(StackHandler::ENTRY));
+    push(r6);  // state
+    mov(r7, Operand(ExternalReference(Top::k_handler_address)));
+    ldr(r6, MemOperand(r7));
+    push(r6);  // next sp
+    str(sp, MemOperand(r7));  // chain handler
+    mov(r5, Operand(Smi::FromInt(StackHandler::kCodeNotPresent)));  // new TOS
+    push(r5);  // flush TOS
+  }
+}
+
+
+Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
+                                   JSObject* holder, Register holder_reg,
+                                   Register scratch,
+                                   Label* miss) {
+  // Make sure there's no overlap between scratch and the other
+  // registers.
+  ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
+
+  // Keep track of the current object in register reg.
+  Register reg = object_reg;
+  int depth = 1;
+
+  // Check the maps in the prototype chain.
+  // Traverse the prototype chain from the object and do map checks.
+  while (object != holder) {
+    depth++;
+
+    // Only global objects and objects that do not require access
+    // checks are allowed in stubs.
+    ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+    // Get the map of the current object.
+    ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
+    cmp(scratch, Operand(Handle<Map>(object->map())));
+
+    // Branch on the result of the map check.
+    b(ne, miss);
+
+    // Check access rights to the global object.  This has to happen
+    // after the map check so that we know that the object is
+    // actually a global object.
+    if (object->IsJSGlobalProxy()) {
+      CheckAccessGlobalProxy(reg, scratch, miss);
+      // Restore scratch register to be the map of the object.  In the
+      // new space case below, we load the prototype from the map in
+      // the scratch register.
+      ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
+    }
+
+    reg = holder_reg;  // from now the object is in holder_reg
+    JSObject* prototype = JSObject::cast(object->GetPrototype());
+    if (Heap::InNewSpace(prototype)) {
+      // The prototype is in new space; we cannot store a reference
+      // to it in the code. Load it from the map.
+      ldr(reg, FieldMemOperand(scratch, Map::kPrototypeOffset));
+    } else {
+      // The prototype is in old space; load it directly.
+      mov(reg, Operand(Handle<JSObject>(prototype)));
+    }
+
+    // Go to the next object in the prototype chain.
+    object = prototype;
+  }
+
+  // Check the holder map.
+  ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
+  cmp(scratch, Operand(Handle<Map>(object->map())));
+  b(ne, miss);
+
+  // Log the check depth.
+  LOG(IntEvent("check-maps-depth", depth));
+
+  // Perform security check for access to the global object and return
+  // the holder register.
+  ASSERT(object == holder);
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+  if (object->IsJSGlobalProxy()) {
+    CheckAccessGlobalProxy(reg, scratch, miss);
+  }
+  return reg;
+}
+
+
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+                                            Register scratch,
+                                            Label* miss) {
+  Label same_contexts;
+
+  ASSERT(!holder_reg.is(scratch));
+  ASSERT(!holder_reg.is(ip));
+  ASSERT(!scratch.is(ip));
+
+  // Load current lexical context from the stack frame.
+  ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  // In debug mode, make sure the lexical context is set.
+  if (kDebug) {
+    cmp(scratch, Operand(0));
+    Check(ne, "we should not have an empty lexical context");
+  }
+
+  // Load the global context of the current context.
+  int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+  ldr(scratch, FieldMemOperand(scratch, offset));
+  ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    // TODO(119): avoid push(holder_reg)/pop(holder_reg)
+    // Cannot use ip as a temporary in this verification code. Due to the fact
+    // that ip is clobbered as part of cmp with an object Operand.
+    push(holder_reg);  // Temporarily save holder on the stack.
+    // Read the first word and compare to the global_context_map.
+    ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
+    cmp(holder_reg, Operand(Factory::global_context_map()));
+    Check(eq, "JSGlobalObject::global_context should be a global context.");
+    pop(holder_reg);  // Restore holder.
+  }
+
+  // Check if both contexts are the same.
+  ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  cmp(scratch, Operand(ip));
+  b(eq, &same_contexts);
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    // TODO(119): avoid push(holder_reg)/pop(holder_reg)
+    // Cannot use ip as a temporary in this verification code. Due to the fact
+    // that ip is clobbered as part of cmp with an object Operand.
+    push(holder_reg);  // Temporarily save holder on the stack.
+    mov(holder_reg, ip);  // Move ip to its holding place.
+    cmp(holder_reg, Operand(Factory::null_value()));
+    Check(ne, "JSGlobalProxy::context() should not be null.");
+
+    ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
+    cmp(holder_reg, Operand(Factory::global_context_map()));
+    Check(eq, "JSGlobalObject::global_context should be a global context.");
+    // Restore ip is not needed. ip is reloaded below.
+    pop(holder_reg);  // Restore holder.
+    // Restore ip to holder's context.
+    ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  }
+
+  // Check that the security token in the calling global object is
+  // compatible with the security token in the receiving global
+  // object.
+  int token_offset = Context::kHeaderSize +
+                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
+
+  ldr(scratch, FieldMemOperand(scratch, token_offset));
+  ldr(ip, FieldMemOperand(ip, token_offset));
+  cmp(scratch, Operand(ip));
+  b(ne, miss);
+
+  bind(&same_contexts);
+}
+
+
+void MacroAssembler::CallStub(CodeStub* stub) {
+  ASSERT(allow_stub_calls());  // stub calls are not allowed in some stubs
+  Call(stub->GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::StubReturn(int argc) {
+  ASSERT(argc >= 1 && generating_stub());
+  if (argc > 1)
+    add(sp, sp, Operand((argc - 1) * kPointerSize));
+  Ret();
+}
+
+
+void MacroAssembler::IllegalOperation(int num_arguments) {
+  if (num_arguments > 0) {
+    add(sp, sp, Operand(num_arguments * kPointerSize));
+  }
+  mov(r0, Operand(Factory::undefined_value()));
+}
+
+
+void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
+  // All parameters are on the stack.  r0 has the return value after call.
+
+  // If the expected number of arguments of the runtime function is
+  // constant, we check that the actual number of arguments match the
+  // expectation.
+  if (f->nargs >= 0 && f->nargs != num_arguments) {
+    IllegalOperation(num_arguments);
+    return;
+  }
+
+  Runtime::FunctionId function_id =
+      static_cast<Runtime::FunctionId>(f->stub_id);
+  RuntimeStub stub(function_id, num_arguments);
+  CallStub(&stub);
+}
+
+
+void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) {
+  CallRuntime(Runtime::FunctionForId(fid), num_arguments);
+}
+
+
+void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
+                                     int num_arguments) {
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  mov(r0, Operand(num_arguments));
+  JumpToBuiltin(ext);
+}
+
+
+void MacroAssembler::JumpToBuiltin(const ExternalReference& builtin) {
+#if defined(__thumb__)
+  // Thumb mode builtin.
+  ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1);
+#endif
+  mov(r1, Operand(builtin));
+  CEntryStub stub;
+  Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
+                                            bool* resolved) {
+  // Contract with compiled functions is that the function is passed in r1.
+  int builtins_offset =
+      JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
+  ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
+  ldr(r1, FieldMemOperand(r1, builtins_offset));
+
+  return Builtins::GetCode(id, resolved);
+}
+
+
+void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
+                                   InvokeJSFlags flags) {
+  bool resolved;
+  Handle<Code> code = ResolveBuiltin(id, &resolved);
+
+  if (flags == CALL_JS) {
+    Call(code, RelocInfo::CODE_TARGET);
+  } else {
+    ASSERT(flags == JUMP_JS);
+    Jump(code, RelocInfo::CODE_TARGET);
+  }
+
+  if (!resolved) {
+    const char* name = Builtins::GetName(id);
+    int argc = Builtins::GetArgumentsCount(id);
+    uint32_t flags =
+        Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
+        Bootstrapper::FixupFlagsIsPCRelative::encode(true);
+    Unresolved entry = { pc_offset() - sizeof(Instr), flags, name };
+    unresolved_.Add(entry);
+  }
+}
+
+
+void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
+  bool resolved;
+  Handle<Code> code = ResolveBuiltin(id, &resolved);
+
+  mov(target, Operand(code));
+  if (!resolved) {
+    const char* name = Builtins::GetName(id);
+    int argc = Builtins::GetArgumentsCount(id);
+    uint32_t flags =
+        Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
+        Bootstrapper::FixupFlagsIsPCRelative::encode(true);
+    Unresolved entry = { pc_offset() - sizeof(Instr), flags, name };
+    unresolved_.Add(entry);
+  }
+}
+
+
+void MacroAssembler::Assert(Condition cc, const char* msg) {
+  if (FLAG_debug_code)
+    Check(cc, msg);
+}
+
+
+void MacroAssembler::Check(Condition cc, const char* msg) {
+  Label L;
+  b(cc, &L);
+  Abort(msg);
+  // will not return here
+  bind(&L);
+}
+
+
+void MacroAssembler::Abort(const char* msg) {
+  // We want to pass the msg string like a smi to avoid GC
+  // problems, however msg is not guaranteed to be aligned
+  // properly. Instead, we pass an aligned pointer that is
+  // a proper v8 smi, but also pass the aligment difference
+  // from the real pointer as a smi.
+  intptr_t p1 = reinterpret_cast<intptr_t>(msg);
+  intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
+  ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
+#ifdef DEBUG
+  if (msg != NULL) {
+    RecordComment("Abort message: ");
+    RecordComment(msg);
+  }
+#endif
+  mov(r0, Operand(p0));
+  push(r0);
+  mov(r0, Operand(Smi::FromInt(p1 - p0)));
+  push(r0);
+  CallRuntime(Runtime::kAbort, 2);
+  // will not return here
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/macro-assembler-arm.h b/regexp2000/src/macro-assembler-arm.h
new file mode 100644 (file)
index 0000000..956cd71
--- /dev/null
@@ -0,0 +1,287 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MACRO_ASSEMBLER_ARM_H_
+#define V8_MACRO_ASSEMBLER_ARM_H_
+
+#include "assembler.h"
+
+namespace v8 { namespace internal {
+
+
+// Give alias names to registers
+extern Register cp;  // JavaScript context pointer
+extern Register pp;  // parameter pointer
+
+
+// Helper types to make boolean flag easier to read at call-site.
+enum InvokeFlag {
+  CALL_FUNCTION,
+  JUMP_FUNCTION
+};
+
+enum InvokeJSFlags {
+  CALL_JS,
+  JUMP_JS
+};
+
+enum ExitJSFlag {
+  RETURN,
+  DO_NOT_RETURN
+};
+
+enum CodeLocation {
+  IN_JAVASCRIPT,
+  IN_JS_ENTRY,
+  IN_C_ENTRY
+};
+
+enum HandlerType {
+  TRY_CATCH_HANDLER,
+  TRY_FINALLY_HANDLER,
+  JS_ENTRY_HANDLER
+};
+
+
+// MacroAssembler implements a collection of frequently used macros.
+class MacroAssembler: public Assembler {
+ public:
+  MacroAssembler(void* buffer, int size);
+
+  // ---------------------------------------------------------------------------
+  // Low-level helpers for compiler
+
+  // Jump, Call, and Ret pseudo instructions implementing inter-working
+ private:
+  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
+  void Call(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
+ public:
+  void Jump(Register target, Condition cond = al);
+  void Jump(byte* target, RelocInfo::Mode rmode, Condition cond = al);
+  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
+  void Call(Register target, Condition cond = al);
+  void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
+  void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
+  void Ret();
+
+
+  // Sets the remembered set bit for [address+offset], where address is the
+  // address of the heap object 'object'.  The address must be in the first 8K
+  // of an allocated page. The 'scratch' register is used in the
+  // implementation and all 3 registers are clobbered by the operation, as
+  // well as the ip register.
+  void RecordWrite(Register object, Register offset, Register scratch);
+
+  // ---------------------------------------------------------------------------
+  // Activation frames
+
+  void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
+  void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
+
+  void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
+  void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
+
+  // Enter specific kind of exit frame; either EXIT or
+  // EXIT_DEBUG. Expects the number of arguments in register r0 and
+  // the builtin function to call in register r1. Exits with argc in
+  // r4, argv in r6, and and the builtin function to call in r5.
+  void EnterExitFrame(StackFrame::Type type);
+
+  // Leave the current exit frame. Expects the return value in r0.
+  void LeaveExitFrame(StackFrame::Type type);
+
+
+  // ---------------------------------------------------------------------------
+  // JavaScript invokes
+
+  // Invoke the JavaScript function code by either calling or jumping.
+  void InvokeCode(Register code,
+                  const ParameterCount& expected,
+                  const ParameterCount& actual,
+                  InvokeFlag flag);
+
+  void InvokeCode(Handle<Code> code,
+                  const ParameterCount& expected,
+                  const ParameterCount& actual,
+                  RelocInfo::Mode rmode,
+                  InvokeFlag flag);
+
+  // Invoke the JavaScript function in the given register. Changes the
+  // current context to the context in the function before invoking.
+  void InvokeFunction(Register function,
+                      const ParameterCount& actual,
+                      InvokeFlag flag);
+
+
+  // ---------------------------------------------------------------------------
+  // Debugger Support
+
+  void SaveRegistersToMemory(RegList regs);
+  void RestoreRegistersFromMemory(RegList regs);
+  void CopyRegistersFromMemoryToStack(Register base, RegList regs);
+  void CopyRegistersFromStackToMemory(Register base,
+                                      Register scratch,
+                                      RegList regs);
+
+
+  // ---------------------------------------------------------------------------
+  // Exception handling
+
+  // Push a new try handler and link into try handler chain.
+  // The return address must be passed in register lr.
+  // On exit, r0 contains TOS (code slot).
+  void PushTryHandler(CodeLocation try_location, HandlerType type);
+
+
+  // ---------------------------------------------------------------------------
+  // Inline caching support
+
+  // Generates code that verifies that the maps of objects in the
+  // prototype chain of object hasn't changed since the code was
+  // generated and branches to the miss label if any map has. If
+  // necessary the function also generates code for security check
+  // in case of global object holders. The scratch and holder
+  // registers are always clobbered, but the object register is only
+  // clobbered if it the same as the holder register. The function
+  // returns a register containing the holder - either object_reg or
+  // holder_reg.
+  Register CheckMaps(JSObject* object, Register object_reg,
+                     JSObject* holder, Register holder_reg,
+                     Register scratch, Label* miss);
+
+  // Generate code for checking access rights - used for security checks
+  // on access to global objects across environments. The holder register
+  // is left untouched, whereas both scratch registers are clobbered.
+  void CheckAccessGlobalProxy(Register holder_reg,
+                              Register scratch,
+                              Label* miss);
+
+
+  // ---------------------------------------------------------------------------
+  // Support functions.
+
+  // Generates code for reporting that an illegal operation has
+  // occurred.
+  void IllegalOperation(int num_arguments);
+
+
+  // ---------------------------------------------------------------------------
+  // Runtime calls
+
+  // Call a code stub.
+  void CallStub(CodeStub* stub);
+  void CallJSExitStub(CodeStub* stub);
+
+  // Return from a code stub after popping its arguments.
+  void StubReturn(int argc);
+
+  // Call a runtime routine.
+  // Eventually this should be used for all C calls.
+  void CallRuntime(Runtime::Function* f, int num_arguments);
+
+  // Convenience function: Same as above, but takes the fid instead.
+  void CallRuntime(Runtime::FunctionId fid, int num_arguments);
+
+  // Tail call of a runtime routine (jump).
+  // Like JumpToBuiltin, but also takes care of passing the number
+  // of parameters.
+  void TailCallRuntime(const ExternalReference& ext, int num_arguments);
+
+  // Jump to the builtin routine.
+  void JumpToBuiltin(const ExternalReference& builtin);
+
+  // Invoke specified builtin JavaScript function. Adds an entry to
+  // the unresolved list if the name does not resolve.
+  void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
+
+  // Store the code object for the given builtin in the target register and
+  // setup the function in r1.
+  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
+
+  struct Unresolved {
+    int pc;
+    uint32_t flags;  // see Bootstrapper::FixupFlags decoders/encoders.
+    const char* name;
+  };
+  List<Unresolved>* unresolved() { return &unresolved_; }
+
+
+  // ---------------------------------------------------------------------------
+  // Debugging
+
+  // Calls Abort(msg) if the condition cc is not satisfied.
+  // Use --debug_code to enable.
+  void Assert(Condition cc, const char* msg);
+
+  // Like Assert(), but always enabled.
+  void Check(Condition cc, const char* msg);
+
+  // Print a message to stdout and abort execution.
+  void Abort(const char* msg);
+
+  // Verify restrictions about code generated in stubs.
+  void set_generating_stub(bool value) { generating_stub_ = value; }
+  bool generating_stub() { return generating_stub_; }
+  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
+  bool allow_stub_calls() { return allow_stub_calls_; }
+
+ private:
+  List<Unresolved> unresolved_;
+  bool generating_stub_;
+  bool allow_stub_calls_;
+
+  // Helper functions for generating invokes.
+  void InvokePrologue(const ParameterCount& expected,
+                      const ParameterCount& actual,
+                      Handle<Code> code_constant,
+                      Register code_reg,
+                      Label* done,
+                      InvokeFlag flag);
+
+  // Get the code for the given builtin. Returns if able to resolve
+  // the function in the 'resolved' flag.
+  Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
+
+  // Activation support.
+  void EnterFrame(StackFrame::Type type);
+  void LeaveFrame(StackFrame::Type type);
+};
+
+
+// -----------------------------------------------------------------------------
+// Static helper functions.
+
+// Generate a MemOperand for loading a field from an object.
+static inline MemOperand FieldMemOperand(Register object, int offset) {
+  return MemOperand(object, offset - kHeapObjectTag);
+}
+
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_MACRO_ASSEMBLER_ARM_H_
diff --git a/regexp2000/src/macro-assembler-ia32.cc b/regexp2000/src/macro-assembler-ia32.cc
new file mode 100644 (file)
index 0000000..72808de
--- /dev/null
@@ -0,0 +1,1014 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "codegen-inl.h"
+#include "debug.h"
+#include "runtime.h"
+#include "serialize.h"
+
+namespace v8 { namespace internal {
+
+MacroAssembler::MacroAssembler(void* buffer, int size)
+    : Assembler(buffer, size),
+      unresolved_(0),
+      generating_stub_(false),
+      allow_stub_calls_(true) {
+}
+
+
+static void RecordWriteHelper(MacroAssembler* masm,
+                              Register object,
+                              Register addr,
+                              Register scratch) {
+  Label fast;
+
+  // Compute the page address from the heap object pointer, leave it
+  // in 'object'.
+  masm->and_(object, ~Page::kPageAlignmentMask);
+
+  // Compute the bit addr in the remembered set, leave it in "addr".
+  masm->sub(addr, Operand(object));
+  masm->shr(addr, kObjectAlignmentBits);
+
+  // If the bit offset lies beyond the normal remembered set range, it is in
+  // the extra remembered set area of a large object.
+  masm->cmp(addr, Page::kPageSize / kPointerSize);
+  masm->j(less, &fast);
+
+  // Adjust 'addr' to be relative to the start of the extra remembered set
+  // and the page address in 'object' to be the address of the extra
+  // remembered set.
+  masm->sub(Operand(addr), Immediate(Page::kPageSize / kPointerSize));
+  // Load the array length into 'scratch' and multiply by four to get the
+  // size in bytes of the elements.
+  masm->mov(scratch, Operand(object, Page::kObjectStartOffset
+                                     + FixedArray::kLengthOffset));
+  masm->shl(scratch, kObjectAlignmentBits);
+  // Add the page header, array header, and array body size to the page
+  // address.
+  masm->add(Operand(object), Immediate(Page::kObjectStartOffset
+                                       + Array::kHeaderSize));
+  masm->add(object, Operand(scratch));
+
+
+  // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
+  // to limit code size. We should probably evaluate this decision by
+  // measuring the performance of an equivalent implementation using
+  // "simpler" instructions
+  masm->bind(&fast);
+  masm->bts(Operand(object, 0), addr);
+}
+
+
+class RecordWriteStub : public CodeStub {
+ public:
+  RecordWriteStub(Register object, Register addr, Register scratch)
+      : object_(object), addr_(addr), scratch_(scratch) { }
+
+  void Generate(MacroAssembler* masm);
+
+ private:
+  Register object_;
+  Register addr_;
+  Register scratch_;
+
+#ifdef DEBUG
+  void Print() {
+    PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
+           object_.code(), addr_.code(), scratch_.code());
+  }
+#endif
+
+  // Minor key encoding in 12 bits of three registers (object, address and
+  // scratch) OOOOAAAASSSS.
+  class ScratchBits: public BitField<uint32_t, 0, 4> {};
+  class AddressBits: public BitField<uint32_t, 4, 4> {};
+  class ObjectBits: public BitField<uint32_t, 8, 4> {
+};
+
+  Major MajorKey() { return RecordWrite; }
+
+  int MinorKey() {
+    // Encode the registers.
+    return ObjectBits::encode(object_.code()) |
+           AddressBits::encode(addr_.code()) |
+           ScratchBits::encode(scratch_.code());
+  }
+};
+
+
+void RecordWriteStub::Generate(MacroAssembler* masm) {
+  RecordWriteHelper(masm, object_, addr_, scratch_);
+  masm->ret(0);
+}
+
+
+// Set the remembered set bit for [object+offset].
+// object is the object being stored into, value is the object being stored.
+// If offset is zero, then the scratch register contains the array index into
+// the elements array represented as a Smi.
+// All registers are clobbered by the operation.
+void MacroAssembler::RecordWrite(Register object, int offset,
+                                 Register value, Register scratch) {
+  // First, check if a remembered set write is even needed. The tests below
+  // catch stores of Smis and stores into young gen (which does not have space
+  // for the remembered set bits.
+  Label done;
+
+  // This optimization cannot survive serialization and deserialization,
+  // so we disable as long as serialization can take place.
+  int32_t new_space_start =
+      reinterpret_cast<int32_t>(ExternalReference::new_space_start().address());
+  if (Serializer::enabled() || new_space_start < 0) {
+    // Cannot do smart bit-twiddling. Need to do two consecutive checks.
+    // Check for Smi first.
+    test(value, Immediate(kSmiTagMask));
+    j(zero, &done);
+    // Test that the object address is not in the new space.  We cannot
+    // set remembered set bits in the new space.
+    mov(value, Operand(object));
+    and_(value, Heap::NewSpaceMask());
+    cmp(Operand(value), Immediate(ExternalReference::new_space_start()));
+    j(equal, &done);
+  } else {
+    // move the value SmiTag into the sign bit
+    shl(value, 31);
+    // combine the object with value SmiTag
+    or_(value, Operand(object));
+    // remove the uninteresing bits inside the page
+    and_(value, Heap::NewSpaceMask() | (1 << 31));
+    // xor has two effects:
+    // - if the value was a smi, then the result will be negative
+    // - if the object is pointing into new space area the page bits will
+    //   all be zero
+    xor_(value, new_space_start | (1 << 31));
+    // Check for both conditions in one branch
+    j(less_equal, &done);
+  }
+
+  if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) {
+    // Compute the bit offset in the remembered set, leave it in 'value'.
+    mov(value, Operand(object));
+    and_(value, Page::kPageAlignmentMask);
+    add(Operand(value), Immediate(offset));
+    shr(value, kObjectAlignmentBits);
+
+    // Compute the page address from the heap object pointer, leave it in
+    // 'object'.
+    and_(object, ~Page::kPageAlignmentMask);
+
+    // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
+    // to limit code size. We should probably evaluate this decision by
+    // measuring the performance of an equivalent implementation using
+    // "simpler" instructions
+    bts(Operand(object, 0), value);
+  } else {
+    Register dst = scratch;
+    if (offset != 0) {
+      lea(dst, Operand(object, offset));
+    } else {
+      // array access: calculate the destination address in the same manner as
+      // KeyedStoreIC::GenerateGeneric
+      lea(dst,
+          Operand(object, dst, times_2, Array::kHeaderSize - kHeapObjectTag));
+    }
+    // If we are already generating a shared stub, not inlining the
+    // record write code isn't going to save us any memory.
+    if (generating_stub()) {
+      RecordWriteHelper(this, object, dst, value);
+    } else {
+      RecordWriteStub stub(object, dst, value);
+      CallStub(&stub);
+    }
+  }
+
+  bind(&done);
+}
+
+
+void MacroAssembler::SaveRegistersToMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of registers to memory location.
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      Register reg = { r };
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      mov(Operand::StaticVariable(reg_addr), reg);
+    }
+  }
+}
+
+
+void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of memory location to registers.
+  for (int i = kNumJSCallerSaved; --i >= 0;) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      Register reg = { r };
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      mov(reg, Operand::StaticVariable(reg_addr));
+    }
+  }
+}
+
+
+void MacroAssembler::PushRegistersFromMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Push the content of the memory location to the stack.
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      push(Operand::StaticVariable(reg_addr));
+    }
+  }
+}
+
+
+void MacroAssembler::PopRegistersToMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Pop the content from the stack to the memory location.
+  for (int i = kNumJSCallerSaved; --i >= 0;) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      pop(Operand::StaticVariable(reg_addr));
+    }
+  }
+}
+
+
+void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
+                                                    Register scratch,
+                                                    RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of the stack to the memory location and adjust base.
+  for (int i = kNumJSCallerSaved; --i >= 0;) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      mov(scratch, Operand(base, 0));
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      mov(Operand::StaticVariable(reg_addr), scratch);
+      lea(base, Operand(base, kPointerSize));
+    }
+  }
+}
+
+
+void MacroAssembler::Set(Register dst, const Immediate& x) {
+  if (x.is_zero()) {
+    xor_(dst, Operand(dst));  // shorter than mov
+  } else {
+    mov(Operand(dst), x);
+  }
+}
+
+
+void MacroAssembler::Set(const Operand& dst, const Immediate& x) {
+  mov(dst, x);
+}
+
+
+void MacroAssembler::FCmp() {
+  fcompp();
+  push(eax);
+  fnstsw_ax();
+  sahf();
+  pop(eax);
+}
+
+
+void MacroAssembler::EnterFrame(StackFrame::Type type) {
+  push(ebp);
+  mov(ebp, Operand(esp));
+  push(esi);
+  push(Immediate(Smi::FromInt(type)));
+  push(Immediate(0));  // Push an empty code cache slot.
+}
+
+
+void MacroAssembler::LeaveFrame(StackFrame::Type type) {
+  if (FLAG_debug_code) {
+    cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
+        Immediate(Smi::FromInt(type)));
+    Check(equal, "stack frame types must match");
+  }
+  leave();
+}
+
+
+void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
+  ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
+
+  // Setup the frame structure on the stack.
+  ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize);
+  ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
+  ASSERT(ExitFrameConstants::kCallerFPOffset ==  0 * kPointerSize);
+  push(ebp);
+  mov(ebp, Operand(esp));
+
+  // Reserve room for entry stack pointer and push the debug marker.
+  ASSERT(ExitFrameConstants::kSPOffset  == -1 * kPointerSize);
+  push(Immediate(0));  // saved entry sp, patched before call
+  push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0));
+
+  // Save the frame pointer and the context in top.
+  ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
+  ExternalReference context_address(Top::k_context_address);
+  mov(Operand::StaticVariable(c_entry_fp_address), ebp);
+  mov(Operand::StaticVariable(context_address), esi);
+
+  // Setup argc and argv in callee-saved registers.
+  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
+  mov(edi, Operand(eax));
+  lea(esi, Operand(ebp, eax, times_4, offset));
+
+  // Save the state of all registers to the stack from the memory
+  // location. This is needed to allow nested break points.
+  if (type == StackFrame::EXIT_DEBUG) {
+    // TODO(1243899): This should be symmetric to
+    // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
+    // correct here, but computed for the other call. Very error
+    // prone! FIX THIS.  Actually there are deeper problems with
+    // register saving than this asymmetry (see the bug report
+    // associated with this issue).
+    PushRegistersFromMemory(kJSCallerSaved);
+  }
+
+  // Reserve space for two arguments: argc and argv.
+  sub(Operand(esp), Immediate(2 * kPointerSize));
+
+  // Get the required frame alignment for the OS.
+  static const int kFrameAlignment = OS::ActivationFrameAlignment();
+  if (kFrameAlignment > 0) {
+    ASSERT(IsPowerOf2(kFrameAlignment));
+    and_(esp, -kFrameAlignment);
+  }
+
+  // Patch the saved entry sp.
+  mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
+}
+
+
+void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
+  // Restore the memory copy of the registers by digging them out from
+  // the stack. This is needed to allow nested break points.
+  if (type == StackFrame::EXIT_DEBUG) {
+    // It's okay to clobber register ebx below because we don't need
+    // the function pointer after this.
+    const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
+    int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
+    lea(ebx, Operand(ebp, kOffset));
+    CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
+  }
+
+  // Get the return address from the stack and restore the frame pointer.
+  mov(ecx, Operand(ebp, 1 * kPointerSize));
+  mov(ebp, Operand(ebp, 0 * kPointerSize));
+
+  // Pop the arguments and the receiver from the caller stack.
+  lea(esp, Operand(esi, 1 * kPointerSize));
+
+  // Restore current context from top and clear it in debug mode.
+  ExternalReference context_address(Top::k_context_address);
+  mov(esi, Operand::StaticVariable(context_address));
+  if (kDebug) {
+    mov(Operand::StaticVariable(context_address), Immediate(0));
+  }
+
+  // Push the return address to get ready to return.
+  push(ecx);
+
+  // Clear the top frame.
+  ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
+  mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
+}
+
+
+void MacroAssembler::PushTryHandler(CodeLocation try_location,
+                                    HandlerType type) {
+  ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize);  // adjust this code
+  // The pc (return address) is already on TOS.
+  if (try_location == IN_JAVASCRIPT) {
+    if (type == TRY_CATCH_HANDLER) {
+      push(Immediate(StackHandler::TRY_CATCH));
+    } else {
+      push(Immediate(StackHandler::TRY_FINALLY));
+    }
+    push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent)));
+    push(ebp);
+    push(edi);
+  } else {
+    ASSERT(try_location == IN_JS_ENTRY);
+    // The parameter pointer is meaningless here and ebp does not
+    // point to a JS frame. So we save NULL for both pp and ebp. We
+    // expect the code throwing an exception to check ebp before
+    // dereferencing it to restore the context.
+    push(Immediate(StackHandler::ENTRY));
+    push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent)));
+    push(Immediate(0));  // NULL frame pointer
+    push(Immediate(0));  // NULL parameter pointer
+  }
+  // Cached TOS.
+  mov(eax, Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
+  // Link this handler.
+  mov(Operand::StaticVariable(ExternalReference(Top::k_handler_address)), esp);
+}
+
+
+Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
+                                   JSObject* holder, Register holder_reg,
+                                   Register scratch,
+                                   Label* miss) {
+  // Make sure there's no overlap between scratch and the other
+  // registers.
+  ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
+
+  // Keep track of the current object in register reg.
+  Register reg = object_reg;
+  int depth = 1;
+
+  // Check the maps in the prototype chain.
+  // Traverse the prototype chain from the object and do map checks.
+  while (object != holder) {
+    depth++;
+
+    // Only global objects and objects that do not require access
+    // checks are allowed in stubs.
+    ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+    JSObject* prototype = JSObject::cast(object->GetPrototype());
+    if (Heap::InNewSpace(prototype)) {
+      // Get the map of the current object.
+      mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+      cmp(Operand(scratch), Immediate(Handle<Map>(object->map())));
+      // Branch on the result of the map check.
+      j(not_equal, miss, not_taken);
+      // Check access rights to the global object.  This has to happen
+      // after the map check so that we know that the object is
+      // actually a global object.
+      if (object->IsJSGlobalProxy()) {
+        CheckAccessGlobalProxy(reg, scratch, miss);
+
+        // Restore scratch register to be the map of the object.
+        // We load the prototype from the map in the scratch register.
+        mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+      }
+      // The prototype is in new space; we cannot store a reference
+      // to it in the code. Load it from the map.
+      reg = holder_reg;  // from now the object is in holder_reg
+      mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
+
+    } else {
+      // Check the map of the current object.
+      cmp(FieldOperand(reg, HeapObject::kMapOffset),
+          Immediate(Handle<Map>(object->map())));
+      // Branch on the result of the map check.
+      j(not_equal, miss, not_taken);
+      // Check access rights to the global object.  This has to happen
+      // after the map check so that we know that the object is
+      // actually a global object.
+      if (object->IsJSGlobalProxy()) {
+        CheckAccessGlobalProxy(reg, scratch, miss);
+      }
+      // The prototype is in old space; load it directly.
+      reg = holder_reg;  // from now the object is in holder_reg
+      mov(reg, Handle<JSObject>(prototype));
+    }
+
+    // Go to the next object in the prototype chain.
+    object = prototype;
+  }
+
+  // Check the holder map.
+  cmp(FieldOperand(reg, HeapObject::kMapOffset),
+      Immediate(Handle<Map>(holder->map())));
+  j(not_equal, miss, not_taken);
+
+  // Log the check depth.
+  LOG(IntEvent("check-maps-depth", depth));
+
+  // Perform security check for access to the global object and return
+  // the holder register.
+  ASSERT(object == holder);
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+  if (object->IsJSGlobalProxy()) {
+    CheckAccessGlobalProxy(reg, scratch, miss);
+  }
+  return reg;
+}
+
+
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+                                          Register scratch,
+                                          Label* miss) {
+  Label same_contexts;
+
+  ASSERT(!holder_reg.is(scratch));
+
+  // Load current lexical context from the stack frame.
+  mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
+
+  // When generating debug code, make sure the lexical context is set.
+  if (FLAG_debug_code) {
+    cmp(Operand(scratch), Immediate(0));
+    Check(not_equal, "we should not have an empty lexical context");
+  }
+  // Load the global context of the current context.
+  int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+  mov(scratch, FieldOperand(scratch, offset));
+  mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    push(scratch);
+    // Read the first word and compare to global_context_map.
+    mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
+    cmp(scratch, Factory::global_context_map());
+    Check(equal, "JSGlobalObject::global_context should be a global context.");
+    pop(scratch);
+  }
+
+  // Check if both contexts are the same.
+  cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  j(equal, &same_contexts, taken);
+
+  // Compare security tokens, save holder_reg on the stack so we can use it
+  // as a temporary register.
+  //
+  // TODO(119): avoid push(holder_reg)/pop(holder_reg)
+  push(holder_reg);
+  // Check that the security token in the calling global object is
+  // compatible with the security token in the receiving global
+  // object.
+  mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    cmp(holder_reg, Factory::null_value());
+    Check(not_equal, "JSGlobalProxy::context() should not be null.");
+
+    push(holder_reg);
+    // Read the first word and compare to global_context_map(),
+    mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
+    cmp(holder_reg, Factory::global_context_map());
+    Check(equal, "JSGlobalObject::global_context should be a global context.");
+    pop(holder_reg);
+  }
+
+  int token_offset = Context::kHeaderSize +
+                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
+  mov(scratch, FieldOperand(scratch, token_offset));
+  cmp(scratch, FieldOperand(holder_reg, token_offset));
+  pop(holder_reg);
+  j(not_equal, miss, not_taken);
+
+  bind(&same_contexts);
+}
+
+
+void MacroAssembler::NegativeZeroTest(Register result,
+                                      Register op,
+                                      Label* then_label) {
+  Label ok;
+  test(result, Operand(result));
+  j(not_zero, &ok, taken);
+  test(op, Operand(op));
+  j(sign, then_label, not_taken);
+  bind(&ok);
+}
+
+
+void MacroAssembler::NegativeZeroTest(Register result,
+                                      Register op1,
+                                      Register op2,
+                                      Register scratch,
+                                      Label* then_label) {
+  Label ok;
+  test(result, Operand(result));
+  j(not_zero, &ok, taken);
+  mov(scratch, Operand(op1));
+  or_(scratch, Operand(op2));
+  j(sign, then_label, not_taken);
+  bind(&ok);
+}
+
+
+void MacroAssembler::TryGetFunctionPrototype(Register function,
+                                             Register result,
+                                             Register scratch,
+                                             Label* miss) {
+  // Check that the receiver isn't a smi.
+  test(function, Immediate(kSmiTagMask));
+  j(zero, miss, not_taken);
+
+  // Check that the function really is a function.
+  mov(result, FieldOperand(function, HeapObject::kMapOffset));
+  movzx_b(scratch, FieldOperand(result, Map::kInstanceTypeOffset));
+  cmp(scratch, JS_FUNCTION_TYPE);
+  j(not_equal, miss, not_taken);
+
+  // Make sure that the function has an instance prototype.
+  Label non_instance;
+  movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
+  test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
+  j(not_zero, &non_instance, not_taken);
+
+  // Get the prototype or initial map from the function.
+  mov(result,
+      FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+
+  // If the prototype or initial map is the hole, don't return it and
+  // simply miss the cache instead. This will allow us to allocate a
+  // prototype object on-demand in the runtime system.
+  cmp(Operand(result), Immediate(Factory::the_hole_value()));
+  j(equal, miss, not_taken);
+
+  // If the function does not have an initial map, we're done.
+  Label done;
+  mov(scratch, FieldOperand(result, HeapObject::kMapOffset));
+  movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+  cmp(scratch, MAP_TYPE);
+  j(not_equal, &done);
+
+  // Get the prototype from the initial map.
+  mov(result, FieldOperand(result, Map::kPrototypeOffset));
+  jmp(&done);
+
+  // Non-instance prototype: Fetch prototype from constructor field
+  // in initial map.
+  bind(&non_instance);
+  mov(result, FieldOperand(result, Map::kConstructorOffset));
+
+  // All done.
+  bind(&done);
+}
+
+
+void MacroAssembler::CallStub(CodeStub* stub) {
+  ASSERT(allow_stub_calls());  // calls are not allowed in some stubs
+  call(stub->GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::StubReturn(int argc) {
+  ASSERT(argc >= 1 && generating_stub());
+  ret((argc - 1) * kPointerSize);
+}
+
+
+void MacroAssembler::IllegalOperation(int num_arguments) {
+  if (num_arguments > 0) {
+    add(Operand(esp), Immediate(num_arguments * kPointerSize));
+  }
+  mov(Operand(eax), Immediate(Factory::undefined_value()));
+}
+
+
+void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
+  CallRuntime(Runtime::FunctionForId(id), num_arguments);
+}
+
+
+void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
+  // If the expected number of arguments of the runtime function is
+  // constant, we check that the actual number of arguments match the
+  // expectation.
+  if (f->nargs >= 0 && f->nargs != num_arguments) {
+    IllegalOperation(num_arguments);
+    return;
+  }
+
+  Runtime::FunctionId function_id =
+      static_cast<Runtime::FunctionId>(f->stub_id);
+  RuntimeStub stub(function_id, num_arguments);
+  CallStub(&stub);
+}
+
+
+void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
+                                     int num_arguments) {
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  mov(Operand(eax), Immediate(num_arguments));
+  JumpToBuiltin(ext);
+}
+
+
+void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) {
+  // Set the entry point and jump to the C entry runtime stub.
+  mov(Operand(ebx), Immediate(ext));
+  CEntryStub ces;
+  jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::InvokePrologue(const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    Handle<Code> code_constant,
+                                    const Operand& code_operand,
+                                    Label* done,
+                                    InvokeFlag flag) {
+  bool definitely_matches = false;
+  Label invoke;
+  if (expected.is_immediate()) {
+    ASSERT(actual.is_immediate());
+    if (expected.immediate() == actual.immediate()) {
+      definitely_matches = true;
+    } else {
+      mov(eax, actual.immediate());
+      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+      if (expected.immediate() == sentinel) {
+        // Don't worry about adapting arguments for builtins that
+        // don't want that done. Skip adaption code by making it look
+        // like we have a match between expected and actual number of
+        // arguments.
+        definitely_matches = true;
+      } else {
+        mov(ebx, expected.immediate());
+      }
+    }
+  } else {
+    if (actual.is_immediate()) {
+      // Expected is in register, actual is immediate. This is the
+      // case when we invoke function values without going through the
+      // IC mechanism.
+      cmp(expected.reg(), actual.immediate());
+      j(equal, &invoke);
+      ASSERT(expected.reg().is(ebx));
+      mov(eax, actual.immediate());
+    } else if (!expected.reg().is(actual.reg())) {
+      // Both expected and actual are in (different) registers. This
+      // is the case when we invoke functions using call and apply.
+      cmp(expected.reg(), Operand(actual.reg()));
+      j(equal, &invoke);
+      ASSERT(actual.reg().is(eax));
+      ASSERT(expected.reg().is(ebx));
+    }
+  }
+
+  if (!definitely_matches) {
+    Handle<Code> adaptor =
+        Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
+    if (!code_constant.is_null()) {
+      mov(Operand(edx), Immediate(code_constant));
+      add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
+    } else if (!code_operand.is_reg(edx)) {
+      mov(edx, code_operand);
+    }
+
+    if (flag == CALL_FUNCTION) {
+      call(adaptor, RelocInfo::CODE_TARGET);
+      jmp(done);
+    } else {
+      jmp(adaptor, RelocInfo::CODE_TARGET);
+    }
+    bind(&invoke);
+  }
+}
+
+
+void MacroAssembler::InvokeCode(const Operand& code,
+                                const ParameterCount& expected,
+                                const ParameterCount& actual,
+                                InvokeFlag flag) {
+  Label done;
+  InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
+  if (flag == CALL_FUNCTION) {
+    call(code);
+  } else {
+    ASSERT(flag == JUMP_FUNCTION);
+    jmp(code);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::InvokeCode(Handle<Code> code,
+                                const ParameterCount& expected,
+                                const ParameterCount& actual,
+                                RelocInfo::Mode rmode,
+                                InvokeFlag flag) {
+  Label done;
+  Operand dummy(eax);
+  InvokePrologue(expected, actual, code, dummy, &done, flag);
+  if (flag == CALL_FUNCTION) {
+    call(code, rmode);
+  } else {
+    ASSERT(flag == JUMP_FUNCTION);
+    jmp(code, rmode);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::InvokeFunction(Register fun,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag) {
+  ASSERT(fun.is(edi));
+  mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+  mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
+  mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
+  lea(edx, FieldOperand(edx, Code::kHeaderSize));
+
+  ParameterCount expected(ebx);
+  InvokeCode(Operand(edx), expected, actual, flag);
+}
+
+
+void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
+  bool resolved;
+  Handle<Code> code = ResolveBuiltin(id, &resolved);
+
+    // Calls are not allowed in some stubs.
+  ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
+
+  // Rely on the assertion to check that the number of provided
+  // arguments match the expected number of arguments. Fake a
+  // parameter count to avoid emitting code to do the check.
+  ParameterCount expected(0);
+  InvokeCode(Handle<Code>(code), expected, expected,
+             RelocInfo::CODE_TARGET, flag);
+
+  const char* name = Builtins::GetName(id);
+  int argc = Builtins::GetArgumentsCount(id);
+
+  if (!resolved) {
+    uint32_t flags =
+        Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
+        Bootstrapper::FixupFlagsIsPCRelative::encode(true);
+    Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
+    unresolved_.Add(entry);
+  }
+}
+
+
+void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
+  bool resolved;
+  Handle<Code> code = ResolveBuiltin(id, &resolved);
+
+  const char* name = Builtins::GetName(id);
+  int argc = Builtins::GetArgumentsCount(id);
+
+  mov(Operand(target), Immediate(code));
+  if (!resolved) {
+    uint32_t flags =
+        Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
+        Bootstrapper::FixupFlagsIsPCRelative::encode(false);
+    Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
+    unresolved_.Add(entry);
+  }
+  add(Operand(target), Immediate(Code::kHeaderSize - kHeapObjectTag));
+}
+
+
+Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
+                                            bool* resolved) {
+  // Move the builtin function into the temporary function slot by
+  // reading it from the builtins object. NOTE: We should be able to
+  // reduce this to two instructions by putting the function table in
+  // the global object instead of the "builtins" object and by using a
+  // real register for the function.
+  mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  mov(edx, FieldOperand(edx, GlobalObject::kBuiltinsOffset));
+  int builtins_offset =
+      JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
+  mov(edi, FieldOperand(edx, builtins_offset));
+
+
+  return Builtins::GetCode(id, resolved);
+}
+
+
+void MacroAssembler::Ret() {
+  ret(0);
+}
+
+
+void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
+  }
+}
+
+
+void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
+  ASSERT(value > 0);
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    Operand operand = Operand::StaticVariable(ExternalReference(counter));
+    if (value == 1) {
+      inc(operand);
+    } else {
+      add(operand, Immediate(value));
+    }
+  }
+}
+
+
+void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
+  ASSERT(value > 0);
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    Operand operand = Operand::StaticVariable(ExternalReference(counter));
+    if (value == 1) {
+      dec(operand);
+    } else {
+      sub(operand, Immediate(value));
+    }
+  }
+}
+
+
+void MacroAssembler::Assert(Condition cc, const char* msg) {
+  if (FLAG_debug_code) Check(cc, msg);
+}
+
+
+void MacroAssembler::Check(Condition cc, const char* msg) {
+  Label L;
+  j(cc, &L, taken);
+  Abort(msg);
+  // will not return here
+  bind(&L);
+}
+
+
+void MacroAssembler::Abort(const char* msg) {
+  // We want to pass the msg string like a smi to avoid GC
+  // problems, however msg is not guaranteed to be aligned
+  // properly. Instead, we pass an aligned pointer that is
+  // a proper v8 smi, but also pass the aligment difference
+  // from the real pointer as a smi.
+  intptr_t p1 = reinterpret_cast<intptr_t>(msg);
+  intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
+  ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
+#ifdef DEBUG
+  if (msg != NULL) {
+    RecordComment("Abort message: ");
+    RecordComment(msg);
+  }
+#endif
+  push(eax);
+  push(Immediate(p0));
+  push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
+  CallRuntime(Runtime::kAbort, 2);
+  // will not return here
+}
+
+
+CodePatcher::CodePatcher(byte* address, int size)
+  : address_(address), size_(size), masm_(address, size + Assembler::kGap) {
+  // Create a new macro assembler pointing to the assress of the code to patch.
+  // The size is adjusted with kGap on order for the assembler to generate size
+  // bytes of instructions without failing with buffer size constraints.
+  ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
+}
+
+
+CodePatcher::~CodePatcher() {
+  // Indicate that code has changed.
+  CPU::FlushICache(address_, size_);
+
+  // Check that the code was patched as expected.
+  ASSERT(masm_.pc_ == address_ + size_);
+  ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/macro-assembler-ia32.h b/regexp2000/src/macro-assembler-ia32.h
new file mode 100644 (file)
index 0000000..8bcc651
--- /dev/null
@@ -0,0 +1,328 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MACRO_ASSEMBLER_IA32_H_
+#define V8_MACRO_ASSEMBLER_IA32_H_
+
+#include "assembler.h"
+
+namespace v8 { namespace internal {
+
+
+// Helper type to make boolean flag easier to read at call-site.
+enum InvokeFlag {
+  CALL_FUNCTION,
+  JUMP_FUNCTION
+};
+
+enum CodeLocation {
+  IN_JAVASCRIPT,
+  IN_JS_ENTRY,
+  IN_C_ENTRY
+};
+
+enum HandlerType {
+  TRY_CATCH_HANDLER,
+  TRY_FINALLY_HANDLER,
+  JS_ENTRY_HANDLER
+};
+
+
+// MacroAssembler implements a collection of frequently used macros.
+class MacroAssembler: public Assembler {
+ public:
+  MacroAssembler(void* buffer, int size);
+
+  // ---------------------------------------------------------------------------
+  // GC Support
+
+  // Set the remembered set bit for [object+offset].
+  // object is the object being stored into, value is the object being stored.
+  // If offset is zero, then the scratch register contains the array index into
+  // the elements array represented as a Smi.
+  // All registers are clobbered by the operation.
+  void RecordWrite(Register object,
+                   int offset,
+                   Register value,
+                   Register scratch);
+
+
+  // ---------------------------------------------------------------------------
+  // Debugger Support
+
+  void SaveRegistersToMemory(RegList regs);
+  void RestoreRegistersFromMemory(RegList regs);
+  void PushRegistersFromMemory(RegList regs);
+  void PopRegistersToMemory(RegList regs);
+  void CopyRegistersFromStackToMemory(Register base,
+                                      Register scratch,
+                                      RegList regs);
+
+
+  // ---------------------------------------------------------------------------
+  // Activation frames
+
+  void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
+  void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }
+
+  void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
+  void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
+
+  // Enter specific kind of exit frame; either EXIT or
+  // EXIT_DEBUG. Expects the number of arguments in register eax and
+  // sets up the number of arguments in register edi and the pointer
+  // to the first argument in register esi.
+  void EnterExitFrame(StackFrame::Type type);
+
+  // Leave the current exit frame. Expects the return value in
+  // register eax:edx (untouched) and the pointer to the first
+  // argument in register esi.
+  void LeaveExitFrame(StackFrame::Type type);
+
+
+  // ---------------------------------------------------------------------------
+  // JavaScript invokes
+
+  // Invoke the JavaScript function code by either calling or jumping.
+  void InvokeCode(const Operand& code,
+                  const ParameterCount& expected,
+                  const ParameterCount& actual,
+                  InvokeFlag flag);
+
+  void InvokeCode(Handle<Code> code,
+                  const ParameterCount& expected,
+                  const ParameterCount& actual,
+                  RelocInfo::Mode rmode,
+                  InvokeFlag flag);
+
+  // Invoke the JavaScript function in the given register. Changes the
+  // current context to the context in the function before invoking.
+  void InvokeFunction(Register function,
+                      const ParameterCount& actual,
+                      InvokeFlag flag);
+
+  // Invoke specified builtin JavaScript function. Adds an entry to
+  // the unresolved list if the name does not resolve.
+  void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag);
+
+  // Store the code object for the given builtin in the target register.
+  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
+
+  // Expression support
+  void Set(Register dst, const Immediate& x);
+  void Set(const Operand& dst, const Immediate& x);
+
+  // FCmp is similar to integer cmp, but requires unsigned
+  // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
+  void FCmp();
+
+  // ---------------------------------------------------------------------------
+  // Exception handling
+
+  // Push a new try handler and link into try handler chain.
+  // The return address must be pushed before calling this helper.
+  // On exit, eax contains TOS (next_sp).
+  void PushTryHandler(CodeLocation try_location, HandlerType type);
+
+
+  // ---------------------------------------------------------------------------
+  // Inline caching support
+
+  // Generates code that verifies that the maps of objects in the
+  // prototype chain of object hasn't changed since the code was
+  // generated and branches to the miss label if any map has. If
+  // necessary the function also generates code for security check
+  // in case of global object holders. The scratch and holder
+  // registers are always clobbered, but the object register is only
+  // clobbered if it the same as the holder register. The function
+  // returns a register containing the holder - either object_reg or
+  // holder_reg.
+  Register CheckMaps(JSObject* object, Register object_reg,
+                     JSObject* holder, Register holder_reg,
+                     Register scratch, Label* miss);
+
+  // Generate code for checking access rights - used for security checks
+  // on access to global objects across environments. The holder register
+  // is left untouched, but the scratch register is clobbered.
+  void CheckAccessGlobalProxy(Register holder_reg,
+                              Register scratch,
+                              Label* miss);
+
+
+  // ---------------------------------------------------------------------------
+  // Support functions.
+
+  // Check if result is zero and op is negative.
+  void NegativeZeroTest(Register result, Register op, Label* then_label);
+
+  // Check if result is zero and any of op1 and op2 are negative.
+  // Register scratch is destroyed, and it must be different from op2.
+  void NegativeZeroTest(Register result, Register op1, Register op2,
+                        Register scratch, Label* then_label);
+
+  // Try to get function prototype of a function and puts the value in
+  // the result register. Checks that the function really is a
+  // function and jumps to the miss label if the fast checks fail. The
+  // function register will be untouched; the other registers may be
+  // clobbered.
+  void TryGetFunctionPrototype(Register function,
+                               Register result,
+                               Register scratch,
+                               Label* miss);
+
+  // Generates code for reporting that an illegal operation has
+  // occurred.
+  void IllegalOperation(int num_arguments);
+
+  // ---------------------------------------------------------------------------
+  // Runtime calls
+
+  // Call a code stub.
+  void CallStub(CodeStub* stub);
+
+  // Return from a code stub after popping its arguments.
+  void StubReturn(int argc);
+
+  // Call a runtime routine.
+  // Eventually this should be used for all C calls.
+  void CallRuntime(Runtime::Function* f, int num_arguments);
+
+  // Convenience function: Same as above, but takes the fid instead.
+  void CallRuntime(Runtime::FunctionId id, int num_arguments);
+
+  // Tail call of a runtime routine (jump).
+  // Like JumpToBuiltin, but also takes care of passing the number
+  // of arguments.
+  void TailCallRuntime(const ExternalReference& ext, int num_arguments);
+
+  // Jump to the builtin routine.
+  void JumpToBuiltin(const ExternalReference& ext);
+
+
+  // ---------------------------------------------------------------------------
+  // Utilities
+
+  void Ret();
+
+  struct Unresolved {
+    int pc;
+    uint32_t flags;  // see Bootstrapper::FixupFlags decoders/encoders.
+    const char* name;
+  };
+  List<Unresolved>* unresolved() { return &unresolved_; }
+
+
+  // ---------------------------------------------------------------------------
+  // StatsCounter support
+
+  void SetCounter(StatsCounter* counter, int value);
+  void IncrementCounter(StatsCounter* counter, int value);
+  void DecrementCounter(StatsCounter* counter, int value);
+
+
+  // ---------------------------------------------------------------------------
+  // Debugging
+
+  // Calls Abort(msg) if the condition cc is not satisfied.
+  // Use --debug_code to enable.
+  void Assert(Condition cc, const char* msg);
+
+  // Like Assert(), but always enabled.
+  void Check(Condition cc, const char* msg);
+
+  // Print a message to stdout and abort execution.
+  void Abort(const char* msg);
+
+  // Verify restrictions about code generated in stubs.
+  void set_generating_stub(bool value) { generating_stub_ = value; }
+  bool generating_stub() { return generating_stub_; }
+  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
+  bool allow_stub_calls() { return allow_stub_calls_; }
+
+ private:
+  List<Unresolved> unresolved_;
+  bool generating_stub_;
+  bool allow_stub_calls_;
+
+  // Helper functions for generating invokes.
+  void InvokePrologue(const ParameterCount& expected,
+                      const ParameterCount& actual,
+                      Handle<Code> code_constant,
+                      const Operand& code_operand,
+                      Label* done,
+                      InvokeFlag flag);
+
+  // Get the code for the given builtin. Returns if able to resolve
+  // the function in the 'resolved' flag.
+  Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
+
+  // Activation support.
+  void EnterFrame(StackFrame::Type type);
+  void LeaveFrame(StackFrame::Type type);
+};
+
+
+// The code patcher is used to patch (typically) small parts of code e.g. for
+// debugging and other types of instrumentation. When using the code patcher
+// the exact number of bytes specified must be emitted. Is not legal to emit
+// relocation information. If any of these constraints are violated it causes
+// an assertion.
+class CodePatcher {
+ public:
+  CodePatcher(byte* address, int size);
+  virtual ~CodePatcher();
+
+  // Macro assembler to emit code.
+  MacroAssembler* masm() { return &masm_; }
+
+ private:
+  byte* address_;  // The address of the code being patched.
+  int size_;  // Number of bytes of the expected patch size.
+  MacroAssembler masm_;  // Macro assembler used to generate the code.
+};
+
+// -----------------------------------------------------------------------------
+// Static helper functions.
+
+// Generate an Operand for loading a field from an object.
+static inline Operand FieldOperand(Register object, int offset) {
+  return Operand(object, offset - kHeapObjectTag);
+}
+
+
+// Generate an Operand for loading an indexed field from an object.
+static inline Operand FieldOperand(Register object,
+                                   Register index,
+                                   ScaleFactor scale,
+                                   int offset) {
+  return Operand(object, index, scale, offset - kHeapObjectTag);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_MACRO_ASSEMBLER_IA32_H_
diff --git a/regexp2000/src/macro-assembler.h b/regexp2000/src/macro-assembler.h
new file mode 100644 (file)
index 0000000..f289346
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MACRO_ASSEMBLER_H_
+#define V8_MACRO_ASSEMBLER_H_
+
+#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+
+#include "constants-arm.h"
+#include "assembler.h"
+#include "assembler-arm.h"
+#include "assembler-arm-inl.h"
+#include "code.h"  // must be after assembler_*.h
+#include "macro-assembler-arm.h"
+
+#else  // ia32
+
+#include "assembler.h"
+#include "assembler-ia32.h"
+#include "assembler-ia32-inl.h"
+#include "code.h"  // must be after assembler_*.h
+#include "macro-assembler-ia32.h"
+
+#endif
+
+#endif  // V8_MACRO_ASSEMBLER_H_
diff --git a/regexp2000/src/macros.py b/regexp2000/src/macros.py
new file mode 100644 (file)
index 0000000..5a7606a
--- /dev/null
@@ -0,0 +1,98 @@
+# Copyright 2006-2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Dictionary that is passed as defines for js2c.py.
+# Used for defines that must be defined for all native js files.
+
+const NONE        = 0;
+const READ_ONLY   = 1;
+const DONT_ENUM   = 2;
+const DONT_DELETE = 4;
+
+# Constants used for getter and setter operations.
+const GETTER = 0;
+const SETTER = 1;
+
+# These definitions must match the index of the properties in objects.h.
+const kApiTagOffset               = 0;
+const kApiPropertyListOffset      = 1;
+const kApiSerialNumberOffset      = 2;
+const kApiConstructorOffset       = 2;
+const kApiPrototypeTemplateOffset = 5;
+const kApiParentTemplateOffset    = 6;
+
+const NO_HINT     = 0;
+const NUMBER_HINT = 1;
+const STRING_HINT = 2;
+
+const kFunctionTag  = 0;
+const kNewObjectTag = 1;
+
+# For date.js.
+const HoursPerDay      = 24;
+const MinutesPerHour   = 60;
+const SecondsPerMinute = 60;
+const msPerSecond      = 1000;
+const msPerMinute      = 60000;
+const msPerHour        = 3600000;
+const msPerDay         = 86400000;
+
+# Note: kDayZeroInJulianDay = ToJulianDay(1970, 0, 1).
+const kInvalidDate        = 'Invalid Date';
+const kDayZeroInJulianDay = 2440588;
+const kMonthMask          = 0x1e0;
+const kDayMask            = 0x01f;
+const kYearShift          = 9;
+const kMonthShift         = 5;
+
+# Type query macros.
+macro IS_NULL(arg)              = (arg === null);
+macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
+macro IS_UNDEFINED(arg)         = (typeof(arg) === 'undefined');
+macro IS_FUNCTION(arg)          = (typeof(arg) === 'function');
+macro IS_NUMBER(arg)            = (typeof(arg) === 'number');
+macro IS_STRING(arg)            = (typeof(arg) === 'string');
+macro IS_OBJECT(arg)            = (typeof(arg) === 'object');
+macro IS_BOOLEAN(arg)           = (typeof(arg) === 'boolean');
+macro IS_REGEXP(arg)            = %HasRegExpClass(arg);
+macro IS_ARRAY(arg)             = %HasArrayClass(arg);
+macro IS_DATE(arg)              = %HasDateClass(arg);
+macro IS_ERROR(arg)             = (%ClassOf(arg) === 'Error');
+macro IS_SCRIPT(arg)            = (%ClassOf(arg) === 'Script');
+macro FLOOR(arg)                = %Math_floor(arg);
+
+# 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 TO_INTEGER(arg)    = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
+macro TO_INT32(arg)      = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInt32(arg));
+
+# Macros implemented in Python.
+python macro CHAR_CODE(str) = ord(str[1]);
+
+# Accessors for original global properties that ensure they have been loaded.
+const ORIGINAL_REGEXP = (global.RegExp, $RegExp);
+const ORIGINAL_DATE   = (global.Date, $Date);
diff --git a/regexp2000/src/mark-compact.cc b/regexp2000/src/mark-compact.cc
new file mode 100644 (file)
index 0000000..8daf28d
--- /dev/null
@@ -0,0 +1,1776 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "execution.h"
+#include "global-handles.h"
+#include "ic-inl.h"
+#include "mark-compact.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+#ifdef DEBUG
+// The verification code used between phases of the m-c collector does not
+// currently work.
+//
+// TODO(1240833): Fix the heap verification code and turn this into a real
+// flag.
+static const bool FLAG_verify_global_gc = false;
+#endif  // DEBUG
+
+// ----------------------------------------------------------------------------
+// MarkCompactCollector
+
+bool MarkCompactCollector::compacting_collection_ = false;
+
+int MarkCompactCollector::previous_marked_count_ = 0;
+GCTracer* MarkCompactCollector::tracer_ = NULL;
+
+
+#ifdef DEBUG
+MarkCompactCollector::CollectorState MarkCompactCollector::state_ = IDLE;
+
+// Counters used for debugging the marking phase of mark-compact or mark-sweep
+// collection.
+int MarkCompactCollector::live_bytes_ = 0;
+int MarkCompactCollector::live_young_objects_ = 0;
+int MarkCompactCollector::live_old_data_objects_ = 0;
+int MarkCompactCollector::live_old_pointer_objects_ = 0;
+int MarkCompactCollector::live_code_objects_ = 0;
+int MarkCompactCollector::live_map_objects_ = 0;
+int MarkCompactCollector::live_lo_objects_ = 0;
+#endif
+
+void MarkCompactCollector::CollectGarbage(GCTracer* tracer) {
+  // Rather than passing the tracer around we stash it in a static member
+  // variable.
+  tracer_ = tracer;
+  Prepare();
+  // Prepare has selected whether to compact the old generation or not.
+  // Tell the tracer.
+  if (IsCompacting()) tracer_->set_is_compacting();
+
+  MarkLiveObjects();
+
+  SweepLargeObjectSpace();
+
+  if (compacting_collection_) {
+    EncodeForwardingAddresses();
+
+    UpdatePointers();
+
+    RelocateObjects();
+
+    RebuildRSets();
+
+  } else {
+    SweepSpaces();
+  }
+
+  Finish();
+
+  // Save the count of marked objects remaining after the collection and
+  // null out the GC tracer.
+  previous_marked_count_ = tracer_->marked_count();
+  ASSERT(previous_marked_count_ == 0);
+  tracer_ = NULL;
+}
+
+
+void MarkCompactCollector::Prepare() {
+  static const int kFragmentationLimit = 50;  // Percent.
+#ifdef DEBUG
+  ASSERT(state_ == IDLE);
+  state_ = PREPARE_GC;
+#endif
+  ASSERT(!FLAG_always_compact || !FLAG_never_compact);
+
+  compacting_collection_ = FLAG_always_compact;
+
+  // We compact the old generation if it gets too fragmented (ie, we could
+  // recover an expected amount of space by reclaiming the waste and free
+  // list blocks).  We always compact when the flag --gc-global is true
+  // because objects do not get promoted out of new space on non-compacting
+  // GCs.
+  if (!compacting_collection_) {
+    int old_gen_recoverable = 0;
+    int old_gen_used = 0;
+
+    OldSpaces spaces;
+    while (OldSpace* space = spaces.next()) {
+      old_gen_recoverable += space->Waste() + space->AvailableFree();
+      old_gen_used += space->Size();
+    }
+    int old_gen_fragmentation =
+      static_cast<int>((old_gen_recoverable * 100.0) / old_gen_used);
+    if (old_gen_fragmentation > kFragmentationLimit) {
+      compacting_collection_ = true;
+    }
+  }
+
+  if (FLAG_never_compact) compacting_collection_ = false;
+
+#ifdef DEBUG
+  if (compacting_collection_) {
+    // We will write bookkeeping information to the remembered set area
+    // starting now.
+    Page::set_rset_state(Page::NOT_IN_USE);
+  }
+#endif
+
+  PagedSpaces spaces;
+  while (PagedSpace* space = spaces.next()) {
+    space->PrepareForMarkCompact(compacting_collection_);
+  }
+
+  Counters::global_objects.Set(0);
+
+#ifdef DEBUG
+  live_bytes_ = 0;
+  live_young_objects_ = 0;
+  live_old_pointer_objects_ = 0;
+  live_old_data_objects_ = 0;
+  live_code_objects_ = 0;
+  live_map_objects_ = 0;
+  live_lo_objects_ = 0;
+#endif
+}
+
+
+void MarkCompactCollector::Finish() {
+#ifdef DEBUG
+  ASSERT(state_ == SWEEP_SPACES || state_ == REBUILD_RSETS);
+  state_ = IDLE;
+#endif
+  // The stub cache is not traversed during GC; clear the cache to
+  // force lazy re-initialization of it. This must be done after the
+  // GC, because it relies on the new address of certain old space
+  // objects (empty string, illegal builtin).
+  StubCache::Clear();
+}
+
+
+// ----------------------------------------------------------------------------
+// Phase 1: tracing and marking live objects.
+//   before: all objects are in normal state.
+//   after: a live object's map pointer is marked as '00'.
+
+// Marking all live objects in the heap as part of mark-sweep or mark-compact
+// collection.  Before marking, all objects are in their normal state.  After
+// marking, live objects' map pointers are marked indicating that the object
+// has been found reachable.
+//
+// The marking algorithm is a (mostly) depth-first (because of possible stack
+// overflow) traversal of the graph of objects reachable from the roots.  It
+// uses an explicit stack of pointers rather than recursion.  The young
+// generation's inactive ('from') space is used as a marking stack.  The
+// objects in the marking stack are the ones that have been reached and marked
+// but their children have not yet been visited.
+//
+// The marking stack can overflow during traversal.  In that case, we set an
+// overflow flag.  When the overflow flag is set, we continue marking objects
+// reachable from the objects on the marking stack, but no longer push them on
+// the marking stack.  Instead, we mark them as both marked and overflowed.
+// When the stack is in the overflowed state, objects marked as overflowed
+// have been reached and marked but their children have not been visited yet.
+// After emptying the marking stack, we clear the overflow flag and traverse
+// the heap looking for objects marked as overflowed, push them on the stack,
+// and continue with marking.  This process repeats until all reachable
+// objects have been marked.
+
+static MarkingStack marking_stack;
+
+
+static inline HeapObject* ShortCircuitConsString(Object** p) {
+  // Optimization: If the heap object pointed to by p is a non-symbol
+  // cons string whose right substring is Heap::empty_string, update
+  // it in place to its left substring.  Return the updated value.
+  //
+  // Here we assume that if we change *p, we replace it with a heap object
+  // (ie, the left substring of a cons string is always a heap object).
+  //
+  // The check performed is:
+  //   object->IsConsString() && !object->IsSymbol() &&
+  //   (ConsString::cast(object)->second() == Heap::empty_string())
+  // except the maps for the object and its possible substrings might be
+  // marked.
+  HeapObject* object = HeapObject::cast(*p);
+  MapWord map_word = object->map_word();
+  map_word.ClearMark();
+  InstanceType type = map_word.ToMap()->instance_type();
+  if (type >= FIRST_NONSTRING_TYPE || (type & kIsSymbolMask) != 0) {
+    return object;
+  }
+
+  StringRepresentationTag rep =
+      static_cast<StringRepresentationTag>(type & kStringRepresentationMask);
+  if (rep != kConsStringTag) return object;
+
+  Object* second = reinterpret_cast<ConsString*>(object)->second();
+  if (reinterpret_cast<String*>(second) != Heap::empty_string()) return object;
+
+  // Since we don't have the object's start, it is impossible to update the
+  // remembered set.  Therefore, we only replace the string with its left
+  // substring when the remembered set does not change.
+  Object* first = reinterpret_cast<ConsString*>(object)->first();
+  if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object;
+
+  *p = first;
+  return HeapObject::cast(first);
+}
+
+
+// Helper class for marking pointers in HeapObjects.
+class MarkingVisitor : public ObjectVisitor {
+ public:
+
+  void VisitPointer(Object** p) {
+    MarkObjectByPointer(p);
+  }
+
+  void VisitPointers(Object** start, Object** end) {
+    // Mark all objects pointed to in [start, end).
+    const int kMinRangeForMarkingRecursion = 64;
+    if (end - start >= kMinRangeForMarkingRecursion) {
+      if (VisitUnmarkedObjects(start, end)) return;
+      // We are close to a stack overflow, so just mark the objects.
+    }
+    for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
+  }
+
+  void BeginCodeIteration(Code* code) {
+    // When iterating over a code object during marking
+    // ic targets are derived pointers.
+    ASSERT(code->ic_flag() == Code::IC_TARGET_IS_ADDRESS);
+  }
+
+  void EndCodeIteration(Code* code) {
+    // If this is a compacting collection, set ic targets
+    // are pointing to object headers.
+    if (IsCompacting()) code->set_ic_flag(Code::IC_TARGET_IS_OBJECT);
+  }
+
+  void VisitCodeTarget(RelocInfo* rinfo) {
+    ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+    Code* code = CodeFromDerivedPointer(rinfo->target_address());
+    if (FLAG_cleanup_ics_at_gc && code->is_inline_cache_stub()) {
+      IC::Clear(rinfo->pc());
+      // Please note targets for cleared inline cached do not have to be
+      // marked since they are contained in Heap::non_monomorphic_cache().
+    } else {
+      MarkCompactCollector::MarkObject(code);
+    }
+    if (IsCompacting()) {
+      // When compacting we convert the target to a real object pointer.
+      code = CodeFromDerivedPointer(rinfo->target_address());
+      rinfo->set_target_object(code);
+    }
+  }
+
+  void VisitDebugTarget(RelocInfo* rinfo) {
+    ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
+           rinfo->is_call_instruction());
+    HeapObject* code = CodeFromDerivedPointer(rinfo->call_address());
+    MarkCompactCollector::MarkObject(code);
+    // When compacting we convert the call to a real object pointer.
+    if (IsCompacting()) rinfo->set_call_object(code);
+  }
+
+ private:
+  // Mark object pointed to by p.
+  void MarkObjectByPointer(Object** p) {
+    if (!(*p)->IsHeapObject()) return;
+    HeapObject* object = ShortCircuitConsString(p);
+    MarkCompactCollector::MarkObject(object);
+  }
+
+  // Tells whether the mark sweep collection will perform compaction.
+  bool IsCompacting() { return MarkCompactCollector::IsCompacting(); }
+
+  // Retrieves the Code pointer from derived code entry.
+  Code* CodeFromDerivedPointer(Address addr) {
+    ASSERT(addr != NULL);
+    return reinterpret_cast<Code*>(
+        HeapObject::FromAddress(addr - Code::kHeaderSize));
+  }
+
+  // Visit an unmarked object.
+  void VisitUnmarkedObject(HeapObject* obj) {
+    ASSERT(Heap::Contains(obj));
+#ifdef DEBUG
+    MarkCompactCollector::UpdateLiveObjectCount(obj);
+#endif
+    Map* map = obj->map();
+    obj->SetMark();
+    MarkCompactCollector::tracer()->increment_marked_count();
+    // Mark the map pointer and the body.
+    MarkCompactCollector::MarkObject(map);
+    obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), this);
+  }
+
+  // Visit all unmarked objects pointed to by [start, end).
+  // Returns false if the operation fails (lack of stack space).
+  inline bool VisitUnmarkedObjects(Object** start, Object** end) {
+    // Return false is we are close to the stack limit.
+    StackLimitCheck check;
+    if (check.HasOverflowed()) return false;
+
+    // Visit the unmarked objects.
+    for (Object** p = start; p < end; p++) {
+      if (!(*p)->IsHeapObject()) continue;
+      HeapObject* obj = HeapObject::cast(*p);
+      if (obj->IsMarked()) continue;
+      VisitUnmarkedObject(obj);
+    }
+    return true;
+  }
+};
+
+
+// Visitor class for marking heap roots.
+class RootMarkingVisitor : public ObjectVisitor {
+ public:
+  void VisitPointer(Object** p) {
+    MarkObjectByPointer(p);
+  }
+
+  void VisitPointers(Object** start, Object** end) {
+    for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
+  }
+
+  MarkingVisitor* stack_visitor() { return &stack_visitor_; }
+
+ private:
+  MarkingVisitor stack_visitor_;
+
+  void MarkObjectByPointer(Object** p) {
+    if (!(*p)->IsHeapObject()) return;
+
+    // Replace flat cons strings in place.
+    HeapObject* object = ShortCircuitConsString(p);
+    if (object->IsMarked()) return;
+
+#ifdef DEBUG
+    MarkCompactCollector::UpdateLiveObjectCount(object);
+#endif
+    Map* map = object->map();
+    // Mark the object.
+    object->SetMark();
+    MarkCompactCollector::tracer()->increment_marked_count();
+    // Mark the map pointer and body, and push them on the marking stack.
+    MarkCompactCollector::MarkObject(map);
+    object->IterateBody(map->instance_type(), object->SizeFromMap(map),
+                        &stack_visitor_);
+
+    // Mark all the objects reachable from the map and body.  May leave
+    // overflowed objects in the heap.
+    MarkCompactCollector::EmptyMarkingStack(&stack_visitor_);
+  }
+};
+
+
+// Helper class for pruning the symbol table.
+class SymbolTableCleaner : public ObjectVisitor {
+ public:
+  SymbolTableCleaner() : pointers_removed_(0) { }
+  void VisitPointers(Object** start, Object** end) {
+    // Visit all HeapObject pointers in [start, end).
+    for (Object** p = start; p < end; p++) {
+      if ((*p)->IsHeapObject() && !HeapObject::cast(*p)->IsMarked()) {
+        // Set the entry to null_value (as deleted).
+        *p = Heap::null_value();
+        pointers_removed_++;
+      }
+    }
+  }
+
+  int PointersRemoved() {
+    return pointers_removed_;
+  }
+ private:
+  int pointers_removed_;
+};
+
+
+void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) {
+#ifdef DEBUG
+  UpdateLiveObjectCount(object);
+#endif
+  ASSERT(!object->IsMarked());
+  if (object->IsJSGlobalObject()) Counters::global_objects.Increment();
+
+  if (FLAG_cleanup_caches_in_maps_at_gc && object->IsMap()) {
+    Map::cast(object)->ClearCodeCache();
+  }
+
+  object->SetMark();
+  tracer_->increment_marked_count();
+  ASSERT(Heap::Contains(object));
+  marking_stack.Push(object);
+}
+
+
+static int OverflowObjectSize(HeapObject* obj) {
+  // Recover the normal map pointer, it might be marked as live and
+  // overflowed.
+  MapWord map_word = obj->map_word();
+  map_word.ClearMark();
+  map_word.ClearOverflow();
+  return obj->SizeFromMap(map_word.ToMap());
+}
+
+
+// Fill the marking stack with overflowed objects returned by the given
+// iterator.  Stop when the marking stack is filled or the end of the space
+// is reached, whichever comes first.
+template<class T>
+static void ScanOverflowedObjects(T* it) {
+  // The caller should ensure that the marking stack is initially not full,
+  // so that we don't waste effort pointlessly scanning for objects.
+  ASSERT(!marking_stack.is_full());
+
+  while (it->has_next()) {
+    HeapObject* object = it->next();
+    if (object->IsOverflowed()) {
+      object->ClearOverflow();
+      ASSERT(object->IsMarked());
+      ASSERT(Heap::Contains(object));
+      marking_stack.Push(object);
+      if (marking_stack.is_full()) return;
+    }
+  }
+}
+
+
+bool MarkCompactCollector::MustBeMarked(Object** p) {
+  // Check whether *p is a HeapObject pointer.
+  if (!(*p)->IsHeapObject()) return false;
+  return !HeapObject::cast(*p)->IsMarked();
+}
+
+
+void MarkCompactCollector::ProcessRoots(RootMarkingVisitor* visitor) {
+  // Mark the heap roots gray, including global variables, stack variables,
+  // etc.
+  Heap::IterateStrongRoots(visitor);
+
+  // Take care of the symbol table specially.
+  SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table());
+  // 1. Mark the prefix of the symbol table gray.
+  symbol_table->IteratePrefix(visitor);
+#ifdef DEBUG
+  UpdateLiveObjectCount(symbol_table);
+#endif
+  // 2. Mark the symbol table black (ie, do not push it on the marking stack
+  // or mark it overflowed).
+  symbol_table->SetMark();
+  tracer_->increment_marked_count();
+
+  // There may be overflowed objects in the heap.  Visit them now.
+  while (marking_stack.overflowed()) {
+    RefillMarkingStack();
+    EmptyMarkingStack(visitor->stack_visitor());
+  }
+}
+
+
+void MarkCompactCollector::MarkObjectGroups() {
+  List<ObjectGroup*>& object_groups = GlobalHandles::ObjectGroups();
+
+  for (int i = 0; i < object_groups.length(); i++) {
+    ObjectGroup* entry = object_groups[i];
+    if (entry == NULL) continue;
+
+    List<Object**>& objects = entry->objects_;
+    bool group_marked = false;
+    for (int j = 0; j < objects.length(); j++) {
+      Object* object = *objects[j];
+      if (object->IsHeapObject() && HeapObject::cast(object)->IsMarked()) {
+        group_marked = true;
+        break;
+      }
+    }
+
+    if (!group_marked) continue;
+
+    // An object in the group is marked, so mark as gray all white heap
+    // objects in the group.
+    for (int j = 0; j < objects.length(); ++j) {
+      if ((*objects[j])->IsHeapObject()) {
+        MarkObject(HeapObject::cast(*objects[j]));
+      }
+    }
+    // Once the entire group has been colored gray, set the object group
+    // to NULL so it won't be processed again.
+    delete object_groups[i];
+    object_groups[i] = NULL;
+  }
+}
+
+
+// Mark all objects reachable from the objects on the marking stack.
+// Before: the marking stack contains zero or more heap object pointers.
+// After: the marking stack is empty, and all objects reachable from the
+// marking stack have been marked, or are overflowed in the heap.
+void MarkCompactCollector::EmptyMarkingStack(MarkingVisitor* visitor) {
+  while (!marking_stack.is_empty()) {
+    HeapObject* object = marking_stack.Pop();
+    ASSERT(object->IsHeapObject());
+    ASSERT(Heap::Contains(object));
+    ASSERT(object->IsMarked());
+    ASSERT(!object->IsOverflowed());
+
+    // Because the object is marked, we have to recover the original map
+    // pointer and use it to mark the object's body.
+    MapWord map_word = object->map_word();
+    map_word.ClearMark();
+    Map* map = map_word.ToMap();
+    MarkObject(map);
+    object->IterateBody(map->instance_type(), object->SizeFromMap(map),
+                        visitor);
+  }
+}
+
+
+// Sweep the heap for overflowed objects, clear their overflow bits, and
+// push them on the marking stack.  Stop early if the marking stack fills
+// before sweeping completes.  If sweeping completes, there are no remaining
+// overflowed objects in the heap so the overflow flag on the markings stack
+// is cleared.
+void MarkCompactCollector::RefillMarkingStack() {
+  ASSERT(marking_stack.overflowed());
+
+  SemiSpaceIterator new_it(Heap::new_space(), &OverflowObjectSize);
+  ScanOverflowedObjects(&new_it);
+  if (marking_stack.is_full()) return;
+
+  HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
+                                    &OverflowObjectSize);
+  ScanOverflowedObjects(&old_pointer_it);
+  if (marking_stack.is_full()) return;
+
+  HeapObjectIterator old_data_it(Heap::old_data_space(), &OverflowObjectSize);
+  ScanOverflowedObjects(&old_data_it);
+  if (marking_stack.is_full()) return;
+
+  HeapObjectIterator code_it(Heap::code_space(), &OverflowObjectSize);
+  ScanOverflowedObjects(&code_it);
+  if (marking_stack.is_full()) return;
+
+  HeapObjectIterator map_it(Heap::map_space(), &OverflowObjectSize);
+  ScanOverflowedObjects(&map_it);
+  if (marking_stack.is_full()) return;
+
+  LargeObjectIterator lo_it(Heap::lo_space(), &OverflowObjectSize);
+  ScanOverflowedObjects(&lo_it);
+  if (marking_stack.is_full()) return;
+
+  marking_stack.clear_overflowed();
+}
+
+
+// Mark all objects reachable (transitively) from objects on the marking
+// stack.  Before: the marking stack contains zero or more heap object
+// pointers.  After: the marking stack is empty and there are no overflowed
+// objects in the heap.
+void MarkCompactCollector::ProcessMarkingStack(MarkingVisitor* visitor) {
+  EmptyMarkingStack(visitor);
+  while (marking_stack.overflowed()) {
+    RefillMarkingStack();
+    EmptyMarkingStack(visitor);
+  }
+}
+
+
+void MarkCompactCollector::ProcessObjectGroups(MarkingVisitor* visitor) {
+  bool work_to_do = true;
+  ASSERT(marking_stack.is_empty());
+  while (work_to_do) {
+    MarkObjectGroups();
+    work_to_do = !marking_stack.is_empty();
+    ProcessMarkingStack(visitor);
+  }
+}
+
+
+void MarkCompactCollector::MarkLiveObjects() {
+#ifdef DEBUG
+  ASSERT(state_ == PREPARE_GC);
+  state_ = MARK_LIVE_OBJECTS;
+#endif
+  // The to space contains live objects, the from space is used as a marking
+  // stack.
+  marking_stack.Initialize(Heap::new_space()->FromSpaceLow(),
+                           Heap::new_space()->FromSpaceHigh());
+
+  ASSERT(!marking_stack.overflowed());
+
+  RootMarkingVisitor root_visitor;
+  ProcessRoots(&root_visitor);
+
+  // The objects reachable from the roots are marked black, unreachable
+  // objects are white.  Mark objects reachable from object groups with at
+  // least one marked object, and continue until no new objects are
+  // reachable from the object groups.
+  ProcessObjectGroups(root_visitor.stack_visitor());
+
+  // The objects reachable from the roots or object groups are marked black,
+  // unreachable objects are white.  Process objects reachable only from
+  // weak global handles.
+  //
+  // First we mark weak pointers not yet reachable.
+  GlobalHandles::MarkWeakRoots(&MustBeMarked);
+  // Then we process weak pointers and process the transitive closure.
+  GlobalHandles::IterateWeakRoots(&root_visitor);
+  while (marking_stack.overflowed()) {
+    RefillMarkingStack();
+    EmptyMarkingStack(root_visitor.stack_visitor());
+  }
+
+  // Repeat the object groups to mark unmarked groups reachable from the
+  // weak roots.
+  ProcessObjectGroups(root_visitor.stack_visitor());
+
+  // Prune the symbol table removing all symbols only pointed to by the
+  // symbol table.  Cannot use SymbolTable::cast here because the symbol
+  // table is marked.
+  SymbolTable* symbol_table =
+      reinterpret_cast<SymbolTable*>(Heap::symbol_table());
+  SymbolTableCleaner v;
+  symbol_table->IterateElements(&v);
+  symbol_table->ElementsRemoved(v.PointersRemoved());
+
+#ifdef DEBUG
+  if (FLAG_verify_global_gc) VerifyHeapAfterMarkingPhase();
+#endif
+
+  // Remove object groups after marking phase.
+  GlobalHandles::RemoveObjectGroups();
+}
+
+
+#ifdef DEBUG
+void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
+  live_bytes_ += obj->Size();
+  if (Heap::new_space()->Contains(obj)) {
+    live_young_objects_++;
+  } else if (Heap::map_space()->Contains(obj)) {
+    ASSERT(obj->IsMap());
+    live_map_objects_++;
+  } else if (Heap::old_pointer_space()->Contains(obj)) {
+    live_old_pointer_objects_++;
+  } else if (Heap::old_data_space()->Contains(obj)) {
+    live_old_data_objects_++;
+  } else if (Heap::code_space()->Contains(obj)) {
+    live_code_objects_++;
+  } else if (Heap::lo_space()->Contains(obj)) {
+    live_lo_objects_++;
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+static int CountMarkedCallback(HeapObject* obj) {
+  MapWord map_word = obj->map_word();
+  map_word.ClearMark();
+  return obj->SizeFromMap(map_word.ToMap());
+}
+
+
+void MarkCompactCollector::VerifyHeapAfterMarkingPhase() {
+  Heap::new_space()->Verify();
+  Heap::old_pointer_space()->Verify();
+  Heap::old_data_space()->Verify();
+  Heap::code_space()->Verify();
+  Heap::map_space()->Verify();
+
+  int live_objects;
+
+#define CHECK_LIVE_OBJECTS(it, expected)                   \
+          live_objects = 0;                                \
+          while (it.has_next()) {                          \
+            HeapObject* obj = HeapObject::cast(it.next()); \
+            if (obj->IsMarked()) live_objects++;           \
+          }                                                \
+          ASSERT(live_objects == expected);
+
+  SemiSpaceIterator new_it(Heap::new_space(), &CountMarkedCallback);
+  CHECK_LIVE_OBJECTS(new_it, live_young_objects_);
+
+  HeapObjectIterator old_pointer_it(Heap::old_pointer_space(),
+                                    &CountMarkedCallback);
+  CHECK_LIVE_OBJECTS(old_pointer_it, live_old_pointer_objects_);
+
+  HeapObjectIterator old_data_it(Heap::old_data_space(), &CountMarkedCallback);
+  CHECK_LIVE_OBJECTS(old_data_it, live_old_data_objects_);
+
+  HeapObjectIterator code_it(Heap::code_space(), &CountMarkedCallback);
+  CHECK_LIVE_OBJECTS(code_it, live_code_objects_);
+
+  HeapObjectIterator map_it(Heap::map_space(), &CountMarkedCallback);
+  CHECK_LIVE_OBJECTS(map_it, live_map_objects_);
+
+  LargeObjectIterator lo_it(Heap::lo_space(), &CountMarkedCallback);
+  CHECK_LIVE_OBJECTS(lo_it, live_lo_objects_);
+
+#undef CHECK_LIVE_OBJECTS
+}
+#endif  // DEBUG
+
+
+void MarkCompactCollector::SweepLargeObjectSpace() {
+#ifdef DEBUG
+  ASSERT(state_ == MARK_LIVE_OBJECTS);
+  state_ =
+      compacting_collection_ ? ENCODE_FORWARDING_ADDRESSES : SWEEP_SPACES;
+#endif
+  // Deallocate unmarked objects and clear marked bits for marked objects.
+  Heap::lo_space()->FreeUnmarkedObjects();
+}
+
+
+// -------------------------------------------------------------------------
+// Phase 2: Encode forwarding addresses.
+// When compacting, forwarding addresses for objects in old space and map
+// space are encoded in their map pointer word (along with an encoding of
+// their map pointers).
+//
+//  31             21 20              10 9               0
+// +-----------------+------------------+-----------------+
+// |forwarding offset|page offset of map|page index of map|
+// +-----------------+------------------+-----------------+
+//  11 bits           11 bits            10 bits
+//
+// An address range [start, end) can have both live and non-live objects.
+// Maximal non-live regions are marked so they can be skipped on subsequent
+// sweeps of the heap.  A distinguished map-pointer encoding is used to mark
+// free regions of one-word size (in which case the next word is the start
+// of a live object).  A second distinguished map-pointer encoding is used
+// to mark free regions larger than one word, and the size of the free
+// region (including the first word) is written to the second word of the
+// region.
+//
+// Any valid map page offset must lie in the object area of the page, so map
+// page offsets less than Page::kObjectStartOffset are invalid.  We use a
+// pair of distinguished invalid map encodings (for single word and multiple
+// words) to indicate free regions in the page found during computation of
+// forwarding addresses and skipped over in subsequent sweeps.
+static const uint32_t kSingleFreeEncoding = 0;
+static const uint32_t kMultiFreeEncoding = 1;
+
+
+// Encode a free region, defined by the given start address and size, in the
+// first word or two of the region.
+void EncodeFreeRegion(Address free_start, int free_size) {
+  ASSERT(free_size >= kIntSize);
+  if (free_size == kIntSize) {
+    Memory::uint32_at(free_start) = kSingleFreeEncoding;
+  } else {
+    ASSERT(free_size >= 2 * kIntSize);
+    Memory::uint32_at(free_start) = kMultiFreeEncoding;
+    Memory::int_at(free_start + kIntSize) = free_size;
+  }
+
+#ifdef DEBUG
+  // Zap the body of the free region.
+  if (FLAG_enable_slow_asserts) {
+    for (int offset = 2 * kIntSize;
+         offset < free_size;
+         offset += kPointerSize) {
+      Memory::Address_at(free_start + offset) = kZapValue;
+    }
+  }
+#endif
+}
+
+
+// Try to promote all objects in new space.  Heap numbers and sequential
+// strings are promoted to the code space, all others to the old space.
+inline Object* MCAllocateFromNewSpace(HeapObject* object, int object_size) {
+  OldSpace* target_space = Heap::TargetSpace(object);
+  ASSERT(target_space == Heap::old_pointer_space() ||
+         target_space == Heap::old_data_space());
+  Object* forwarded = target_space->MCAllocateRaw(object_size);
+
+  if (forwarded->IsFailure()) {
+    forwarded = Heap::new_space()->MCAllocateRaw(object_size);
+  }
+  return forwarded;
+}
+
+
+// Allocation functions for the paged spaces call the space's MCAllocateRaw.
+inline Object* MCAllocateFromOldPointerSpace(HeapObject* object,
+                                             int object_size) {
+  return Heap::old_pointer_space()->MCAllocateRaw(object_size);
+}
+
+
+inline Object* MCAllocateFromOldDataSpace(HeapObject* object, int object_size) {
+  return Heap::old_data_space()->MCAllocateRaw(object_size);
+}
+
+
+inline Object* MCAllocateFromCodeSpace(HeapObject* object, int object_size) {
+  return Heap::code_space()->MCAllocateRaw(object_size);
+}
+
+
+inline Object* MCAllocateFromMapSpace(HeapObject* object, int object_size) {
+  return Heap::map_space()->MCAllocateRaw(object_size);
+}
+
+
+// The forwarding address is encoded at the same offset as the current
+// to-space object, but in from space.
+inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object,
+                                              int object_size,
+                                              Object* new_object,
+                                              int* ignored) {
+  int offset =
+      Heap::new_space()->ToSpaceOffsetForAddress(old_object->address());
+  Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset) =
+      HeapObject::cast(new_object)->address();
+}
+
+
+// The forwarding address is encoded in the map pointer of the object as an
+// offset (in terms of live bytes) from the address of the first live object
+// in the page.
+inline void EncodeForwardingAddressInPagedSpace(HeapObject* old_object,
+                                                int object_size,
+                                                Object* new_object,
+                                                int* offset) {
+  // Record the forwarding address of the first live object if necessary.
+  if (*offset == 0) {
+    Page::FromAddress(old_object->address())->mc_first_forwarded =
+        HeapObject::cast(new_object)->address();
+  }
+
+  MapWord encoding =
+      MapWord::EncodeAddress(old_object->map()->address(), *offset);
+  old_object->set_map_word(encoding);
+  *offset += object_size;
+  ASSERT(*offset <= Page::kObjectAreaSize);
+}
+
+
+// Most non-live objects are ignored.
+inline void IgnoreNonLiveObject(HeapObject* object) {}
+
+
+// A code deletion event is logged for non-live code objects.
+inline void LogNonLiveCodeObject(HeapObject* object) {
+  if (object->IsCode()) LOG(CodeDeleteEvent(object->address()));
+}
+
+
+// Function template that, given a range of addresses (eg, a semispace or a
+// paged space page), iterates through the objects in the range to clear
+// mark bits and compute and encode forwarding addresses.  As a side effect,
+// maximal free chunks are marked so that they can be skipped on subsequent
+// sweeps.
+//
+// The template parameters are an allocation function, a forwarding address
+// encoding function, and a function to process non-live objects.
+template<MarkCompactCollector::AllocationFunction Alloc,
+         MarkCompactCollector::EncodingFunction Encode,
+         MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
+inline void EncodeForwardingAddressesInRange(Address start,
+                                             Address end,
+                                             int* offset) {
+  // The start address of the current free region while sweeping the space.
+  // This address is set when a transition from live to non-live objects is
+  // encountered.  A value (an encoding of the 'next free region' pointer)
+  // is written to memory at this address when a transition from non-live to
+  // live objects is encountered.
+  Address free_start = NULL;
+
+  // A flag giving the state of the previously swept object.  Initially true
+  // to ensure that free_start is initialized to a proper address before
+  // trying to write to it.
+  bool is_prev_alive = true;
+
+  int object_size;  // Will be set on each iteration of the loop.
+  for (Address current = start; current < end; current += object_size) {
+    HeapObject* object = HeapObject::FromAddress(current);
+    if (object->IsMarked()) {
+      object->ClearMark();
+      MarkCompactCollector::tracer()->decrement_marked_count();
+      object_size = object->Size();
+
+      Object* forwarded = Alloc(object, object_size);
+      // Allocation cannot fail, because we are compacting the space.
+      ASSERT(!forwarded->IsFailure());
+      Encode(object, object_size, forwarded, offset);
+
+#ifdef DEBUG
+      if (FLAG_gc_verbose) {
+        PrintF("forward %p -> %p.\n", object->address(),
+               HeapObject::cast(forwarded)->address());
+      }
+#endif
+      if (!is_prev_alive) {  // Transition from non-live to live.
+        EncodeFreeRegion(free_start, current - free_start);
+        is_prev_alive = true;
+      }
+    } else {  // Non-live object.
+      object_size = object->Size();
+      ProcessNonLive(object);
+      if (is_prev_alive) {  // Transition from live to non-live.
+        free_start = current;
+        is_prev_alive = false;
+      }
+    }
+  }
+
+  // If we ended on a free region, mark it.
+  if (!is_prev_alive) EncodeFreeRegion(free_start, end - free_start);
+}
+
+
+// Functions to encode the forwarding pointers in each compactable space.
+void MarkCompactCollector::EncodeForwardingAddressesInNewSpace() {
+  int ignored;
+  EncodeForwardingAddressesInRange<MCAllocateFromNewSpace,
+                                   EncodeForwardingAddressInNewSpace,
+                                   IgnoreNonLiveObject>(
+      Heap::new_space()->bottom(),
+      Heap::new_space()->top(),
+      &ignored);
+}
+
+
+template<MarkCompactCollector::AllocationFunction Alloc,
+         MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive>
+void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace(
+    PagedSpace* space) {
+  PageIterator it(space, PageIterator::PAGES_IN_USE);
+  while (it.has_next()) {
+    Page* p = it.next();
+    // The offset of each live object in the page from the first live object
+    // in the page.
+    int offset = 0;
+    EncodeForwardingAddressesInRange<Alloc,
+                                     EncodeForwardingAddressInPagedSpace,
+                                     ProcessNonLive>(
+        p->ObjectAreaStart(),
+        p->AllocationTop(),
+        &offset);
+  }
+}
+
+
+static void SweepSpace(NewSpace* space) {
+  HeapObject* object;
+  for (Address current = space->bottom();
+       current < space->top();
+       current += object->Size()) {
+    object = HeapObject::FromAddress(current);
+    if (object->IsMarked()) {
+      object->ClearMark();
+      MarkCompactCollector::tracer()->decrement_marked_count();
+    } else {
+      // We give non-live objects a map that will correctly give their size,
+      // since their existing map might not be live after the collection.
+      int size = object->Size();
+      if (size >= Array::kHeaderSize) {
+        object->set_map(Heap::byte_array_map());
+        ByteArray::cast(object)->set_length(ByteArray::LengthFor(size));
+      } else {
+        ASSERT(size == kPointerSize);
+        object->set_map(Heap::one_word_filler_map());
+      }
+      ASSERT(object->Size() == size);
+    }
+    // The object is now unmarked for the call to Size() at the top of the
+    // loop.
+  }
+}
+
+
+static void SweepSpace(PagedSpace* space, DeallocateFunction dealloc) {
+  PageIterator it(space, PageIterator::PAGES_IN_USE);
+  while (it.has_next()) {
+    Page* p = it.next();
+
+    bool is_previous_alive = true;
+    Address free_start = NULL;
+    HeapObject* object;
+
+    for (Address current = p->ObjectAreaStart();
+         current < p->AllocationTop();
+         current += object->Size()) {
+      object = HeapObject::FromAddress(current);
+      if (object->IsMarked()) {
+        object->ClearMark();
+        MarkCompactCollector::tracer()->decrement_marked_count();
+        if (MarkCompactCollector::IsCompacting() && object->IsCode()) {
+          // If this is compacting collection marked code objects have had
+          // their IC targets converted to objects.
+          // They need to be converted back to addresses.
+          Code::cast(object)->ConvertICTargetsFromObjectToAddress();
+        }
+        if (!is_previous_alive) {  // Transition from free to live.
+          dealloc(free_start, current - free_start);
+          is_previous_alive = true;
+        }
+      } else {
+        if (object->IsCode()) {
+          LOG(CodeDeleteEvent(Code::cast(object)->address()));
+        }
+        if (is_previous_alive) {  // Transition from live to free.
+          free_start = current;
+          is_previous_alive = false;
+        }
+      }
+      // The object is now unmarked for the call to Size() at the top of the
+      // loop.
+    }
+
+    // If the last region was not live we need to from free_start to the
+    // allocation top in the page.
+    if (!is_previous_alive) {
+      int free_size = p->AllocationTop() - free_start;
+      if (free_size > 0) {
+        dealloc(free_start, free_size);
+      }
+    }
+  }
+}
+
+
+void MarkCompactCollector::DeallocateOldPointerBlock(Address start,
+                                                     int size_in_bytes) {
+  Heap::ClearRSetRange(start, size_in_bytes);
+  Heap::old_pointer_space()->Free(start, size_in_bytes);
+}
+
+
+void MarkCompactCollector::DeallocateOldDataBlock(Address start,
+                                                  int size_in_bytes) {
+  Heap::old_data_space()->Free(start, size_in_bytes);
+}
+
+
+void MarkCompactCollector::DeallocateCodeBlock(Address start,
+                                               int size_in_bytes) {
+  Heap::code_space()->Free(start, size_in_bytes);
+}
+
+
+void MarkCompactCollector::DeallocateMapBlock(Address start,
+                                              int size_in_bytes) {
+  // Objects in map space are frequently assumed to have size Map::kSize and a
+  // valid map in their first word.  Thus, we break the free block up into
+  // chunks and free them separately.
+  ASSERT(size_in_bytes % Map::kSize == 0);
+  Heap::ClearRSetRange(start, size_in_bytes);
+  Address end = start + size_in_bytes;
+  for (Address a = start; a < end; a += Map::kSize) {
+    Heap::map_space()->Free(a);
+  }
+}
+
+
+void MarkCompactCollector::EncodeForwardingAddresses() {
+  ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
+  // Objects in the active semispace of the young generation may be
+  // relocated to the inactive semispace (if not promoted).  Set the
+  // relocation info to the beginning of the inactive semispace.
+  Heap::new_space()->MCResetRelocationInfo();
+
+  // Compute the forwarding pointers in each space.
+  EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldPointerSpace,
+                                        IgnoreNonLiveObject>(
+      Heap::old_pointer_space());
+
+  EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldDataSpace,
+                                        IgnoreNonLiveObject>(
+      Heap::old_data_space());
+
+  EncodeForwardingAddressesInPagedSpace<MCAllocateFromCodeSpace,
+                                        LogNonLiveCodeObject>(
+      Heap::code_space());
+
+  // Compute new space next to last after the old and code spaces have been
+  // compacted.  Objects in new space can be promoted to old or code space.
+  EncodeForwardingAddressesInNewSpace();
+
+  // Compute map space last because computing forwarding addresses
+  // overwrites non-live objects.  Objects in the other spaces rely on
+  // non-live map pointers to get the sizes of non-live objects.
+  EncodeForwardingAddressesInPagedSpace<MCAllocateFromMapSpace,
+                                        IgnoreNonLiveObject>(
+      Heap::map_space());
+
+  // Write relocation info to the top page, so we can use it later.  This is
+  // done after promoting objects from the new space so we get the correct
+  // allocation top.
+  Heap::old_pointer_space()->MCWriteRelocationInfoToPage();
+  Heap::old_data_space()->MCWriteRelocationInfoToPage();
+  Heap::code_space()->MCWriteRelocationInfoToPage();
+  Heap::map_space()->MCWriteRelocationInfoToPage();
+}
+
+
+void MarkCompactCollector::SweepSpaces() {
+  ASSERT(state_ == SWEEP_SPACES);
+  ASSERT(!IsCompacting());
+  // Noncompacting collections simply sweep the spaces to clear the mark
+  // bits and free the nonlive blocks (for old and map spaces).  We sweep
+  // the map space last because freeing non-live maps overwrites them and
+  // the other spaces rely on possibly non-live maps to get the sizes for
+  // non-live objects.
+  SweepSpace(Heap::old_pointer_space(), &DeallocateOldPointerBlock);
+  SweepSpace(Heap::old_data_space(), &DeallocateOldDataBlock);
+  SweepSpace(Heap::code_space(), &DeallocateCodeBlock);
+  SweepSpace(Heap::new_space());
+  SweepSpace(Heap::map_space(), &DeallocateMapBlock);
+}
+
+
+// Iterate the live objects in a range of addresses (eg, a page or a
+// semispace).  The live regions of the range have been linked into a list.
+// The first live region is [first_live_start, first_live_end), and the last
+// address in the range is top.  The callback function is used to get the
+// size of each live object.
+int MarkCompactCollector::IterateLiveObjectsInRange(
+    Address start,
+    Address end,
+    HeapObjectCallback size_func) {
+  int live_objects = 0;
+  Address current = start;
+  while (current < end) {
+    uint32_t encoded_map = Memory::uint32_at(current);
+    if (encoded_map == kSingleFreeEncoding) {
+      current += kPointerSize;
+    } else if (encoded_map == kMultiFreeEncoding) {
+      current += Memory::int_at(current + kIntSize);
+    } else {
+      live_objects++;
+      current += size_func(HeapObject::FromAddress(current));
+    }
+  }
+  return live_objects;
+}
+
+
+int MarkCompactCollector::IterateLiveObjects(NewSpace* space,
+                                             HeapObjectCallback size_f) {
+  ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
+  return IterateLiveObjectsInRange(space->bottom(), space->top(), size_f);
+}
+
+
+int MarkCompactCollector::IterateLiveObjects(PagedSpace* space,
+                                             HeapObjectCallback size_f) {
+  ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS);
+  int total = 0;
+  PageIterator it(space, PageIterator::PAGES_IN_USE);
+  while (it.has_next()) {
+    Page* p = it.next();
+    total += IterateLiveObjectsInRange(p->ObjectAreaStart(),
+                                       p->AllocationTop(),
+                                       size_f);
+  }
+  return total;
+}
+
+
+#ifdef DEBUG
+static int VerifyMapObject(HeapObject* obj) {
+  InstanceType type = reinterpret_cast<Map*>(obj)->instance_type();
+  ASSERT(FIRST_TYPE <= type && type <= LAST_TYPE);
+  return Map::kSize;
+}
+
+
+void MarkCompactCollector::VerifyHeapAfterEncodingForwardingAddresses() {
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) space->Verify();
+
+  ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
+  int live_maps = IterateLiveObjects(Heap::map_space(), &VerifyMapObject);
+  ASSERT(live_maps == live_map_objects_);
+
+  // Verify page headers in paged spaces.
+  PagedSpaces paged_spaces;
+  while (PagedSpace* space = paged_spaces.next()) VerifyPageHeaders(space);
+}
+
+
+void MarkCompactCollector::VerifyPageHeaders(PagedSpace* space) {
+  PageIterator mc_it(space, PageIterator::PAGES_USED_BY_MC);
+  while (mc_it.has_next()) {
+    Page* p = mc_it.next();
+    Address mc_alloc_top = p->mc_relocation_top;
+    ASSERT(p->ObjectAreaStart() <= mc_alloc_top &&
+           mc_alloc_top <= p->ObjectAreaEnd());
+  }
+
+  int page_count = 0;
+  PageIterator it(space, PageIterator::PAGES_IN_USE);
+  while (it.has_next()) {
+    Page* p = it.next();
+    ASSERT(p->mc_page_index == page_count);
+    page_count++;
+
+    // first_forwarded could be 'deadbeed' if no live objects in this page
+    Address first_forwarded = p->mc_first_forwarded;
+    ASSERT(first_forwarded == kZapValue ||
+           space->Contains(first_forwarded));
+  }
+}
+#endif
+
+
+// ----------------------------------------------------------------------------
+// Phase 3: Update pointers
+
+// Helper class for updating pointers in HeapObjects.
+class UpdatingVisitor: public ObjectVisitor {
+ public:
+  void VisitPointer(Object** p) {
+    UpdatePointer(p);
+  }
+
+  void VisitPointers(Object** start, Object** end) {
+    // Mark all HeapObject pointers in [start, end)
+    for (Object** p = start; p < end; p++) UpdatePointer(p);
+  }
+
+ private:
+  void UpdatePointer(Object** p) {
+    if (!(*p)->IsHeapObject()) return;
+
+    HeapObject* obj = HeapObject::cast(*p);
+    Address old_addr = obj->address();
+    Address new_addr;
+    ASSERT(!Heap::InFromSpace(obj));
+
+    if (Heap::new_space()->Contains(obj)) {
+      Address f_addr = Heap::new_space()->FromSpaceLow() +
+                       Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
+      new_addr = Memory::Address_at(f_addr);
+
+#ifdef DEBUG
+      ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
+             Heap::old_data_space()->Contains(new_addr) ||
+             Heap::code_space()->Contains(new_addr) ||
+             Heap::new_space()->FromSpaceContains(new_addr));
+
+      if (Heap::new_space()->FromSpaceContains(new_addr)) {
+        ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
+               Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
+      }
+#endif
+
+    } else if (Heap::lo_space()->Contains(obj)) {
+      // Don't move objects in the large object space.
+      return;
+
+    } else {
+      ASSERT(Heap::old_pointer_space()->Contains(obj) ||
+             Heap::old_data_space()->Contains(obj) ||
+             Heap::code_space()->Contains(obj) ||
+             Heap::map_space()->Contains(obj));
+
+      new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj);
+      ASSERT(Heap::old_pointer_space()->Contains(new_addr) ||
+             Heap::old_data_space()->Contains(new_addr) ||
+             Heap::code_space()->Contains(new_addr) ||
+             Heap::map_space()->Contains(new_addr));
+
+#ifdef DEBUG
+      if (Heap::old_pointer_space()->Contains(obj)) {
+        ASSERT(Heap::old_pointer_space()->MCSpaceOffsetForAddress(new_addr) <=
+               Heap::old_pointer_space()->MCSpaceOffsetForAddress(old_addr));
+      } else if (Heap::old_data_space()->Contains(obj)) {
+        ASSERT(Heap::old_data_space()->MCSpaceOffsetForAddress(new_addr) <=
+               Heap::old_data_space()->MCSpaceOffsetForAddress(old_addr));
+      } else if (Heap::code_space()->Contains(obj)) {
+        ASSERT(Heap::code_space()->MCSpaceOffsetForAddress(new_addr) <=
+               Heap::code_space()->MCSpaceOffsetForAddress(old_addr));
+      } else {
+        ASSERT(Heap::map_space()->MCSpaceOffsetForAddress(new_addr) <=
+               Heap::map_space()->MCSpaceOffsetForAddress(old_addr));
+      }
+#endif
+    }
+
+    *p = HeapObject::FromAddress(new_addr);
+
+#ifdef DEBUG
+    if (FLAG_gc_verbose) {
+      PrintF("update %p : %p -> %p\n",
+             reinterpret_cast<Address>(p), old_addr, new_addr);
+    }
+#endif
+  }
+};
+
+
+void MarkCompactCollector::UpdatePointers() {
+#ifdef DEBUG
+  ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES);
+  state_ = UPDATE_POINTERS;
+#endif
+  UpdatingVisitor updating_visitor;
+  Heap::IterateRoots(&updating_visitor);
+  GlobalHandles::IterateWeakRoots(&updating_visitor);
+
+  int live_maps = IterateLiveObjects(Heap::map_space(),
+                                     &UpdatePointersInOldObject);
+  int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
+                                             &UpdatePointersInOldObject);
+  int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
+                                          &UpdatePointersInOldObject);
+  int live_codes = IterateLiveObjects(Heap::code_space(),
+                                      &UpdatePointersInOldObject);
+  int live_news = IterateLiveObjects(Heap::new_space(),
+                                     &UpdatePointersInNewObject);
+
+  // Large objects do not move, the map word can be updated directly.
+  LargeObjectIterator it(Heap::lo_space());
+  while (it.has_next()) UpdatePointersInNewObject(it.next());
+
+  USE(live_maps);
+  USE(live_pointer_olds);
+  USE(live_data_olds);
+  USE(live_codes);
+  USE(live_news);
+
+#ifdef DEBUG
+  ASSERT(live_maps == live_map_objects_);
+  ASSERT(live_data_olds == live_old_data_objects_);
+  ASSERT(live_pointer_olds == live_old_pointer_objects_);
+  ASSERT(live_codes == live_code_objects_);
+  ASSERT(live_news == live_young_objects_);
+
+  if (FLAG_verify_global_gc) VerifyHeapAfterUpdatingPointers();
+#endif
+}
+
+
+int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) {
+  // Keep old map pointers
+  Map* old_map = obj->map();
+  ASSERT(old_map->IsHeapObject());
+
+  Address forwarded = GetForwardingAddressInOldSpace(old_map);
+
+  ASSERT(Heap::map_space()->Contains(old_map));
+  ASSERT(Heap::map_space()->Contains(forwarded));
+#ifdef DEBUG
+  if (FLAG_gc_verbose) {
+    PrintF("update %p : %p -> %p\n", obj->address(), old_map->address(),
+           forwarded);
+  }
+#endif
+  // Update the map pointer.
+  obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(forwarded)));
+
+  // We have to compute the object size relying on the old map because
+  // map objects are not relocated yet.
+  int obj_size = obj->SizeFromMap(old_map);
+
+  // Update pointers in the object body.
+  UpdatingVisitor updating_visitor;
+  obj->IterateBody(old_map->instance_type(), obj_size, &updating_visitor);
+  return obj_size;
+}
+
+
+int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) {
+  // Decode the map pointer.
+  MapWord encoding = obj->map_word();
+  Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
+  ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
+
+  // At this point, the first word of map_addr is also encoded, cannot
+  // cast it to Map* using Map::cast.
+  Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr));
+  int obj_size = obj->SizeFromMap(map);
+  InstanceType type = map->instance_type();
+
+  // Update map pointer.
+  Address new_map_addr = GetForwardingAddressInOldSpace(map);
+  int offset = encoding.DecodeOffset();
+  obj->set_map_word(MapWord::EncodeAddress(new_map_addr, offset));
+
+#ifdef DEBUG
+  if (FLAG_gc_verbose) {
+    PrintF("update %p : %p -> %p\n", obj->address(),
+           map_addr, new_map_addr);
+  }
+#endif
+
+  // Update pointers in the object body.
+  UpdatingVisitor updating_visitor;
+  obj->IterateBody(type, obj_size, &updating_visitor);
+  return obj_size;
+}
+
+
+Address MarkCompactCollector::GetForwardingAddressInOldSpace(HeapObject* obj) {
+  // Object should either in old or map space.
+  MapWord encoding = obj->map_word();
+
+  // Offset to the first live object's forwarding address.
+  int offset = encoding.DecodeOffset();
+  Address obj_addr = obj->address();
+
+  // Find the first live object's forwarding address.
+  Page* p = Page::FromAddress(obj_addr);
+  Address first_forwarded = p->mc_first_forwarded;
+
+  // Page start address of forwarded address.
+  Page* forwarded_page = Page::FromAddress(first_forwarded);
+  int forwarded_offset = forwarded_page->Offset(first_forwarded);
+
+  // Find end of allocation of in the page of first_forwarded.
+  Address mc_top = forwarded_page->mc_relocation_top;
+  int mc_top_offset = forwarded_page->Offset(mc_top);
+
+  // Check if current object's forward pointer is in the same page
+  // as the first live object's forwarding pointer
+  if (forwarded_offset + offset < mc_top_offset) {
+    // In the same page.
+    return first_forwarded + offset;
+  }
+
+  // Must be in the next page, NOTE: this may cross chunks.
+  Page* next_page = forwarded_page->next_page();
+  ASSERT(next_page->is_valid());
+
+  offset -= (mc_top_offset - forwarded_offset);
+  offset += Page::kObjectStartOffset;
+
+  ASSERT_PAGE_OFFSET(offset);
+  ASSERT(next_page->OffsetToAddress(offset) < next_page->mc_relocation_top);
+
+  return next_page->OffsetToAddress(offset);
+}
+
+
+#ifdef DEBUG
+void MarkCompactCollector::VerifyHeapAfterUpdatingPointers() {
+  ASSERT(state_ == UPDATE_POINTERS);
+
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) space->Verify();
+  PagedSpaces paged_spaces;
+  while (PagedSpace* space = paged_spaces.next()) VerifyPageHeaders(space);
+}
+#endif
+
+
+// ----------------------------------------------------------------------------
+// Phase 4: Relocate objects
+
+void MarkCompactCollector::RelocateObjects() {
+#ifdef DEBUG
+  ASSERT(state_ == UPDATE_POINTERS);
+  state_ = RELOCATE_OBJECTS;
+#endif
+  // Relocates objects, always relocate map objects first. Relocating
+  // objects in other space relies on map objects to get object size.
+  int live_maps = IterateLiveObjects(Heap::map_space(), &RelocateMapObject);
+  int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
+                                             &RelocateOldPointerObject);
+  int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
+                                          &RelocateOldDataObject);
+  int live_codes = IterateLiveObjects(Heap::code_space(), &RelocateCodeObject);
+  int live_news = IterateLiveObjects(Heap::new_space(), &RelocateNewObject);
+
+  USE(live_maps);
+  USE(live_data_olds);
+  USE(live_pointer_olds);
+  USE(live_codes);
+  USE(live_news);
+#ifdef DEBUG
+  ASSERT(live_maps == live_map_objects_);
+  ASSERT(live_data_olds == live_old_data_objects_);
+  ASSERT(live_pointer_olds == live_old_pointer_objects_);
+  ASSERT(live_codes == live_code_objects_);
+  ASSERT(live_news == live_young_objects_);
+#endif
+
+  // Notify code object in LO to convert IC target to address
+  // This must happen after lo_space_->Compact
+  LargeObjectIterator it(Heap::lo_space());
+  while (it.has_next()) { ConvertCodeICTargetToAddress(it.next()); }
+
+  // Flips from and to spaces
+  Heap::new_space()->Flip();
+
+  // Sets age_mark to bottom in to space
+  Address mark = Heap::new_space()->bottom();
+  Heap::new_space()->set_age_mark(mark);
+
+  Heap::new_space()->MCCommitRelocationInfo();
+#ifdef DEBUG
+  // It is safe to write to the remembered sets as remembered sets on a
+  // page-by-page basis after committing the m-c forwarding pointer.
+  Page::set_rset_state(Page::IN_USE);
+#endif
+  PagedSpaces spaces;
+  while (PagedSpace* space = spaces.next()) space->MCCommitRelocationInfo();
+
+#ifdef DEBUG
+  if (FLAG_verify_global_gc) VerifyHeapAfterRelocatingObjects();
+#endif
+}
+
+
+int MarkCompactCollector::ConvertCodeICTargetToAddress(HeapObject* obj) {
+  if (obj->IsCode()) {
+    Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
+  }
+  return obj->Size();
+}
+
+
+int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
+  // decode map pointer (forwarded address)
+  MapWord encoding = obj->map_word();
+  Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
+  ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
+
+  // Get forwarding address before resetting map pointer
+  Address new_addr = GetForwardingAddressInOldSpace(obj);
+
+  // recover map pointer
+  obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
+
+  // The meta map object may not be copied yet.
+  Address old_addr = obj->address();
+
+  if (new_addr != old_addr) {
+    memmove(new_addr, old_addr, Map::kSize);  // copy contents
+  }
+
+#ifdef DEBUG
+  if (FLAG_gc_verbose) {
+    PrintF("relocate %p -> %p\n", old_addr, new_addr);
+  }
+#endif
+
+  return Map::kSize;
+}
+
+
+static inline int RelocateOldObject(HeapObject* obj,
+                                    OldSpace* space,
+                                    Address new_addr,
+                                    Address map_addr) {
+  // recover map pointer
+  obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)));
+
+  // This is a non-map object, it relies on the assumption that the Map space
+  // is compacted before the Old space (see RelocateObjects).
+  int obj_size = obj->Size();
+  ASSERT_OBJECT_SIZE(obj_size);
+
+  ASSERT(space->MCSpaceOffsetForAddress(new_addr) <=
+         space->MCSpaceOffsetForAddress(obj->address()));
+
+  space->MCAdjustRelocationEnd(new_addr, obj_size);
+
+#ifdef DEBUG
+  if (FLAG_gc_verbose) {
+    PrintF("relocate %p -> %p\n", obj->address(), new_addr);
+  }
+#endif
+
+  return obj_size;
+}
+
+
+int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj,
+                                                   OldSpace* space) {
+  // decode map pointer (forwarded address)
+  MapWord encoding = obj->map_word();
+  Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
+  ASSERT(Heap::map_space()->Contains(map_addr));
+
+  // Get forwarding address before resetting map pointer
+  Address new_addr = GetForwardingAddressInOldSpace(obj);
+
+  int obj_size = RelocateOldObject(obj, space, new_addr, map_addr);
+
+  Address old_addr = obj->address();
+
+  if (new_addr != old_addr) {
+    memmove(new_addr, old_addr, obj_size);  // copy contents
+  }
+
+  ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
+
+  return obj_size;
+}
+
+
+int MarkCompactCollector::RelocateOldPointerObject(HeapObject* obj) {
+  return RelocateOldNonCodeObject(obj, Heap::old_pointer_space());
+}
+
+
+int MarkCompactCollector::RelocateOldDataObject(HeapObject* obj) {
+  return RelocateOldNonCodeObject(obj, Heap::old_data_space());
+}
+
+
+int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
+  // decode map pointer (forwarded address)
+  MapWord encoding = obj->map_word();
+  Address map_addr = encoding.DecodeMapAddress(Heap::map_space());
+  ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr)));
+
+  // Get forwarding address before resetting map pointer
+  Address new_addr = GetForwardingAddressInOldSpace(obj);
+
+  int obj_size = RelocateOldObject(obj, Heap::code_space(), new_addr, map_addr);
+
+  // convert inline cache target to address using old address
+  if (obj->IsCode()) {
+    // convert target to address first related to old_address
+    Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
+  }
+
+  Address old_addr = obj->address();
+
+  if (new_addr != old_addr) {
+    memmove(new_addr, old_addr, obj_size);  // copy contents
+  }
+
+  HeapObject* copied_to = HeapObject::FromAddress(new_addr);
+  if (copied_to->IsCode()) {
+    // may also update inline cache target.
+    Code::cast(copied_to)->Relocate(new_addr - old_addr);
+    // Notify the logger that compile code has moved.
+    LOG(CodeMoveEvent(old_addr, new_addr));
+  }
+
+  return obj_size;
+}
+
+
+#ifdef DEBUG
+class VerifyCopyingVisitor: public ObjectVisitor {
+ public:
+  void VisitPointers(Object** start, Object** end) {
+    for (Object** p = start; p < end; p++) {
+      MarkCompactCollector::VerifyCopyingObjects(p);
+    }
+  }
+};
+
+#endif
+
+int MarkCompactCollector::RelocateNewObject(HeapObject* obj) {
+  int obj_size = obj->Size();
+
+  // Get forwarding address
+  Address old_addr = obj->address();
+  int offset = Heap::new_space()->ToSpaceOffsetForAddress(old_addr);
+
+  Address new_addr =
+    Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset);
+
+  if (Heap::new_space()->FromSpaceContains(new_addr)) {
+    ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <=
+           Heap::new_space()->ToSpaceOffsetForAddress(old_addr));
+  } else {
+    OldSpace* target_space = Heap::TargetSpace(obj);
+    ASSERT(target_space == Heap::old_pointer_space() ||
+           target_space == Heap::old_data_space());
+    target_space->MCAdjustRelocationEnd(new_addr, obj_size);
+  }
+
+  // New and old addresses cannot overlap.
+  memcpy(reinterpret_cast<void*>(new_addr),
+         reinterpret_cast<void*>(old_addr),
+         obj_size);
+
+#ifdef DEBUG
+  if (FLAG_gc_verbose) {
+    PrintF("relocate %p -> %p\n", old_addr, new_addr);
+  }
+  if (FLAG_verify_global_gc) {
+    VerifyCopyingVisitor v;
+    HeapObject* copied_to = HeapObject::FromAddress(new_addr);
+    copied_to->Iterate(&v);
+  }
+#endif
+
+  return obj_size;
+}
+
+
+#ifdef DEBUG
+void MarkCompactCollector::VerifyHeapAfterRelocatingObjects() {
+  ASSERT(state_ == RELOCATE_OBJECTS);
+
+  Heap::new_space()->Verify();
+  PagedSpaces spaces;
+  while (PagedSpace* space = spaces.next()) {
+    space->Verify();
+    PageIterator it(space, PageIterator::PAGES_IN_USE);
+    while (it.has_next()) {
+      Page* p = it.next();
+      ASSERT_PAGE_OFFSET(p->Offset(p->AllocationTop()));
+    }
+  }
+}
+#endif
+
+
+#ifdef DEBUG
+void MarkCompactCollector::VerifyCopyingObjects(Object** p) {
+  if (!(*p)->IsHeapObject()) return;
+  ASSERT(!Heap::InToSpace(*p));
+}
+#endif  // DEBUG
+
+
+// -----------------------------------------------------------------------------
+// Phase 5: rebuild remembered sets
+
+void MarkCompactCollector::RebuildRSets() {
+#ifdef DEBUG
+  ASSERT(state_ == RELOCATE_OBJECTS);
+  state_ = REBUILD_RSETS;
+#endif
+  Heap::RebuildRSets();
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/mark-compact.h b/regexp2000/src/mark-compact.h
new file mode 100644 (file)
index 0000000..f3b4e2a
--- /dev/null
@@ -0,0 +1,365 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MARK_COMPACT_H_
+#define V8_MARK_COMPACT_H_
+
+namespace v8 { namespace internal {
+
+// Callback function, returns whether an object is alive. The heap size
+// of the object is returned in size. It optionally updates the offset
+// to the first live object in the page (only used for old and map objects).
+typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset);
+
+// Callback function for non-live blocks in the old generation.
+typedef void (*DeallocateFunction)(Address start, int size_in_bytes);
+
+
+// Forward declarations.
+class RootMarkingVisitor;
+class MarkingVisitor;
+
+
+// ----------------------------------------------------------------------------
+// Mark-Compact collector
+//
+// All methods are static.
+
+class MarkCompactCollector : public AllStatic {
+ public:
+  // Type of functions to compute forwarding addresses of objects in
+  // compacted spaces.  Given an object and its size, return a (non-failure)
+  // Object* that will be the object after forwarding.  There is a separate
+  // allocation function for each (compactable) space based on the location
+  // of the object before compaction.
+  typedef Object* (*AllocationFunction)(HeapObject* object, int object_size);
+
+  // Type of functions to encode the forwarding address for an object.
+  // Given the object, its size, and the new (non-failure) object it will be
+  // forwarded to, encode the forwarding address.  For paged spaces, the
+  // 'offset' input/output parameter contains the offset of the forwarded
+  // object from the forwarding address of the previous live object in the
+  // page as input, and is updated to contain the offset to be used for the
+  // next live object in the same page.  For spaces using a different
+  // encoding (ie, contiguous spaces), the offset parameter is ignored.
+  typedef void (*EncodingFunction)(HeapObject* old_object,
+                                   int object_size,
+                                   Object* new_object,
+                                   int* offset);
+
+  // Type of functions to process non-live objects.
+  typedef void (*ProcessNonLiveFunction)(HeapObject* object);
+
+  // Performs a global garbage collection.
+  static void CollectGarbage(GCTracer* tracer);
+
+  // True if the last full GC performed heap compaction.
+  static bool HasCompacted() { return compacting_collection_; }
+
+  // True after the Prepare phase if the compaction is taking place.
+  static bool IsCompacting() { return compacting_collection_; }
+
+  // The count of the number of objects left marked at the end of the last
+  // completed full GC (expected to be zero).
+  static int previous_marked_count() { return previous_marked_count_; }
+
+  // During a full GC, there is a stack-allocated GCTracer that is used for
+  // bookkeeping information.  Return a pointer to that tracer.
+  static GCTracer* tracer() { return tracer_; }
+
+#ifdef DEBUG
+  // Checks whether performing mark-compact collection.
+  static bool in_use() { return state_ > PREPARE_GC; }
+#endif
+
+ private:
+#ifdef DEBUG
+  enum CollectorState {
+    IDLE,
+    PREPARE_GC,
+    MARK_LIVE_OBJECTS,
+    SWEEP_SPACES,
+    ENCODE_FORWARDING_ADDRESSES,
+    UPDATE_POINTERS,
+    RELOCATE_OBJECTS,
+    REBUILD_RSETS
+  };
+
+  // The current stage of the collector.
+  static CollectorState state_;
+#endif
+  // Global flag indicating whether spaces were compacted on the last GC.
+  static bool compacting_collection_;
+
+  // The number of objects left marked at the end of the last completed full
+  // GC (expected to be zero).
+  static int previous_marked_count_;
+
+  // A pointer to the current stack-allocated GC tracer object during a full
+  // collection (NULL before and after).
+  static GCTracer* tracer_;
+
+  // Prepares for GC by resetting relocation info in old and map spaces and
+  // choosing spaces to compact.
+  static void Prepare();
+
+  // Finishes GC, performs heap verification.
+  static void Finish();
+
+  // --------------------------------------------------------------------------
+  // Phase 1: functions related to marking phase.
+  //   before: Heap is in normal state, collector is 'IDLE'.
+  //
+  //           The first word of a page in old spaces has the end of
+  //           allocation address of the page.
+  //
+  //           The word at Chunk::high_ address has the address of the
+  //           first page in the next chunk. (The address is tagged to
+  //           distinguish it from end-of-allocation address).
+  //
+  //    after: live objects are marked.
+
+  friend class RootMarkingVisitor;
+  friend class MarkingVisitor;
+
+  // Marking operations for objects reachable from roots.
+  static void MarkLiveObjects();
+
+  static void MarkUnmarkedObject(HeapObject* obj);
+
+  static inline void MarkObject(HeapObject* obj) {
+     if (!obj->IsMarked()) MarkUnmarkedObject(obj);
+  }
+
+  // Mark the heap roots and all objects reachable from them.
+  static void ProcessRoots(RootMarkingVisitor* visitor);
+
+  // Mark objects in object groups that have at least one object in the
+  // group marked.
+  static void MarkObjectGroups();
+
+  // Mark all objects in an object group with at least one marked
+  // object, then all objects reachable from marked objects in object
+  // groups, and repeat.
+  static void ProcessObjectGroups(MarkingVisitor* visitor);
+
+  // Mark objects reachable (transitively) from objects in the marking stack
+  // or overflowed in the heap.
+  static void ProcessMarkingStack(MarkingVisitor* visitor);
+
+  // Mark objects reachable (transitively) from objects in the marking
+  // stack.  This function empties the marking stack, but may leave
+  // overflowed objects in the heap, in which case the marking stack's
+  // overflow flag will be set.
+  static void EmptyMarkingStack(MarkingVisitor* visitor);
+
+  // Refill the marking stack with overflowed objects from the heap.  This
+  // function either leaves the marking stack full or clears the overflow
+  // flag on the marking stack.
+  static void RefillMarkingStack();
+
+  // Callback function for telling whether the object *p must be marked.
+  static bool MustBeMarked(Object** p);
+
+#ifdef DEBUG
+  static void UpdateLiveObjectCount(HeapObject* obj);
+  static void VerifyHeapAfterMarkingPhase();
+#endif
+
+  // We sweep the large object space in the same way whether we are
+  // compacting or not, because the large object space is never compacted.
+  static void SweepLargeObjectSpace();
+
+  // --------------------------------------------------------------------------
+  // Phase 2: functions related to computing and encoding forwarding pointers
+  //   before: live objects' map pointers are marked as '00'
+  //    after: Map pointers of live old and map objects have encoded
+  //           forwarding pointers and map pointers
+  //
+  //           The 3rd word of a page has the page top offset after compaction.
+  //
+  //           The 4th word of a page in the map space has the map index
+  //           of this page in the map table. This word is not used in
+  //           the old space.
+  //
+  //           The 5th and 6th words of a page have the start and end
+  //           addresses of the first free region in the page.
+  //
+  //           The 7th word of a page in old spaces has the forwarding address
+  //           of the first live object in the page.
+  //
+  //           Live young objects have their forwarding pointers in
+  //           the from space at the same offset to the beginning of the space.
+
+  // Encodes forwarding addresses of objects in compactable parts of the
+  // heap.
+  static void EncodeForwardingAddresses();
+
+  // Encodes the forwarding addresses of objects in new space.
+  static void EncodeForwardingAddressesInNewSpace();
+
+  // Function template to encode the forwarding addresses of objects in
+  // paged spaces, parameterized by allocation and non-live processing
+  // functions.
+  template<AllocationFunction Alloc, ProcessNonLiveFunction ProcessNonLive>
+  static void EncodeForwardingAddressesInPagedSpace(PagedSpace* space);
+
+  // Iterates live objects in a space, passes live objects
+  // to a callback function which returns the heap size of the object.
+  // Returns the number of live objects iterated.
+  static int IterateLiveObjects(NewSpace* space, HeapObjectCallback size_f);
+  static int IterateLiveObjects(PagedSpace* space, HeapObjectCallback size_f);
+
+  // Iterates the live objects between a range of addresses, returning the
+  // number of live objects.
+  static int IterateLiveObjectsInRange(Address start, Address end,
+                                       HeapObjectCallback size_func);
+
+  // Callback functions for deallocating non-live blocks in the old
+  // generation.
+  static void DeallocateOldPointerBlock(Address start, int size_in_bytes);
+  static void DeallocateOldDataBlock(Address start, int size_in_bytes);
+  static void DeallocateCodeBlock(Address start, int size_in_bytes);
+  static void DeallocateMapBlock(Address start, int size_in_bytes);
+
+  // Phase 2: If we are not compacting the heap, we simply sweep the spaces
+  // except for the large object space, clearing mark bits and adding
+  // unmarked regions to each space's free list.
+  static void SweepSpaces();
+
+#ifdef DEBUG
+  static void VerifyHeapAfterEncodingForwardingAddresses();
+#endif
+
+  // --------------------------------------------------------------------------
+  // Phase 3: function related to updating pointers and decode map pointers
+  //   before: see after phase 2
+  //    after: all pointers are updated to forwarding addresses.
+
+  friend class UpdatingVisitor;  // helper for updating visited objects
+
+  // Updates pointers in all spaces.
+  static void UpdatePointers();
+
+  // Updates pointers in an object in new space.
+  // Returns the heap size of the object.
+  static int UpdatePointersInNewObject(HeapObject* obj);
+
+  // Updates pointers in an object in old spaces.
+  // Returns the heap size of the object.
+  static int UpdatePointersInOldObject(HeapObject* obj);
+
+  // Calculates the forwarding address of an object in an old space.
+  static Address GetForwardingAddressInOldSpace(HeapObject* obj);
+
+#ifdef DEBUG
+  static void VerifyHeapAfterUpdatingPointers();
+#endif
+
+  // --------------------------------------------------------------------------
+  // Phase 4: functions related to relocating objects
+  //     before: see after phase 3
+  //      after: heap is in a normal state, except remembered set is not built
+
+  // Relocates objects in all spaces.
+  static void RelocateObjects();
+
+  // Converts a code object's inline target to addresses, convention from
+  // address to target happens in the marking phase.
+  static int ConvertCodeICTargetToAddress(HeapObject* obj);
+
+  // Relocate a map object.
+  static int RelocateMapObject(HeapObject* obj);
+
+  // Relocates an old object.
+  static int RelocateOldPointerObject(HeapObject* obj);
+  static int RelocateOldDataObject(HeapObject* obj);
+
+  // Helper function.
+  static inline int RelocateOldNonCodeObject(HeapObject* obj, OldSpace* space);
+
+  // Relocates an object in the code space.
+  static int RelocateCodeObject(HeapObject* obj);
+
+  // Copy a new object.
+  static int RelocateNewObject(HeapObject* obj);
+
+#ifdef DEBUG
+  static void VerifyHeapAfterRelocatingObjects();
+#endif
+
+  // ---------------------------------------------------------------------------
+  // Phase 5: functions related to rebuilding remembered sets
+
+  // Rebuild remembered set in old and map spaces.
+  static void RebuildRSets();
+
+#ifdef DEBUG
+  // ---------------------------------------------------------------------------
+  // Debugging variables, functions and classes
+  // Counters used for debugging the marking phase of mark-compact or
+  // mark-sweep collection.
+
+  // Number of live objects in Heap::to_space_.
+  static int live_young_objects_;
+
+  // Number of live objects in Heap::old_pointer_space_.
+  static int live_old_pointer_objects_;
+
+  // Number of live objects in Heap::old_data_space_.
+  static int live_old_data_objects_;
+
+  // Number of live objects in Heap::code_space_.
+  static int live_code_objects_;
+
+  // Number of live objects in Heap::map_space_.
+  static int live_map_objects_;
+
+  // Number of live objects in Heap::lo_space_.
+  static int live_lo_objects_;
+
+  // Number of live bytes in this collection.
+  static int live_bytes_;
+
+  static void VerifyPageHeaders(PagedSpace* space);
+
+  // Verification functions when relocating objects.
+  friend class VerifyCopyingVisitor;
+  static void VerifyCopyingObjects(Object** p);
+
+  friend class MarkObjectVisitor;
+  static void VisitObject(HeapObject* obj);
+
+  friend class UnmarkObjectVisitor;
+  static void UnmarkObject(HeapObject* obj);
+#endif
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_MARK_COMPACT_H_
diff --git a/regexp2000/src/math.js b/regexp2000/src/math.js
new file mode 100644 (file)
index 0000000..5b7c396
--- /dev/null
@@ -0,0 +1,190 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Keep reference to original values of some global properties.  This
+// has the added benefit that the code in this file is isolated from
+// changes to these properties.
+const $Infinity = global.Infinity;
+const $floor = MathFloor;
+const $random = MathRandom;
+const $abs = MathAbs;
+
+// Instance class name can only be set on functions. That is the only
+// purpose for MathConstructor.
+function MathConstructor() {}
+%FunctionSetInstanceClassName(MathConstructor, 'Math');
+const $Math = new MathConstructor();
+$Math.__proto__ = global.Object.prototype;
+%SetProperty(global, "Math", $Math, DONT_ENUM);
+
+// ECMA 262 - 15.8.2.1
+function MathAbs(x) {
+  if (%_IsSmi(x)) {
+    return x >= 0 ? x : -x;
+  } else {
+    return %Math_abs(ToNumber(x));
+  }
+}
+
+// ECMA 262 - 15.8.2.2
+function MathAcos(x) { return %Math_acos(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.3
+function MathAsin(x) { return %Math_asin(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.4
+function MathAtan(x) { return %Math_atan(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.5
+function MathAtan2(x, y) { return %Math_atan2(ToNumber(x), ToNumber(y)); }
+
+// ECMA 262 - 15.8.2.6
+function MathCeil(x) { return %Math_ceil(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.7
+function MathCos(x) { return %Math_cos(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.8
+function MathExp(x) { return %Math_exp(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.9
+function MathFloor(x) { return %Math_floor(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.10
+function MathLog(x) { return %Math_log(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.11
+function MathMax(arg1, arg2) {  // length == 2
+  var r = -$Infinity;
+  for (var i = %_ArgumentsLength() - 1; i >= 0; --i) {
+    var n = ToNumber(%_Arguments(i));
+    if (NUMBER_IS_NAN(n)) return n;
+    // Make sure +0 is consider greater than -0.
+    if (n > r || (n === 0 && r === 0 && (1 / n) > (1 / r))) r = n;
+  }
+  return r;
+}
+
+// ECMA 262 - 15.8.2.12
+function MathMin(arg1, arg2) {  // length == 2
+  var r = $Infinity;
+  for (var i = %_ArgumentsLength() - 1; i >= 0; --i) {
+    var n = ToNumber(%_Arguments(i));
+    if (NUMBER_IS_NAN(n)) return n;
+    // Make sure -0 is consider less than +0.
+    if (n < r || (n === 0 && r === 0 && (1 / n) < (1 / r))) r = n;
+  }
+  return r;
+}
+
+// ECMA 262 - 15.8.2.13
+function MathPow(x, y) { return %Math_pow(ToNumber(x), ToNumber(y)); }
+
+// ECMA 262 - 15.8.2.14
+function MathRandom() { return %Math_random(); }
+
+// ECMA 262 - 15.8.2.15
+function MathRound(x) { return %Math_round(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.16
+function MathSin(x) { return %Math_sin(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.17
+function MathSqrt(x) { return %Math_sqrt(ToNumber(x)); }
+
+// ECMA 262 - 15.8.2.18
+function MathTan(x) { return %Math_tan(ToNumber(x)); }
+
+
+// -------------------------------------------------------------------
+
+function SetupMath() {
+  // Setup math constants.
+  // ECMA-262, section 15.8.1.1.
+  %SetProperty($Math,
+               "E",
+               2.7182818284590452354,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+  // ECMA-262, section 15.8.1.2.
+  %SetProperty($Math,
+               "LN10",
+               2.302585092994046,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+  // ECMA-262, section 15.8.1.3.
+  %SetProperty($Math,
+               "LN2",
+               0.6931471805599453,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+  // ECMA-262, section 15.8.1.4.
+  %SetProperty($Math,
+               "LOG2E",
+               1.4426950408889634,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+  %SetProperty($Math,
+               "LOG10E",
+               0.43429448190325176,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+  %SetProperty($Math,
+               "PI",
+               3.1415926535897932,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+  %SetProperty($Math,
+               "SQRT1_2",
+               0.7071067811865476,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+  %SetProperty($Math,
+               "SQRT2",
+               1.4142135623730951,
+               DONT_ENUM |  DONT_DELETE | READ_ONLY);
+
+  // Setup non-enumerable functions of the Math object and
+  // set their names.
+  InstallFunctions($Math, DONT_ENUM, $Array(
+    "random", MathRandom,
+    "abs", MathAbs,
+    "acos", MathAcos,
+    "asin", MathAsin,
+    "atan", MathAtan,
+    "ceil", MathCeil,
+    "cos", MathCos,
+    "exp", MathExp,
+    "floor", MathFloor,
+    "log", MathLog,
+    "round", MathRound,
+    "sin", MathSin,
+    "sqrt", MathSqrt,
+    "tan", MathTan,
+    "atan2", MathAtan2,
+    "pow", MathPow,
+    "max", MathMax,
+    "min", MathMin
+  ));
+};
+
+
+SetupMath();
diff --git a/regexp2000/src/memory.h b/regexp2000/src/memory.h
new file mode 100644 (file)
index 0000000..2397bc6
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_MEMORY_H_
+#define V8_MEMORY_H_
+
+namespace v8 { namespace internal {
+
+// Memory provides an interface to 'raw' memory. It encapsulates the casts
+// that typically are needed when incompatible pointer types are used.
+
+class Memory {
+ public:
+  static uint32_t& uint32_at(Address addr)  {
+    return *reinterpret_cast<uint32_t*>(addr);
+  }
+
+  static int32_t& int32_at(Address addr)  {
+    return *reinterpret_cast<int32_t*>(addr);
+  }
+
+  static int& int_at(Address addr)  {
+    return *reinterpret_cast<int*>(addr);
+  }
+
+  static Address& Address_at(Address addr)  {
+    return *reinterpret_cast<Address*>(addr);
+  }
+
+  static Object*& Object_at(Address addr)  {
+    return *reinterpret_cast<Object**>(addr);
+  }
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_MEMORY_H_
diff --git a/regexp2000/src/messages.cc b/regexp2000/src/messages.cc
new file mode 100644 (file)
index 0000000..7edb07f
--- /dev/null
@@ -0,0 +1,179 @@
+
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "execution.h"
+#include "spaces-inl.h"
+#include "top.h"
+
+namespace v8 { namespace internal {
+
+
+// If no message listeners have been registered this one is called
+// by default.
+void MessageHandler::DefaultMessageReport(const MessageLocation* loc,
+                                          Handle<Object> message_obj) {
+  SmartPointer<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;
+    if (data->IsString())
+      data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
+    PrintF("%s:%i: %s\n", *data_str ? *data_str : "<unknown>",
+           loc->start_pos(), *str);
+  }
+}
+
+
+void MessageHandler::ReportMessage(const char* msg) {
+  PrintF("%s\n", msg);
+}
+
+
+Handle<Object> MessageHandler::MakeMessageObject(
+    const char* type,
+    MessageLocation* loc,
+    Vector< Handle<Object> > args,
+    Handle<String> stack_trace) {
+  // Build error message object
+  HandleScope scope;
+  Handle<Object> type_str = Factory::LookupAsciiSymbol(type);
+  Handle<Object> array = Factory::NewJSArray(args.length());
+  for (int i = 0; i < args.length(); i++)
+    SetElement(Handle<JSArray>::cast(array), i, args[i]);
+
+  Handle<JSFunction> fun(Top::global_context()->make_message_fun());
+  int start, end;
+  Handle<Object> script;
+  if (loc) {
+    start = loc->start_pos();
+    end = loc->end_pos();
+    script = GetScriptWrapper(loc->script());
+  } else {
+    start = end = 0;
+    script = Factory::undefined_value();
+  }
+  Handle<Object> start_handle(Smi::FromInt(start));
+  Handle<Object> end_handle(Smi::FromInt(end));
+  Handle<Object> stack_trace_val = stack_trace.is_null()
+    ? Factory::undefined_value()
+    : Handle<Object>::cast(stack_trace);
+  const int argc = 6;
+  Object** argv[argc] = { type_str.location(),
+                          array.location(),
+                          start_handle.location(),
+                          end_handle.location(),
+                          script.location(),
+                          stack_trace_val.location() };
+
+  // Setup a catch handler to catch exceptions in creating the message. This
+  // handler is non-verbose to avoid calling MakeMessage recursively in case of
+  // an exception.
+  v8::TryCatch catcher;
+  catcher.SetVerbose(false);
+  catcher.SetCaptureMessage(false);
+
+  // Format the message.
+  bool caught_exception = false;
+  Handle<Object> message =
+      Execution::Call(fun, Factory::undefined_value(), argc, argv,
+                      &caught_exception);
+  if (caught_exception) {
+    // If creating the message (in JS code) resulted in an exception, we
+    // skip doing the callback. This usually only happens in case of
+    // stack overflow exceptions being thrown by the parser when the
+    // stack is almost full.
+    if (caught_exception) return Handle<Object>();
+  }
+
+  return message.EscapeFrom(&scope);
+}
+
+
+void MessageHandler::ReportMessage(MessageLocation* loc,
+                                   Handle<Object> message) {
+  v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
+
+  v8::NeanderArray global_listeners(Factory::message_listeners());
+  int global_length = global_listeners.length();
+  if (global_length == 0) {
+    DefaultMessageReport(loc, message);
+  } else {
+    for (int i = 0; i < global_length; i++) {
+      HandleScope scope;
+      if (global_listeners.get(i)->IsUndefined()) continue;
+      v8::NeanderObject listener(JSObject::cast(global_listeners.get(i)));
+      Handle<Proxy> callback_obj(Proxy::cast(listener.get(0)));
+      v8::MessageCallback callback =
+          FUNCTION_CAST<v8::MessageCallback>(callback_obj->proxy());
+      Handle<Object> callback_data(listener.get(1));
+      callback(api_message_obj, v8::Utils::ToLocal(callback_data));
+    }
+  }
+}
+
+
+Handle<String> MessageHandler::GetMessage(Handle<Object> data) {
+  Handle<String> fmt_str = Factory::LookupAsciiSymbol("FormatMessage");
+  Handle<JSFunction> fun =
+      Handle<JSFunction>(
+          JSFunction::cast(
+              Top::builtins()->GetProperty(*fmt_str)));
+  Object** argv[1] = { data.location() };
+
+  bool caught_exception;
+  Handle<Object> result =
+      Execution::TryCall(fun, Top::builtins(), 1, argv,
+                         &caught_exception);
+
+  if (caught_exception || !result->IsString()) {
+    return Factory::LookupAsciiSymbol("<error>");
+  }
+  Handle<String> result_string = Handle<String>::cast(result);
+  // A string that has been obtained from JS code in this way is
+  // likely to be a complicated ConsString of some sort.  We flatten it
+  // here to improve the efficiency of converting it to a C string and
+  // other operations that are likely to take place (see GetLocalizedMessage
+  // for example).
+  FlattenString(result_string);
+  return result_string;
+}
+
+
+SmartPointer<char> MessageHandler::GetLocalizedMessage(Handle<Object> data) {
+  HandleScope scope;
+  return GetMessage(data)->ToCString(DISALLOW_NULLS);
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/messages.h b/regexp2000/src/messages.h
new file mode 100644 (file)
index 0000000..1ff10aa
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The infrastructure used for (localized) message reporting in V8.
+//
+// Note: there's a big unresolved issue about ownership of the data
+// structures used by this framework.
+
+#ifndef V8_MESSAGES_H_
+#define V8_MESSAGES_H_
+
+#include "handles-inl.h"
+
+// Forward declaration of MessageLocation.
+namespace v8 { namespace internal {
+class MessageLocation;
+} }  // namespace v8::internal
+
+
+class V8Message {
+ public:
+  V8Message(char* type,
+            v8::internal::Handle<v8::internal::JSArray> args,
+            const v8::internal::MessageLocation* loc) :
+      type_(type), args_(args), loc_(loc) { }
+  char* type() const { return type_; }
+  v8::internal::Handle<v8::internal::JSArray> args() const { return args_; }
+  const v8::internal::MessageLocation* loc() const { return loc_; }
+ private:
+  char* type_;
+  v8::internal::Handle<v8::internal::JSArray> const args_;
+  const v8::internal::MessageLocation* loc_;
+};
+
+
+namespace v8 { namespace internal {
+
+struct Language;
+class SourceInfo;
+
+class MessageLocation {
+ public:
+  MessageLocation(Handle<Script> script,
+                  int start_pos,
+                  int end_pos)
+      : script_(script),
+        start_pos_(start_pos),
+        end_pos_(end_pos) { }
+  MessageLocation() : start_pos_(-1), end_pos_(-1) { }
+
+  Handle<Script> script() const { return script_; }
+  int start_pos() const { return start_pos_; }
+  int end_pos() const { return end_pos_; }
+
+ private:
+  Handle<Script> script_;
+  int start_pos_;
+  int end_pos_;
+};
+
+
+// A message handler is a convenience interface for accessing the list
+// of message listeners registered in an environment
+class MessageHandler {
+ public:
+  // Report a message (w/o JS heap allocation).
+  static void ReportMessage(const char* msg);
+
+  // Returns a message object for the API to use.
+  static Handle<Object> MakeMessageObject(const char* type,
+                                          MessageLocation* loc,
+                                          Vector< Handle<Object> > args,
+                                          Handle<String> stack_trace);
+
+  // Report a formatted message (needs JS allocation).
+  static void ReportMessage(MessageLocation* loc, Handle<Object> message);
+
+  static void DefaultMessageReport(const MessageLocation* loc,
+                                   Handle<Object> message_obj);
+  static Handle<String> GetMessage(Handle<Object> data);
+  static SmartPointer<char> GetLocalizedMessage(Handle<Object> data);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_MESSAGES_H_
diff --git a/regexp2000/src/messages.js b/regexp2000/src/messages.js
new file mode 100644 (file)
index 0000000..531c710
--- /dev/null
@@ -0,0 +1,678 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// -------------------------------------------------------------------
+
+const kVowelSounds = {a: true, e: true, i: true, o: true, u: true, y: true};
+const kCapitalVowelSounds = {a: true, e: true, i: true, o: true, u: true,
+    h: true, f: true, l: true, m: true, n: true, r: true, s: true, x: true,
+    y: true};
+
+function GetInstanceName(cons) {
+  if (cons.length == 0) {
+    return "";
+  }
+  var first = cons.charAt(0).toLowerCase();
+  var mapping = kVowelSounds;
+  if (cons.length > 1 && (cons.charAt(0) != first)) {
+    // First char is upper case
+    var second = cons.charAt(1).toLowerCase();
+    // Second char is upper case
+    if (cons.charAt(1) != second)
+      mapping = kCapitalVowelSounds;
+  }
+  var s = mapping[first] ? "an " : "a ";
+  return s + cons;
+}
+
+
+const kMessages = {
+  // Error
+  cyclic_proto:                 "Cyclic __proto__ value",
+  // TypeError
+  unexpected_token:             "Unexpected token %0",
+  unexpected_token_number:      "Unexpected number",
+  unexpected_token_string:      "Unexpected string",
+  unexpected_token_identifier:  "Unexpected identifier",
+  unexpected_eos:               "Unexpected end of input",
+  expected_label:               "Expected label",
+  malformed_regexp:             "Invalid regular expression: /%0/: %1",
+  unterminated_regexp:          "Invalid regular expression: missing /",
+  pcre_error:                   "PCRE function %0, error code %1",
+  regexp_flags:                 "Cannot supply flags when constructing one RegExp from another",
+  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'",
+  invalid_break:                "Invalid break statement",
+  invalid_continue:             "Invalid continue statement",
+  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",
+  null_or_undefined:            "Cannot access property of null or undefined",
+  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",
+  illegal_eval:                 "Unsupported indirect eval() call",
+  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",
+  // RangeError
+  invalid_array_length:         "Invalid array length",
+  invalid_array_apply_length:   "Function.prototype.apply supports only up to 1024 arguments",
+  stack_overflow:               "Maximum call stack size exceeded",
+  apply_overflow:               "Function.prototype.apply cannot support %0 arguments", 
+  // SyntaxError
+  unable_to_parse:              "Parse error",
+  duplicate_regexp_flag:        "Duplicate RegExp flag %0",
+  unrecognized_regexp_flag:     "Unrecognized RegExp flag %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 %0",
+};
+
+
+function FormatString(format, args) {
+  var result = format;
+  for (var i = 0; i < args.length; i++) {
+    var str;
+    try { str = ToDetailString(args[i]); }
+    catch (e) { str = "#<error>"; }
+    result = result.split("%" + i).join(str);
+  }
+  return result;
+}
+
+
+function ToDetailString(obj) {
+  if (obj != null && IS_OBJECT(obj) && obj.toString === $Object.prototype.toString) {
+    var constructor = obj.constructor;
+    if (!constructor) return ToString(obj);
+    var constructorName = constructor.name;
+    if (!constructorName) return ToString(obj);
+    return "#<" + GetInstanceName(constructorName) + ">";
+  } else {
+    return ToString(obj);
+  }
+}
+
+
+function MakeGenericError(constructor, type, args) {
+  if (args instanceof $Array) {
+    for (var i = 0; i < args.length; i++) {
+      var elem = args[i];
+      if (elem instanceof $Array && elem.length > 100) { // arbitrary limit, grab a reasonable slice to report
+        args[i] = elem.slice(0,20).concat("...");
+      }
+    }
+  } else if (IS_UNDEFINED(args)) {
+    args = [];
+  }
+
+  var e = new constructor();
+  e.type = type;
+  e.arguments = args;
+  return e;
+}
+
+
+/**
+ * Setup the Script function and constructor.
+ */
+%FunctionSetInstanceClassName(Script, 'Script');
+%SetProperty(Script.prototype, 'constructor', Script, DONT_ENUM);
+%SetCode(Script, function(x) {
+  // Script objects can only be created by the VM.
+  throw new $Error("Not supported");
+});
+
+
+// Helper functions; called from the runtime system.
+function FormatMessage(message) {
+  var format = kMessages[message.type];
+  if (!format) return "<unknown message " + message.type + ">";
+  return FormatString(format, message.args);
+}
+
+
+function GetLineNumber(message) {
+  if (message.startPos == -1) return -1;
+  var location = message.script.locationFromPosition(message.startPos);
+  if (location == null) return -1;
+  return location.line + 1;
+}
+
+
+// Returns the source code line containing the given source
+// position, or the empty string if the position is invalid.
+function GetSourceLine(message) {
+  var location = message.script.locationFromPosition(message.startPos);
+  if (location == null) return "";
+  location.restrict();
+  return location.sourceText();
+}
+
+
+function MakeTypeError(type, args) {
+  return MakeGenericError($TypeError, type, args);
+}
+
+
+function MakeRangeError(type, args) {
+  return MakeGenericError($RangeError, type, args);
+}
+
+
+function MakeSyntaxError(type, args) {
+  return MakeGenericError($SyntaxError, type, args);
+}
+
+
+function MakeReferenceError(type, args) {
+  return MakeGenericError($ReferenceError, type, args);
+}
+
+
+function MakeEvalError(type, args) {
+  return MakeGenericError($EvalError, type, args);
+}
+
+
+function MakeError(type, args) {
+  return MakeGenericError($Error, type, args);
+}
+
+
+/**
+ * Initialize the cached source information in a script. Currently all line
+ * end positions are cached.
+ */
+Script.prototype.initSourceInfo_ = function () {
+  // Just return if initialized.
+  if (this.lineEnds_) return;
+
+  // Collect all line endings.
+  this.lineEnds_ = [];
+  for (var i = 0; i < this.source.length; i++) {
+    var current = this.source.charAt(i);
+    if (current == '\n') {
+      this.lineEnds_.push(i);
+    }
+  }
+
+  // If the script does not end with a line ending add the final end position
+  // as just past the last line ending.
+  if (this.lineEnds_[this.lineEnds_.length - 1] != this.source.length - 1) {
+    this.lineEnds_.push(this.source.length);
+  }
+};
+
+
+/**
+ * Get information on a specific source position.
+ * @param {number} position The source position
+ * @return {SourceLocation}
+ *     If line is negative or not in the source null is returned.
+ */
+Script.prototype.locationFromPosition = function (position) {
+  // Make sure source info has been initialized.
+  this.initSourceInfo_();
+
+  var lineCount = this.lineCount();
+  var line = -1;
+  if (position <= this.lineEnds_[0]) {
+    line = 0;
+  } else {
+    for (var i = 1; i < lineCount; i++) {
+      if (this.lineEnds_[i - 1] < position && position <= this.lineEnds_[i]) {
+        line = i;
+        break;
+      }
+    }
+  }
+
+  if (line == -1) return null;
+
+  // Determine start, end and column.
+  var start = line == 0 ? 0 : this.lineEnds_[line - 1] + 1;
+  var end = this.lineEnds_[line];
+  if (end > 0 && this.source.charAt(end - 1) == '\r') end--;
+  var column = position - start;
+
+  // Adjust according to the offset within the resource.
+  line += this.line_offset;
+  if (line == this.line_offset) {
+    column += this.column_offset;
+  }
+
+  return new SourceLocation(this, position, line, column, start, end);
+};
+
+
+/**
+ * Get information on a specific source line and column possibly offset by a
+ * fixed source position. This function is used to find a source position from
+ * a line and column position. The fixed source position offset is typically
+ * used to find a source position in a function based on a line and column in
+ * the source for the function alone. The offset passed will then be the
+ * start position of the source for the function within the full script source.
+ * @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
+ * @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) {
+  // Make soure source info has been initialized.
+  this.initSourceInfo_();
+
+  // Default is the first line in the script. Lines in the script is relative
+  // to the offset within the resource.
+  var line = 0;
+  if (!IS_UNDEFINED(opt_line)) {
+    line = opt_line - this.line_offset;
+  }
+
+  // Default is first column. If on the first line add the offset within the
+  // resource.
+  var column = opt_column || 0;
+  if (line == 0) {
+    column -= this.column_offset
+  }
+
+  var offset_position = opt_offset_position || 0;
+  if (line < 0 || column < 0 || offset_position < 0) return null;
+  if (line == 0) {
+    return this.locationFromPosition(offset_position + column);
+  } else {
+    // Find the line where the offset position is located
+    var lineCount = this.lineCount();
+    var offset_line;
+    for (var i = 0; i < lineCount; i++) {
+      if (offset_position <= this.lineEnds_[i]) {
+        offset_line = i;
+        break;
+      }
+    }
+    if (offset_line + line >= lineCount) return null;
+    return this.locationFromPosition(this.lineEnds_[offset_line + line - 1] + 1 + column);  // line > 0 here.
+  }
+}
+
+
+/**
+ * Get a slice of source code from the script. The boundaries for the slice is
+ * specified in lines.
+ * @param {number} opt_from_line The first line (zero bound) in the slice.
+ *     Default is 0
+ * @param {number} opt_to_column The last line (zero bound) in the slice (non
+ *     inclusive). Default is the number of lines in the script
+ * @return {SourceSlice} The source slice or null of the parameters where
+ *     invalid
+ */
+Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
+  // Make soure source info has been initialized.
+  this.initSourceInfo_();
+
+  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
+
+  // Adjust according to the offset within the resource.
+  from_line -= this.line_offset;
+  to_line -= this.line_offset;
+  if (from_line < 0) from_line = 0;
+  if (to_line > this.lineCount()) to_line = this.lineCount();
+
+  // Check parameters.  
+  if (from_line >= this.lineCount() ||
+      to_line < 0 ||
+      from_line > to_line) {
+    return null;
+  }
+
+  var from_position = from_line == 0 ? 0 : this.lineEnds_[from_line - 1] + 1;
+  var to_position = to_line == 0 ? 0 : this.lineEnds_[to_line - 1] + 1;
+
+  // Return a source slice with line numbers re-adjusted to the resource.
+  return new SourceSlice(this, from_line + this.line_offset, to_line + this.line_offset,
+                         from_position, to_position);
+}
+
+
+Script.prototype.sourceLine = function (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;
+  if (!IS_UNDEFINED(opt_line)) {
+    line = opt_line - this.line_offset;
+  }
+  
+  // Check parameter.  
+  if (line < 0 || this.lineCount() <= line) {
+    return null;
+  }
+
+  // Return the source line.  
+  var start = line == 0 ? 0 : this.lineEnds_[line - 1] + 1;
+  var end = this.lineEnds_[line];
+  return this.source.substring(start, end);
+}
+
+
+/**
+ * Returns the number of source lines.
+ * @return {number}
+ *     Number of source lines.
+ */
+Script.prototype.lineCount = function() {
+  // Make soure source info has been initialized.
+  this.initSourceInfo_();
+
+  // Return number of source lines.  
+  return this.lineEnds_.length;
+};
+
+
+/**
+ * Class for source location. A source location is a position within some
+ * source with the following properties:
+ *   script   : script object for the source
+ *   line     : source line number
+ *   column   : source column within the line
+ *   position : position within the source
+ *   start    : position of start of source context (inclusive)
+ *   end      : position of end of source context (not inclusive)
+ * Source text for the source context is the character interval [start, end[. In
+ * most cases end will point to a newline character. It might point just past
+ * the final position of the source if the last source line does not end with a
+ * newline character. 
+ * @param {Script} script The Script object for which this is a location
+ * @param {number} position Source position for the location
+ * @param {number} line The line number for the location
+ * @param {number} column The column within the line for the location
+ * @param {number} start Source position for start of source context
+ * @param {number} end Source position for end of source context
+ * @constructor
+ */
+function SourceLocation(script, position, line, column, start, end) {
+  this.script = script;
+  this.position = position;
+  this.line = line;
+  this.column = column;
+  this.start = start;
+  this.end = end;
+}
+
+
+const kLineLengthLimit = 78;
+
+/**
+ * Restrict source location start and end positions to make the source slice
+ * no more that a certain number of characters wide.
+ * @param {number} opt_limit The with limit of the source text with a default
+ *     of 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) {
+  // Find the actual limit to use.
+  var limit;
+  var before;
+  if (!IS_UNDEFINED(opt_limit)) {
+    limit = opt_limit;
+  } else {
+    limit = kLineLengthLimit;
+  }
+  if (!IS_UNDEFINED(opt_before)) {
+    before = opt_before;
+  } else {
+    // If no before is specified center for small limits and perfer more source
+    // before the the position that after for longer limits.
+    if (limit <= 20) {
+      before = $floor(limit / 2);
+    } else {
+      before = limit - 10;
+    }
+  }
+  if (before >= limit) {
+    before = limit - 1;
+  }
+
+  // If the [start, end[ interval is too big we restrict
+  // it in one or both ends. We make sure to always produce
+  // restricted intervals of maximum allowed size.
+  if (this.end - this.start > limit) {
+    var start_limit = this.position - before;
+    var end_limit = this.position + limit - before;
+    if (this.start < start_limit && end_limit < this.end) {
+      this.start = start_limit;
+      this.end = end_limit;
+    } else if (this.start < start_limit) {
+      this.start = this.end - limit;
+    } else {
+      this.end = this.start + limit;
+    }
+  }
+};
+
+
+/**
+ * Get the source text for a SourceLocation
+ * @return {String}
+ *     Source text for this location.
+ */
+SourceLocation.prototype.sourceText = function () {
+  return this.script.source.substring(this.start, this.end);
+};
+
+
+/**
+ * Class for a source slice. A source slice is a part of a script source with
+ * the following properties:
+ *   script        : script object for the source
+ *   from_line     : line number for the first line in the slice
+ *   to_line       : source line number for the last line in the slice
+ *   from_position : position of the first character in the slice
+ *   to_position   : position of the last character in the slice
+ * The to_line and to_position are not included in the slice, that is the lines
+ * in the slice are [from_line, to_line[. Likewise the characters in the slice
+ * are [from_position, to_position[.
+ * @param {Script} script The Script object for the source slice
+ * @param {number} from_line
+ * @param {number} to_line
+ * @param {number} from_position
+ * @param {number} to_position
+ * @constructor
+ */
+function SourceSlice(script, from_line, to_line, from_position, to_position) {
+  this.script = script;
+  this.from_line = from_line;
+  this.to_line = to_line;
+  this.from_position = from_position;
+  this.to_position = to_position;
+}
+
+
+/**
+ * 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 () {
+  return this.script.source.substring(this.from_position, this.to_position);
+};
+
+
+// Returns the offset of the given position within the containing
+// line.
+function GetPositionInLine(message) {
+  var location = message.script.locationFromPosition(message.startPos);
+  if (location == null) return -1;
+  location.restrict();
+  return message.startPos - location.start;
+}
+
+
+function ErrorMessage(type, args, startPos, endPos, script, stackTrace) {
+  this.startPos = startPos;
+  this.endPos = endPos;
+  this.type = type;
+  this.args = args;
+  this.script = script;
+  this.stackTrace = stackTrace;
+}
+
+
+function MakeMessage(type, args, startPos, endPos, script, stackTrace) {
+  return new ErrorMessage(type, args, startPos, endPos, script, stackTrace);
+}
+
+
+function GetStackTraceLine(recv, fun, pos, isGlobal) {
+  try {
+    return UnsafeGetStackTraceLine(recv, fun, pos, isGlobal);
+  } catch (e) {
+    return "<error: " + e + ">";
+  }
+}
+
+
+function GetFunctionName(fun, recv) {
+  var name = %FunctionGetName(fun);
+  if (name) return name;
+  for (var prop in recv) {
+    if (recv[prop] === fun)
+      return prop;
+  }
+  return "[anonymous]";
+}
+
+
+function UnsafeGetStackTraceLine(recv, fun, pos, isTopLevel) {
+  var result = "";
+  // The global frame has no meaningful function or receiver
+  if (!isTopLevel) {
+    // If the receiver is not the global object then prefix the
+    // message send
+    if (recv !== global)
+      result += ToDetailString(recv) + ".";
+    result += GetFunctionName(fun, recv);
+  }
+  if (pos != -1) {
+    var script = %FunctionGetScript(fun);
+    var file;
+    if (script) {
+      file = %FunctionGetScript(fun).data;
+    }
+    if (file) {
+      var location = %FunctionGetScript(fun).locationFromPosition(pos);
+      if (!isTopLevel) result += "(";
+      result += file;
+      if (location != null) {
+        result += ":" + (location.line + 1) + ":" + (location.column + 1);
+      }
+      if (!isTopLevel) result += ")";
+    }
+  }
+  return (result) ? "    at " + result : result;
+}
+
+
+// ----------------------------------------------------------------------------
+// Error implementation
+
+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.
+  // prototype of 'Error' must be as default: new Object().
+  if (name != 'Error') %FunctionSetPrototype(f, new $Error());
+  %FunctionSetInstanceClassName(f, 'Error');
+  %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
+  f.prototype.name = name;
+  %SetCode(f, function(m) {
+    if (%IsConstructCall()) {
+      if (!IS_UNDEFINED(m)) this.message = ToString(m);
+    } else {
+      return new f(m);
+    }
+  });
+}
+
+$Math.__proto__ = global.Object.prototype;
+
+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.
+$Error.prototype.message = '';
+
+%SetProperty($Error.prototype, 'toString', function toString() {
+  var type = this.type;
+  if (type && !this.hasOwnProperty("message")) {
+    return this.name + ": " + FormatMessage({ type: type, args: this.arguments });
+  }
+  var message = this.message;
+  return this.name + (message ? (": " + message) : "");
+}, DONT_ENUM);
+
+
+// Boilerplate for exceptions for stack overflows. Used from
+// Top::StackOverflow().
+const kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);
diff --git a/regexp2000/src/mirror-delay.js b/regexp2000/src/mirror-delay.js
new file mode 100644 (file)
index 0000000..caf963e
--- /dev/null
@@ -0,0 +1,1924 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Touch the RegExp and Date functions to make sure that date-delay.js and
+// regexp-delay.js has been loaded. This is required as the mirrors use
+// functions within these files through the builtins object. See the
+// function DateToISO8601_ as an example.
+RegExp;
+Date;
+
+
+function MakeMirror(value) {
+  if (IS_UNDEFINED(value)) return new UndefinedMirror();
+  if (IS_NULL(value)) return new NullMirror();
+  if (IS_BOOLEAN(value)) return new BooleanMirror(value);
+  if (IS_NUMBER(value)) return new NumberMirror(value);
+  if (IS_STRING(value)) return new StringMirror(value);
+  if (IS_ARRAY(value)) return new ArrayMirror(value);
+  if (IS_DATE(value)) return new DateMirror(value);
+  if (IS_FUNCTION(value)) return new FunctionMirror(value);
+  if (IS_REGEXP(value)) return new RegExpMirror(value);
+  if (IS_ERROR(value)) return new ErrorMirror(value);
+  return new ObjectMirror(value);
+}
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * The Function.prototype.inherits from lang.js rewritten as a standalone
+ * function (not on Function.prototype). NOTE: If this file is to be loaded
+ * during bootstrapping this function needs to be revritten using some native
+ * functions as prototype setup using normal JavaScript does not work as
+ * expected during bootstrapping (see mirror.js in r114903).
+ *
+ * @param {function} ctor Constructor function which needs to inherit the
+ *     prototype
+ * @param {function} superCtor Constructor function to inherit prototype from
+ */
+function inherits(ctor, superCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = superCtor.prototype;
+  ctor.super_ = superCtor.prototype;
+  ctor.prototype = new tempCtor();
+  ctor.prototype.constructor = ctor;
+}
+
+
+// Type names of the different mirrors.
+const UNDEFINED_TYPE = 'undefined';
+const NULL_TYPE = 'null';
+const BOOLEAN_TYPE = 'boolean';
+const NUMBER_TYPE = 'number';
+const STRING_TYPE = 'string';
+const OBJECT_TYPE = 'object';
+const FUNCTION_TYPE = 'function';
+const REGEXP_TYPE = 'regexp';
+const ERROR_TYPE = 'error';
+const PROPERTY_TYPE = 'property';
+const ACCESSOR_TYPE = 'accessor';
+const FRAME_TYPE = 'frame';
+const SCRIPT_TYPE = 'script';
+
+// Maximum length when sending strings through the JSON protocol.
+const kMaxProtocolStringLength = 80;
+
+// Different kind of properties.
+PropertyKind = {};
+PropertyKind.Named   = 1;
+PropertyKind.Indexed = 2;
+
+
+// A copy of the PropertyType enum from global.h
+PropertyType = {};
+PropertyType.Normal             = 0;
+PropertyType.Field              = 1;
+PropertyType.ConstantFunction   = 2;
+PropertyType.Callbacks          = 3;
+PropertyType.Interceptor        = 4;
+PropertyType.MapTransition      = 5;
+PropertyType.ConstantTransition = 6;
+PropertyType.NullDescriptor     = 7;
+
+
+
+// Different attributes for a property.
+PropertyAttribute = {};
+PropertyAttribute.None       = NONE;
+PropertyAttribute.ReadOnly   = READ_ONLY;
+PropertyAttribute.DontEnum   = DONT_ENUM;
+PropertyAttribute.DontDelete = DONT_DELETE;
+
+
+// Mirror hierarchy:
+//   - Mirror
+//     - ValueMirror
+//       - UndefinedMirror
+//       - NullMirror
+//       - NumberMirror
+//       - StringMirror
+//       - ObjectMirror
+//       - FunctionMirror
+//         - UnresolvedFunctionMirror
+//       - ArrayMirror
+//       - DateMirror
+//       - RegExpMirror
+//       - ErrorMirror
+//     - PropertyMirror
+//       - InterceptorPropertyMirror
+//     - AccessorMirror
+//     - FrameMirror
+//     - ScriptMirror
+
+
+/**
+ * Base class for all mirror objects.
+ * @param {string} type The type of the mirror
+ * @constructor
+ */
+function Mirror(type) {
+  this.type_ = type;
+};
+
+
+Mirror.prototype.type = function() {
+  return this.type_;
+};
+
+
+/**
+ * Check whether the mirror reflects the undefined value.
+ * @returns {boolean} True if the mirror reflects the undefined value.
+ */
+Mirror.prototype.isUndefined = function() {
+  return this instanceof UndefinedMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects the null value.
+ * @returns {boolean} True if the mirror reflects the null value
+ */
+Mirror.prototype.isNull = function() {
+  return this instanceof NullMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a boolean value.
+ * @returns {boolean} True if the mirror reflects a boolean value
+ */
+Mirror.prototype.isBoolean = function() {
+  return this instanceof BooleanMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a number value.
+ * @returns {boolean} True if the mirror reflects a number value
+ */
+Mirror.prototype.isNumber = function() {
+  return this instanceof NumberMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a string value.
+ * @returns {boolean} True if the mirror reflects a string value
+ */
+Mirror.prototype.isString = function() {
+  return this instanceof StringMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects an object.
+ * @returns {boolean} True if the mirror reflects an object
+ */
+Mirror.prototype.isObject = function() {
+  return this instanceof ObjectMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a function.
+ * @returns {boolean} True if the mirror reflects a function
+ */
+Mirror.prototype.isFunction = function() {
+  return this instanceof FunctionMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects an unresolved function.
+ * @returns {boolean} True if the mirror reflects an unresolved function
+ */
+Mirror.prototype.isUnresolvedFunction = function() {
+  return this instanceof UnresolvedFunctionMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects an array.
+ * @returns {boolean} True if the mirror reflects an array
+ */
+Mirror.prototype.isArray = function() {
+  return this instanceof ArrayMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a date.
+ * @returns {boolean} True if the mirror reflects a date
+ */
+Mirror.prototype.isDate = function() {
+  return this instanceof DateMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a regular expression.
+ * @returns {boolean} True if the mirror reflects a regular expression
+ */
+Mirror.prototype.isRegExp = function() {
+  return this instanceof RegExpMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects an error.
+ * @returns {boolean} True if the mirror reflects an error
+ */
+Mirror.prototype.isError = function() {
+  return this instanceof ErrorMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a property.
+ * @returns {boolean} True if the mirror reflects a property
+ */
+Mirror.prototype.isProperty = function() {
+  return this instanceof PropertyMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a property from an interceptor.
+ * @returns {boolean} True if the mirror reflects a property from an
+ *     interceptor
+ */
+Mirror.prototype.isInterceptorProperty = function() {
+  return this instanceof InterceptorPropertyMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects an accessor.
+ * @returns {boolean} True if the mirror reflects an accessor
+ */
+Mirror.prototype.isAccessor = function() {
+  return this instanceof AccessorMirror;
+}
+
+
+/**
+ * Check whether the mirror reflects a stack frame.
+ * @returns {boolean} True if the mirror reflects a stack frame
+ */
+Mirror.prototype.isFrame = function() {
+  return this instanceof FrameMirror;
+}
+
+
+Mirror.prototype.fillJSONType_ = function(content) {
+  content.push(MakeJSONPair_('type', StringToJSON_(this.type())));
+};
+
+
+Mirror.prototype.fillJSON_ = function(content) {
+  this.fillJSONType_(content);
+};
+
+
+/**
+ * Serialize object in JSON format. For the basic mirrors this includes only
+ * the type in the following format.
+ *   {"type":"<type name>"}
+ * For specialized mirrors inheriting from the base Mirror
+ * @param {boolean} details Indicate level of details to include
+ * @return {string} JSON serialization
+ */
+Mirror.prototype.toJSONProtocol = function(details, propertiesKind, interceptorPropertiesKind) {
+  var content = new Array();
+  this.fillJSON_(content, details, propertiesKind, interceptorPropertiesKind);
+  content.push(MakeJSONPair_('text', StringToJSON_(this.toText())));
+  return ArrayToJSONObject_(content);
+}
+
+
+Mirror.prototype.toText = function() {
+  // Simpel to text which is used when on specialization in subclass.
+  return "#<" + builtins.GetInstanceName(this.constructor.name) + ">";
+}
+
+
+/**
+ * Base class for all value mirror objects.
+ * @param {string} type The type of the mirror
+ * @param {value} value The value reflected by this mirror
+ * @constructor
+ * @extends Mirror
+ */
+function ValueMirror(type, value) {
+  Mirror.call(this, type);
+  this.value_ = value;
+}
+inherits(ValueMirror, Mirror);
+
+
+/**
+ * Check whether this is a primitive value.
+ * @return {boolean} True if the mirror reflects a primitive value
+ */
+ValueMirror.prototype.isPrimitive = function() {
+  var type = this.type();
+  return type === 'undefined' ||
+         type === 'null' ||
+         type === 'boolean' ||
+         type === 'number' ||
+         type === 'string';
+};
+
+
+ /**
+ * Get the actual value reflected by this mirror.
+ * @return {value} The value reflected by this mirror
+ */
+ValueMirror.prototype.value = function() {
+  return this.value_;
+};
+
+
+/**
+ * Mirror object for Undefined.
+ * @constructor
+ * @extends ValueMirror
+ */
+function UndefinedMirror() {
+  ValueMirror.call(this, UNDEFINED_TYPE, void 0);
+}
+inherits(UndefinedMirror, ValueMirror);
+
+
+UndefinedMirror.prototype.toText = function() {
+  return 'undefined';
+}
+
+
+/**
+ * Mirror object for null.
+ * @constructor
+ * @extends ValueMirror
+ */
+function NullMirror() {
+  ValueMirror.call(this, NULL_TYPE, null);
+}
+inherits(NullMirror, ValueMirror);
+
+
+NullMirror.prototype.toText = function() {
+  return 'null';
+}
+
+
+/**
+ * Mirror object for boolean values.
+ * @param {boolean} value The boolean value reflected by this mirror
+ * @constructor
+ * @extends ValueMirror
+ */
+function BooleanMirror(value) {
+  ValueMirror.call(this, BOOLEAN_TYPE, value);
+}
+inherits(BooleanMirror, ValueMirror);
+
+
+BooleanMirror.prototype.fillJSON_ = function(content, details) {
+  BooleanMirror.super_.fillJSONType_.call(this, content);
+  content.push(MakeJSONPair_('value', BooleanToJSON_(this.value_)));
+}
+
+
+BooleanMirror.prototype.toText = function() {
+  return this.value_ ? 'true' : 'false';
+}
+
+
+/**
+ * Mirror object for number values.
+ * @param {number} value The number value reflected by this mirror
+ * @constructor
+ * @extends ValueMirror
+ */
+function NumberMirror(value) {
+  ValueMirror.call(this, NUMBER_TYPE, value);
+}
+inherits(NumberMirror, ValueMirror);
+
+
+NumberMirror.prototype.fillJSON_ = function(content, details) {
+  NumberMirror.super_.fillJSONType_.call(this, content);
+  content.push(MakeJSONPair_('value', NumberToJSON_(this.value_)));
+}
+
+
+NumberMirror.prototype.toText = function() {
+  return %NumberToString(this.value_);
+}
+
+
+/**
+ * Mirror object for string values.
+ * @param {string} value The string value reflected by this mirror
+ * @constructor
+ * @extends ValueMirror
+ */
+function StringMirror(value) {
+  ValueMirror.call(this, STRING_TYPE, value);
+}
+inherits(StringMirror, ValueMirror);
+
+
+StringMirror.prototype.length = function() {
+  return this.value_.length;
+};
+
+
+StringMirror.prototype.fillJSON_ = function(content, details) {
+  StringMirror.super_.fillJSONType_.call(this, content);
+  content.push(MakeJSONPair_('length', NumberToJSON_(this.length())));
+  if (this.length() > kMaxProtocolStringLength) {
+    content.push(MakeJSONPair_('fromIndex', NumberToJSON_(0)));
+    content.push(MakeJSONPair_('toIndex',
+                               NumberToJSON_(kMaxProtocolStringLength)));
+    var str = this.value_.substring(0, kMaxProtocolStringLength);
+    content.push(MakeJSONPair_('value', StringToJSON_(str)));
+  } else {
+    content.push(MakeJSONPair_('value', StringToJSON_(this.value_)));
+  }
+}
+
+
+StringMirror.prototype.toText = function() {
+  if (this.length() > kMaxProtocolStringLength) {
+    return this.value_.substring(0, kMaxProtocolStringLength) +
+           '... (length: ' + this.length() + ')';
+  } else {
+    return this.value_;
+  }
+}
+
+
+/**
+ * Mirror object for objects.
+ * @param {object} value The object reflected by this mirror
+ * @constructor
+ * @extends ValueMirror
+ */
+function ObjectMirror(value, type) {
+  ValueMirror.call(this, type || OBJECT_TYPE, value);
+}
+inherits(ObjectMirror, ValueMirror);
+
+
+ObjectMirror.prototype.className = function() {
+  return %ClassOf(this.value_);
+};
+
+
+ObjectMirror.prototype.constructorFunction = function() {
+  return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
+};
+
+
+ObjectMirror.prototype.prototypeObject = function() {
+  return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
+};
+
+
+ObjectMirror.prototype.protoObject = function() {
+  return MakeMirror(%GetPrototype(this.value_));
+};
+
+
+ObjectMirror.prototype.hasNamedInterceptor = function() {
+  // Get information on interceptors for this object.
+  var x = %DebugInterceptorInfo(this.value_);
+  return (x & 2) != 0;
+};
+
+
+ObjectMirror.prototype.hasIndexedInterceptor = function() {
+  // Get information on interceptors for this object.
+  var x = %DebugInterceptorInfo(this.value_);
+  return (x & 1) != 0;
+};
+
+
+/**
+ * Return the property names for this object.
+ * @param {number} kind Indicate whether named, indexed or both kinds of
+ *     properties are requested
+ * @param {number} limit Limit the number of names returend to the specified
+       value
+ * @return {Array} Property names for this object
+ */
+ObjectMirror.prototype.propertyNames = function(kind, limit) {
+  // Find kind and limit and allocate array for the result
+  kind = kind || PropertyKind.Named | PropertyKind.Indexed;
+
+  var propertyNames;
+  var elementNames;
+  var total = 0;
+  if (kind & PropertyKind.Named) {
+    propertyNames = %DebugLocalPropertyNames(this.value_);
+    total += propertyNames.length;
+  }
+  if (kind & PropertyKind.Indexed) {
+    elementNames = %DebugLocalElementNames(this.value_)
+    total += elementNames.length;
+  }
+  limit = Math.min(limit || total, total);
+
+  var names = new Array(limit);
+  var index = 0;
+
+  // Copy names for named properties.
+  if (kind & PropertyKind.Named) {
+    for (var i = 0; index < limit && i < propertyNames.length; i++) {
+      names[index++] = propertyNames[i];
+    }
+  }
+
+  // Copy names for indexed properties.
+  if (kind & PropertyKind.Indexed) {
+    for (var i = 0; index < limit && i < elementNames.length; i++) {
+      names[index++] = elementNames[i];
+    }
+  }
+
+  return names;
+};
+
+
+/**
+ * Return the properties for this object as an array of PropertyMirror objects.
+ * @param {number} kind Indicate whether named, indexed or both kinds of
+ *     properties are requested
+ * @param {number} limit Limit the number of properties returend to the
+       specified value
+ * @return {Array} Property mirrors for this object
+ */
+ObjectMirror.prototype.properties = function(kind, limit) {
+  var names = this.propertyNames(kind, limit);
+  var properties = new Array(names.length);
+  for (var i = 0; i < names.length; i++) {
+    properties[i] = this.property(names[i]);
+  }
+
+  return properties;
+};
+
+
+/**
+ * Return the interceptor property names for this object.
+ * @param {number} kind Indicate whether named, indexed or both kinds of
+ *     interceptor properties are requested
+ * @param {number} limit Limit the number of names returend to the specified
+       value
+ * @return {Array} interceptor property names for this object
+ */
+ObjectMirror.prototype.interceptorPropertyNames = function(kind, limit) {
+  // Find kind.
+  kind = kind || PropertyKind.Named | PropertyKind.Indexed;
+  var namedInterceptorNames;
+  var indexedInterceptorNames;
+
+  // Get names for named interceptor properties.
+  if (this.hasNamedInterceptor() && kind & PropertyKind.Named) {
+    namedInterceptorNames = %DebugNamedInterceptorPropertyNames(this.value_);
+  }
+
+  // Get names for indexed interceptor properties.
+  if (this.hasIndexedInterceptor() && kind & PropertyKind.Indexed) {
+    indexedInterceptorNames = %DebugIndexedInterceptorElementNames(this.value_);
+  }
+
+  // Return either retult or both concattenated.
+  if (namedInterceptorNames && indexedInterceptorNames) {
+    return namedInterceptorNames.concat(indexedInterceptorNames);
+  } else if (namedInterceptorNames) {
+    return namedInterceptorNames;
+  } else if (indexedInterceptorNames) {
+    return indexedInterceptorNames;
+  } else {
+    return new Array(0);
+  }
+};
+
+
+/**
+ * Return interceptor properties this object.
+ * @param {number} opt_kind Indicate whether named, indexed or both kinds of
+ *     interceptor properties are requested
+ * @param {Array} opt_names Limit the number of properties returned to the
+       specified value
+ * @return {Array} properties this object as an array of PropertyMirror objects
+ */
+ObjectMirror.prototype.interceptorProperties = function(opt_kind, opt_names) {
+  // Find kind.
+  var kind = opt_kind || PropertyKind.Named | PropertyKind.Indexed;
+  var namedInterceptorProperties;
+  var indexedInterceptorProperties;
+
+  // Get values for named interceptor properties.
+  if (kind & PropertyKind.Named) {
+    var names = opt_names || this.interceptorPropertyNames(PropertyKind.Named);
+    namedInterceptorProperties = new Array(names.length);
+    for (i = 0; i < names.length; i++) {
+      var value = %DebugNamedInterceptorPropertyValue(this.value_, names[i]);
+      namedInterceptorProperties[i] = new InterceptorPropertyMirror(this, names[i], value);
+    }
+  }
+
+  // Get values for indexed interceptor properties.
+  if (kind & PropertyKind.Indexed) {
+    var names = opt_names || this.interceptorPropertyNames(PropertyKind.Indexed);
+    indexedInterceptorProperties = new Array(names.length);
+    for (i = 0; i < names.length; i++) {
+      // Don't try to get the value if the name is not a number.
+      if (IS_NUMBER(names[i])) {
+        var value = %DebugIndexedInterceptorElementValue(this.value_, names[i]);
+        indexedInterceptorProperties[i] = new InterceptorPropertyMirror(this, names[i], value);
+      }
+    }
+  }
+
+  // Return either result or both concattenated.
+  if (namedInterceptorProperties && indexedInterceptorProperties) {
+    return namedInterceptorProperties.concat(indexedInterceptorProperties);
+  } else if (namedInterceptorProperties) {
+    return namedInterceptorProperties;
+  } else {
+    return indexedInterceptorProperties;
+  }
+};
+
+
+ObjectMirror.prototype.property = function(name) {
+  var details = %DebugGetPropertyDetails(this.value_, %ToString(name));
+  if (details) {
+    return new PropertyMirror(this, name, details[0], details[1]);
+  }
+
+  // Nothing found.
+  return new UndefinedMirror();
+};
+
+
+
+/**
+ * Try to find a property from its value.
+ * @param {Mirror} value The property value to look for
+ * @return {PropertyMirror} The property with the specified value. If no
+ *     property was found with the specified value UndefinedMirror is returned
+ */
+ObjectMirror.prototype.lookupProperty = function(value) {
+  var properties = this.properties();
+
+  // Look for property value in properties.
+  for (var i = 0; i < properties.length; i++) {
+
+    // Skip properties which are defined through assessors.
+    var property = properties[i];
+    if (property.propertyType() != PropertyType.Callbacks) {
+      if (%_ObjectEquals(property.value_, value.value_)) {
+        return property;
+      }
+    }
+  }
+
+  // Nothing found.
+  return new UndefinedMirror();
+};
+
+
+/**
+ * Returns objects which has direct references to this object
+ * @param {number} opt_max_instances Optional parameter specifying the maximum
+ *     number of instances to return.
+ * @return {Array} The objects which has direct references to this object.
+ */
+ObjectMirror.prototype.referencedBy = function(opt_max_instances) {
+  // Find all objects constructed from this function.
+  var result = %DebugReferencedBy(this.value_, Mirror.prototype, opt_max_instances || 0);
+
+  // Make mirrors for all the instances found.
+  for (var i = 0; i < result.length; i++) {
+    result[i] = MakeMirror(result[i]);
+  }
+
+  return result;
+};
+
+
+ObjectMirror.prototype.fillJSONProperties_ = function(content, kind, name, details) {
+  var propertyNames = this.propertyNames(kind);
+  var x = new Array(propertyNames.length);
+  for (var i = 0; i < propertyNames.length; i++) {
+    x[i] = this.property(propertyNames[i]).toJSONProtocol(details);
+  }
+  content.push(MakeJSONPair_(name || 'properties', ArrayToJSONArray_(x)));
+};
+
+
+ObjectMirror.prototype.fillJSONInterceptorProperties_ = function(content, kind, name, details) {
+  var propertyNames = this.interceptorPropertyNames(kind);
+  var x = new Array(propertyNames.length);
+  for (var i = 0; i < propertyNames.length; i++) {
+    x[i] = properties[i].toJSONProtocol(details);
+  }
+  content.push(MakeJSONPair_(name || 'interceptorProperties', ArrayToJSONArray_(x)));
+};
+
+
+ObjectMirror.prototype.fillJSON_ = function(content, details, propertiesKind, interceptorPropertiesKind) {
+  ObjectMirror.super_.fillJSONType_.call(this, content);
+  content.push(MakeJSONPair_('className', StringToJSON_(this.className())));
+  if (details) {
+    content.push(MakeJSONPair_('constructorFunction', this.constructorFunction().toJSONProtocol(false)));
+    content.push(MakeJSONPair_('protoObject', this.protoObject().toJSONProtocol(false)));
+    content.push(MakeJSONPair_('prototypeObject', this.prototypeObject().toJSONProtocol(false)));
+  }
+  if (details) {
+    this.fillJSONProperties_(content, propertiesKind)
+    if (interceptorPropertiesKind) {
+      this.fillJSONInterceptorProperties_(content, interceptorPropertiesKind)
+    }
+  }
+  if (this.hasNamedInterceptor()) {
+    content.push(MakeJSONPair_('namedInterceptor', BooleanToJSON_(true)));
+  }
+  if (this.hasIndexedInterceptor()) {
+    content.push(MakeJSONPair_('indexedInterceptor', BooleanToJSON_(true)));
+  }
+};
+
+
+ObjectMirror.prototype.toText = function() {
+  var name;
+  var ctor = this.constructorFunction();
+  if (ctor.isUndefined()) {
+    name = this.className();
+  } else {
+    name = ctor.name();
+    if (!name) {
+      name = this.className();
+    }
+  }
+  return '#<' + builtins.GetInstanceName(name) + '>';
+};
+
+
+/**
+ * Mirror object for functions.
+ * @param {function} value The function object reflected by this mirror.
+ * @constructor
+ * @extends ObjectMirror
+ */
+function FunctionMirror(value) {
+  ObjectMirror.call(this, value, FUNCTION_TYPE);
+  this.resolved_ = true;
+}
+inherits(FunctionMirror, ObjectMirror);
+
+
+/**
+ * Returns whether the function is resolved.
+ * @return {boolean} True if the function is resolved. Unresolved functions can
+ *     only originate as functions from stack frames
+ */
+FunctionMirror.prototype.resolved = function() {
+  return this.resolved_;
+};
+
+
+/**
+ * Returns the name of the function.
+ * @return {string} Name of the function
+ */
+FunctionMirror.prototype.name = function() {
+  return %FunctionGetName(this.value_);
+};
+
+
+/**
+ * Returns the source code for the function.
+ * @return {string or undefined} The source code for the function. If the
+ *     function is not resolved undefined will be returned.
+ */
+FunctionMirror.prototype.source = function() {
+  // Return source if function is resolved. Otherwise just fall through to
+  // return undefined.
+  if (this.resolved()) {
+    // This builtins function is context independant (only uses runtime
+    // calls and typeof.
+    return builtins.FunctionSourceString(this.value_);
+  }
+};
+
+
+/**
+ * Returns the script object for the function.
+ * @return {ScriptMirror or undefined} Script object for the function or
+ *     undefined if the function has no script
+ */
+FunctionMirror.prototype.script = function() {
+  // Return script if function is resolved. Otherwise just fall through
+  // to return undefined.
+  if (this.resolved()) {
+    var script = %FunctionGetScript(this.value_);
+    if (script) {
+      return new ScriptMirror(script);
+    }
+  }
+};
+
+
+/**
+ * Returns objects constructed by this function.
+ * @param {number} opt_max_instances Optional parameter specifying the maximum
+ *     number of instances to return.
+ * @return {Array or undefined} The objects constructed by this function.
+ */
+FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
+  if (this.resolved()) {
+    // Find all objects constructed from this function.
+    var result = %DebugConstructedBy(this.value_, opt_max_instances || 0);
+
+    // Make mirrors for all the instances found.
+    for (var i = 0; i < result.length; i++) {
+      result[i] = MakeMirror(result[i]);
+    }
+
+    return result;
+  } else {
+    return [];
+  }
+};
+
+
+FunctionMirror.prototype.fillJSON_ = function(content, details) {
+  // Fill JSON properties from parent (ObjectMirror).
+  FunctionMirror.super_.fillJSON_.call(this, content, details);
+  // Add function specific properties.
+  content.push(MakeJSONPair_('name', StringToJSON_(this.name())));
+  content.push(MakeJSONPair_('resolved', BooleanToJSON_(this.resolved())));
+  if (details && this.resolved()) {
+    content.push(MakeJSONPair_('source', StringToJSON_(this.source())));
+  }
+  if (this.script()) {
+    content.push(MakeJSONPair_('script', this.script().toJSONProtocol()));
+  }
+}
+
+
+FunctionMirror.prototype.toText = function() {
+  return this.source();
+}
+
+
+/**
+ * Mirror object for unresolved functions.
+ * @param {string} value The name for the unresolved function reflected by this
+ *     mirror.
+ * @constructor
+ * @extends ObjectMirror
+ */
+function UnresolvedFunctionMirror(value) {
+  // Construct this using the ValueMirror as an unresolved function is not a
+  // real object but just a string.
+  ValueMirror.call(this, FUNCTION_TYPE, value);
+  this.propertyCount_ = 0;
+  this.elementCount_ = 0;
+  this.resolved_ = false;
+}
+inherits(UnresolvedFunctionMirror, FunctionMirror);
+
+
+UnresolvedFunctionMirror.prototype.className = function() {
+  return 'Function';
+};
+
+
+UnresolvedFunctionMirror.prototype.constructorFunction = function() {
+  return new UndefinedMirror();
+};
+
+
+UnresolvedFunctionMirror.prototype.prototypeObject = function() {
+  return new UndefinedMirror();
+};
+
+
+UnresolvedFunctionMirror.prototype.protoObject = function() {
+  return new UndefinedMirror();
+};
+
+
+UnresolvedFunctionMirror.prototype.name = function() {
+  return this.value_;
+};
+
+
+UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) {
+  return [];
+}
+
+
+/**
+ * Mirror object for arrays.
+ * @param {Array} value The Array object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function ArrayMirror(value) {
+  ObjectMirror.call(this, value);
+}
+inherits(ArrayMirror, ObjectMirror);
+
+
+ArrayMirror.prototype.length = function() {
+  return this.value_.length;
+};
+
+
+ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, opt_to_index) {
+  var from_index = opt_from_index || 0;
+  var to_index = opt_to_index || this.length() - 1;
+  if (from_index > to_index) return new Array();
+  var values = new Array(to_index - from_index + 1);
+  for (var i = from_index; i <= to_index; i++) {
+    var details = %DebugGetPropertyDetails(this.value_, %ToString(i));
+    var value;
+    if (details) {
+      value = new PropertyMirror(this, i, details[0], details[1]);
+    } else {
+      value = new UndefinedMirror();
+    }
+    values[i - from_index] = value;
+  }
+  return values;
+}
+
+
+ArrayMirror.prototype.fillJSON_ = function(content, details) {
+  // Fill JSON as for parent (ObjectMirror) but just with named properties.
+  ArrayMirror.super_.fillJSON_.call(this, content, details, PropertyKind.Named);
+  // Fill indexed properties seperately.
+  if (details) {
+    this.fillJSONProperties_(content, PropertyKind.Indexed, 'indexedProperties')
+  }
+  // Add the array length.
+  content.push(MakeJSONPair_('length', NumberToJSON_(this.length())));
+}
+
+
+/**
+ * Mirror object for dates.
+ * @param {Date} value The Date object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function DateMirror(value) {
+  ObjectMirror.call(this, value);
+}
+inherits(DateMirror, ObjectMirror);
+
+
+DateMirror.prototype.fillJSON_ = function(content, details) {
+  // Fill JSON properties from parent (ObjectMirror).
+  DateMirror.super_.fillJSON_.call(this, content, details);
+  // Add date specific properties.
+  content.push(MakeJSONPair_('value', DateToJSON_(this.value_)));
+}
+
+
+DateMirror.prototype.toText = function() {
+  return DateToISO8601_(this.value_);
+}
+
+
+/**
+ * Mirror object for regular expressions.
+ * @param {RegExp} value The RegExp object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function RegExpMirror(value) {
+  ObjectMirror.call(this, value, REGEXP_TYPE);
+}
+inherits(RegExpMirror, ObjectMirror);
+
+
+/**
+ * Returns the source to the regular expression.
+ * @return {string or undefined} The source to the regular expression
+ */
+RegExpMirror.prototype.source = function() {
+  return this.value_.source;
+};
+
+
+/**
+ * Returns whether this regular expression has the global (g) flag set.
+ * @return {boolean} Value of the global flag
+ */
+RegExpMirror.prototype.global = function() {
+  return this.value_.global;
+};
+
+
+/**
+ * Returns whether this regular expression has the ignore case (i) flag set.
+ * @return {boolean} Value of the ignore case flag
+ */
+RegExpMirror.prototype.ignoreCase = function() {
+  return this.value_.ignoreCase;
+};
+
+
+/**
+ * Returns whether this regular expression has the multiline (m) flag set.
+ * @return {boolean} Value of the multiline flag
+ */
+RegExpMirror.prototype.multiline = function() {
+  return this.value_.multiline;
+};
+
+
+RegExpMirror.prototype.fillJSON_ = function(content, details) {
+  // Fill JSON properties from parent (ObjectMirror).
+  RegExpMirror.super_.fillJSON_.call(this, content, details);
+  // Add regexp specific properties.
+  content.push(MakeJSONPair_('source', StringToJSON_(this.source())));
+  content.push(MakeJSONPair_('global', BooleanToJSON_(this.global())));
+  content.push(MakeJSONPair_('ignoreCase', BooleanToJSON_(this.ignoreCase())));
+  content.push(MakeJSONPair_('multiline', BooleanToJSON_(this.multiline())));
+}
+
+
+RegExpMirror.prototype.toText = function() {
+  // Simpel to text which is used when on specialization in subclass.
+  return "/" + this.source() + "/";
+}
+
+
+/**
+ * Mirror object for error objects.
+ * @param {Error} value The error object reflected by this mirror
+ * @constructor
+ * @extends ObjectMirror
+ */
+function ErrorMirror(value) {
+  ObjectMirror.call(this, value, ERROR_TYPE);
+}
+inherits(ErrorMirror, ObjectMirror);
+
+
+/**
+ * Returns the message for this eror object.
+ * @return {string or undefined} The message for this eror object
+ */
+ErrorMirror.prototype.message = function() {
+  return this.value_.message;
+};
+
+
+ErrorMirror.prototype.fillJSON_ = function(content, details) {
+  // Fill JSON properties from parent (ObjectMirror).
+  ErrorMirror.super_.fillJSON_.call(this, content, details);
+  // Add error specific properties.
+  content.push(MakeJSONPair_('message', StringToJSON_(this.message())));
+}
+
+
+ErrorMirror.prototype.toText = function() {
+  // Use the same text representation as in messages.js.
+  var text;
+  try {
+    str = builtins.ToDetailString(this.value_);
+  } catch (e) {
+    str = '#<an Error>';
+  }
+  return str;
+}
+
+
+/**
+ * Base mirror object for properties.
+ * @param {ObjectMirror} mirror The mirror object having this property
+ * @param {string} name The name of the property
+ * @param {Object} value The value of the property
+ * @constructor
+ * @extends Mirror
+ */
+function PropertyMirror(mirror, name, value, details) {
+  Mirror.call(this, PROPERTY_TYPE);
+  this.mirror_ = mirror;
+  this.name_ = name;
+  this.value_ = value;
+  this.details_ = details;
+}
+inherits(PropertyMirror, Mirror);
+
+
+PropertyMirror.prototype.isReadOnly = function() {
+  return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
+}
+
+
+PropertyMirror.prototype.isEnum = function() {
+  return (this.attributes() & PropertyAttribute.DontEnum) == 0;
+}
+
+
+PropertyMirror.prototype.canDelete = function() {
+  return (this.attributes() & PropertyAttribute.DontDelete) == 0;
+}
+
+
+PropertyMirror.prototype.name = function() {
+  return this.name_;
+}
+
+
+PropertyMirror.prototype.isIndexed = function() {
+  for (var i = 0; i < this.name_.length; i++) {
+    if (this.name_[i] < '0' || '9' < this.name_[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+PropertyMirror.prototype.value = function() {
+  if (this.propertyType() == PropertyType.Callbacks) {
+    // TODO(1242933): AccessorMirror should have getter/setter values.
+    return new AccessorMirror();
+  } else if (this.type() == PropertyType.Interceptor) {
+    return new UndefinedMirror();
+  } else {
+    return MakeMirror(this.value_);
+  }
+}
+
+
+PropertyMirror.prototype.attributes = function() {
+  return %DebugPropertyAttributesFromDetails(this.details_);
+}
+
+
+PropertyMirror.prototype.propertyType = function() {
+  return %DebugPropertyTypeFromDetails(this.details_);
+}
+
+
+PropertyMirror.prototype.insertionIndex = function() {
+  return %DebugPropertyIndexFromDetails(this.details_);
+}
+
+
+PropertyMirror.prototype.fillJSON_ = function(content, details) {
+  content.push(MakeJSONPair_('name', StringToJSON_(this.name())));
+  content.push(MakeJSONPair_('value', this.value().toJSONProtocol(details)));
+  if (this.attributes() != PropertyAttribute.None) {
+    content.push(MakeJSONPair_('attributes', NumberToJSON_(this.attributes())));
+  }
+  if (this.propertyType() != PropertyType.Normal) {
+    content.push(MakeJSONPair_('propertyType', NumberToJSON_(this.propertyType())));
+  }
+}
+
+
+/**
+ * Mirror object for interceptor named properties.
+ * @param {ObjectMirror} mirror The mirror object having this property
+ * @param {String} name The name of the property
+ * @param {value} value The value of the property
+ * @constructor
+ * @extends PropertyMirror
+ */
+function InterceptorPropertyMirror(mirror, name, value) {
+  PropertyMirror.call(this, mirror, name, value, PropertyType.Interceptor);
+}
+inherits(InterceptorPropertyMirror, PropertyMirror);
+
+
+/**
+ * Mirror object for property accessors.
+ * @param {Function} getter The getter function for this accessor
+ * @param {Function} setter The setter function for this accessor
+ * @constructor
+ * @extends Mirror
+ */
+function AccessorMirror(getter, setter) {
+  Mirror.call(this, ACCESSOR_TYPE);
+  this.getter_ = getter;
+  this.setter_ = setter;
+}
+inherits(AccessorMirror, Mirror);
+
+
+/**
+ * Returns whether this accessor is native or not. A native accessor is either
+ * a VM buildin or provided through the API. A non native accessor is defined
+ * in JavaScript using the __defineGetter__ and/or __defineGetter__ functions.
+ * @return {boolean} True is the accessor is native
+ */
+AccessorMirror.prototype.isNative = function() {
+  return IS_UNDEFINED(this.getter_) && IS_UNDEFINED(this.setter_);
+}
+
+
+/**
+ * Returns a mirror for the function of a non native getter.
+ * @return {FunctionMirror} Function mirror for the getter set using
+ *     __defineGetter__.
+ */
+AccessorMirror.prototype.getter = function(details) {
+  return MakeMirror(this.getter_);
+}
+
+
+/**
+ * Returns a mirror for the function of a non native setter.
+ * @return {FunctionMirror} Function mirror for the getter set using
+ *     __defineSetter__.
+ */
+AccessorMirror.prototype.setter = function(details) {
+  return MakeMirror(this.setter_);
+}
+
+
+/**
+ * Serialize the accessor mirror into JSON format. For accessor it has the
+ * following format.
+ *   {"type":"accessor",
+      "native:"<boolean>,
+      "getter":<function mirror JSON serialization>,
+      "setter":<function mirror JSON serialization>}
+ * For specialized mirrors inheriting from the base Mirror
+ * @param {boolean} details Indicate level of details to include
+ * @return {string} JSON serialization
+ */
+AccessorMirror.prototype.fillJSON_ = function(content, details) {
+  AccessorMirror.super_.fillJSONType_.call(this, content);
+  if (this.isNative()) {
+    content.push(MakeJSONPair_('native', BooleanToJSON_(true)));
+  } else {
+    content.push(MakeJSONPair_('getter', this.getter().toJSONProtocol(false)));
+    content.push(MakeJSONPair_('setter', this.setter().toJSONProtocol(false)));
+  }
+}
+
+
+const kFrameDetailsFrameIdIndex = 0;
+const kFrameDetailsReceiverIndex = 1;
+const kFrameDetailsFunctionIndex = 2;
+const kFrameDetailsArgumentCountIndex = 3;
+const kFrameDetailsLocalCountIndex = 4;
+const kFrameDetailsSourcePositionIndex = 5;
+const kFrameDetailsConstructCallIndex = 6;
+const kFrameDetailsDebuggerFrameIndex = 7;
+const kFrameDetailsFirstDynamicIndex = 8;
+
+const kFrameDetailsNameIndex = 0;
+const kFrameDetailsValueIndex = 1;
+const kFrameDetailsNameValueSize = 2;
+
+/**
+ * Wrapper for the frame details information retreived from the VM. The frame
+ * details from the VM is an array with the following content. See runtime.cc
+ * Runtime_GetFrameDetails.
+ *     0: Id
+ *     1: Receiver
+ *     2: Function
+ *     3: Argument count
+ *     4: Local count
+ *     5: Source position
+ *     6: Construct call
+ *     Arguments name, value
+ *     Locals name, value
+ * @param {number} break_id Current break id
+ * @param {number} index Frame number
+ * @constructor
+ */
+function FrameDetails(break_id, index) {
+  this.break_id_ = break_id;
+  this.details_ = %GetFrameDetails(break_id, index);
+}
+
+
+FrameDetails.prototype.frameId = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsFrameIdIndex];
+}
+
+
+FrameDetails.prototype.receiver = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsReceiverIndex];
+}
+
+
+FrameDetails.prototype.func = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsFunctionIndex];
+}
+
+
+FrameDetails.prototype.isConstructCall = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsConstructCallIndex];
+}
+
+
+FrameDetails.prototype.isDebuggerFrame = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsDebuggerFrameIndex];
+}
+
+
+FrameDetails.prototype.argumentCount = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsArgumentCountIndex];
+}
+
+
+FrameDetails.prototype.argumentName = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.argumentCount()) {
+    return this.details_[kFrameDetailsFirstDynamicIndex +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsNameIndex]
+  }
+}
+
+
+FrameDetails.prototype.argumentValue = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.argumentCount()) {
+    return this.details_[kFrameDetailsFirstDynamicIndex +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsValueIndex]
+  }
+}
+
+
+FrameDetails.prototype.localCount = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsLocalCountIndex];
+}
+
+
+FrameDetails.prototype.sourcePosition = function() {
+  %CheckExecutionState(this.break_id_);
+  return this.details_[kFrameDetailsSourcePositionIndex];
+}
+
+
+FrameDetails.prototype.localName = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.localCount()) {
+    var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
+    return this.details_[locals_offset +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsNameIndex]
+  }
+}
+
+
+FrameDetails.prototype.localValue = function(index) {
+  %CheckExecutionState(this.break_id_);
+  if (index >= 0 && index < this.localCount()) {
+    var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
+    return this.details_[locals_offset +
+                         index * kFrameDetailsNameValueSize +
+                         kFrameDetailsValueIndex]
+  }
+}
+
+
+/**
+ * Mirror object for stack frames.
+ * @param {number} break_id The break id in the VM for which this frame is
+       valid
+ * @param {number} index The frame index (top frame is index 0)
+ * @constructor
+ * @extends Mirror
+ */
+function FrameMirror(break_id, index) {
+  Mirror.call(this, FRAME_TYPE);
+  this.break_id_ = break_id;
+  this.index_ = index;
+  this.details_ = new FrameDetails(break_id, index);
+}
+inherits(FrameMirror, Mirror);
+
+
+FrameMirror.prototype.index = function() {
+  return this.index_;
+};
+
+
+FrameMirror.prototype.func = function() {
+  // Get the function for this frame from the VM.
+  var f = this.details_.func();
+  
+  // Create a function mirror. NOTE: MakeMirror cannot be used here as the
+  // value returned from the VM might be a string if the function for the
+  // frame is unresolved.
+  if (IS_FUNCTION(f)) {
+    return new FunctionMirror(f);
+  } else {
+    return new UnresolvedFunctionMirror(f);
+  }
+};
+
+
+FrameMirror.prototype.receiver = function() {
+  return MakeMirror(this.details_.receiver());
+};
+
+
+FrameMirror.prototype.isConstructCall = function() {
+  return this.details_.isConstructCall();
+};
+
+
+FrameMirror.prototype.isDebuggerFrame = function() {
+  return this.details_.isDebuggerFrame();
+};
+
+
+FrameMirror.prototype.argumentCount = function() {
+  return this.details_.argumentCount();
+};
+
+
+FrameMirror.prototype.argumentName = function(index) {
+  return this.details_.argumentName(index);
+};
+
+
+FrameMirror.prototype.argumentValue = function(index) {
+  return MakeMirror(this.details_.argumentValue(index));
+};
+
+
+FrameMirror.prototype.localCount = function() {
+  return this.details_.localCount();
+};
+
+
+FrameMirror.prototype.localName = function(index) {
+  return this.details_.localName(index);
+};
+
+
+FrameMirror.prototype.localValue = function(index) {
+  return MakeMirror(this.details_.localValue(index));
+};
+
+
+FrameMirror.prototype.sourcePosition = function() {
+  return this.details_.sourcePosition();
+};
+
+
+FrameMirror.prototype.sourceLocation = function() {
+  if (this.func().resolved() && this.func().script()) {
+    return this.func().script().locationFromPosition(this.sourcePosition());
+  }
+};
+
+
+FrameMirror.prototype.sourceLine = function() {
+  if (this.func().resolved()) {
+    var location = this.sourceLocation();
+    if (location) {
+      return location.line;
+    }
+  }
+};
+
+
+FrameMirror.prototype.sourceColumn = function() {
+  if (this.func().resolved()) {
+    var location = this.sourceLocation();
+    if (location) {
+      return location.column;
+    }
+  }
+};
+
+
+FrameMirror.prototype.sourceLineText = function() {
+  if (this.func().resolved()) {
+    var location = this.sourceLocation();
+    if (location) {
+      return location.sourceText();
+    }
+  }
+};
+
+
+FrameMirror.prototype.evaluate = function(source, disable_break) {
+  var result = %DebugEvaluate(this.break_id_, this.details_.frameId(),
+                              source, Boolean(disable_break));
+  return MakeMirror(result);
+};
+
+
+FrameMirror.prototype.fillJSON_ = function(content, details) {
+  FrameMirror.super_.fillJSONType_.call(this, content);
+  content.push(MakeJSONPair_('index', NumberToJSON_(this.index())));
+  content.push(MakeJSONPair_('receiver', this.receiver().toJSONProtocol(false)));
+  content.push(MakeJSONPair_('func', this.func().toJSONProtocol(false)));
+  content.push(MakeJSONPair_('constructCall', BooleanToJSON_(this.isConstructCall())));
+  content.push(MakeJSONPair_('debuggerFrame', BooleanToJSON_(this.isDebuggerFrame())));
+  var x = new Array(this.argumentCount());
+  for (var i = 0; i < this.argumentCount(); i++) {
+    arg = new Array();
+    var argument_name = this.argumentName(i)
+    if (argument_name) {
+      arg.push(MakeJSONPair_('name', StringToJSON_(argument_name)));
+    }
+    arg.push(MakeJSONPair_('value', this.argumentValue(i).toJSONProtocol(false)));
+    x[i] = ArrayToJSONObject_(arg);
+  }
+  content.push(MakeJSONPair_('arguments', ArrayToJSONArray_(x)));
+  var x = new Array(this.localCount());
+  for (var i = 0; i < this.localCount(); i++) {
+    var name = MakeJSONPair_('name', StringToJSON_(this.localName(i)));
+    var value = MakeJSONPair_('value', this.localValue(i).toJSONProtocol(false));
+    x[i] = '{' + name + ',' + value + '}';
+  }
+  content.push(MakeJSONPair_('locals', ArrayToJSONArray_(x)));
+  content.push(MakeJSONPair_('position', NumberToJSON_(this.sourcePosition())));
+  var line = this.sourceLine();
+  if (!IS_UNDEFINED(line)) {
+    content.push(MakeJSONPair_('line', NumberToJSON_(line)));
+  }
+  var column = this.sourceColumn();
+  if (!IS_UNDEFINED(column)) {
+    content.push(MakeJSONPair_('column', NumberToJSON_(column)));
+  }
+  var source_line_text = this.sourceLineText();
+  if (!IS_UNDEFINED(source_line_text)) {
+    content.push(MakeJSONPair_('sourceLineText', StringToJSON_(source_line_text)));
+  }
+}
+
+
+FrameMirror.prototype.invocationText = function() {
+  // Format frame invoaction (receiver, function and arguments).
+  var result = '';
+  var func = this.func();
+  var receiver = this.receiver();
+  if (this.isConstructCall()) {
+    // For constructor frames display new followed by the function name.
+    result += 'new ';
+    result += func.name() ? func.name() : '[anonymous]';
+  } else if (this.isDebuggerFrame()) {
+    result += '[debugger]';
+  } else {
+    // If the receiver has a className which is 'global' don't display it.
+    var display_receiver = !receiver.className || receiver.className() != 'global';
+    if (display_receiver) {
+      result += receiver.toText();
+    }
+    // Try to find the function as a property in the receiver. Include the
+    // prototype chain in the lookup.
+    var property = new UndefinedMirror();
+    if (!receiver.isUndefined()) {
+      for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) {
+        property = r.lookupProperty(func);
+      }
+    }
+    if (!property.isUndefined()) {
+      // The function invoked was found on the receiver. Use the property name
+      // for the backtrace.
+      if (!property.isIndexed()) {
+        if (display_receiver) {
+          result += '.';
+        }
+        result += property.name();
+      } else {
+        result += '[';
+        result += property.name();
+        result += ']';
+      }
+      // Also known as - if the name in the function doesn't match the name
+      // under which it was looked up.
+      if (func.name() && func.name() != property.name()) {
+        result += '(aka ' + func.name() + ')';
+      }
+    } else {
+      // The function invoked was not found on the receiver. Use the function
+      // name if available for the backtrace.
+      if (display_receiver) {
+        result += '.';
+      }
+      result += func.name() ? func.name() : '[anonymous]';
+    }
+  }
+
+  // Render arguments for normal frames.
+  if (!this.isDebuggerFrame()) {
+    result += '(';
+    for (var i = 0; i < this.argumentCount(); i++) {
+      if (i != 0) result += ', ';
+      if (this.argumentName(i)) {
+        result += this.argumentName(i);
+        result += '=';
+      }
+      result += this.argumentValue(i).toText();
+    }
+    result += ')';
+  }
+
+  return result;
+}
+
+
+FrameMirror.prototype.sourceAndPositionText = function() {
+  // Format source and position.
+  var result = '';
+  var func = this.func();
+  if (func.resolved()) {
+    if (func.script()) {
+      if (func.script().name()) {
+        result += func.script().name();
+      } else {
+        result += '[unnamed]';
+      }
+      if (!this.isDebuggerFrame()) {
+        var location = this.sourceLocation();
+        result += ' line ';
+        result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
+        result += ' column ';
+        result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
+        if (!IS_UNDEFINED(this.sourcePosition())) {
+          result += ' (position ' + (this.sourcePosition() + 1) + ')';
+        }
+      }
+    } else {
+      result += '[no source]';
+    }
+  } else {
+    result += '[unresolved]';
+  }
+
+  return result;
+}
+
+
+FrameMirror.prototype.localsText = function() {
+  // Format local variables.
+  var result = '';
+  var locals_count = this.localCount()
+  if (locals_count > 0) {
+    for (var i = 0; i < locals_count; ++i) {
+      result += '      var ';
+      result += this.localName(i);
+      result += ' = ';
+      result += this.localValue(i).toText();
+      if (i < locals_count - 1) result += '\n';
+    }
+  }
+
+  return result;
+}
+
+
+FrameMirror.prototype.toText = function(opt_locals) {
+  var result = '';
+  result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
+  result += ' ';
+  result += this.invocationText();
+  result += ' ';
+  result += this.sourceAndPositionText();
+  if (opt_locals) {
+    result += '\n';
+    result += this.localsText();
+  }
+  return result;
+}
+
+
+/**
+ * Mirror object for script source.
+ * @param {Script} script The script object
+ * @constructor
+ * @extends Mirror
+ */
+function ScriptMirror(script) {
+  Mirror.call(this, SCRIPT_TYPE);
+  this.script_ = script;
+}
+inherits(ScriptMirror, Mirror);
+
+
+ScriptMirror.prototype.name = function() {
+  return this.script_.name;
+};
+
+
+ScriptMirror.prototype.lineOffset = function() {
+  return this.script_.line_offset;
+};
+
+
+ScriptMirror.prototype.columnOffset = function() {
+  return this.script_.column_offset;
+};
+
+
+ScriptMirror.prototype.scriptType = function() {
+  return this.script_.type;
+};
+
+
+ScriptMirror.prototype.lineCount = function() {
+  return this.script_.lineCount();
+};
+
+
+ScriptMirror.prototype.locationFromPosition = function(position) {
+  return this.script_.locationFromPosition(position);
+}
+
+
+ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
+  return this.script_.sourceSlice(opt_from_line, opt_to_line);
+}
+
+
+ScriptMirror.prototype.fillJSON_ = function(content, details) {
+  ScriptMirror.super_.fillJSONType_.call(this, content);
+  if (this.name()) {
+    content.push(MakeJSONPair_('name', StringToJSON_(this.name())));
+  }
+  content.push(MakeJSONPair_('lineOffset', NumberToJSON_(this.lineOffset())));
+  content.push(MakeJSONPair_('columnOffset', NumberToJSON_(this.columnOffset())));
+  content.push(MakeJSONPair_('lineCount', NumberToJSON_(this.lineCount())));
+  content.push(MakeJSONPair_('scriptType', NumberToJSON_(this.scriptType())));
+}
+
+
+ScriptMirror.prototype.toText = function() {
+  var result = '';
+  result += this.name();
+  result += ' (lines: ';
+  if (this.lineOffset() > 0) {
+    result += this.lineOffset();
+    result += '-';
+    result += this.lineOffset() + this.lineCount() - 1;
+  } else {
+    result += this.lineCount();
+  }
+  result += ')';
+  return result;
+}
+
+
+function MakeJSONPair_(name, value) {
+  return '"' + name + '":' + value;
+}
+
+
+function ArrayToJSONObject_(content) {
+  return '{' + content.join(',') + '}';
+}
+
+
+function ArrayToJSONArray_(content) {
+  return '[' + content.join(',') + ']';
+}
+
+
+function BooleanToJSON_(value) {
+  return String(value); 
+}
+
+
+function NumberToJSON_(value) {
+  return String(value); 
+}
+
+
+// Mapping of some control characters to avoid the \uXXXX syntax for most
+// commonly used control cahracters.
+const ctrlCharMap_ = {
+  '\b': '\\b',
+  '\t': '\\t',
+  '\n': '\\n',
+  '\f': '\\f',
+  '\r': '\\r',
+  '"' : '\\"',
+  '\\': '\\\\'
+};
+
+
+// Regular expression testing for ", \ and control characters (0x00 - 0x1F).
+const ctrlCharTest_ = new RegExp('["\\\\\x00-\x1F]');
+
+
+// Regular expression matching ", \ and control characters (0x00 - 0x1F)
+// globally.
+const ctrlCharMatch_ = new RegExp('["\\\\\x00-\x1F]', 'g');
+
+
+/**
+ * Convert a String to its JSON representation (see http://www.json.org/). To
+ * avoid depending on the String object this method calls the functions in
+ * string.js directly and not through the value.
+ * @param {String} value The String value to format as JSON
+ * @return {string} JSON formatted String value
+ */
+function StringToJSON_(value) {
+  // Check for" , \ and control characters (0x00 - 0x1F). No need to call
+  // RegExpTest as ctrlchar is constructed using RegExp.
+  if (ctrlCharTest_.test(value)) {
+    // Replace ", \ and control characters (0x00 - 0x1F).
+    return '"' +
+      value.replace(ctrlCharMatch_, function (char) {
+        // Use charmap if possible.
+        var mapped = ctrlCharMap_[char];
+        if (mapped) return mapped;
+        mapped = char.charCodeAt();
+        // Convert control character to unicode escape sequence.
+        return '\\u00' +
+          %NumberToRadixString(Math.floor(mapped / 16), 16) +
+          %NumberToRadixString(mapped % 16, 16);
+      })
+    + '"';
+  }
+
+  // Simple string with no special characters.
+  return '"' + value + '"';
+}
+
+
+/**
+ * Convert a Date to ISO 8601 format. To avoid depending on the Date object
+ * this method calls the functions in date.js directly and not through the
+ * value.
+ * @param {Date} value The Date value to format as JSON
+ * @return {string} JSON formatted Date value
+ */
+function DateToISO8601_(value) {
+  function f(n) {
+    return n < 10 ? '0' + n : n;
+  }
+  function g(n) {
+    return n < 10 ? '00' + n : n < 100 ? '0' + n : n;
+  }
+  return builtins.GetUTCFullYearFrom(value)         + '-' +
+          f(builtins.GetUTCMonthFrom(value) + 1)    + '-' +
+          f(builtins.GetUTCDateFrom(value))         + 'T' +
+          f(builtins.GetUTCHoursFrom(value))        + ':' +
+          f(builtins.GetUTCMinutesFrom(value))      + ':' +
+          f(builtins.GetUTCSecondsFrom(value))      + '.' +
+          g(builtins.GetUTCMillisecondsFrom(value)) + 'Z';
+}
+
+/**
+ * Convert a Date to ISO 8601 format. To avoid depending on the Date object
+ * this method calls the functions in date.js directly and not through the
+ * value.
+ * @param {Date} value The Date value to format as JSON
+ * @return {string} JSON formatted Date value
+ */
+function DateToJSON_(value) {
+  return '"' + DateToISO8601_(value) + '"';
+}
diff --git a/regexp2000/src/mksnapshot.cc b/regexp2000/src/mksnapshot.cc
new file mode 100644 (file)
index 0000000..275fb47
--- /dev/null
@@ -0,0 +1,186 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// To avoid warnings from <map> on windows we disable exceptions.
+#define _HAS_EXCEPTIONS 0
+#include <signal.h>
+#include <string>
+#include <map>
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "natives.h"
+#include "platform.h"
+#include "serialize.h"
+
+// use explicit namespace to avoid clashing with types in namespace v8
+namespace i = v8::internal;
+using namespace v8;
+
+static const unsigned int kMaxCounters = 256;
+
+// A single counter in a counter collection.
+class Counter {
+ public:
+  static const int kMaxNameSize = 64;
+  int32_t* Bind(const wchar_t* name) {
+    int i;
+    for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) {
+      name_[i] = static_cast<char>(name[i]);
+    }
+    name_[i] = '\0';
+    return &counter_;
+  }
+ private:
+  int32_t counter_;
+  uint8_t name_[kMaxNameSize];
+};
+
+
+// A set of counters and associated information.  An instance of this
+// class is stored directly in the memory-mapped counters file if
+// the --save-counters options is used
+class CounterCollection {
+ public:
+  CounterCollection() {
+    magic_number_ = 0xDEADFACE;
+    max_counters_ = kMaxCounters;
+    max_name_size_ = Counter::kMaxNameSize;
+    counters_in_use_ = 0;
+  }
+  Counter* GetNextCounter() {
+    if (counters_in_use_ == kMaxCounters) return NULL;
+    return &counters_[counters_in_use_++];
+  }
+ private:
+  uint32_t magic_number_;
+  uint32_t max_counters_;
+  uint32_t max_name_size_;
+  uint32_t counters_in_use_;
+  Counter counters_[kMaxCounters];
+};
+
+
+// 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;
+static CounterCollection* counters = &local_counters;
+
+
+typedef std::map<std::wstring, int*> CounterMap;
+typedef std::map<std::wstring, int*>::iterator CounterMapIterator;
+static CounterMap counter_table_;
+
+// Callback receiver when v8 has a counter to track.
+static int* counter_callback(const wchar_t* name) {
+  std::wstring counter = name;
+  // See if this counter name is already known.
+  if (counter_table_.find(counter) != counter_table_.end())
+    return counter_table_[counter];
+
+  Counter* ctr = counters->GetNextCounter();
+  if (ctr == NULL) return NULL;
+  int* ptr = ctr->Bind(name);
+  counter_table_[counter] = ptr;
+  return ptr;
+}
+
+
+// Write C++ code that defines Snapshot::snapshot_ to contain the snapshot
+// to the file given by filename. Only the first size chars are written.
+static int WriteInternalSnapshotToFile(const char* filename,
+                                       const char* str,
+                                       int size) {
+  FILE* f = i::OS::FOpen(filename, "wb");
+  if (f == NULL) {
+    i::OS::PrintError("Cannot open file %s for reading.\n", filename);
+    return 0;
+  }
+  fprintf(f, "// Autogenerated snapshot file. Do not edit.\n\n");
+  fprintf(f, "#include \"v8.h\"\n");
+  fprintf(f, "#include \"platform.h\"\n\n");
+  fprintf(f, "#include \"snapshot.h\"\n\n");
+  fprintf(f, "namespace v8 {\nnamespace internal {\n\n");
+  fprintf(f, "const char Snapshot::data_[] = {");
+  int written = 0;
+  written += fprintf(f, "%i", str[0]);
+  for (int i = 1; i < size; ++i) {
+    written += fprintf(f, ",%i", str[i]);
+    // The following is needed to keep the line length low on Visual C++:
+    if (i % 512 == 0) fprintf(f, "\n");
+  }
+  fprintf(f, "};\n\n");
+  fprintf(f, "int Snapshot::size_ = %d;\n\n", size);
+  fprintf(f, "} }  // namespace v8::internal\n");
+  fclose(f);
+  return written;
+}
+
+
+int main(int argc, char** argv) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  // By default, log code create information in the snapshot.
+  i::FLAG_log_code = true;
+#endif
+  // Print the usage if an error occurs when parsing the command line
+  // flags or if the help flag is set.
+  int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
+  if (result > 0 || argc != 2 || i::FLAG_h) {
+    ::printf("Usage: %s [flag] ... outfile\n", argv[0]);
+    i::FlagList::PrintHelp();
+    return !i::FLAG_h;
+  }
+
+  v8::V8::SetCounterFunction(counter_callback);
+  v8::HandleScope scope;
+
+  const int kExtensionCount = 1;
+  const char* extension_list[kExtensionCount] = { "v8/gc" };
+  v8::ExtensionConfiguration extensions(kExtensionCount, extension_list);
+  v8::Context::New(&extensions);
+
+  // Make sure all builtin scripts are cached.
+  { HandleScope scope;
+    for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
+      i::Bootstrapper::NativesSourceLookup(i);
+    }
+  }
+  // Get rid of unreferenced scripts with a global GC.
+  i::Heap::CollectAllGarbage();
+  i::Serializer ser;
+  ser.Serialize();
+  char* str;
+  int len;
+  ser.Finalize(&str, &len);
+
+  WriteInternalSnapshotToFile(argv[1], str, len);
+
+  i::DeleteArray(str);
+
+  return 0;
+}
diff --git a/regexp2000/src/natives.h b/regexp2000/src/natives.h
new file mode 100644 (file)
index 0000000..3eb8090
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_NATIVES_H_
+#define V8_NATIVES_H_
+
+namespace v8 { namespace internal {
+
+typedef bool (*NativeSourceCallback)(Vector<const char> name,
+                                     Vector<const char> source,
+                                     int index);
+
+enum NativeType {
+  CORE, D8
+};
+
+template <NativeType type>
+class NativesCollection {
+ public:
+  // Number of built-in scripts.
+  static int GetBuiltinsCount();
+  // Number of delayed/lazy loading scripts.
+  static int GetDelayCount();
+
+  // These are used to access built-in scripts.
+  // The delayed script has an index in the interval [0, GetDelayCount()).
+  // The non-delayed script has an index in the interval
+  // [GetDelayCount(), GetNativesCount()).
+  static int GetIndex(const char* name);
+  static Vector<const char> GetScriptSource(int index);
+  static Vector<const char> GetScriptName(int index);
+};
+
+typedef NativesCollection<CORE> Natives;
+
+} }  // namespace v8::internal
+
+#endif  // V8_NATIVES_H_
diff --git a/regexp2000/src/objects-debug.cc b/regexp2000/src/objects-debug.cc
new file mode 100644 (file)
index 0000000..d67544e
--- /dev/null
@@ -0,0 +1,1057 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "disassembler.h"
+#include "disasm.h"
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+#ifdef DEBUG
+
+static const char* TypeToString(InstanceType type);
+
+
+void Object::Print() {
+  if (IsSmi()) {
+    Smi::cast(this)->SmiPrint();
+  } else if (IsFailure()) {
+    Failure::cast(this)->FailurePrint();
+  } else {
+    HeapObject::cast(this)->HeapObjectPrint();
+  }
+  Flush();
+}
+
+
+void Object::PrintLn() {
+  Print();
+  PrintF("\n");
+}
+
+
+void Object::Verify() {
+  if (IsSmi()) {
+    Smi::cast(this)->SmiVerify();
+  } else if (IsFailure()) {
+    Failure::cast(this)->FailureVerify();
+  } else {
+    HeapObject::cast(this)->HeapObjectVerify();
+  }
+}
+
+
+void Object::VerifyPointer(Object* p) {
+  if (p->IsHeapObject()) {
+    HeapObject::VerifyHeapPointer(p);
+  } else {
+    ASSERT(p->IsSmi());
+  }
+}
+
+
+void Smi::SmiVerify() {
+  ASSERT(IsSmi());
+}
+
+
+void Failure::FailureVerify() {
+  ASSERT(IsFailure());
+}
+
+
+void HeapObject::PrintHeader(const char* id) {
+  PrintF("%p: [%s]\n", this, id);
+}
+
+
+void HeapObject::HeapObjectPrint() {
+  InstanceType instance_type = map()->instance_type();
+
+  HandleScope scope;
+  if (instance_type < FIRST_NONSTRING_TYPE) {
+    String::cast(this)->StringPrint();
+    return;
+  }
+
+  switch (instance_type) {
+    case MAP_TYPE:
+      Map::cast(this)->MapPrint();
+      break;
+    case HEAP_NUMBER_TYPE:
+      HeapNumber::cast(this)->HeapNumberPrint();
+      break;
+    case FIXED_ARRAY_TYPE:
+      FixedArray::cast(this)->FixedArrayPrint();
+      break;
+    case BYTE_ARRAY_TYPE:
+      ByteArray::cast(this)->ByteArrayPrint();
+      break;
+    case FILLER_TYPE:
+      PrintF("filler");
+      break;
+    case JS_OBJECT_TYPE:  // fall through
+    case JS_ARRAY_TYPE:
+    case JS_REGEXP_TYPE:
+      JSObject::cast(this)->JSObjectPrint();
+      break;
+    case ODDBALL_TYPE:
+      Oddball::cast(this)->to_string()->Print();
+      break;
+    case JS_FUNCTION_TYPE:
+      JSFunction::cast(this)->JSFunctionPrint();
+      break;
+    case JS_GLOBAL_PROXY_TYPE:
+      JSGlobalProxy::cast(this)->JSGlobalProxyPrint();
+      break;
+    case JS_GLOBAL_OBJECT_TYPE:
+      JSGlobalObject::cast(this)->JSGlobalObjectPrint();
+      break;
+    case JS_BUILTINS_OBJECT_TYPE:
+      JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint();
+      break;
+    case JS_VALUE_TYPE:
+      PrintF("Value wrapper around:");
+      JSValue::cast(this)->value()->Print();
+      break;
+    case CODE_TYPE:
+      Code::cast(this)->CodePrint();
+      break;
+    case PROXY_TYPE:
+      Proxy::cast(this)->ProxyPrint();
+      break;
+    case SHARED_FUNCTION_INFO_TYPE:
+      SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint();
+      break;
+
+#define MAKE_STRUCT_CASE(NAME, Name, name) \
+  case NAME##_TYPE:                        \
+    Name::cast(this)->Name##Print();       \
+    break;
+  STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+
+    default:
+      PrintF("UNKNOWN TYPE %d", map()->instance_type());
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void HeapObject::HeapObjectVerify() {
+  InstanceType instance_type = map()->instance_type();
+
+  if (instance_type < FIRST_NONSTRING_TYPE) {
+    String::cast(this)->StringVerify();
+    return;
+  }
+
+  switch (instance_type) {
+    case MAP_TYPE:
+      Map::cast(this)->MapVerify();
+      break;
+    case HEAP_NUMBER_TYPE:
+      HeapNumber::cast(this)->HeapNumberVerify();
+      break;
+    case FIXED_ARRAY_TYPE:
+      FixedArray::cast(this)->FixedArrayVerify();
+      break;
+    case BYTE_ARRAY_TYPE:
+      ByteArray::cast(this)->ByteArrayVerify();
+      break;
+    case CODE_TYPE:
+      Code::cast(this)->CodeVerify();
+      break;
+    case ODDBALL_TYPE:
+      Oddball::cast(this)->OddballVerify();
+      break;
+    case JS_OBJECT_TYPE:
+      JSObject::cast(this)->JSObjectVerify();
+      break;
+    case JS_VALUE_TYPE:
+      JSValue::cast(this)->JSValueVerify();
+      break;
+    case JS_FUNCTION_TYPE:
+      JSFunction::cast(this)->JSFunctionVerify();
+      break;
+    case JS_GLOBAL_PROXY_TYPE:
+      JSGlobalProxy::cast(this)->JSGlobalProxyVerify();
+      break;
+    case JS_GLOBAL_OBJECT_TYPE:
+      JSGlobalObject::cast(this)->JSGlobalObjectVerify();
+      break;
+    case JS_BUILTINS_OBJECT_TYPE:
+      JSBuiltinsObject::cast(this)->JSBuiltinsObjectVerify();
+      break;
+    case JS_ARRAY_TYPE:
+      JSArray::cast(this)->JSArrayVerify();
+      break;
+    case JS_REGEXP_TYPE:
+      JSRegExp::cast(this)->JSRegExpVerify();
+      break;
+    case FILLER_TYPE:
+      break;
+    case PROXY_TYPE:
+      Proxy::cast(this)->ProxyVerify();
+      break;
+    case SHARED_FUNCTION_INFO_TYPE:
+      SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify();
+      break;
+
+#define MAKE_STRUCT_CASE(NAME, Name, name) \
+  case NAME##_TYPE:                        \
+    Name::cast(this)->Name##Verify();      \
+    break;
+    STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void HeapObject::VerifyHeapPointer(Object* p) {
+  ASSERT(p->IsHeapObject());
+  ASSERT(Heap::Contains(HeapObject::cast(p)));
+}
+
+
+void HeapNumber::HeapNumberVerify() {
+  ASSERT(IsHeapNumber());
+}
+
+
+void ByteArray::ByteArrayPrint() {
+  PrintF("byte array, data starts at %p", GetDataStartAddress());
+}
+
+
+void ByteArray::ByteArrayVerify() {
+  ASSERT(IsByteArray());
+}
+
+
+void JSObject::PrintProperties() {
+  if (HasFastProperties()) {
+    for (DescriptorReader r(map()->instance_descriptors());
+         !r.eos();
+         r.advance()) {
+      PrintF("   ");
+      r.GetKey()->StringPrint();
+      PrintF(": ");
+      if (r.type() == FIELD) {
+        FastPropertyAt(r.GetFieldIndex())->ShortPrint();
+        PrintF(" (field at offset %d)\n", r.GetFieldIndex());
+      } else if (r.type() ==  CONSTANT_FUNCTION) {
+        r.GetConstantFunction()->ShortPrint();
+        PrintF(" (constant function)\n");
+      } else if (r.type() == CALLBACKS) {
+        r.GetCallbacksObject()->ShortPrint();
+        PrintF(" (callback)\n");
+      } else if (r.type() == MAP_TRANSITION) {
+        PrintF(" (map transition)\n");
+      } else {
+        UNREACHABLE();
+      }
+    }
+  } else {
+    property_dictionary()->Print();
+  }
+}
+
+
+void JSObject::PrintElements() {
+  if (HasFastElements()) {
+    FixedArray* p = FixedArray::cast(elements());
+    for (int i = 0; i < p->length(); i++) {
+      PrintF("   %d: ", i);
+      p->get(i)->ShortPrint();
+      PrintF("\n");
+    }
+  } else {
+    elements()->Print();
+  }
+}
+
+
+void JSObject::JSObjectPrint() {
+  PrintF("%p: [JSObject]\n", this);
+  PrintF(" - map = %p\n", map());
+  PrintF(" - prototype = %p\n", GetPrototype());
+  PrintF(" {\n");
+  PrintProperties();
+  PrintElements();
+  PrintF(" }\n");
+}
+
+
+void JSObject::JSObjectVerify() {
+  VerifyHeapPointer(properties());
+  VerifyHeapPointer(elements());
+  if (HasFastProperties()) {
+    CHECK(map()->unused_property_fields() ==
+          (map()->inobject_properties() + properties()->length() -
+           map()->NextFreePropertyIndex()));
+  }
+}
+
+
+static const char* TypeToString(InstanceType type) {
+  switch (type) {
+    case INVALID_TYPE: return "INVALID";
+    case MAP_TYPE: return "MAP";
+    case HEAP_NUMBER_TYPE: return "HEAP_NUMBER";
+    case SHORT_SYMBOL_TYPE:
+    case MEDIUM_SYMBOL_TYPE:
+    case LONG_SYMBOL_TYPE: return "SYMBOL";
+    case SHORT_ASCII_SYMBOL_TYPE:
+    case MEDIUM_ASCII_SYMBOL_TYPE:
+    case LONG_ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
+    case SHORT_SLICED_SYMBOL_TYPE:
+    case MEDIUM_SLICED_SYMBOL_TYPE:
+    case LONG_SLICED_SYMBOL_TYPE: return "SLICED_SYMBOL";
+    case SHORT_SLICED_ASCII_SYMBOL_TYPE:
+    case MEDIUM_SLICED_ASCII_SYMBOL_TYPE:
+    case LONG_SLICED_ASCII_SYMBOL_TYPE: return "SLICED_ASCII_SYMBOL";
+    case SHORT_CONS_SYMBOL_TYPE:
+    case MEDIUM_CONS_SYMBOL_TYPE:
+    case LONG_CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
+    case SHORT_CONS_ASCII_SYMBOL_TYPE:
+    case MEDIUM_CONS_ASCII_SYMBOL_TYPE:
+    case LONG_CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
+    case SHORT_EXTERNAL_ASCII_SYMBOL_TYPE:
+    case MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE:
+    case LONG_EXTERNAL_ASCII_SYMBOL_TYPE:
+    case SHORT_EXTERNAL_SYMBOL_TYPE:
+    case MEDIUM_EXTERNAL_SYMBOL_TYPE:
+    case LONG_EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
+    case SHORT_ASCII_STRING_TYPE:
+    case MEDIUM_ASCII_STRING_TYPE:
+    case LONG_ASCII_STRING_TYPE: return "ASCII_STRING";
+    case SHORT_STRING_TYPE:
+    case MEDIUM_STRING_TYPE:
+    case LONG_STRING_TYPE: return "TWO_BYTE_STRING";
+    case SHORT_CONS_STRING_TYPE:
+    case MEDIUM_CONS_STRING_TYPE:
+    case LONG_CONS_STRING_TYPE:
+    case SHORT_CONS_ASCII_STRING_TYPE:
+    case MEDIUM_CONS_ASCII_STRING_TYPE:
+    case LONG_CONS_ASCII_STRING_TYPE: return "CONS_STRING";
+    case SHORT_SLICED_STRING_TYPE:
+    case MEDIUM_SLICED_STRING_TYPE:
+    case LONG_SLICED_STRING_TYPE:
+    case SHORT_SLICED_ASCII_STRING_TYPE:
+    case MEDIUM_SLICED_ASCII_STRING_TYPE:
+    case LONG_SLICED_ASCII_STRING_TYPE: return "SLICED_STRING";
+    case SHORT_EXTERNAL_ASCII_STRING_TYPE:
+    case MEDIUM_EXTERNAL_ASCII_STRING_TYPE:
+    case LONG_EXTERNAL_ASCII_STRING_TYPE:
+    case SHORT_EXTERNAL_STRING_TYPE:
+    case MEDIUM_EXTERNAL_STRING_TYPE:
+    case LONG_EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
+    case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
+    case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
+    case FILLER_TYPE: return "FILLER";
+    case JS_OBJECT_TYPE: return "JS_OBJECT";
+    case ODDBALL_TYPE: return "ODDBALL";
+    case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO";
+    case JS_FUNCTION_TYPE: return "JS_FUNCTION";
+    case CODE_TYPE: return "CODE";
+    case JS_ARRAY_TYPE: return "JS_ARRAY";
+    case JS_REGEXP_TYPE: return "JS_REGEXP";
+    case JS_VALUE_TYPE: return "JS_VALUE";
+    case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT";
+    case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT";
+    case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY";
+    case PROXY_TYPE: return "PROXY";
+    case SMI_TYPE: return "SMI";
+#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME;
+  STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+  }
+  return "UNKNOWN";
+}
+
+
+void Map::MapPrint() {
+  HeapObject::PrintHeader("Map");
+  PrintF(" - type: %s\n", TypeToString(instance_type()));
+  PrintF(" - instance size: %d\n", instance_size());
+  PrintF(" - unused property fields: %d\n", unused_property_fields());
+  PrintF(" - instance descriptors: ");
+  instance_descriptors()->ShortPrint();
+  PrintF("\n - prototype: ");
+  prototype()->ShortPrint();
+  PrintF("\n - constructor: ");
+  constructor()->ShortPrint();
+  PrintF("\n");
+}
+
+
+void Map::MapVerify() {
+  ASSERT(!Heap::InNewSpace(this));
+  ASSERT(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE);
+  ASSERT(kPointerSize <= instance_size()
+         && instance_size() < Heap::Capacity());
+  VerifyHeapPointer(prototype());
+  VerifyHeapPointer(instance_descriptors());
+}
+
+
+void FixedArray::FixedArrayPrint() {
+  HeapObject::PrintHeader("FixedArray");
+  PrintF(" - length: %d", length());
+  for (int i = 0; i < length(); i++) {
+    PrintF("\n  [%d]: ", i);
+    get(i)->ShortPrint();
+  }
+  PrintF("\n");
+}
+
+
+void FixedArray::FixedArrayVerify() {
+  for (int i = 0; i < length(); i++) {
+    Object* e = get(i);
+    if (e->IsHeapObject()) {
+      VerifyHeapPointer(e);
+    } else {
+      e->Verify();
+    }
+  }
+}
+
+
+void JSValue::JSValuePrint() {
+  HeapObject::PrintHeader("ValueObject");
+  value()->Print();
+}
+
+
+void JSValue::JSValueVerify() {
+  Object* v = value();
+  if (v->IsHeapObject()) {
+    VerifyHeapPointer(v);
+  }
+}
+
+
+void String::StringPrint() {
+  if (IsSymbol()) {
+    PrintF("#");
+  } else if (IsConsString()) {
+    PrintF("c\"");
+  } else {
+    PrintF("\"");
+  }
+
+  for (int i = 0; i < length(); i++) {
+    PrintF("%c", Get(i));
+  }
+
+  if (!IsSymbol()) PrintF("\"");
+}
+
+
+void String::StringVerify() {
+  CHECK(IsString());
+  CHECK(length() >= 0 && length() <= Smi::kMaxValue);
+  if (IsSymbol()) {
+    CHECK(!Heap::InNewSpace(this));
+  }
+}
+
+
+void JSFunction::JSFunctionPrint() {
+  HeapObject::PrintHeader("Function");
+  PrintF(" - map = 0x%p\n", map());
+  PrintF(" - is boilerplate: %s\n", IsBoilerplate() ? "yes" : "no");
+  PrintF(" - initial_map = ");
+  if (has_initial_map()) {
+    initial_map()->ShortPrint();
+  }
+  PrintF("\n - shared_info = ");
+  shared()->ShortPrint();
+  PrintF("\n   - name = ");
+  shared()->name()->Print();
+  PrintF("\n - context = ");
+  unchecked_context()->ShortPrint();
+  PrintF("\n - code = ");
+  code()->ShortPrint();
+  PrintF("\n");
+
+  PrintProperties();
+  PrintElements();
+
+  PrintF("\n");
+}
+
+
+void JSFunction::JSFunctionVerify() {
+  CHECK(IsJSFunction());
+  VerifyObjectField(kPrototypeOrInitialMapOffset);
+}
+
+
+void SharedFunctionInfo::SharedFunctionInfoPrint() {
+  HeapObject::PrintHeader("SharedFunctionInfo");
+  PrintF(" - name: ");
+  name()->ShortPrint();
+  PrintF("\n - expected_nof_properties: %d", expected_nof_properties());
+  PrintF("\n - instance class name =");
+  instance_class_name()->Print();
+  PrintF("\n - code =");
+  code()->ShortPrint();
+  PrintF("\n - source code =");
+  GetSourceCode()->ShortPrint();
+  PrintF("\n - lazy load: %s",
+         lazy_load_data() == Heap::undefined_value() ? "no" : "yes");
+  // Script files are often large, hard to read.
+  // PrintF("\n - script =");
+  // script()->Print();
+  PrintF("\n - function token position = %d", function_token_position());
+  PrintF("\n - start position = %d", start_position());
+  PrintF("\n - end position = %d", end_position());
+  PrintF("\n - is expression = %d", is_expression());
+  PrintF("\n - debug info = ");
+  debug_info()->Print();
+  PrintF("\n - length = %d", length());
+  PrintF("\n");
+}
+
+void SharedFunctionInfo::SharedFunctionInfoVerify() {
+  CHECK(IsSharedFunctionInfo());
+  VerifyObjectField(kNameOffset);
+  VerifyObjectField(kCodeOffset);
+  VerifyObjectField(kInstanceClassNameOffset);
+  VerifyObjectField(kExternalReferenceDataOffset);
+  VerifyObjectField(kLazyLoadDataOffset);
+  VerifyObjectField(kScriptOffset);
+  VerifyObjectField(kDebugInfoOffset);
+}
+
+
+void JSGlobalProxy::JSGlobalProxyPrint() {
+  PrintF("global_proxy");
+  JSObjectPrint();
+  PrintF("context : ");
+  context()->ShortPrint();
+  PrintF("\n");
+}
+
+
+void JSGlobalProxy::JSGlobalProxyVerify() {
+  CHECK(IsJSGlobalProxy());
+  JSObjectVerify();
+  VerifyObjectField(JSGlobalProxy::kContextOffset);
+  // Make sure that this object has no properties, elements.
+  CHECK_EQ(0, properties()->length());
+  CHECK_EQ(0, elements()->length());
+}
+
+
+void JSGlobalObject::JSGlobalObjectPrint() {
+  PrintF("global ");
+  JSObjectPrint();
+  PrintF("global context : ");
+  global_context()->ShortPrint();
+  PrintF("\n");
+}
+
+
+void JSGlobalObject::JSGlobalObjectVerify() {
+  CHECK(IsJSGlobalObject());
+  JSObjectVerify();
+  for (int i = GlobalObject::kBuiltinsOffset;
+       i < JSGlobalObject::kSize;
+       i += kPointerSize) {
+    VerifyObjectField(i);
+  }
+}
+
+
+void JSBuiltinsObject::JSBuiltinsObjectPrint() {
+  PrintF("builtins ");
+  JSObjectPrint();
+}
+
+
+void JSBuiltinsObject::JSBuiltinsObjectVerify() {
+  CHECK(IsJSBuiltinsObject());
+  JSObjectVerify();
+  for (int i = GlobalObject::kBuiltinsOffset;
+       i < JSBuiltinsObject::kSize;
+       i += kPointerSize) {
+    VerifyObjectField(i);
+  }
+}
+
+
+void Oddball::OddballVerify() {
+  CHECK(IsOddball());
+  VerifyHeapPointer(to_string());
+  Object* number = to_number();
+  if (number->IsHeapObject()) {
+    ASSERT(number == Heap::nan_value());
+  } else {
+    ASSERT(number->IsSmi());
+    int value = Smi::cast(number)->value();
+    ASSERT(value == 0 || value == 1 || value == -1);
+  }
+}
+
+
+void Code::CodePrint() {
+  HeapObject::PrintHeader("Code");
+#ifdef ENABLE_DISASSEMBLER
+  Disassemble();
+#endif
+}
+
+
+void Code::CodeVerify() {
+  CHECK(ic_flag() == IC_TARGET_IS_ADDRESS);
+  Address last_gc_pc = NULL;
+  for (RelocIterator it(this); !it.done(); it.next()) {
+    it.rinfo()->Verify();
+    // Ensure that GC will not iterate twice over the same pointer.
+    if (RelocInfo::IsGCRelocMode(it.rinfo()->rmode())) {
+      CHECK(it.rinfo()->pc() != last_gc_pc);
+      last_gc_pc = it.rinfo()->pc();
+    }
+  }
+}
+
+
+void JSArray::JSArrayVerify() {
+  JSObjectVerify();
+  ASSERT(length()->IsNumber() || length()->IsUndefined());
+  ASSERT(elements()->IsUndefined() || elements()->IsFixedArray());
+}
+
+
+void JSRegExp::JSRegExpVerify() {
+  JSObjectVerify();
+  ASSERT(data()->IsUndefined() || data()->IsFixedArray());
+  switch (TypeTag()) {
+    case JSRegExp::ATOM: {
+      FixedArray* arr = FixedArray::cast(data());
+      ASSERT(arr->get(JSRegExp::kAtomPatternIndex)->IsString());
+      break;
+    }
+    case JSRegExp::JSCRE: {
+      FixedArray* arr = FixedArray::cast(data());
+      ASSERT(arr->get(JSRegExp::kJscreDataIndex)->IsFixedArray());
+      break;
+    }
+    default:
+      ASSERT_EQ(JSRegExp::NOT_COMPILED, TypeTag());
+      ASSERT(data()->IsUndefined());
+      break;
+  }
+}
+
+
+void Proxy::ProxyPrint() {
+  PrintF("proxy to %p", proxy());
+}
+
+
+void Proxy::ProxyVerify() {
+  ASSERT(IsProxy());
+}
+
+
+void Dictionary::Print() {
+  int capacity = Capacity();
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k)) {
+      PrintF(" ");
+      if (k->IsString()) {
+        String::cast(k)->StringPrint();
+      } else {
+        k->ShortPrint();
+      }
+      PrintF(": ");
+      ValueAt(i)->ShortPrint();
+      PrintF("\n");
+    }
+  }
+}
+
+
+void AccessorInfo::AccessorInfoVerify() {
+  CHECK(IsAccessorInfo());
+  VerifyPointer(getter());
+  VerifyPointer(setter());
+  VerifyPointer(name());
+  VerifyPointer(data());
+  VerifyPointer(flag());
+}
+
+void AccessorInfo::AccessorInfoPrint() {
+  PrintF("AccessorInfo");
+  PrintF("\n - getter: ");
+  getter()->ShortPrint();
+  PrintF("\n - setter: ");
+  setter()->ShortPrint();
+  PrintF("\n - name: ");
+  name()->ShortPrint();
+  PrintF("\n - data: ");
+  data()->ShortPrint();
+  PrintF("\n - flag: ");
+  flag()->ShortPrint();
+}
+
+void AccessCheckInfo::AccessCheckInfoVerify() {
+  CHECK(IsAccessCheckInfo());
+  VerifyPointer(named_callback());
+  VerifyPointer(indexed_callback());
+  VerifyPointer(data());
+}
+
+void AccessCheckInfo::AccessCheckInfoPrint() {
+  PrintF("AccessCheckInfo");
+  PrintF("\n - named_callback: ");
+  named_callback()->ShortPrint();
+  PrintF("\n - indexed_callback: ");
+  indexed_callback()->ShortPrint();
+  PrintF("\n - data: ");
+  data()->ShortPrint();
+}
+
+void InterceptorInfo::InterceptorInfoVerify() {
+  CHECK(IsInterceptorInfo());
+  VerifyPointer(getter());
+  VerifyPointer(setter());
+  VerifyPointer(query());
+  VerifyPointer(deleter());
+  VerifyPointer(enumerator());
+  VerifyPointer(data());
+}
+
+void InterceptorInfo::InterceptorInfoPrint() {
+  PrintF("InterceptorInfo");
+  PrintF("\n - getter: ");
+  getter()->ShortPrint();
+  PrintF("\n - setter: ");
+  setter()->ShortPrint();
+  PrintF("\n - query: ");
+  query()->ShortPrint();
+  PrintF("\n - deleter: ");
+  deleter()->ShortPrint();
+  PrintF("\n - enumerator: ");
+  enumerator()->ShortPrint();
+  PrintF("\n - data: ");
+  data()->ShortPrint();
+}
+
+void CallHandlerInfo::CallHandlerInfoVerify() {
+  CHECK(IsCallHandlerInfo());
+  VerifyPointer(callback());
+  VerifyPointer(data());
+}
+
+void CallHandlerInfo::CallHandlerInfoPrint() {
+  PrintF("CallHandlerInfo");
+  PrintF("\n - callback: ");
+  callback()->ShortPrint();
+  PrintF("\n - data: ");
+  data()->ShortPrint();
+}
+
+void TemplateInfo::TemplateInfoVerify() {
+  VerifyPointer(tag());
+  VerifyPointer(property_list());
+}
+
+void FunctionTemplateInfo::FunctionTemplateInfoVerify() {
+  CHECK(IsFunctionTemplateInfo());
+  TemplateInfoVerify();
+  VerifyPointer(serial_number());
+  VerifyPointer(call_code());
+  VerifyPointer(property_accessors());
+  VerifyPointer(prototype_template());
+  VerifyPointer(parent_template());
+  VerifyPointer(named_property_handler());
+  VerifyPointer(indexed_property_handler());
+  VerifyPointer(instance_template());
+  VerifyPointer(signature());
+  VerifyPointer(access_check_info());
+}
+
+void FunctionTemplateInfo::FunctionTemplateInfoPrint() {
+  PrintF("FunctionTemplateInfo");
+  PrintF("\n - tag: ");
+  tag()->ShortPrint();
+  PrintF("\n - property_list: ");
+  property_list()->ShortPrint();
+  PrintF("\n - serial_number: ");
+  serial_number()->ShortPrint();
+  PrintF("\n - call_code: ");
+  call_code()->ShortPrint();
+  PrintF("\n - property_accessors: ");
+  property_accessors()->ShortPrint();
+  PrintF("\n - prototype_template: ");
+  prototype_template()->ShortPrint();
+  PrintF("\n - parent_template: ");
+  parent_template()->ShortPrint();
+  PrintF("\n - named_property_handler: ");
+  named_property_handler()->ShortPrint();
+  PrintF("\n - indexed_property_handler: ");
+  indexed_property_handler()->ShortPrint();
+  PrintF("\n - instance_template: ");
+  instance_template()->ShortPrint();
+  PrintF("\n - signature: ");
+  signature()->ShortPrint();
+  PrintF("\n - access_check_info: ");
+  access_check_info()->ShortPrint();
+  PrintF("\n - hidden_prototype: %s", hidden_prototype() ? "true" : "false");
+  PrintF("\n - undetectable: %s", undetectable() ? "true" : "false");
+  PrintF("\n - need_access_check: %s", needs_access_check() ? "true" : "false");
+}
+
+void ObjectTemplateInfo::ObjectTemplateInfoVerify() {
+  CHECK(IsObjectTemplateInfo());
+  TemplateInfoVerify();
+  VerifyPointer(constructor());
+  VerifyPointer(internal_field_count());
+}
+
+void ObjectTemplateInfo::ObjectTemplateInfoPrint() {
+  PrintF("ObjectTemplateInfo");
+  PrintF("\n - constructor: ");
+  constructor()->ShortPrint();
+  PrintF("\n - internal_field_count: ");
+  internal_field_count()->ShortPrint();
+}
+
+void SignatureInfo::SignatureInfoVerify() {
+  CHECK(IsSignatureInfo());
+  VerifyPointer(receiver());
+  VerifyPointer(args());
+}
+
+void SignatureInfo::SignatureInfoPrint() {
+  PrintF("SignatureInfo");
+  PrintF("\n - receiver: ");
+  receiver()->ShortPrint();
+  PrintF("\n - args: ");
+  args()->ShortPrint();
+}
+
+void TypeSwitchInfo::TypeSwitchInfoVerify() {
+  CHECK(IsTypeSwitchInfo());
+  VerifyPointer(types());
+}
+
+void TypeSwitchInfo::TypeSwitchInfoPrint() {
+  PrintF("TypeSwitchInfo");
+  PrintF("\n - types: ");
+  types()->ShortPrint();
+}
+
+
+void Script::ScriptVerify() {
+  CHECK(IsScript());
+  VerifyPointer(source());
+  VerifyPointer(name());
+  line_offset()->SmiVerify();
+  column_offset()->SmiVerify();
+  type()->SmiVerify();
+}
+
+
+void Script::ScriptPrint() {
+  HeapObject::PrintHeader("Script");
+  PrintF("\n - source: ");
+  source()->ShortPrint();
+  PrintF("\n - name: ");
+  name()->ShortPrint();
+  PrintF("\n - line_offset: ");
+  line_offset()->ShortPrint();
+  PrintF("\n - column_offset: ");
+  column_offset()->ShortPrint();
+  PrintF("\n - type: ");
+  type()->ShortPrint();
+  PrintF("\n");
+}
+
+
+void DebugInfo::DebugInfoVerify() {
+  CHECK(IsDebugInfo());
+  VerifyPointer(shared());
+  VerifyPointer(original_code());
+  VerifyPointer(code());
+  VerifyPointer(break_points());
+}
+
+
+void DebugInfo::DebugInfoPrint() {
+  PrintF("DebugInfo");
+  PrintF("\n - shared");
+  shared()->ShortPrint();
+  PrintF("\n - original_code");
+  original_code()->ShortPrint();
+  PrintF("\n - code");
+  code()->ShortPrint();
+  PrintF("\n - break_points");
+  break_points()->ShortPrint();
+}
+
+
+void BreakPointInfo::BreakPointInfoVerify() {
+  CHECK(IsBreakPointInfo());
+  code_position()->SmiVerify();
+  source_position()->SmiVerify();
+  statement_position()->SmiVerify();
+  VerifyPointer(break_point_objects());
+}
+
+
+void BreakPointInfo::BreakPointInfoPrint() {
+  PrintF("BreakPointInfo");
+  PrintF("\n - code_position %d", code_position());
+  PrintF("\n - source_position %d", source_position());
+  PrintF("\n - statement_position %d", statement_position());
+  PrintF("\n - break_point_objects ");
+  break_point_objects()->ShortPrint();
+}
+
+
+void JSObject::IncrementSpillStatistics(SpillInformation* info) {
+  info->number_of_objects_++;
+  // Named properties
+  if (HasFastProperties()) {
+    info->number_of_objects_with_fast_properties_++;
+    info->number_of_fast_used_fields_   += map()->NextFreePropertyIndex();
+    info->number_of_fast_unused_fields_ += map()->unused_property_fields();
+  } else {
+    Dictionary* dict = property_dictionary();
+    info->number_of_slow_used_properties_ += dict->NumberOfElements();
+    info->number_of_slow_unused_properties_ +=
+        dict->Capacity() - dict->NumberOfElements();
+  }
+  // Indexed properties
+  if (HasFastElements()) {
+    info->number_of_objects_with_fast_elements_++;
+    int holes = 0;
+    FixedArray* e = FixedArray::cast(elements());
+    int len = e->length();
+    for (int i = 0; i < len; i++) {
+      if (e->get(i) == Heap::the_hole_value()) holes++;
+    }
+    info->number_of_fast_used_elements_   += len - holes;
+    info->number_of_fast_unused_elements_ += holes;
+  } else {
+    Dictionary* dict = element_dictionary();
+    info->number_of_slow_used_elements_ += dict->NumberOfElements();
+    info->number_of_slow_unused_elements_ +=
+        dict->Capacity() - dict->NumberOfElements();
+  }
+}
+
+
+void JSObject::SpillInformation::Clear() {
+  number_of_objects_ = 0;
+  number_of_objects_with_fast_properties_ = 0;
+  number_of_objects_with_fast_elements_ = 0;
+  number_of_fast_used_fields_ = 0;
+  number_of_fast_unused_fields_ = 0;
+  number_of_slow_used_properties_ = 0;
+  number_of_slow_unused_properties_ = 0;
+  number_of_fast_used_elements_ = 0;
+  number_of_fast_unused_elements_ = 0;
+  number_of_slow_used_elements_ = 0;
+  number_of_slow_unused_elements_ = 0;
+}
+
+void JSObject::SpillInformation::Print() {
+  PrintF("\n  JSObject Spill Statistics (#%d):\n", number_of_objects_);
+
+  PrintF("    - fast properties (#%d): %d (used) %d (unused)\n",
+         number_of_objects_with_fast_properties_,
+         number_of_fast_used_fields_, number_of_fast_unused_fields_);
+
+  PrintF("    - slow properties (#%d): %d (used) %d (unused)\n",
+         number_of_objects_ - number_of_objects_with_fast_properties_,
+         number_of_slow_used_properties_, number_of_slow_unused_properties_);
+
+  PrintF("    - fast elements (#%d): %d (used) %d (unused)\n",
+         number_of_objects_with_fast_elements_,
+         number_of_fast_used_elements_, number_of_fast_unused_elements_);
+
+  PrintF("    - slow elements (#%d): %d (used) %d (unused)\n",
+         number_of_objects_ - number_of_objects_with_fast_elements_,
+         number_of_slow_used_elements_, number_of_slow_unused_elements_);
+
+  PrintF("\n");
+}
+
+
+void DescriptorArray::PrintDescriptors() {
+  PrintF("Descriptor array  %d\n", number_of_descriptors());
+  int number = 0;
+  for (DescriptorReader r(this); !r.eos(); r.advance()) {
+    Descriptor desc;
+    r.Get(&desc);
+    PrintF(" %d: ", number++);
+    desc.Print();
+  }
+  PrintF("\n");
+}
+
+
+bool DescriptorArray::IsSortedNoDuplicates() {
+  String* current_key = NULL;
+  uint32_t current = 0;
+  for (DescriptorReader r(this); !r.eos(); r.advance()) {
+    String* key = r.GetKey();
+    if (key == current_key) {
+      PrintDescriptors();
+      return false;
+    }
+    current_key = key;
+    uint32_t hash = r.GetKey()->Hash();
+    if (hash < current) {
+      PrintDescriptors();
+      return false;
+    }
+    current = hash;
+  }
+  return true;
+}
+
+
+#endif  // DEBUG
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/objects-inl.h b/regexp2000/src/objects-inl.h
new file mode 100644 (file)
index 0000000..33bca56
--- /dev/null
@@ -0,0 +1,2393 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Review notes:
+//
+// - The use of macros in these inline fuctions may seem superfluous
+// but it is absolutely needed to make sure gcc generates optimal
+// code. gcc is not happy when attempting to inline too deep.
+//
+
+#ifndef V8_OBJECTS_INL_H_
+#define V8_OBJECTS_INL_H_
+
+#include "objects.h"
+#include "contexts.h"
+#include "conversions-inl.h"
+#include "property.h"
+
+namespace v8 { namespace internal {
+
+PropertyDetails::PropertyDetails(Smi* smi) {
+  value_ = smi->value();
+}
+
+
+Smi* PropertyDetails::AsSmi() {
+  return Smi::FromInt(value_);
+}
+
+
+#define CAST_ACCESSOR(type)                     \
+  type* type::cast(Object* object) {            \
+    ASSERT(object->Is##type());                 \
+    return reinterpret_cast<type*>(object);     \
+  }
+
+
+#define INT_ACCESSORS(holder, name, offset)                             \
+  int holder::name() { return READ_INT_FIELD(this, offset); }           \
+  void holder::set_##name(int value) { WRITE_INT_FIELD(this, offset, value); }
+
+
+#define ACCESSORS(holder, name, type, offset)                           \
+  type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \
+  void holder::set_##name(type* value, WriteBarrierMode mode) {         \
+    WRITE_FIELD(this, offset, value);                                   \
+    CONDITIONAL_WRITE_BARRIER(this, offset, mode);                      \
+  }
+
+
+
+#define SMI_ACCESSORS(holder, name, offset)             \
+  int holder::name() {                                  \
+    Object* value = READ_FIELD(this, offset);           \
+    return Smi::cast(value)->value();                   \
+  }                                                     \
+  void holder::set_##name(int value) {                  \
+    WRITE_FIELD(this, offset, Smi::FromInt(value));     \
+  }
+
+
+#define BOOL_ACCESSORS(holder, field, name, offset) \
+  bool holder::name() {                                    \
+    return BooleanBit::get(field(), offset);               \
+  }                                                        \
+  void holder::set_##name(bool value) {                    \
+    set_##field(BooleanBit::set(field(), offset, value));  \
+  }
+
+
+bool Object::IsSmi() {
+  return HAS_SMI_TAG(this);
+}
+
+
+bool Object::IsHeapObject() {
+  return HAS_HEAP_OBJECT_TAG(this);
+}
+
+
+bool Object::IsHeapNumber() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == HEAP_NUMBER_TYPE;
+}
+
+
+bool Object::IsString() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() < FIRST_NONSTRING_TYPE;
+}
+
+
+bool Object::IsSeqString() {
+  return IsString()
+    && (String::cast(this)->representation_tag() == kSeqStringTag);
+}
+
+
+bool Object::IsSeqAsciiString() {
+  return IsSeqString()
+      && String::cast(this)->IsAsciiRepresentation();
+}
+
+
+bool String::IsSeqAsciiString() {
+  return (this->representation_tag() == kSeqStringTag)
+    && is_ascii_representation();
+}
+
+
+bool Object::IsSeqTwoByteString() {
+  return IsSeqString()
+      && !String::cast(this)->IsAsciiRepresentation();
+}
+
+
+bool Object::IsAsciiStringRepresentation() {
+  return IsString() && (String::cast(this)->is_ascii_representation());
+}
+
+
+bool Object::IsTwoByteStringRepresentation() {
+  return IsString() && (!String::cast(this)->is_ascii_representation());
+}
+
+
+bool Object::IsConsString() {
+  return IsString()
+    && (String::cast(this)->representation_tag() == kConsStringTag);
+}
+
+
+bool Object::IsSlicedString() {
+  return IsString()
+    && (String::cast(this)->representation_tag() == kSlicedStringTag);
+}
+
+
+bool Object::IsExternalString() {
+  return IsString()
+    && (String::cast(this)->representation_tag() == kExternalStringTag);
+}
+
+
+bool Object::IsExternalAsciiString() {
+  return IsExternalString() && (String::cast(this)->is_ascii_representation());
+}
+
+
+bool Object::IsExternalTwoByteString() {
+  return IsExternalString() && (!String::cast(this)->is_ascii_representation());
+}
+
+
+bool Object::IsShortString() {
+  return IsString() && (String::cast(this)->size_tag() == kShortStringTag);
+}
+
+
+bool Object::IsMediumString() {
+  return IsString() && (String::cast(this)->size_tag() == kMediumStringTag);
+}
+
+
+bool Object::IsLongString() {
+  return IsString() && (String::cast(this)->size_tag() == kLongStringTag);
+}
+
+
+bool Object::IsSymbol() {
+  return IsString() && (String::cast(this)->is_symbol());
+}
+
+
+bool Object::IsNumber() {
+  return IsSmi() || IsHeapNumber();
+}
+
+
+bool Object::IsByteArray() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == BYTE_ARRAY_TYPE;
+}
+
+
+bool Object::IsFailure() {
+  return HAS_FAILURE_TAG(this);
+}
+
+
+bool Object::IsRetryAfterGC() {
+  return HAS_FAILURE_TAG(this)
+    && Failure::cast(this)->type() == Failure::RETRY_AFTER_GC;
+}
+
+
+bool Object::IsOutOfMemoryFailure() {
+  return HAS_FAILURE_TAG(this)
+    && Failure::cast(this)->IsOutOfMemoryException();
+}
+
+
+bool Object::IsException() {
+  return this == Failure::Exception();
+}
+
+
+bool Object::IsJSObject() {
+  return IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE;
+}
+
+
+bool Object::IsMap() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == MAP_TYPE;
+}
+
+
+bool Object::IsFixedArray() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE;
+}
+
+
+bool Object::IsDescriptorArray() {
+  return IsFixedArray();
+}
+
+
+bool Object::IsContext() {
+  return Object::IsHeapObject()
+    && (HeapObject::cast(this)->map() == Heap::context_map() ||
+        HeapObject::cast(this)->map() == Heap::global_context_map());
+}
+
+
+bool Object::IsGlobalContext() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map() == Heap::global_context_map();
+}
+
+
+bool Object::IsJSFunction() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE;
+}
+
+
+template <> inline bool Is<JSFunction>(Object* obj) {
+  return obj->IsJSFunction();
+}
+
+
+bool Object::IsCode() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == CODE_TYPE;
+}
+
+
+bool Object::IsOddball() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == ODDBALL_TYPE;
+}
+
+
+bool Object::IsSharedFunctionInfo() {
+  return Object::IsHeapObject() &&
+      (HeapObject::cast(this)->map()->instance_type() ==
+       SHARED_FUNCTION_INFO_TYPE);
+}
+
+
+bool Object::IsJSValue() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE;
+}
+
+
+bool Object::IsProxy() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE;
+}
+
+
+bool Object::IsBoolean() {
+  return IsTrue() || IsFalse();
+}
+
+
+bool Object::IsJSArray() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE;
+}
+
+
+bool Object::IsJSRegExp() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE;
+}
+
+
+template <> inline bool Is<JSArray>(Object* obj) {
+  return obj->IsJSArray();
+}
+
+
+bool Object::IsHashTable() {
+  return Object::IsHeapObject()
+    && HeapObject::cast(this)->map() == Heap::hash_table_map();
+}
+
+
+bool Object::IsDictionary() {
+  return IsHashTable() && this != Heap::symbol_table();
+}
+
+
+bool Object::IsSymbolTable() {
+  return IsHashTable() && this == Heap::symbol_table();
+}
+
+
+bool Object::IsCompilationCacheTable() {
+  return IsHashTable();
+}
+
+
+bool Object::IsMapCache() {
+  return IsHashTable();
+}
+
+
+bool Object::IsLookupCache() {
+  return IsHashTable();
+}
+
+
+bool Object::IsPrimitive() {
+  return IsOddball() || IsNumber() || IsString();
+}
+
+
+bool Object::IsJSGlobalProxy() {
+  bool result = IsHeapObject() &&
+                (HeapObject::cast(this)->map()->instance_type() ==
+                 JS_GLOBAL_PROXY_TYPE);
+  ASSERT(!result || IsAccessCheckNeeded());
+  return result;
+}
+
+
+bool Object::IsGlobalObject() {
+  if (!IsHeapObject()) return false;
+
+  InstanceType type =  HeapObject::cast(this)->map()->instance_type();
+  return type == JS_GLOBAL_OBJECT_TYPE ||
+         type == JS_BUILTINS_OBJECT_TYPE;
+}
+
+
+bool Object::IsJSGlobalObject() {
+  return IsHeapObject() &&
+      (HeapObject::cast(this)->map()->instance_type() ==
+       JS_GLOBAL_OBJECT_TYPE);
+}
+
+
+bool Object::IsJSBuiltinsObject() {
+  return IsHeapObject() &&
+      (HeapObject::cast(this)->map()->instance_type() ==
+       JS_BUILTINS_OBJECT_TYPE);
+}
+
+
+bool Object::IsUndetectableObject() {
+  return IsHeapObject()
+    && HeapObject::cast(this)->map()->is_undetectable();
+}
+
+
+bool Object::IsAccessCheckNeeded() {
+  return IsHeapObject()
+    && HeapObject::cast(this)->map()->is_access_check_needed();
+}
+
+
+bool Object::IsStruct() {
+  if (!IsHeapObject()) return false;
+  switch (HeapObject::cast(this)->map()->instance_type()) {
+#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return true;
+  STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+    default: return false;
+  }
+}
+
+
+#define MAKE_STRUCT_PREDICATE(NAME, Name, name)                  \
+  bool Object::Is##Name() {                                      \
+    return Object::IsHeapObject()                                \
+      && HeapObject::cast(this)->map()->instance_type() == NAME##_TYPE; \
+  }
+  STRUCT_LIST(MAKE_STRUCT_PREDICATE)
+#undef MAKE_STRUCT_PREDICATE
+
+
+bool Object::IsUndefined() {
+  return this == Heap::undefined_value();
+}
+
+
+bool Object::IsTheHole() {
+  return this == Heap::the_hole_value();
+}
+
+
+bool Object::IsNull() {
+  return this == Heap::null_value();
+}
+
+
+bool Object::IsTrue() {
+  return this == Heap::true_value();
+}
+
+
+bool Object::IsFalse() {
+  return this == Heap::false_value();
+}
+
+
+double Object::Number() {
+  ASSERT(IsNumber());
+  return IsSmi()
+    ? static_cast<double>(reinterpret_cast<Smi*>(this)->value())
+    : reinterpret_cast<HeapNumber*>(this)->value();
+}
+
+
+
+Object* Object::ToSmi() {
+  if (IsSmi()) return this;
+  if (IsHeapNumber()) {
+    double value = HeapNumber::cast(this)->value();
+    int int_value = FastD2I(value);
+    if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
+      return Smi::FromInt(int_value);
+    }
+  }
+  return Failure::Exception();
+}
+
+
+bool Object::HasSpecificClassOf(String* name) {
+  return this->IsJSObject() && (JSObject::cast(this)->class_name() == name);
+}
+
+
+Object* Object::GetElement(uint32_t index) {
+  return GetElementWithReceiver(this, index);
+}
+
+
+Object* Object::GetProperty(String* key) {
+  PropertyAttributes attributes;
+  return GetPropertyWithReceiver(this, key, &attributes);
+}
+
+
+Object* Object::GetProperty(String* key, PropertyAttributes* attributes) {
+  return GetPropertyWithReceiver(this, key, attributes);
+}
+
+
+#define FIELD_ADDR(p, offset) \
+  (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
+
+#define READ_FIELD(p, offset) \
+  (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)))
+
+#define WRITE_FIELD(p, offset, value) \
+  (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)
+
+
+#define WRITE_BARRIER(object, offset) \
+  Heap::RecordWrite(object->address(), offset);
+
+// CONDITIONAL_WRITE_BARRIER must be issued after the actual
+// write due to the assert validating the written value.
+#define CONDITIONAL_WRITE_BARRIER(object, offset, mode) \
+  if (mode == UPDATE_WRITE_BARRIER) { \
+    Heap::RecordWrite(object->address(), offset); \
+  } else { \
+    ASSERT(mode == SKIP_WRITE_BARRIER); \
+    ASSERT(Heap::InNewSpace(object) || \
+           !Heap::InNewSpace(READ_FIELD(object, offset))); \
+  }
+
+#define READ_DOUBLE_FIELD(p, offset) \
+  (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)))
+
+#define WRITE_DOUBLE_FIELD(p, offset, value) \
+  (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)) = value)
+
+#define READ_INT_FIELD(p, offset) \
+  (*reinterpret_cast<int*>(FIELD_ADDR(p, offset)))
+
+#define WRITE_INT_FIELD(p, offset, value) \
+  (*reinterpret_cast<int*>(FIELD_ADDR(p, offset)) = value)
+
+#define READ_UINT32_FIELD(p, offset) \
+  (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset)))
+
+#define WRITE_UINT32_FIELD(p, offset, value) \
+  (*reinterpret_cast<uint32_t*>(FIELD_ADDR(p, offset)) = value)
+
+#define READ_SHORT_FIELD(p, offset) \
+  (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset)))
+
+#define WRITE_SHORT_FIELD(p, offset, value) \
+  (*reinterpret_cast<uint16_t*>(FIELD_ADDR(p, offset)) = value)
+
+#define READ_BYTE_FIELD(p, offset) \
+  (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset)))
+
+#define WRITE_BYTE_FIELD(p, offset, value) \
+  (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset)) = value)
+
+
+Object* HeapObject::GetHeapObjectField(HeapObject* obj, int index) {
+  return READ_FIELD(obj, HeapObject::kHeaderSize + kPointerSize * index);
+}
+
+
+int Smi::value() {
+  return reinterpret_cast<int>(this) >> kSmiTagSize;
+}
+
+
+Smi* Smi::FromInt(int value) {
+  ASSERT(Smi::IsValid(value));
+  return reinterpret_cast<Smi*>((value << kSmiTagSize) | kSmiTag);
+}
+
+
+Failure::Type Failure::type() const {
+  return static_cast<Type>(value() & kFailureTypeTagMask);
+}
+
+
+bool Failure::IsInternalError() const {
+  return type() == INTERNAL_ERROR;
+}
+
+
+bool Failure::IsOutOfMemoryException() const {
+  return type() == OUT_OF_MEMORY_EXCEPTION;
+}
+
+
+int Failure::requested() const {
+  const int kShiftBits =
+      kFailureTypeTagSize + kSpaceTagSize - kObjectAlignmentBits;
+  STATIC_ASSERT(kShiftBits >= 0);
+  ASSERT(type() == RETRY_AFTER_GC);
+  return value() >> kShiftBits;
+}
+
+
+AllocationSpace Failure::allocation_space() const {
+  ASSERT_EQ(RETRY_AFTER_GC, type());
+  return static_cast<AllocationSpace>((value() >> kFailureTypeTagSize)
+                                      & kSpaceTagMask);
+}
+
+
+Failure* Failure::InternalError() {
+  return Construct(INTERNAL_ERROR);
+}
+
+
+Failure* Failure::Exception() {
+  return Construct(EXCEPTION);
+}
+
+Failure* Failure::OutOfMemoryException() {
+  return Construct(OUT_OF_MEMORY_EXCEPTION);
+}
+
+
+int Failure::value() const {
+  return reinterpret_cast<int>(this) >> kFailureTagSize;
+}
+
+
+Failure* Failure::RetryAfterGC(int requested_bytes) {
+  int requested = requested_bytes >> kObjectAlignmentBits;
+  int value = (requested << kSpaceTagSize) | NEW_SPACE;
+  ASSERT(value >> kSpaceTagSize == requested);
+  ASSERT(Smi::IsValid(value));
+  ASSERT(value == ((value << kFailureTypeTagSize) >> kFailureTypeTagSize));
+  ASSERT(Smi::IsValid(value << kFailureTypeTagSize));
+  return Construct(RETRY_AFTER_GC, value);
+}
+
+
+Failure* Failure::Construct(Type type, int value) {
+  int info = (value << kFailureTypeTagSize) | type;
+  ASSERT(Smi::IsValid(info));  // Same validation check as in Smi
+  return reinterpret_cast<Failure*>((info << kFailureTagSize) | kFailureTag);
+}
+
+
+bool Smi::IsValid(int value) {
+#ifdef DEBUG
+  bool in_range = (value >= kMinValue) && (value <= kMaxValue);
+#endif
+  // To be representable as an tagged small integer, the two
+  // most-significant bits of 'value' must be either 00 or 11 due to
+  // sign-extension. To check this we add 01 to the two
+  // most-significant bits, and check if the most-significant bit is 0
+  //
+  // CAUTION: The original code below:
+  // bool result = ((value + 0x40000000) & 0x80000000) == 0;
+  // may lead to incorrect results according to the C language spec, and
+  // in fact doesn't work correctly with gcc4.1.1 in some cases: The
+  // compiler may produce undefined results in case of signed integer
+  // overflow. The computation must be done w/ unsigned ints.
+  bool result =
+      ((static_cast<unsigned int>(value) + 0x40000000U) & 0x80000000U) == 0;
+  ASSERT(result == in_range);
+  return result;
+}
+
+
+MapWord MapWord::FromMap(Map* map) {
+  return MapWord(reinterpret_cast<uintptr_t>(map));
+}
+
+
+Map* MapWord::ToMap() {
+  return reinterpret_cast<Map*>(value_);
+}
+
+
+bool MapWord::IsForwardingAddress() {
+  return HAS_SMI_TAG(reinterpret_cast<Object*>(value_));
+}
+
+
+MapWord MapWord::FromForwardingAddress(HeapObject* object) {
+  Address raw = reinterpret_cast<Address>(object) - kHeapObjectTag;
+  return MapWord(reinterpret_cast<uintptr_t>(raw));
+}
+
+
+HeapObject* MapWord::ToForwardingAddress() {
+  ASSERT(IsForwardingAddress());
+  return HeapObject::FromAddress(reinterpret_cast<Address>(value_));
+}
+
+
+bool MapWord::IsMarked() {
+  return (value_ & kMarkingMask) == 0;
+}
+
+
+void MapWord::SetMark() {
+  value_ &= ~kMarkingMask;
+}
+
+
+void MapWord::ClearMark() {
+  value_ |= kMarkingMask;
+}
+
+
+bool MapWord::IsOverflowed() {
+  return (value_ & kOverflowMask) != 0;
+}
+
+
+void MapWord::SetOverflow() {
+  value_ |= kOverflowMask;
+}
+
+
+void MapWord::ClearOverflow() {
+  value_ &= ~kOverflowMask;
+}
+
+
+MapWord MapWord::EncodeAddress(Address map_address, int offset) {
+  // Offset is the distance in live bytes from the first live object in the
+  // same page. The offset between two objects in the same page should not
+  // exceed the object area size of a page.
+  ASSERT(0 <= offset && offset < Page::kObjectAreaSize);
+
+  int compact_offset = offset >> kObjectAlignmentBits;
+  ASSERT(compact_offset < (1 << kForwardingOffsetBits));
+
+  Page* map_page = Page::FromAddress(map_address);
+  ASSERT_MAP_PAGE_INDEX(map_page->mc_page_index);
+
+  int map_page_offset =
+      map_page->Offset(map_address) >> kObjectAlignmentBits;
+
+  uintptr_t encoding =
+      (compact_offset << kForwardingOffsetShift) |
+      (map_page_offset << kMapPageOffsetShift) |
+      (map_page->mc_page_index << kMapPageIndexShift);
+  return MapWord(encoding);
+}
+
+
+Address MapWord::DecodeMapAddress(MapSpace* map_space) {
+  int map_page_index = (value_ & kMapPageIndexMask) >> kMapPageIndexShift;
+  ASSERT_MAP_PAGE_INDEX(map_page_index);
+
+  int map_page_offset =
+      ((value_ & kMapPageOffsetMask) >> kMapPageOffsetShift)
+      << kObjectAlignmentBits;
+
+  return (map_space->PageAddress(map_page_index) + map_page_offset);
+}
+
+
+int MapWord::DecodeOffset() {
+  // The offset field is represented in the kForwardingOffsetBits
+  // most-significant bits.
+  int offset = (value_ >> kForwardingOffsetShift) << kObjectAlignmentBits;
+  ASSERT(0 <= offset && offset < Page::kObjectAreaSize);
+  return offset;
+}
+
+
+MapWord MapWord::FromEncodedAddress(Address address) {
+  return MapWord(reinterpret_cast<uintptr_t>(address));
+}
+
+
+Address MapWord::ToEncodedAddress() {
+  return reinterpret_cast<Address>(value_);
+}
+
+
+#ifdef DEBUG
+void HeapObject::VerifyObjectField(int offset) {
+  VerifyPointer(READ_FIELD(this, offset));
+}
+#endif
+
+
+Map* HeapObject::map() {
+  return map_word().ToMap();
+}
+
+
+void HeapObject::set_map(Map* value) {
+  set_map_word(MapWord::FromMap(value));
+}
+
+
+MapWord HeapObject::map_word() {
+  return MapWord(reinterpret_cast<uintptr_t>(READ_FIELD(this, kMapOffset)));
+}
+
+
+void HeapObject::set_map_word(MapWord map_word) {
+  // WRITE_FIELD does not update the remembered set, but there is no need
+  // here.
+  WRITE_FIELD(this, kMapOffset, reinterpret_cast<Object*>(map_word.value_));
+}
+
+
+HeapObject* HeapObject::FromAddress(Address address) {
+  ASSERT_TAG_ALIGNED(address);
+  return reinterpret_cast<HeapObject*>(address + kHeapObjectTag);
+}
+
+
+Address HeapObject::address() {
+  return reinterpret_cast<Address>(this) - kHeapObjectTag;
+}
+
+
+int HeapObject::Size() {
+  return SizeFromMap(map());
+}
+
+
+void HeapObject::IteratePointers(ObjectVisitor* v, int start, int end) {
+  v->VisitPointers(reinterpret_cast<Object**>(FIELD_ADDR(this, start)),
+                   reinterpret_cast<Object**>(FIELD_ADDR(this, end)));
+}
+
+
+void HeapObject::IteratePointer(ObjectVisitor* v, int offset) {
+  v->VisitPointer(reinterpret_cast<Object**>(FIELD_ADDR(this, offset)));
+}
+
+
+bool HeapObject::IsMarked() {
+  return map_word().IsMarked();
+}
+
+
+void HeapObject::SetMark() {
+  ASSERT(!IsMarked());
+  MapWord first_word = map_word();
+  first_word.SetMark();
+  set_map_word(first_word);
+}
+
+
+void HeapObject::ClearMark() {
+  ASSERT(IsMarked());
+  MapWord first_word = map_word();
+  first_word.ClearMark();
+  set_map_word(first_word);
+}
+
+
+bool HeapObject::IsOverflowed() {
+  return map_word().IsOverflowed();
+}
+
+
+void HeapObject::SetOverflow() {
+  MapWord first_word = map_word();
+  first_word.SetOverflow();
+  set_map_word(first_word);
+}
+
+
+void HeapObject::ClearOverflow() {
+  ASSERT(IsOverflowed());
+  MapWord first_word = map_word();
+  first_word.ClearOverflow();
+  set_map_word(first_word);
+}
+
+
+double HeapNumber::value() {
+  return READ_DOUBLE_FIELD(this, kValueOffset);
+}
+
+
+void HeapNumber::set_value(double value) {
+  WRITE_DOUBLE_FIELD(this, kValueOffset, value);
+}
+
+
+ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
+ACCESSORS(JSObject, elements, FixedArray, kElementsOffset)
+
+
+void JSObject::initialize_properties() {
+  ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
+  WRITE_FIELD(this, kPropertiesOffset, Heap::empty_fixed_array());
+}
+
+
+void JSObject::initialize_elements() {
+  ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
+  WRITE_FIELD(this, kElementsOffset, Heap::empty_fixed_array());
+}
+
+
+ACCESSORS(Oddball, to_string, String, kToStringOffset)
+ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
+
+
+int JSObject::GetHeaderSize() {
+  switch (map()->instance_type()) {
+    case JS_GLOBAL_PROXY_TYPE:
+      return JSGlobalProxy::kSize;
+    case JS_GLOBAL_OBJECT_TYPE:
+      return JSGlobalObject::kSize;
+    case JS_BUILTINS_OBJECT_TYPE:
+      return JSBuiltinsObject::kSize;
+    case JS_FUNCTION_TYPE:
+      return JSFunction::kSize;
+    case JS_VALUE_TYPE:
+      return JSValue::kSize;
+    case JS_ARRAY_TYPE:
+      return JSValue::kSize;
+    case JS_REGEXP_TYPE:
+      return JSValue::kSize;
+    case JS_OBJECT_TYPE:
+      return JSObject::kHeaderSize;
+    default:
+      UNREACHABLE();
+      return 0;
+  }
+}
+
+
+int JSObject::GetInternalFieldCount() {
+  ASSERT(1 << kPointerSizeLog2 == kPointerSize);
+  // Make sure to adjust for the number of in-object properties. These
+  // properties do contribute to the size, but are not internal fields.
+  return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) -
+         map()->inobject_properties();
+}
+
+
+Object* JSObject::GetInternalField(int index) {
+  ASSERT(index < GetInternalFieldCount() && index >= 0);
+  // Internal objects do follow immediately after the header, whereas in-object
+  // properties are at the end of the object. Therefore there is no need
+  // to adjust the index here.
+  return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index));
+}
+
+
+void JSObject::SetInternalField(int index, Object* value) {
+  ASSERT(index < GetInternalFieldCount() && index >= 0);
+  // Internal objects do follow immediately after the header, whereas in-object
+  // properties are at the end of the object. Therefore there is no need
+  // to adjust the index here.
+  int offset = GetHeaderSize() + (kPointerSize * index);
+  WRITE_FIELD(this, offset, value);
+  WRITE_BARRIER(this, offset);
+}
+
+
+// Access fast-case object properties at index. The use of these routines
+// is needed to correctly distinguish between properties stored in-object and
+// properties stored in the properties array.
+Object* JSObject::FastPropertyAt(int index) {
+  // Adjust for the number of properties stored in the object.
+  index -= map()->inobject_properties();
+  if (index < 0) {
+    int offset = map()->instance_size() + (index * kPointerSize);
+    return READ_FIELD(this, offset);
+  } else {
+    ASSERT(index < properties()->length());
+    return properties()->get(index);
+  }
+}
+
+
+Object* JSObject::FastPropertyAtPut(int index, Object* value) {
+  // Adjust for the number of properties stored in the object.
+  index -= map()->inobject_properties();
+  if (index < 0) {
+    int offset = map()->instance_size() + (index * kPointerSize);
+    WRITE_FIELD(this, offset, value);
+    WRITE_BARRIER(this, offset);
+  } else {
+    ASSERT(index < properties()->length());
+    properties()->set(index, value);
+  }
+  return value;
+}
+
+
+Object* JSObject::InObjectPropertyAtPut(int index,
+                                        Object* value,
+                                        WriteBarrierMode mode) {
+  // Adjust for the number of properties stored in the object.
+  index -= map()->inobject_properties();
+  ASSERT(index < 0);
+  int offset = map()->instance_size() + (index * kPointerSize);
+  WRITE_FIELD(this, offset, value);
+  CONDITIONAL_WRITE_BARRIER(this, offset, mode);
+  return value;
+}
+
+
+
+void JSObject::InitializeBody(int object_size) {
+  Object* value = Heap::undefined_value();
+  for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
+    WRITE_FIELD(this, offset, value);
+  }
+}
+
+
+void Struct::InitializeBody(int object_size) {
+  Object* value = Heap::undefined_value();
+  for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
+    WRITE_FIELD(this, offset, value);
+  }
+}
+
+
+bool JSObject::HasFastProperties() {
+  return !properties()->IsDictionary();
+}
+
+
+bool Array::IndexFromObject(Object* object, uint32_t* index) {
+  if (object->IsSmi()) {
+    int value = Smi::cast(object)->value();
+    if (value < 0) return false;
+    *index = value;
+    return true;
+  }
+  if (object->IsHeapNumber()) {
+    double value = HeapNumber::cast(object)->value();
+    uint32_t uint_value = static_cast<uint32_t>(value);
+    if (value == static_cast<double>(uint_value)) {
+      *index = uint_value;
+      return true;
+    }
+  }
+  return false;
+}
+
+
+bool Object::IsStringObjectWithCharacterAt(uint32_t index) {
+  if (!this->IsJSValue()) return false;
+
+  JSValue* js_value = JSValue::cast(this);
+  if (!js_value->value()->IsString()) return false;
+
+  String* str = String::cast(js_value->value());
+  if (index >= (uint32_t)str->length()) return false;
+
+  return true;
+}
+
+
+Object* FixedArray::get(int index) {
+  ASSERT(index >= 0 && index < this->length());
+  return READ_FIELD(this, kHeaderSize + index * kPointerSize);
+}
+
+
+void FixedArray::set(int index, Object* value) {
+  ASSERT(index >= 0 && index < this->length());
+  int offset = kHeaderSize + index * kPointerSize;
+  WRITE_FIELD(this, offset, value);
+  WRITE_BARRIER(this, offset);
+}
+
+
+WriteBarrierMode HeapObject::GetWriteBarrierMode() {
+  if (Heap::InNewSpace(this)) return SKIP_WRITE_BARRIER;
+  return UPDATE_WRITE_BARRIER;
+}
+
+
+void FixedArray::set(int index,
+                     Object* value,
+                     WriteBarrierMode mode) {
+  ASSERT(index >= 0 && index < this->length());
+  int offset = kHeaderSize + index * kPointerSize;
+  WRITE_FIELD(this, offset, value);
+  CONDITIONAL_WRITE_BARRIER(this, offset, mode);
+}
+
+
+void FixedArray::fast_set(FixedArray* array, int index, Object* value) {
+  ASSERT(index >= 0 && index < array->length());
+  WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value);
+}
+
+
+void FixedArray::set_undefined(int index) {
+  ASSERT(index >= 0 && index < this->length());
+  ASSERT(!Heap::InNewSpace(Heap::undefined_value()));
+  WRITE_FIELD(this, kHeaderSize + index * kPointerSize,
+              Heap::undefined_value());
+}
+
+
+void FixedArray::set_null(int index) {
+  ASSERT(index >= 0 && index < this->length());
+  ASSERT(!Heap::InNewSpace(Heap::null_value()));
+  WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::null_value());
+}
+
+
+void FixedArray::set_the_hole(int index) {
+  ASSERT(index >= 0 && index < this->length());
+  ASSERT(!Heap::InNewSpace(Heap::the_hole_value()));
+  WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::the_hole_value());
+}
+
+
+bool DescriptorArray::IsEmpty() {
+  ASSERT(this == Heap::empty_descriptor_array() ||
+         this->length() > 2);
+  return this == Heap::empty_descriptor_array();
+}
+
+
+void DescriptorArray::fast_swap(FixedArray* array, int first, int second) {
+  Object* tmp = array->get(first);
+  fast_set(array, first, array->get(second));
+  fast_set(array, second, tmp);
+}
+
+
+int DescriptorArray::Search(String* name) {
+  SLOW_ASSERT(IsSortedNoDuplicates());
+
+  // Check for empty descriptor array.
+  int nof = number_of_descriptors();
+  if (nof == 0) return kNotFound;
+
+  // Fast case: do linear search for small arrays.
+  const int kMaxElementsForLinearSearch = 8;
+  if (name->IsSymbol() && nof < kMaxElementsForLinearSearch) {
+    return LinearSearch(name, nof);
+  }
+
+  // Slow case: perform binary search.
+  return BinarySearch(name, 0, nof - 1);
+}
+
+
+
+String* DescriptorArray::GetKey(int descriptor_number) {
+  ASSERT(descriptor_number < number_of_descriptors());
+  return String::cast(get(ToKeyIndex(descriptor_number)));
+}
+
+
+Object* DescriptorArray::GetValue(int descriptor_number) {
+  ASSERT(descriptor_number < number_of_descriptors());
+  return GetContentArray()->get(ToValueIndex(descriptor_number));
+}
+
+
+Smi* DescriptorArray::GetDetails(int descriptor_number) {
+  ASSERT(descriptor_number < number_of_descriptors());
+  return Smi::cast(GetContentArray()->get(ToDetailsIndex(descriptor_number)));
+}
+
+
+void DescriptorArray::Get(int descriptor_number, Descriptor* desc) {
+  desc->Init(GetKey(descriptor_number),
+             GetValue(descriptor_number),
+             GetDetails(descriptor_number));
+}
+
+
+void DescriptorArray::Set(int descriptor_number, Descriptor* desc) {
+  // Range check.
+  ASSERT(descriptor_number < number_of_descriptors());
+
+  // Make sure non of the elements in desc are in new space.
+  ASSERT(!Heap::InNewSpace(desc->GetKey()));
+  ASSERT(!Heap::InNewSpace(desc->GetValue()));
+
+  fast_set(this, ToKeyIndex(descriptor_number), desc->GetKey());
+  FixedArray* content_array = GetContentArray();
+  fast_set(content_array, ToValueIndex(descriptor_number), desc->GetValue());
+  fast_set(content_array, ToDetailsIndex(descriptor_number),
+           desc->GetDetails().AsSmi());
+}
+
+
+void DescriptorArray::Swap(int first, int second) {
+  fast_swap(this, ToKeyIndex(first), ToKeyIndex(second));
+  FixedArray* content_array = GetContentArray();
+  fast_swap(content_array, ToValueIndex(first), ToValueIndex(second));
+  fast_swap(content_array, ToDetailsIndex(first),  ToDetailsIndex(second));
+}
+
+
+bool Dictionary::requires_slow_elements() {
+  Object* max_index_object = get(kMaxNumberKeyIndex);
+  if (!max_index_object->IsSmi()) return false;
+  return 0 !=
+      (Smi::cast(max_index_object)->value() & kRequiresSlowElementsMask);
+}
+
+
+uint32_t Dictionary::max_number_key() {
+  ASSERT(!requires_slow_elements());
+  Object* max_index_object = get(kMaxNumberKeyIndex);
+  if (!max_index_object->IsSmi()) return 0;
+  uint32_t value = static_cast<uint32_t>(Smi::cast(max_index_object)->value());
+  return value >> kRequiresSlowElementsTagSize;
+}
+
+
+// ------------------------------------
+// Cast operations
+
+
+CAST_ACCESSOR(FixedArray)
+CAST_ACCESSOR(DescriptorArray)
+CAST_ACCESSOR(Dictionary)
+CAST_ACCESSOR(SymbolTable)
+CAST_ACCESSOR(CompilationCacheTable)
+CAST_ACCESSOR(MapCache)
+CAST_ACCESSOR(LookupCache)
+CAST_ACCESSOR(String)
+CAST_ACCESSOR(SeqString)
+CAST_ACCESSOR(SeqAsciiString)
+CAST_ACCESSOR(SeqTwoByteString)
+CAST_ACCESSOR(ConsString)
+CAST_ACCESSOR(SlicedString)
+CAST_ACCESSOR(ExternalString)
+CAST_ACCESSOR(ExternalAsciiString)
+CAST_ACCESSOR(ExternalTwoByteString)
+CAST_ACCESSOR(JSObject)
+CAST_ACCESSOR(Smi)
+CAST_ACCESSOR(Failure)
+CAST_ACCESSOR(HeapObject)
+CAST_ACCESSOR(HeapNumber)
+CAST_ACCESSOR(Oddball)
+CAST_ACCESSOR(SharedFunctionInfo)
+CAST_ACCESSOR(Map)
+CAST_ACCESSOR(JSFunction)
+CAST_ACCESSOR(GlobalObject)
+CAST_ACCESSOR(JSGlobalProxy)
+CAST_ACCESSOR(JSGlobalObject)
+CAST_ACCESSOR(JSBuiltinsObject)
+CAST_ACCESSOR(Code)
+CAST_ACCESSOR(JSArray)
+CAST_ACCESSOR(JSRegExp)
+CAST_ACCESSOR(Proxy)
+CAST_ACCESSOR(ByteArray)
+CAST_ACCESSOR(Struct)
+
+
+#define MAKE_STRUCT_CAST(NAME, Name, name) CAST_ACCESSOR(Name)
+  STRUCT_LIST(MAKE_STRUCT_CAST)
+#undef MAKE_STRUCT_CAST
+
+template <int prefix_size, int elem_size>
+HashTable<prefix_size, elem_size>* HashTable<prefix_size, elem_size>::cast(
+    Object* obj) {
+  ASSERT(obj->IsHashTable());
+  return reinterpret_cast<HashTable*>(obj);
+}
+
+
+INT_ACCESSORS(Array, length, kLengthOffset)
+
+
+bool String::Equals(String* other) {
+  if (other == this) return true;
+  if (IsSymbol() && other->IsSymbol()) return false;
+  return SlowEquals(other);
+}
+
+
+int String::length() {
+  uint32_t len = READ_INT_FIELD(this, kLengthOffset);
+
+  switch (size_tag()) {
+    case kShortStringTag:
+      return  len >> kShortLengthShift;
+    case kMediumStringTag:
+      return len >> kMediumLengthShift;
+    case kLongStringTag:
+      return len >> kLongLengthShift;
+    default:
+      break;
+  }
+  UNREACHABLE();
+  return 0;
+}
+
+
+void String::set_length(int value) {
+  switch (size_tag()) {
+    case kShortStringTag:
+      WRITE_INT_FIELD(this, kLengthOffset, value << kShortLengthShift);
+      break;
+    case kMediumStringTag:
+      WRITE_INT_FIELD(this, kLengthOffset, value << kMediumLengthShift);
+      break;
+    case kLongStringTag:
+      WRITE_INT_FIELD(this, kLengthOffset, value << kLongLengthShift);
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+uint32_t String::length_field() {
+  return READ_UINT32_FIELD(this, kLengthOffset);
+}
+
+
+void String::set_length_field(uint32_t value) {
+  WRITE_UINT32_FIELD(this, kLengthOffset, value);
+}
+
+
+void String::TryFlatten() {
+  // We don't need to flatten strings that are already flat.  Since this code
+  // is inlined, it can be helpful in the flat case to not call out to Flatten.
+  StringRepresentationTag str_type = representation_tag();
+  if (str_type != kSeqStringTag && str_type != kExternalStringTag) {
+    Flatten();
+  }
+}
+
+
+uint16_t String::Get(int index) {
+  ASSERT(index >= 0 && index < length());
+  switch (representation_tag()) {
+    case kSeqStringTag:
+      return is_ascii_representation()
+        ? SeqAsciiString::cast(this)->SeqAsciiStringGet(index)
+        : SeqTwoByteString::cast(this)->SeqTwoByteStringGet(index);
+    case kConsStringTag:
+      return ConsString::cast(this)->ConsStringGet(index);
+    case kSlicedStringTag:
+      return SlicedString::cast(this)->SlicedStringGet(index);
+    case kExternalStringTag:
+      return is_ascii_representation()
+        ? ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index)
+        : ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index);
+    default:
+      break;
+  }
+
+  UNREACHABLE();
+  return 0;
+}
+
+
+void String::Set(int index, uint16_t value) {
+  ASSERT(index >= 0 && index < length());
+  ASSERT(IsSeqString());
+
+  return is_ascii_representation()
+      ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
+      : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
+}
+
+
+bool String::IsAsciiRepresentation() {
+  return is_ascii_representation();
+}
+
+
+bool String::StringIsConsString() {
+  return representation_tag() == kConsStringTag;
+}
+
+
+bool String::StringIsSlicedString() {
+  return representation_tag() == kSlicedStringTag;
+}
+
+
+uint32_t String::size_tag() {
+  return map_size_tag(map());
+}
+
+
+uint32_t String::map_size_tag(Map* map) {
+  return map->instance_type() & kStringSizeMask;
+}
+
+
+bool String::is_symbol() {
+  return is_symbol_map(map());
+}
+
+
+bool String::is_symbol_map(Map* map) {
+  return (map->instance_type() & kIsSymbolMask) != 0;
+}
+
+
+bool String::is_ascii_representation() {
+  return is_ascii_representation_map(map());
+}
+
+
+bool String::is_ascii_representation_map(Map* map) {
+  return (map->instance_type() & kStringEncodingMask) != 0;
+}
+
+
+int String::full_representation_tag() {
+  return map()->instance_type() &
+         (kStringRepresentationMask | kStringEncodingMask);
+}
+
+
+StringRepresentationTag String::representation_tag() {
+  return map_representation_tag(map());
+}
+
+
+StringRepresentationTag String::map_representation_tag(Map* map) {
+  uint32_t tag = map->instance_type() & kStringRepresentationMask;
+  return static_cast<StringRepresentationTag>(tag);
+}
+
+
+bool String::IsFlat() {
+  switch (this->representation_tag()) {
+    case kConsStringTag:
+      // Only flattened strings have second part empty.
+      return String::cast(ConsString::cast(this)->second())->length() == 0;
+    case kSlicedStringTag: {
+      String* slice = String::cast(SlicedString::cast(this)->buffer());
+      StringRepresentationTag tag = slice->representation_tag();
+      return tag == kSeqStringTag || tag == kExternalStringTag;
+    }
+    default:
+      return true;
+  }
+}
+
+
+uint16_t SeqAsciiString::SeqAsciiStringGet(int index) {
+  ASSERT(index >= 0 && index < length());
+  return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
+}
+
+
+void SeqAsciiString::SeqAsciiStringSet(int index, uint16_t value) {
+  ASSERT(index >= 0 && index < length() && value <= kMaxAsciiCharCode);
+  WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize,
+                   static_cast<byte>(value));
+}
+
+
+Address SeqAsciiString::GetCharsAddress() {
+  return FIELD_ADDR(this, kHeaderSize);
+}
+
+
+char* SeqAsciiString::GetChars() {
+  return reinterpret_cast<char*>(GetCharsAddress());
+}
+
+
+Address SeqTwoByteString::GetCharsAddress() {
+  return FIELD_ADDR(this, kHeaderSize);
+}
+
+
+uc16* SeqTwoByteString::GetChars() {
+  return reinterpret_cast<uc16*>(FIELD_ADDR(this, kHeaderSize));
+}
+
+
+uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) {
+  ASSERT(index >= 0 && index < length());
+  return READ_SHORT_FIELD(this, kHeaderSize + index * kShortSize);
+}
+
+
+void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
+  ASSERT(index >= 0 && index < length());
+  WRITE_SHORT_FIELD(this, kHeaderSize + index * kShortSize, value);
+}
+
+
+int SeqTwoByteString::SeqTwoByteStringSize(Map* map) {
+  uint32_t length = READ_INT_FIELD(this, kLengthOffset);
+
+  // Use the map (and not 'this') to compute the size tag, since
+  // TwoByteStringSize is called during GC when maps are encoded.
+  switch (map_size_tag(map)) {
+    case kShortStringTag:
+      length = length >> kShortLengthShift;
+      break;
+    case kMediumStringTag:
+      length = length >> kMediumLengthShift;
+      break;
+    case kLongStringTag:
+      length = length >> kLongLengthShift;
+      break;
+    default:
+      break;
+  }
+  return SizeFor(length);
+}
+
+
+int SeqAsciiString::SeqAsciiStringSize(Map* map) {
+  uint32_t length = READ_INT_FIELD(this, kLengthOffset);
+
+  // Use the map (and not 'this') to compute the size tag, since
+  // AsciiStringSize is called during GC when maps are encoded.
+  switch (map_size_tag(map)) {
+    case kShortStringTag:
+      length = length >> kShortLengthShift;
+      break;
+    case kMediumStringTag:
+      length = length >> kMediumLengthShift;
+      break;
+    case kLongStringTag:
+      length = length >> kLongLengthShift;
+      break;
+    default:
+      break;
+  }
+
+  return SizeFor(length);
+}
+
+
+Object* ConsString::first() {
+  return READ_FIELD(this, kFirstOffset);
+}
+
+
+void ConsString::set_first(Object* value, WriteBarrierMode mode) {
+  WRITE_FIELD(this, kFirstOffset, value);
+  CONDITIONAL_WRITE_BARRIER(this, kFirstOffset, mode);
+}
+
+
+Object* ConsString::second() {
+  return READ_FIELD(this, kSecondOffset);
+}
+
+
+void ConsString::set_second(Object* value, WriteBarrierMode mode) {
+  WRITE_FIELD(this, kSecondOffset, value);
+  CONDITIONAL_WRITE_BARRIER(this, kSecondOffset, mode);
+}
+
+
+Object* SlicedString::buffer() {
+  return READ_FIELD(this, kBufferOffset);
+}
+
+
+void SlicedString::set_buffer(Object* buffer) {
+  WRITE_FIELD(this, kBufferOffset, buffer);
+  WRITE_BARRIER(this, kBufferOffset);
+}
+
+
+int SlicedString::start() {
+  return READ_INT_FIELD(this, kStartOffset);
+}
+
+
+void SlicedString::set_start(int start) {
+  WRITE_INT_FIELD(this, kStartOffset, start);
+}
+
+
+ExternalAsciiString::Resource* ExternalAsciiString::resource() {
+  return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
+}
+
+
+void ExternalAsciiString::set_resource(
+    ExternalAsciiString::Resource* resource) {
+  *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource;
+}
+
+
+ExternalTwoByteString::Resource* ExternalTwoByteString::resource() {
+  return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
+}
+
+
+void ExternalTwoByteString::set_resource(
+    ExternalTwoByteString::Resource* resource) {
+  *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource;
+}
+
+
+byte ByteArray::get(int index) {
+  ASSERT(index >= 0 && index < this->length());
+  return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
+}
+
+
+void ByteArray::set(int index, byte value) {
+  ASSERT(index >= 0 && index < this->length());
+  WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value);
+}
+
+
+int ByteArray::get_int(int index) {
+  ASSERT(index >= 0 && (index * kIntSize) < this->length());
+  return READ_INT_FIELD(this, kHeaderSize + index * kIntSize);
+}
+
+
+ByteArray* ByteArray::FromDataStartAddress(Address address) {
+  ASSERT_TAG_ALIGNED(address);
+  return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag);
+}
+
+
+Address ByteArray::GetDataStartAddress() {
+  return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
+}
+
+
+int Map::instance_size() {
+  return READ_BYTE_FIELD(this, kInstanceSizeOffset) << kPointerSizeLog2;
+}
+
+
+int Map::inobject_properties() {
+  return READ_BYTE_FIELD(this, kInObjectPropertiesOffset);
+}
+
+
+int HeapObject::SizeFromMap(Map* map) {
+  InstanceType instance_type = map->instance_type();
+  // Only inline the two most frequent cases.
+  if (instance_type == JS_OBJECT_TYPE) return  map->instance_size();
+  if (instance_type == FIXED_ARRAY_TYPE) {
+    return reinterpret_cast<FixedArray*>(this)->FixedArraySize();
+  }
+  // Otherwise do the general size computation.
+  return SlowSizeFromMap(map);
+}
+
+
+void Map::set_instance_size(int value) {
+  ASSERT((value & ~(kPointerSize - 1)) == value);
+  value >>= kPointerSizeLog2;
+  ASSERT(0 <= value && value < 256);
+  WRITE_BYTE_FIELD(this, kInstanceSizeOffset, static_cast<byte>(value));
+}
+
+
+void Map::set_inobject_properties(int value) {
+  ASSERT(0 <= value && value < 256);
+  WRITE_BYTE_FIELD(this, kInObjectPropertiesOffset, static_cast<byte>(value));
+}
+
+
+InstanceType Map::instance_type() {
+  return static_cast<InstanceType>(READ_BYTE_FIELD(this, kInstanceTypeOffset));
+}
+
+
+void Map::set_instance_type(InstanceType value) {
+  ASSERT(0 <= value && value < 256);
+  WRITE_BYTE_FIELD(this, kInstanceTypeOffset, value);
+}
+
+
+int Map::unused_property_fields() {
+  return READ_BYTE_FIELD(this, kUnusedPropertyFieldsOffset);
+}
+
+
+void Map::set_unused_property_fields(int value) {
+  WRITE_BYTE_FIELD(this, kUnusedPropertyFieldsOffset, Min(value, 255));
+}
+
+
+byte Map::bit_field() {
+  return READ_BYTE_FIELD(this, kBitFieldOffset);
+}
+
+
+void Map::set_bit_field(byte value) {
+  WRITE_BYTE_FIELD(this, kBitFieldOffset, value);
+}
+
+
+void Map::set_non_instance_prototype(bool value) {
+  if (value) {
+    set_bit_field(bit_field() | (1 << kHasNonInstancePrototype));
+  } else {
+    set_bit_field(bit_field() & ~(1 << kHasNonInstancePrototype));
+  }
+}
+
+
+bool Map::has_non_instance_prototype() {
+  return ((1 << kHasNonInstancePrototype) & bit_field()) != 0;
+}
+
+
+Code::Flags Code::flags() {
+  return static_cast<Flags>(READ_INT_FIELD(this, kFlagsOffset));
+}
+
+
+void Code::set_flags(Code::Flags flags) {
+  // Make sure that all call stubs have an arguments count.
+  ASSERT(ExtractKindFromFlags(flags) != CALL_IC ||
+         ExtractArgumentsCountFromFlags(flags) >= 0);
+  WRITE_INT_FIELD(this, kFlagsOffset, flags);
+}
+
+
+Code::Kind Code::kind() {
+  return ExtractKindFromFlags(flags());
+}
+
+
+InlineCacheState Code::ic_state() {
+  InlineCacheState result = ExtractICStateFromFlags(flags());
+  // Only allow uninitialized or debugger states for non-IC code
+  // objects. This is used in the debugger to determine whether or not
+  // a call to code object has been replaced with a debug break call.
+  ASSERT(is_inline_cache_stub() ||
+         result == UNINITIALIZED ||
+         result == DEBUG_BREAK ||
+         result == DEBUG_PREPARE_STEP_IN);
+  return result;
+}
+
+
+PropertyType Code::type() {
+  ASSERT(ic_state() == MONOMORPHIC);
+  return ExtractTypeFromFlags(flags());
+}
+
+
+int Code::arguments_count() {
+  ASSERT(is_call_stub() || kind() == STUB);
+  return ExtractArgumentsCountFromFlags(flags());
+}
+
+
+CodeStub::Major Code::major_key() {
+  ASSERT(kind() == STUB);
+  return static_cast<CodeStub::Major>(READ_BYTE_FIELD(this,
+                                                      kStubMajorKeyOffset));
+}
+
+
+void Code::set_major_key(CodeStub::Major major) {
+  ASSERT(kind() == STUB);
+  ASSERT(0 <= major && major < 256);
+  WRITE_BYTE_FIELD(this, kStubMajorKeyOffset, major);
+}
+
+
+bool Code::is_inline_cache_stub() {
+  Kind kind = this->kind();
+  return kind >= FIRST_IC_KIND && kind <= LAST_IC_KIND;
+}
+
+
+Code::Flags Code::ComputeFlags(Kind kind,
+                               InlineCacheState ic_state,
+                               PropertyType type,
+                               int argc) {
+  // Compute the bit mask.
+  int bits = kind << kFlagsKindShift;
+  bits |= ic_state << kFlagsICStateShift;
+  bits |= type << kFlagsTypeShift;
+  bits |= argc << kFlagsArgumentsCountShift;
+  // 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(ExtractTypeFromFlags(result) == type);
+  ASSERT(ExtractArgumentsCountFromFlags(result) == argc);
+  return result;
+}
+
+
+Code::Flags Code::ComputeMonomorphicFlags(Kind kind,
+                                          PropertyType type,
+                                          int argc) {
+  return ComputeFlags(kind, MONOMORPHIC, type, argc);
+}
+
+
+Code::Kind Code::ExtractKindFromFlags(Flags flags) {
+  int bits = (flags & kFlagsKindMask) >> kFlagsKindShift;
+  return static_cast<Kind>(bits);
+}
+
+
+InlineCacheState Code::ExtractICStateFromFlags(Flags flags) {
+  int bits = (flags & kFlagsICStateMask) >> kFlagsICStateShift;
+  return static_cast<InlineCacheState>(bits);
+}
+
+
+PropertyType Code::ExtractTypeFromFlags(Flags flags) {
+  int bits = (flags & kFlagsTypeMask) >> kFlagsTypeShift;
+  return static_cast<PropertyType>(bits);
+}
+
+
+int Code::ExtractArgumentsCountFromFlags(Flags flags) {
+  return (flags & kFlagsArgumentsCountMask) >> kFlagsArgumentsCountShift;
+}
+
+
+Code::Flags Code::RemoveTypeFromFlags(Flags flags) {
+  int bits = flags & ~kFlagsTypeMask;
+  return static_cast<Flags>(bits);
+}
+
+
+Object* Map::prototype() {
+  return READ_FIELD(this, kPrototypeOffset);
+}
+
+
+void Map::set_prototype(Object* value, WriteBarrierMode mode) {
+  ASSERT(value->IsNull() || value->IsJSObject());
+  WRITE_FIELD(this, kPrototypeOffset, value);
+  CONDITIONAL_WRITE_BARRIER(this, kPrototypeOffset, mode);
+}
+
+
+ACCESSORS(Map, instance_descriptors, DescriptorArray,
+          kInstanceDescriptorsOffset)
+ACCESSORS(Map, code_cache, FixedArray, kCodeCacheOffset)
+ACCESSORS(Map, constructor, Object, kConstructorOffset)
+
+ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
+ACCESSORS(JSFunction, literals, FixedArray, kLiteralsOffset)
+
+ACCESSORS(GlobalObject, builtins, JSBuiltinsObject, kBuiltinsOffset)
+ACCESSORS(GlobalObject, global_context, Context, kGlobalContextOffset)
+ACCESSORS(GlobalObject, global_receiver, JSObject, kGlobalReceiverOffset)
+
+ACCESSORS(JSGlobalProxy, context, Object, kContextOffset)
+
+ACCESSORS(AccessorInfo, getter, Object, kGetterOffset)
+ACCESSORS(AccessorInfo, setter, Object, kSetterOffset)
+ACCESSORS(AccessorInfo, data, Object, kDataOffset)
+ACCESSORS(AccessorInfo, name, Object, kNameOffset)
+ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset)
+
+ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset)
+ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset)
+ACCESSORS(AccessCheckInfo, data, Object, kDataOffset)
+
+ACCESSORS(InterceptorInfo, getter, Object, kGetterOffset)
+ACCESSORS(InterceptorInfo, setter, Object, kSetterOffset)
+ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
+ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
+ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
+ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
+
+ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
+ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
+
+ACCESSORS(TemplateInfo, tag, Object, kTagOffset)
+ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset)
+
+ACCESSORS(FunctionTemplateInfo, serial_number, Object, kSerialNumberOffset)
+ACCESSORS(FunctionTemplateInfo, call_code, Object, kCallCodeOffset)
+ACCESSORS(FunctionTemplateInfo, property_accessors, Object,
+          kPropertyAccessorsOffset)
+ACCESSORS(FunctionTemplateInfo, prototype_template, Object,
+          kPrototypeTemplateOffset)
+ACCESSORS(FunctionTemplateInfo, parent_template, Object, kParentTemplateOffset)
+ACCESSORS(FunctionTemplateInfo, named_property_handler, Object,
+          kNamedPropertyHandlerOffset)
+ACCESSORS(FunctionTemplateInfo, indexed_property_handler, Object,
+          kIndexedPropertyHandlerOffset)
+ACCESSORS(FunctionTemplateInfo, instance_template, Object,
+          kInstanceTemplateOffset)
+ACCESSORS(FunctionTemplateInfo, class_name, Object, kClassNameOffset)
+ACCESSORS(FunctionTemplateInfo, signature, Object, kSignatureOffset)
+ACCESSORS(FunctionTemplateInfo, instance_call_handler, Object,
+          kInstanceCallHandlerOffset)
+ACCESSORS(FunctionTemplateInfo, access_check_info, Object,
+          kAccessCheckInfoOffset)
+ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset)
+
+ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset)
+ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
+          kInternalFieldCountOffset)
+
+ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
+ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
+
+ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset)
+
+ACCESSORS(Script, source, Object, kSourceOffset)
+ACCESSORS(Script, name, Object, kNameOffset)
+ACCESSORS(Script, line_offset, Smi, kLineOffsetOffset)
+ACCESSORS(Script, column_offset, Smi, kColumnOffsetOffset)
+ACCESSORS(Script, wrapper, Proxy, kWrapperOffset)
+ACCESSORS(Script, type, Smi, kTypeOffset)
+
+ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoIndex)
+ACCESSORS(DebugInfo, original_code, Code, kOriginalCodeIndex)
+ACCESSORS(DebugInfo, code, Code, kPatchedCodeIndex)
+ACCESSORS(DebugInfo, break_points, FixedArray, kBreakPointsStateIndex)
+
+ACCESSORS(BreakPointInfo, code_position, Smi, kCodePositionIndex)
+ACCESSORS(BreakPointInfo, source_position, Smi, kSourcePositionIndex)
+ACCESSORS(BreakPointInfo, statement_position, Smi, kStatementPositionIndex)
+ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsIndex)
+
+ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset)
+ACCESSORS(SharedFunctionInfo, instance_class_name, Object,
+          kInstanceClassNameOffset)
+ACCESSORS(SharedFunctionInfo, function_data, Object,
+          kExternalReferenceDataOffset)
+ACCESSORS(SharedFunctionInfo, lazy_load_data, Object, kLazyLoadDataOffset)
+ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
+ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset)
+
+BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype,
+               kHiddenPrototypeBit)
+BOOL_ACCESSORS(FunctionTemplateInfo, flag, undetectable, kUndetectableBit)
+BOOL_ACCESSORS(FunctionTemplateInfo, flag, needs_access_check,
+               kNeedsAccessCheckBit)
+BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_expression,
+               kIsExpressionBit)
+BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel,
+               kIsTopLevelBit)
+
+INT_ACCESSORS(SharedFunctionInfo, length, kLengthOffset)
+INT_ACCESSORS(SharedFunctionInfo, formal_parameter_count,
+              kFormalParameterCountOffset)
+INT_ACCESSORS(SharedFunctionInfo, expected_nof_properties,
+              kExpectedNofPropertiesOffset)
+INT_ACCESSORS(SharedFunctionInfo, start_position_and_type,
+              kStartPositionAndTypeOffset)
+INT_ACCESSORS(SharedFunctionInfo, end_position, kEndPositionOffset)
+INT_ACCESSORS(SharedFunctionInfo, function_token_position,
+              kFunctionTokenPositionOffset)
+
+
+void SharedFunctionInfo::DontAdaptArguments() {
+  ASSERT(code()->kind() == Code::BUILTIN);
+  set_formal_parameter_count(kDontAdaptArgumentsSentinel);
+}
+
+
+int SharedFunctionInfo::start_position() {
+  return start_position_and_type() >> kStartPositionShift;
+}
+
+
+void SharedFunctionInfo::set_start_position(int start_position) {
+  set_start_position_and_type((start_position << kStartPositionShift)
+    | (start_position_and_type() & ~kStartPositionMask));
+}
+
+
+Code* SharedFunctionInfo::code() {
+  return Code::cast(READ_FIELD(this, kCodeOffset));
+}
+
+
+void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) {
+  WRITE_FIELD(this, kCodeOffset, value);
+  CONDITIONAL_WRITE_BARRIER(this, kCodeOffset, mode);
+}
+
+
+bool SharedFunctionInfo::is_compiled() {
+  // TODO(1242782): Create a code kind for uncompiled code.
+  return code()->kind() != Code::STUB;
+}
+
+
+bool JSFunction::IsBoilerplate() {
+  return map() == Heap::boilerplate_function_map();
+}
+
+
+bool JSFunction::IsLoaded() {
+  return shared()->lazy_load_data() == Heap::undefined_value();
+}
+
+
+Code* JSFunction::code() {
+  return shared()->code();
+}
+
+
+void JSFunction::set_code(Code* value) {
+  shared()->set_code(value);
+}
+
+
+Context* JSFunction::context() {
+  return Context::cast(READ_FIELD(this, kContextOffset));
+}
+
+
+Object* JSFunction::unchecked_context() {
+  return READ_FIELD(this, kContextOffset);
+}
+
+
+void JSFunction::set_context(Object* value) {
+  ASSERT(value == Heap::undefined_value() || value->IsContext());
+  WRITE_FIELD(this, kContextOffset, value);
+  WRITE_BARRIER(this, kContextOffset);
+}
+
+ACCESSORS(JSFunction, prototype_or_initial_map, Object,
+          kPrototypeOrInitialMapOffset)
+
+
+Map* JSFunction::initial_map() {
+  return Map::cast(prototype_or_initial_map());
+}
+
+
+void JSFunction::set_initial_map(Map* value) {
+  set_prototype_or_initial_map(value);
+}
+
+
+bool JSFunction::has_initial_map() {
+  return prototype_or_initial_map()->IsMap();
+}
+
+
+bool JSFunction::has_instance_prototype() {
+  return has_initial_map() || !prototype_or_initial_map()->IsTheHole();
+}
+
+
+bool JSFunction::has_prototype() {
+  return map()->has_non_instance_prototype() || has_instance_prototype();
+}
+
+
+Object* JSFunction::instance_prototype() {
+  ASSERT(has_instance_prototype());
+  if (has_initial_map()) return initial_map()->prototype();
+  // When there is no initial map and the prototype is a JSObject, the
+  // initial map field is used for the prototype field.
+  return prototype_or_initial_map();
+}
+
+
+Object* JSFunction::prototype() {
+  ASSERT(has_prototype());
+  // If the function's prototype property has been set to a non-JSObject
+  // value, that value is stored in the constructor field of the map.
+  if (map()->has_non_instance_prototype()) return map()->constructor();
+  return instance_prototype();
+}
+
+
+bool JSFunction::is_compiled() {
+  return shared()->is_compiled();
+}
+
+
+int JSFunction::NumberOfLiterals() {
+  return literals()->length();
+}
+
+
+Object* JSBuiltinsObject::javascript_builtin(Builtins::JavaScript id) {
+  ASSERT(0 <= id && id < kJSBuiltinsCount);
+  return READ_FIELD(this, kJSBuiltinsOffset + (id * kPointerSize));
+}
+
+
+void JSBuiltinsObject::set_javascript_builtin(Builtins::JavaScript id,
+                                              Object* value) {
+  ASSERT(0 <= id && id < kJSBuiltinsCount);
+  WRITE_FIELD(this, kJSBuiltinsOffset + (id * kPointerSize), value);
+  WRITE_BARRIER(this, kJSBuiltinsOffset + (id * kPointerSize));
+}
+
+
+Address Proxy::proxy() {
+  return AddressFrom<Address>(READ_INT_FIELD(this, kProxyOffset));
+}
+
+
+void Proxy::set_proxy(Address value) {
+  WRITE_INT_FIELD(this, kProxyOffset, OffsetFrom(value));
+}
+
+
+void Proxy::ProxyIterateBody(ObjectVisitor* visitor) {
+  visitor->VisitExternalReference(
+      reinterpret_cast<Address *>(FIELD_ADDR(this, kProxyOffset)));
+}
+
+
+ACCESSORS(JSValue, value, Object, kValueOffset)
+
+
+JSValue* JSValue::cast(Object* obj) {
+  ASSERT(obj->IsJSValue());
+  ASSERT(HeapObject::cast(obj)->Size() == JSValue::kSize);
+  return reinterpret_cast<JSValue*>(obj);
+}
+
+
+INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
+INT_ACCESSORS(Code, relocation_size, kRelocationSizeOffset)
+INT_ACCESSORS(Code, sinfo_size, kSInfoSizeOffset)
+
+
+Code::ICTargetState Code::ic_flag() {
+  return static_cast<ICTargetState>(READ_BYTE_FIELD(this, kICFlagOffset));
+}
+
+
+void Code::set_ic_flag(ICTargetState value) {
+  WRITE_BYTE_FIELD(this, kICFlagOffset, value);
+}
+
+
+byte* Code::instruction_start()  {
+  return FIELD_ADDR(this, kHeaderSize);
+}
+
+
+int Code::body_size() {
+  return RoundUp(instruction_size() + relocation_size(), kObjectAlignment);
+}
+
+
+byte* Code::relocation_start() {
+  return FIELD_ADDR(this, CodeSize() - sinfo_size() - relocation_size());
+}
+
+
+byte* Code::entry() {
+  return instruction_start();
+}
+
+
+bool Code::contains(byte* pc) {
+  return (instruction_start() <= pc) &&
+      (pc < instruction_start() + instruction_size());
+}
+
+
+byte* Code::sinfo_start() {
+  return FIELD_ADDR(this, CodeSize() - sinfo_size());
+}
+
+
+ACCESSORS(JSArray, length, Object, kLengthOffset)
+
+
+ACCESSORS(JSRegExp, data, Object, kDataOffset)
+
+
+JSRegExp::Type JSRegExp::TypeTag() {
+  Object* data = this->data();
+  if (data->IsUndefined()) return JSRegExp::NOT_COMPILED;
+  Smi* smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex));
+  return static_cast<JSRegExp::Type>(smi->value());
+}
+
+
+Object* JSRegExp::DataAt(int index) {
+  ASSERT(TypeTag() != NOT_COMPILED);
+  return FixedArray::cast(data())->get(index);
+}
+
+
+bool JSObject::HasFastElements() {
+  return !elements()->IsDictionary();
+}
+
+
+bool JSObject::HasNamedInterceptor() {
+  return map()->has_named_interceptor();
+}
+
+
+bool JSObject::HasIndexedInterceptor() {
+  return map()->has_indexed_interceptor();
+}
+
+
+Dictionary* JSObject::property_dictionary() {
+  ASSERT(!HasFastProperties());
+  return Dictionary::cast(properties());
+}
+
+
+Dictionary* JSObject::element_dictionary() {
+  ASSERT(!HasFastElements());
+  return Dictionary::cast(elements());
+}
+
+
+bool String::HasHashCode() {
+  return (length_field() & kHashComputedMask) != 0;
+}
+
+
+uint32_t String::Hash() {
+  // Fast case: has hash code already been computed?
+  uint32_t field = length_field();
+  if (field & kHashComputedMask) return field >> kHashShift;
+  // Slow case: compute hash code and set it.
+  return ComputeAndSetHash();
+}
+
+
+StringHasher::StringHasher(int length)
+  : length_(length),
+    raw_running_hash_(0),
+    array_index_(0),
+    is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize),
+    is_first_char_(true),
+    is_valid_(true) { }
+
+
+bool StringHasher::has_trivial_hash() {
+  return length_ > String::kMaxMediumStringSize;
+}
+
+
+void StringHasher::AddCharacter(uc32 c) {
+  // Use the Jenkins one-at-a-time hash function to update the hash
+  // for the given character.
+  raw_running_hash_ += c;
+  raw_running_hash_ += (raw_running_hash_ << 10);
+  raw_running_hash_ ^= (raw_running_hash_ >> 6);
+  // Incremental array index computation.
+  if (is_array_index_) {
+    if (c < '0' || c > '9') {
+      is_array_index_ = false;
+    } else {
+      int d = c - '0';
+      if (is_first_char_) {
+        is_first_char_ = false;
+        if (c == '0' && length_ > 1) {
+          is_array_index_ = false;
+          return;
+        }
+      }
+      if (array_index_ > 429496729U - ((d + 2) >> 3)) {
+        is_array_index_ = false;
+      } else {
+        array_index_ = array_index_ * 10 + d;
+      }
+    }
+  }
+}
+
+
+void StringHasher::AddCharacterNoIndex(uc32 c) {
+  ASSERT(!is_array_index());
+  raw_running_hash_ += c;
+  raw_running_hash_ += (raw_running_hash_ << 10);
+  raw_running_hash_ ^= (raw_running_hash_ >> 6);
+}
+
+
+uint32_t StringHasher::GetHash() {
+  uint32_t result = raw_running_hash_;
+  result += (result << 3);
+  result ^= (result >> 11);
+  result += (result << 15);
+  return result;
+}
+
+
+bool String::AsArrayIndex(uint32_t* index) {
+  uint32_t field = length_field();
+  if ((field & kHashComputedMask) && !(field & kIsArrayIndexMask)) return false;
+  return SlowAsArrayIndex(index);
+}
+
+
+Object* JSObject::GetPrototype() {
+  return JSObject::cast(this)->map()->prototype();
+}
+
+
+PropertyAttributes JSObject::GetPropertyAttribute(String* key) {
+  return GetPropertyAttributeWithReceiver(this, key);
+}
+
+
+bool JSObject::HasElement(uint32_t index) {
+  return HasElementWithReceiver(this, index);
+}
+
+
+bool AccessorInfo::all_can_read() {
+  return BooleanBit::get(flag(), kAllCanReadBit);
+}
+
+
+void AccessorInfo::set_all_can_read(bool value) {
+  set_flag(BooleanBit::set(flag(), kAllCanReadBit, value));
+}
+
+
+bool AccessorInfo::all_can_write() {
+  return BooleanBit::get(flag(), kAllCanWriteBit);
+}
+
+
+void AccessorInfo::set_all_can_write(bool value) {
+  set_flag(BooleanBit::set(flag(), kAllCanWriteBit, value));
+}
+
+
+PropertyAttributes AccessorInfo::property_attributes() {
+  return AttributesField::decode(static_cast<uint32_t>(flag()->value()));
+}
+
+
+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)));
+}
+
+void Dictionary::SetEntry(int entry,
+                          Object* key,
+                          Object* value,
+                          PropertyDetails details) {
+  ASSERT(!key->IsString() || details.index() > 0);
+  int index = EntryToIndex(entry);
+  WriteBarrierMode mode = GetWriteBarrierMode();
+  set(index, key, mode);
+  set(index+1, value, mode);
+  fast_set(this, index+2, details.AsSmi());
+}
+
+
+void Map::ClearCodeCache() {
+  // No write barrier is needed since empty_fixed_array is not in new space.
+  // Please note this function is used during marking:
+  //  - MarkCompactCollector::MarkUnmarkedObject
+  ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
+  WRITE_FIELD(this, kCodeCacheOffset, Heap::empty_fixed_array());
+}
+
+
+void JSArray::SetContent(FixedArray* storage) {
+  set_length(Smi::FromInt(storage->length()), SKIP_WRITE_BARRIER);
+  set_elements(storage);
+}
+
+
+Object* FixedArray::Copy() {
+  if (length() == 0) return this;
+  return Heap::CopyFixedArray(this);
+}
+
+
+#undef CAST_ACCESSOR
+#undef INT_ACCESSORS
+#undef SMI_ACCESSORS
+#undef ACCESSORS
+#undef FIELD_ADDR
+#undef READ_FIELD
+#undef WRITE_FIELD
+#undef WRITE_BARRIER
+#undef CONDITIONAL_WRITE_BARRIER
+#undef READ_MEMADDR_FIELD
+#undef WRITE_MEMADDR_FIELD
+#undef READ_DOUBLE_FIELD
+#undef WRITE_DOUBLE_FIELD
+#undef READ_INT_FIELD
+#undef WRITE_INT_FIELD
+#undef READ_SHORT_FIELD
+#undef WRITE_SHORT_FIELD
+#undef READ_BYTE_FIELD
+#undef WRITE_BYTE_FIELD
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_OBJECTS_INL_H_
diff --git a/regexp2000/src/objects.cc b/regexp2000/src/objects.cc
new file mode 100644 (file)
index 0000000..7cfa5a0
--- /dev/null
@@ -0,0 +1,6731 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "bootstrapper.h"
+#include "debug.h"
+#include "execution.h"
+#include "objects-inl.h"
+#include "macro-assembler.h"
+#include "scanner.h"
+#include "scopeinfo.h"
+#include "string-stream.h"
+
+#ifdef ENABLE_DISASSEMBLER
+#include "disassembler.h"
+#endif
+
+namespace v8 { namespace internal {
+
+// Getters and setters are stored in a fixed array property.  These are
+// constants for their indices.
+const int kGetterIndex = 0;
+const int kSetterIndex = 1;
+
+bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
+  // There is a constraint on the object; check
+  if (!this->IsJSObject()) return false;
+  // Fetch the constructor function of the object
+  Object* cons_obj = JSObject::cast(this)->map()->constructor();
+  if (!cons_obj->IsJSFunction()) return false;
+  JSFunction* fun = JSFunction::cast(cons_obj);
+  // Iterate through the chain of inheriting function templates to
+  // see if the required one occurs.
+  for (Object* type = fun->shared()->function_data();
+       type->IsFunctionTemplateInfo();
+       type = FunctionTemplateInfo::cast(type)->parent_template()) {
+    if (type == expected) return true;
+  }
+  // Didn't find the required type in the inheritance chain.
+  return false;
+}
+
+
+static Object* CreateJSValue(JSFunction* constructor, Object* value) {
+  Object* result = Heap::AllocateJSObject(constructor);
+  if (result->IsFailure()) return result;
+  JSValue::cast(result)->set_value(value);
+  return result;
+}
+
+
+Object* Object::ToObject(Context* global_context) {
+  if (IsNumber()) {
+    return CreateJSValue(global_context->number_function(), this);
+  } else if (IsBoolean()) {
+    return CreateJSValue(global_context->boolean_function(), this);
+  } else if (IsString()) {
+    return CreateJSValue(global_context->string_function(), this);
+  }
+  ASSERT(IsJSObject());
+  return this;
+}
+
+
+Object* Object::ToObject() {
+  Context* global_context = Top::context()->global_context();
+  if (IsJSObject()) {
+    return this;
+  } else if (IsNumber()) {
+    return CreateJSValue(global_context->number_function(), this);
+  } else if (IsBoolean()) {
+    return CreateJSValue(global_context->boolean_function(), this);
+  } else if (IsString()) {
+    return CreateJSValue(global_context->string_function(), this);
+  }
+
+  // Throw a type error.
+  return Failure::InternalError();
+}
+
+
+Object* Object::ToBoolean() {
+  if (IsTrue()) return Heap::true_value();
+  if (IsFalse()) return Heap::false_value();
+  if (IsSmi()) {
+    return Heap::ToBoolean(Smi::cast(this)->value() != 0);
+  }
+  if (IsUndefined() || IsNull()) return Heap::false_value();
+  // Undetectable object is false
+  if (IsUndetectableObject()) {
+    return Heap::false_value();
+  }
+  if (IsString()) {
+    return Heap::ToBoolean(String::cast(this)->length() != 0);
+  }
+  if (IsHeapNumber()) {
+    return HeapNumber::cast(this)->HeapNumberToBoolean();
+  }
+  return Heap::true_value();
+}
+
+
+void Object::Lookup(String* name, LookupResult* result) {
+  if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result);
+  Object* holder = NULL;
+  Context* global_context = Top::context()->global_context();
+  if (IsString()) {
+    holder = global_context->string_function()->instance_prototype();
+  } else if (IsNumber()) {
+    holder = global_context->number_function()->instance_prototype();
+  } else if (IsBoolean()) {
+    holder = global_context->boolean_function()->instance_prototype();
+  }
+  ASSERT(holder != NULL);  // cannot handle null or undefined.
+  JSObject::cast(holder)->Lookup(name, result);
+}
+
+
+Object* Object::GetPropertyWithReceiver(Object* receiver,
+                                        String* name,
+                                        PropertyAttributes* attributes) {
+  LookupResult result;
+  Lookup(name, &result);
+  return GetProperty(receiver, &result, name, attributes);
+}
+
+
+Object* Object::GetPropertyWithCallback(Object* receiver,
+                                        Object* structure,
+                                        String* name,
+                                        Object* holder) {
+  // To accommodate both the old and the new api we switch on the
+  // data structure used to store the callbacks.  Eventually proxy
+  // callbacks should be phased out.
+  if (structure->IsProxy()) {
+    AccessorDescriptor* callback =
+        reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
+    Object* value = (callback->getter)(receiver, callback->data);
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    return value;
+  }
+
+  // api style callbacks.
+  if (structure->IsAccessorInfo()) {
+    AccessorInfo* data = AccessorInfo::cast(structure);
+    Object* fun_obj = data->getter();
+    v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
+    HandleScope scope;
+    Handle<JSObject> self(JSObject::cast(receiver));
+    Handle<JSObject> holder_handle(JSObject::cast(holder));
+    Handle<String> key(name);
+    Handle<Object> fun_data(data->data());
+    LOG(ApiNamedPropertyAccess("load", *self, name));
+    v8::AccessorInfo info(v8::Utils::ToLocal(self),
+                          v8::Utils::ToLocal(fun_data),
+                          v8::Utils::ToLocal(holder_handle));
+    v8::Handle<v8::Value> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = call_fun(v8::Utils::ToLocal(key), info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (result.IsEmpty()) return Heap::undefined_value();
+    return *v8::Utils::OpenHandle(*result);
+  }
+
+  // __defineGetter__ callback
+  if (structure->IsFixedArray()) {
+    Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
+    if (getter->IsJSFunction()) {
+      HandleScope scope;
+      Handle<JSFunction> fun(JSFunction::cast(getter));
+      Handle<Object> self(receiver);
+      bool has_pending_exception;
+      Object* result =
+          *Execution::Call(fun, self, 0, NULL, &has_pending_exception);
+      // Check for pending exception and return the result.
+      if (has_pending_exception) return Failure::Exception();
+      return result;
+    }
+    // Getter is not a function.
+    return Heap::undefined_value();
+  }
+
+  UNREACHABLE();
+  return 0;
+}
+
+
+// Only deal with CALLBACKS and INTERCEPTOR
+Object* JSObject::GetPropertyWithFailedAccessCheck(Object* receiver,
+                                                   LookupResult* result,
+                                                   String* name) {
+  if (result->IsValid()) {
+    switch (result->type()) {
+      case CALLBACKS: {
+        // Only allow API accessors.
+        Object* obj = result->GetCallbackObject();
+        if (obj->IsAccessorInfo()) {
+          AccessorInfo* info = AccessorInfo::cast(obj);
+          if (info->all_can_read()) {
+            return GetPropertyWithCallback(receiver,
+                                           result->GetCallbackObject(),
+                                           name,
+                                           result->holder());
+          }
+        }
+        break;
+      }
+      case NORMAL:
+      case FIELD:
+      case CONSTANT_FUNCTION: {
+        // Search ALL_CAN_READ accessors in prototype chain.
+        LookupResult r;
+        result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
+        if (r.IsValid()) {
+          return GetPropertyWithFailedAccessCheck(receiver, &r, name);
+        }
+        break;
+      }
+      case INTERCEPTOR: {
+        // If the object has an interceptor, try real named properties.
+        // No access check in GetPropertyAttributeWithInterceptor.
+        LookupResult r;
+        result->holder()->LookupRealNamedProperty(name, &r);
+        if (r.IsValid()) {
+          return GetPropertyWithFailedAccessCheck(receiver, &r, name);
+        }
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+  }
+
+  Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
+  return Heap::undefined_value();
+}
+
+
+Object* JSObject::GetLazyProperty(Object* receiver,
+                                  LookupResult* result,
+                                  String* name,
+                                  PropertyAttributes* attributes) {
+  HandleScope scope;
+  Handle<Object> this_handle(this);
+  Handle<Object> receiver_handle(receiver);
+  Handle<String> name_handle(name);
+  bool pending_exception;
+  LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
+           &pending_exception);
+  if (pending_exception) return Failure::Exception();
+  return this_handle->GetPropertyWithReceiver(*receiver_handle,
+                                              *name_handle,
+                                              attributes);
+}
+
+
+Object* JSObject::SetLazyProperty(LookupResult* result,
+                                  String* name,
+                                  Object* value,
+                                  PropertyAttributes attributes) {
+  ASSERT(!IsJSGlobalProxy());
+  HandleScope scope;
+  Handle<JSObject> this_handle(this);
+  Handle<String> name_handle(name);
+  Handle<Object> value_handle(value);
+  bool pending_exception;
+  LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
+           &pending_exception);
+  if (pending_exception) return Failure::Exception();
+  return this_handle->SetProperty(*name_handle, *value_handle, attributes);
+}
+
+
+Object* JSObject::DeleteLazyProperty(LookupResult* result, String* name) {
+  HandleScope scope;
+  Handle<JSObject> this_handle(this);
+  Handle<String> name_handle(name);
+  bool pending_exception;
+  LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
+           &pending_exception);
+  if (pending_exception) return Failure::Exception();
+  return this_handle->DeleteProperty(*name_handle);
+}
+
+
+Object* Object::GetProperty(Object* receiver,
+                            LookupResult* result,
+                            String* name,
+                            PropertyAttributes* attributes) {
+  // Make sure that the top context does not change when doing
+  // callbacks or interceptor calls.
+  AssertNoContextChange ncc;
+
+  // Traverse the prototype chain from the current object (this) to
+  // the holder and check for access rights. This avoid traversing the
+  // objects more than once in case of interceptors, because the
+  // holder will always be the interceptor holder and the search may
+  // only continue with a current object just after the interceptor
+  // holder in the prototype chain.
+  Object* last = result->IsValid() ? result->holder() : Heap::null_value();
+  for (Object* current = this; true; current = current->GetPrototype()) {
+    if (current->IsAccessCheckNeeded()) {
+      // Check if we're allowed to read from the current object. Note
+      // that even though we may not actually end up loading the named
+      // property from the current object, we still check that we have
+      // access to the it.
+      JSObject* checked = JSObject::cast(current);
+      if (!Top::MayNamedAccess(checked, name, v8::ACCESS_GET)) {
+        return checked->GetPropertyWithFailedAccessCheck(receiver,
+                                                         result,
+                                                         name);
+      }
+    }
+    // Stop traversing the chain once we reach the last object in the
+    // chain; either the holder of the result or null in case of an
+    // absent property.
+    if (current == last) break;
+  }
+
+  if (!result->IsProperty()) {
+    *attributes = ABSENT;
+    return Heap::undefined_value();
+  }
+  *attributes = result->GetAttributes();
+  if (!result->IsLoaded()) {
+    return JSObject::cast(this)->GetLazyProperty(receiver,
+                                                 result,
+                                                 name,
+                                                 attributes);
+  }
+  Object* value;
+  JSObject* holder = result->holder();
+  switch (result->type()) {
+    case NORMAL:
+      value =
+          holder->property_dictionary()->ValueAt(result->GetDictionaryEntry());
+      ASSERT(!value->IsTheHole() || result->IsReadOnly());
+      return value->IsTheHole() ? Heap::undefined_value() : value;
+    case FIELD:
+      value = holder->FastPropertyAt(result->GetFieldIndex());
+      ASSERT(!value->IsTheHole() || result->IsReadOnly());
+      return value->IsTheHole() ? Heap::undefined_value() : value;
+    case CONSTANT_FUNCTION:
+      return result->GetConstantFunction();
+    case CALLBACKS:
+      return GetPropertyWithCallback(receiver,
+                                     result->GetCallbackObject(),
+                                     name,
+                                     holder);
+    case INTERCEPTOR: {
+      JSObject* recvr = JSObject::cast(receiver);
+      return holder->GetPropertyWithInterceptor(recvr, name, attributes);
+    }
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+Object* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
+  // Non-JS objects do not have integer indexed properties.
+  if (!IsJSObject()) return Heap::undefined_value();
+  return JSObject::cast(this)->GetElementWithReceiver(JSObject::cast(receiver),
+                                                      index);
+}
+
+
+Object* Object::GetPrototype() {
+  // The object is either a number, a string, a boolean, or a real JS object.
+  if (IsJSObject()) return JSObject::cast(this)->map()->prototype();
+  Context* context = Top::context()->global_context();
+
+  if (IsNumber()) return context->number_function()->instance_prototype();
+  if (IsString()) return context->string_function()->instance_prototype();
+  if (IsBoolean()) {
+    return context->boolean_function()->instance_prototype();
+  } else {
+    return Heap::null_value();
+  }
+}
+
+
+void Object::ShortPrint() {
+  HeapStringAllocator allocator;
+  StringStream accumulator(&allocator);
+  ShortPrint(&accumulator);
+  accumulator.OutputToStdOut();
+}
+
+
+void Object::ShortPrint(StringStream* accumulator) {
+  if (IsSmi()) {
+    Smi::cast(this)->SmiPrint(accumulator);
+  } else if (IsFailure()) {
+    Failure::cast(this)->FailurePrint(accumulator);
+  } else {
+    HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
+  }
+}
+
+
+void Smi::SmiPrint() {
+  PrintF("%d", value());
+}
+
+
+void Smi::SmiPrint(StringStream* accumulator) {
+  accumulator->Add("%d", value());
+}
+
+
+void Failure::FailurePrint(StringStream* accumulator) {
+  accumulator->Add("Failure(%d)", value());
+}
+
+
+void Failure::FailurePrint() {
+  PrintF("Failure(%d)", value());
+}
+
+
+Failure* Failure::RetryAfterGC(int requested_bytes, AllocationSpace space) {
+  ASSERT((space & ~kSpaceTagMask) == 0);
+  int requested = requested_bytes >> kObjectAlignmentBits;
+  int value = (requested << kSpaceTagSize) | space;
+  // We can't very well allocate a heap number in this situation, and if the
+  // requested memory is so large it seems reasonable to say that this is an
+  // out of memory situation.  This fixes a crash in
+  // js1_5/Regress/regress-303213.js.
+  if (value >> kSpaceTagSize != requested ||
+      !Smi::IsValid(value) ||
+      value != ((value << kFailureTypeTagSize) >> kFailureTypeTagSize) ||
+      !Smi::IsValid(value << kFailureTypeTagSize)) {
+    Top::context()->mark_out_of_memory();
+    return Failure::OutOfMemoryException();
+  }
+  return Construct(RETRY_AFTER_GC, value);
+}
+
+
+// Should a word be prefixed by 'a' or 'an' in order to read naturally in
+// English?  Returns false for non-ASCII or words that don't start with
+// a capital letter.  The a/an rule follows pronunciation in English.
+// We don't use the BBC's overcorrect "an historic occasion" though if
+// you speak a dialect you may well say "an 'istoric occasion".
+static bool AnWord(String* str) {
+  if (str->length() == 0) return false;  // a nothing
+  int c0 = str->Get(0);
+  int c1 = str->length() > 1 ? str->Get(1) : 0;
+  if (c0 == 'U') {
+    if (c1 > 'Z') {
+      return true;  // an Umpire, but a UTF8String, a U
+    }
+  } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
+    return true;   // an Ape, an ABCBook
+  } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
+           (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
+            c0 == 'S' || c0 == 'X')) {
+    return true;   // an MP3File, an M
+  }
+  return false;
+}
+
+
+Object* String::Flatten() {
+#ifdef DEBUG
+  // Do not attempt to flatten in debug mode when allocation is not
+  // allowed.  This is to avoid an assertion failure when allocating.
+  // Flattening strings is the only case where we always allow
+  // allocation because no GC is performed if the allocation fails.
+  if (!Heap::IsAllocationAllowed()) return this;
+#endif
+
+  switch (representation_tag()) {
+    case kSlicedStringTag: {
+      SlicedString* ss = SlicedString::cast(this);
+      // The SlicedString constructor should ensure that there are no
+      // SlicedStrings that are constructed directly on top of other
+      // SlicedStrings.
+      ASSERT(!ss->buffer()->IsSlicedString());
+      Object* ok = String::cast(ss->buffer())->Flatten();
+      if (ok->IsFailure()) return ok;
+      // Under certain circumstances (TryFlatten fails in String::Slice)
+      // we can have a cons string under a slice.  In this case we need
+      // to get the flat string out of the cons!
+      if (String::cast(ok)->StringIsConsString()) {
+        ss->set_buffer(ConsString::cast(ok)->first());
+      }
+      return this;
+    }
+    case kConsStringTag: {
+      ConsString* cs = ConsString::cast(this);
+      if (String::cast(cs->second())->length() == 0) {
+        return this;
+      }
+      // There's little point in putting the flat string in new space if the
+      // cons string is in old space.  It can never get GCed until there is
+      // an old space GC.
+      PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
+      int len = length();
+      Object* object;
+      String* result;
+      if (IsAsciiRepresentation()) {
+        object = Heap::AllocateRawAsciiString(len, tenure);
+        if (object->IsFailure()) return object;
+        result = String::cast(object);
+        String* first = String::cast(cs->first());
+        int first_length = first->length();
+        char* dest = SeqAsciiString::cast(result)->GetChars();
+        WriteToFlat(first, dest, 0, first_length);
+        WriteToFlat(String::cast(cs->second()),
+                    dest + first_length,
+                    0,
+                    len - first_length);
+      } else {
+        object = Heap::AllocateRawTwoByteString(len, tenure);
+        if (object->IsFailure()) return object;
+        result = String::cast(object);
+        uc16* dest = SeqTwoByteString::cast(result)->GetChars();
+        String* first = String::cast(cs->first());
+        int first_length = first->length();
+        WriteToFlat(first, dest, 0, first_length);
+        WriteToFlat(String::cast(cs->second()),
+                    dest + first_length,
+                    0,
+                    len - first_length);
+      }
+      cs->set_first(result);
+      cs->set_second(Heap::empty_string());
+      return this;
+    }
+    default:
+      return this;
+  }
+}
+
+
+void String::StringShortPrint(StringStream* accumulator) {
+  int len = length();
+  if (len > kMaxMediumStringSize) {
+    accumulator->Add("<Very long string[%u]>", len);
+    return;
+  }
+
+  if (!LooksValid()) {
+    accumulator->Add("<Invalid String>");
+    return;
+  }
+
+  StringInputBuffer buf(this);
+
+  bool truncated = false;
+  if (len > kMaxShortPrintLength) {
+    len = kMaxShortPrintLength;
+    truncated = true;
+  }
+  bool ascii = true;
+  for (int i = 0; i < len; i++) {
+    int c = buf.GetNext();
+
+    if (c < 32 || c >= 127) {
+      ascii = false;
+    }
+  }
+  buf.Reset(this);
+  if (ascii) {
+    accumulator->Add("<String[%u]: ", length());
+    for (int i = 0; i < len; i++) {
+      accumulator->Put(buf.GetNext());
+    }
+    accumulator->Put('>');
+  } else {
+    // Backslash indicates that the string contains control
+    // characters and that backslashes are therefore escaped.
+    accumulator->Add("<String[%u]\\: ", length());
+    for (int i = 0; i < len; i++) {
+      int c = buf.GetNext();
+      if (c == '\n') {
+        accumulator->Add("\\n");
+      } else if (c == '\r') {
+        accumulator->Add("\\r");
+      } else if (c == '\\') {
+        accumulator->Add("\\\\");
+      } else if (c < 32 || c > 126) {
+        accumulator->Add("\\x%02x", c);
+      } else {
+        accumulator->Put(c);
+      }
+    }
+    if (truncated) {
+      accumulator->Put('.');
+      accumulator->Put('.');
+      accumulator->Put('.');
+    }
+    accumulator->Put('>');
+  }
+  return;
+}
+
+
+void JSObject::JSObjectShortPrint(StringStream* accumulator) {
+  switch (map()->instance_type()) {
+    case JS_ARRAY_TYPE: {
+      double length = JSArray::cast(this)->length()->Number();
+      accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
+      break;
+    }
+    case JS_REGEXP_TYPE: {
+      accumulator->Add("<JS RegExp>");
+      break;
+    }
+    case JS_FUNCTION_TYPE: {
+      Object* fun_name = JSFunction::cast(this)->shared()->name();
+      bool printed = false;
+      if (fun_name->IsString()) {
+        String* str = String::cast(fun_name);
+        if (str->length() > 0) {
+          accumulator->Add("<JS Function ");
+          accumulator->Put(str);
+          accumulator->Put('>');
+          printed = true;
+        }
+      }
+      if (!printed) {
+        accumulator->Add("<JS Function>");
+      }
+      break;
+    }
+    // All other JSObjects are rather similar to each other (JSObject,
+    // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
+    default: {
+      Object* constructor = map()->constructor();
+      bool printed = false;
+      if (constructor->IsHeapObject() &&
+          !Heap::Contains(HeapObject::cast(constructor))) {
+        accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
+      } else {
+        bool global_object = IsJSGlobalProxy();
+        if (constructor->IsJSFunction()) {
+          if (!Heap::Contains(JSFunction::cast(constructor)->shared())) {
+            accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
+          } else {
+            Object* constructor_name =
+                JSFunction::cast(constructor)->shared()->name();
+            if (constructor_name->IsString()) {
+              String* str = String::cast(constructor_name);
+              if (str->length() > 0) {
+                bool vowel = AnWord(str);
+                accumulator->Add("<%sa%s ",
+                       global_object ? "Global Object: " : "",
+                       vowel ? "n" : "");
+                accumulator->Put(str);
+                accumulator->Put('>');
+                printed = true;
+              }
+            }
+          }
+        }
+        if (!printed) {
+          accumulator->Add("<JS %sObject", global_object ? "Global " : "");
+        }
+      }
+      if (IsJSValue()) {
+        accumulator->Add(" value = ");
+        JSValue::cast(this)->value()->ShortPrint(accumulator);
+      }
+      accumulator->Put('>');
+      break;
+    }
+  }
+}
+
+
+void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
+  // if (!Heap::InNewSpace(this)) PrintF("*", this);
+  if (!Heap::Contains(this)) {
+    accumulator->Add("!!!INVALID POINTER!!!");
+    return;
+  }
+  if (!Heap::Contains(map())) {
+    accumulator->Add("!!!INVALID MAP!!!");
+    return;
+  }
+
+  accumulator->Add("%p ", this);
+
+  if (IsString()) {
+    String::cast(this)->StringShortPrint(accumulator);
+    return;
+  }
+  if (IsJSObject()) {
+    JSObject::cast(this)->JSObjectShortPrint(accumulator);
+    return;
+  }
+  switch (map()->instance_type()) {
+    case MAP_TYPE:
+      accumulator->Add("<Map>");
+      break;
+    case FIXED_ARRAY_TYPE:
+      accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
+      break;
+    case BYTE_ARRAY_TYPE:
+      accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
+      break;
+    case SHARED_FUNCTION_INFO_TYPE:
+      accumulator->Add("<SharedFunctionInfo>");
+      break;
+#define MAKE_STRUCT_CASE(NAME, Name, name) \
+  case NAME##_TYPE:                        \
+    accumulator->Add(#Name);               \
+    break;
+  STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+    case CODE_TYPE:
+      accumulator->Add("<Code>");
+      break;
+    case ODDBALL_TYPE: {
+      if (IsUndefined())
+        accumulator->Add("<undefined>");
+      else if (IsTheHole())
+        accumulator->Add("<the hole>");
+      else if (IsNull())
+        accumulator->Add("<null>");
+      else if (IsTrue())
+        accumulator->Add("<true>");
+      else if (IsFalse())
+        accumulator->Add("<false>");
+      else
+        accumulator->Add("<Odd Oddball>");
+      break;
+    }
+    case HEAP_NUMBER_TYPE:
+      accumulator->Add("<Number: ");
+      HeapNumber::cast(this)->HeapNumberPrint(accumulator);
+      accumulator->Put('>');
+      break;
+    case PROXY_TYPE:
+      accumulator->Add("<Proxy>");
+      break;
+    default:
+      accumulator->Add("<Other heap object (%d)>", map()->instance_type());
+      break;
+  }
+}
+
+
+int HeapObject::SlowSizeFromMap(Map* map) {
+  // Avoid calling functions such as FixedArray::cast during GC, which
+  // read map pointer of this object again.
+  InstanceType instance_type = map->instance_type();
+
+  if (instance_type < FIRST_NONSTRING_TYPE
+      && (reinterpret_cast<String*>(this)->map_representation_tag(map)
+          == kSeqStringTag)) {
+    if (reinterpret_cast<String*>(this)->is_ascii_representation_map(map)) {
+      return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(map);
+    } else {
+      SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this);
+      return self->SeqTwoByteStringSize(map);
+    }
+  }
+
+  switch (instance_type) {
+    case FIXED_ARRAY_TYPE:
+      return reinterpret_cast<FixedArray*>(this)->FixedArraySize();
+    case BYTE_ARRAY_TYPE:
+      return reinterpret_cast<ByteArray*>(this)->ByteArraySize();
+    case CODE_TYPE:
+      return reinterpret_cast<Code*>(this)->CodeSize();
+    case MAP_TYPE:
+      return Map::kSize;
+    default:
+      return map->instance_size();
+  }
+}
+
+
+void HeapObject::Iterate(ObjectVisitor* v) {
+  // Handle header
+  IteratePointer(v, kMapOffset);
+  // Handle object body
+  Map* m = map();
+  IterateBody(m->instance_type(), SizeFromMap(m), v);
+}
+
+
+void HeapObject::IterateBody(InstanceType type, int object_size,
+                             ObjectVisitor* v) {
+  // Avoiding <Type>::cast(this) because it accesses the map pointer field.
+  // During GC, the map pointer field is encoded.
+  if (type < FIRST_NONSTRING_TYPE) {
+    switch (type & kStringRepresentationMask) {
+      case kSeqStringTag:
+        break;
+      case kConsStringTag:
+        reinterpret_cast<ConsString*>(this)->ConsStringIterateBody(v);
+        break;
+      case kSlicedStringTag:
+        reinterpret_cast<SlicedString*>(this)->SlicedStringIterateBody(v);
+        break;
+    }
+    return;
+  }
+
+  switch (type) {
+    case FIXED_ARRAY_TYPE:
+      reinterpret_cast<FixedArray*>(this)->FixedArrayIterateBody(v);
+      break;
+    case JS_OBJECT_TYPE:
+    case JS_VALUE_TYPE:
+    case JS_ARRAY_TYPE:
+    case JS_REGEXP_TYPE:
+    case JS_FUNCTION_TYPE:
+    case JS_GLOBAL_PROXY_TYPE:
+    case JS_GLOBAL_OBJECT_TYPE:
+    case JS_BUILTINS_OBJECT_TYPE:
+      reinterpret_cast<JSObject*>(this)->JSObjectIterateBody(object_size, v);
+      break;
+    case ODDBALL_TYPE:
+      reinterpret_cast<Oddball*>(this)->OddballIterateBody(v);
+      break;
+    case PROXY_TYPE:
+      reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v);
+      break;
+    case MAP_TYPE:
+      reinterpret_cast<Map*>(this)->MapIterateBody(v);
+      break;
+    case CODE_TYPE:
+      reinterpret_cast<Code*>(this)->CodeIterateBody(v);
+      break;
+    case HEAP_NUMBER_TYPE:
+    case FILLER_TYPE:
+    case BYTE_ARRAY_TYPE:
+      break;
+    case SHARED_FUNCTION_INFO_TYPE: {
+      SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
+      shared->SharedFunctionInfoIterateBody(v);
+      break;
+    }
+#define MAKE_STRUCT_CASE(NAME, Name, name) \
+        case NAME##_TYPE:
+      STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+      IterateStructBody(object_size, v);
+      break;
+    default:
+      PrintF("Unknown type: %d\n", type);
+      UNREACHABLE();
+  }
+}
+
+
+void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) {
+  IteratePointers(v, HeapObject::kHeaderSize, object_size);
+}
+
+
+Object* HeapNumber::HeapNumberToBoolean() {
+  // NaN, +0, and -0 should return the false object
+  switch (fpclassify(value())) {
+    case FP_NAN:  // fall through
+    case FP_ZERO: return Heap::false_value();
+    default: return Heap::true_value();
+  }
+}
+
+
+void HeapNumber::HeapNumberPrint() {
+  PrintF("%.16g", Number());
+}
+
+
+void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
+  // The Windows version of vsnprintf can allocate when printing a %g string
+  // into a buffer that may not be big enough.  We don't want random memory
+  // allocation when producing post-crash stack traces, so we print into a
+  // buffer that is plenty big enough for any floating point number, then
+  // print that using vsnprintf (which may truncate but never allocate if
+  // there is no more space in the buffer).
+  EmbeddedVector<char, 100> buffer;
+  OS::SNPrintF(buffer, "%.16g", Number());
+  accumulator->Add("%s", buffer.start());
+}
+
+
+String* JSObject::class_name() {
+  if (IsJSFunction()) return Heap::function_class_symbol();
+  if (map()->constructor()->IsJSFunction()) {
+    JSFunction* constructor = JSFunction::cast(map()->constructor());
+    return String::cast(constructor->shared()->instance_class_name());
+  }
+  // If the constructor is not present, return "Object".
+  return Heap::Object_symbol();
+}
+
+
+void JSObject::JSObjectIterateBody(int object_size, ObjectVisitor* v) {
+  // Iterate over all fields in the body. Assumes all are Object*.
+  IteratePointers(v, kPropertiesOffset, object_size);
+}
+
+
+Object* JSObject::AddFastPropertyUsingMap(Map* new_map,
+                                          String* name,
+                                          Object* value) {
+  int index = new_map->PropertyIndexFor(name);
+  if (map()->unused_property_fields() == 0) {
+    ASSERT(map()->unused_property_fields() == 0);
+    int new_unused = new_map->unused_property_fields();
+    Object* values =
+        properties()->CopySize(properties()->length() + new_unused + 1);
+    if (values->IsFailure()) return values;
+    set_properties(FixedArray::cast(values));
+  }
+  set_map(new_map);
+  return FastPropertyAtPut(index, value);
+}
+
+
+Object* JSObject::AddFastProperty(String* name,
+                                  Object* value,
+                                  PropertyAttributes attributes) {
+  // Normalize the object if the name is not a real identifier.
+  StringInputBuffer buffer(name);
+  if (!Scanner::IsIdentifier(&buffer)) {
+    Object* obj = NormalizeProperties();
+    if (obj->IsFailure()) return obj;
+    return AddSlowProperty(name, value, attributes);
+  }
+
+  DescriptorArray* old_descriptors = map()->instance_descriptors();
+  // Compute the new index for new field.
+  int index = map()->NextFreePropertyIndex();
+
+  // Allocate new instance descriptors with (name, index) added
+  FieldDescriptor new_field(name, index, attributes);
+  Object* new_descriptors =
+      old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
+  if (new_descriptors->IsFailure()) return new_descriptors;
+
+  // Only allow map transition if the object's map is NOT equal to the
+  // global object_function's map and there is not a transition for name.
+  bool allow_map_transition =
+        !old_descriptors->Contains(name) &&
+        (Top::context()->global_context()->object_function()->map() != map());
+
+  ASSERT(index < map()->inobject_properties() ||
+         (index - map()->inobject_properties()) < properties()->length() ||
+         map()->unused_property_fields() == 0);
+  // Allocate a new map for the object.
+  Object* r = map()->Copy();
+  if (r->IsFailure()) return r;
+  Map* new_map = Map::cast(r);
+  if (allow_map_transition) {
+    // Allocate new instance descriptors for the old map with map transition.
+    MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
+    Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
+    if (r->IsFailure()) return r;
+    old_descriptors = DescriptorArray::cast(r);
+  }
+
+  if (map()->unused_property_fields() == 0) {
+    if (properties()->length() > kMaxFastProperties) {
+      Object* obj = NormalizeProperties();
+      if (obj->IsFailure()) return obj;
+      return AddSlowProperty(name, value, attributes);
+    }
+    // Make room for the new value
+    Object* values =
+        properties()->CopySize(properties()->length() + kFieldsAdded);
+    if (values->IsFailure()) return values;
+    set_properties(FixedArray::cast(values));
+    new_map->set_unused_property_fields(kFieldsAdded - 1);
+  } else {
+    new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
+  }
+  // We have now allocated all the necessary objects.
+  // All the changes can be applied at once, so they are atomic.
+  map()->set_instance_descriptors(old_descriptors);
+  new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+  set_map(new_map);
+  return FastPropertyAtPut(index, value);
+}
+
+
+Object* JSObject::AddConstantFunctionProperty(String* name,
+                                              JSFunction* function,
+                                              PropertyAttributes attributes) {
+  // Allocate new instance descriptors with (name, function) added
+  ConstantFunctionDescriptor d(name, function, attributes);
+  Object* new_descriptors =
+      map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
+  if (new_descriptors->IsFailure()) return new_descriptors;
+
+  // Allocate a new map for the object.
+  Object* new_map = map()->Copy();
+  if (new_map->IsFailure()) return new_map;
+
+  DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
+  Map::cast(new_map)->set_instance_descriptors(descriptors);
+  Map* old_map = map();
+  set_map(Map::cast(new_map));
+
+  // If the old map is the global object map (from new Object()),
+  // then transitions are not added to it, so we are done.
+  if (old_map == Top::context()->global_context()->object_function()->map()) {
+    return function;
+  }
+
+  // Do not add CONSTANT_TRANSITIONS to global objects
+  if (IsGlobalObject()) {
+    return function;
+  }
+
+  // Add a CONSTANT_TRANSITION descriptor to the old map,
+  // so future assignments to this property on other objects
+  // of the same type will create a normal field, not a constant function.
+  // Don't do this for special properties, with non-trival attributes.
+  if (attributes != NONE) {
+    return function;
+  }
+  ConstTransitionDescriptor mark(name);
+  new_descriptors =
+      old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
+  if (new_descriptors->IsFailure()) {
+    return function;  // We have accomplished the main goal, so return success.
+  }
+  old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+
+  return function;
+}
+
+
+// Add property in slow mode
+Object* JSObject::AddSlowProperty(String* name,
+                                  Object* value,
+                                  PropertyAttributes attributes) {
+  PropertyDetails details = PropertyDetails(attributes, NORMAL);
+  Object* result = property_dictionary()->AddStringEntry(name, value, details);
+  if (result->IsFailure()) return result;
+  if (property_dictionary() != result) {
+     set_properties(Dictionary::cast(result));
+  }
+  return value;
+}
+
+
+Object* JSObject::AddProperty(String* name,
+                              Object* value,
+                              PropertyAttributes attributes) {
+  ASSERT(!IsJSGlobalProxy());
+  if (HasFastProperties()) {
+    // Ensure the descriptor array does not get too big.
+    if (map()->instance_descriptors()->number_of_descriptors() <
+        DescriptorArray::kMaxNumberOfDescriptors) {
+      if (value->IsJSFunction()) {
+        return AddConstantFunctionProperty(name,
+                                           JSFunction::cast(value),
+                                           attributes);
+      } else {
+        return AddFastProperty(name, value, attributes);
+      }
+    } else {
+      // Normalize the object to prevent very large instance descriptors.
+      // This eliminates unwanted N^2 allocation and lookup behavior.
+      Object* obj = NormalizeProperties();
+      if (obj->IsFailure()) return obj;
+    }
+  }
+  return AddSlowProperty(name, value, attributes);
+}
+
+
+Object* JSObject::SetPropertyPostInterceptor(String* name,
+                                             Object* value,
+                                             PropertyAttributes attributes) {
+  // Check local property, ignore interceptor.
+  LookupResult result;
+  LocalLookupRealNamedProperty(name, &result);
+  if (result.IsValid()) return SetProperty(&result, name, value, attributes);
+  // Add real property.
+  return AddProperty(name, value, attributes);
+}
+
+
+Object* JSObject::ReplaceSlowProperty(String* name,
+                                       Object* value,
+                                       PropertyAttributes attributes) {
+  Dictionary* dictionary = property_dictionary();
+  PropertyDetails old_details =
+      dictionary->DetailsAt(dictionary->FindStringEntry(name));
+  int new_index = old_details.index();
+  if (old_details.IsTransition()) new_index = 0;
+
+  PropertyDetails new_details(attributes, NORMAL, old_details.index());
+  Object* result =
+      property_dictionary()->SetOrAddStringEntry(name, value, new_details);
+  if (result->IsFailure()) return result;
+  if (property_dictionary() != result) {
+    set_properties(Dictionary::cast(result));
+  }
+  return value;
+}
+
+Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
+    String* name,
+    Object* new_value,
+    PropertyAttributes attributes) {
+  Map* old_map = map();
+  Object* result = ConvertDescriptorToField(name, new_value, attributes);
+  if (result->IsFailure()) return result;
+  // If we get to this point we have succeeded - do not return failure
+  // after this point.  Later stuff is optional.
+  if (!HasFastProperties()) {
+    return result;
+  }
+  // Do not add transitions to the map of "new Object()".
+  if (map() == Top::context()->global_context()->object_function()->map()) {
+    return result;
+  }
+
+  MapTransitionDescriptor transition(name,
+                                     map(),
+                                     attributes);
+  Object* new_descriptors =
+      old_map->instance_descriptors()->
+          CopyInsert(&transition, KEEP_TRANSITIONS);
+  if (new_descriptors->IsFailure()) return result;  // Yes, return _result_.
+  old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+  return result;
+}
+
+
+Object* JSObject::ConvertDescriptorToField(String* name,
+                                           Object* new_value,
+                                           PropertyAttributes attributes) {
+  if (map()->unused_property_fields() == 0 &&
+      properties()->length() > kMaxFastProperties) {
+    Object* obj = NormalizeProperties();
+    if (obj->IsFailure()) return obj;
+    return ReplaceSlowProperty(name, new_value, attributes);
+  }
+
+  int index = map()->NextFreePropertyIndex();
+  FieldDescriptor new_field(name, index, attributes);
+  // Make a new DescriptorArray replacing an entry with FieldDescriptor.
+  Object* descriptors_unchecked = map()->instance_descriptors()->
+      CopyInsert(&new_field, REMOVE_TRANSITIONS);
+  if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
+  DescriptorArray* new_descriptors =
+      DescriptorArray::cast(descriptors_unchecked);
+
+  // Make a new map for the object.
+  Object* new_map_unchecked = map()->Copy();
+  if (new_map_unchecked->IsFailure()) return new_map_unchecked;
+  Map* new_map = Map::cast(new_map_unchecked);
+  new_map->set_instance_descriptors(new_descriptors);
+
+  // Make new properties array if necessary.
+  FixedArray* new_properties = 0;  // Will always be NULL or a valid pointer.
+  int new_unused_property_fields = map()->unused_property_fields() - 1;
+  if (map()->unused_property_fields() == 0) {
+     new_unused_property_fields = kFieldsAdded - 1;
+     Object* new_properties_unchecked =
+        properties()->CopySize(properties()->length() + kFieldsAdded);
+    if (new_properties_unchecked->IsFailure()) return new_properties_unchecked;
+    new_properties = FixedArray::cast(new_properties_unchecked);
+  }
+
+  // Update pointers to commit changes.
+  // Object points to the new map.
+  new_map->set_unused_property_fields(new_unused_property_fields);
+  set_map(new_map);
+  if (new_properties) {
+    set_properties(FixedArray::cast(new_properties));
+  }
+  return FastPropertyAtPut(index, new_value);
+}
+
+
+
+Object* JSObject::SetPropertyWithInterceptor(String* name,
+                                             Object* value,
+                                             PropertyAttributes attributes) {
+  HandleScope scope;
+  Handle<JSObject> this_handle(this);
+  Handle<String> name_handle(name);
+  Handle<Object> value_handle(value);
+  Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
+  if (!interceptor->setter()->IsUndefined()) {
+    Handle<Object> data_handle(interceptor->data());
+    LOG(ApiNamedPropertyAccess("interceptor-named-set", this, name));
+    v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
+                          v8::Utils::ToLocal(data_handle),
+                          v8::Utils::ToLocal(this_handle));
+    v8::NamedPropertySetter setter =
+        v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
+    v8::Handle<v8::Value> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      Handle<Object> value_unhole(value->IsTheHole() ?
+                                  Heap::undefined_value() :
+                                  value);
+      result = setter(v8::Utils::ToLocal(name_handle),
+                      v8::Utils::ToLocal(value_unhole),
+                      info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (!result.IsEmpty()) return *value_handle;
+  }
+  Object* raw_result = this_handle->SetPropertyPostInterceptor(*name_handle,
+                                                               *value_handle,
+                                                               attributes);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return raw_result;
+}
+
+
+Object* JSObject::SetProperty(String* name,
+                              Object* value,
+                              PropertyAttributes attributes) {
+  LookupResult result;
+  LocalLookup(name, &result);
+  return SetProperty(&result, name, value, attributes);
+}
+
+
+Object* JSObject::SetPropertyWithCallback(Object* structure,
+                                          String* name,
+                                          Object* value,
+                                          JSObject* holder) {
+  HandleScope scope;
+
+  // We should never get here to initialize a const with the hole
+  // value since a const declaration would conflict with the setter.
+  ASSERT(!value->IsTheHole());
+  Handle<Object> value_handle(value);
+
+  // To accommodate both the old and the new api we switch on the
+  // data structure used to store the callbacks.  Eventually proxy
+  // callbacks should be phased out.
+  if (structure->IsProxy()) {
+    AccessorDescriptor* callback =
+        reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
+    Object* obj = (callback->setter)(this,  value, callback->data);
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (obj->IsFailure()) return obj;
+    return *value_handle;
+  }
+
+  if (structure->IsAccessorInfo()) {
+    // api style callbacks
+    AccessorInfo* data = AccessorInfo::cast(structure);
+    Object* call_obj = data->setter();
+    v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
+    if (call_fun == NULL) return value;
+    Handle<JSObject> self(this);
+    Handle<JSObject> holder_handle(JSObject::cast(holder));
+    Handle<String> key(name);
+    Handle<Object> fun_data(data->data());
+    LOG(ApiNamedPropertyAccess("store", this, name));
+    v8::AccessorInfo info(v8::Utils::ToLocal(self),
+                          v8::Utils::ToLocal(fun_data),
+                          v8::Utils::ToLocal(holder_handle));
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      call_fun(v8::Utils::ToLocal(key),
+               v8::Utils::ToLocal(value_handle),
+               info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    return *value_handle;
+  }
+
+  if (structure->IsFixedArray()) {
+    Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
+    if (setter->IsJSFunction()) {
+      Handle<JSFunction> fun(JSFunction::cast(setter));
+      Handle<JSObject> self(this);
+      bool has_pending_exception;
+      Object** argv[] = { value_handle.location() };
+      Execution::Call(fun, self, 1, argv, &has_pending_exception);
+      // Check for pending exception and return the result.
+      if (has_pending_exception) return Failure::Exception();
+    } else {
+      Handle<String> key(name);
+      Handle<Object> holder_handle(holder);
+      Handle<Object> args[2] = { key, holder_handle };
+      return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
+                                               HandleVector(args, 2)));
+    }
+    return *value_handle;
+  }
+
+  UNREACHABLE();
+  return 0;
+}
+
+
+void JSObject::LookupCallbackSetterInPrototypes(String* name,
+                                                LookupResult* result) {
+  for (Object* pt = GetPrototype();
+       pt != Heap::null_value();
+       pt = pt->GetPrototype()) {
+    JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
+    if (result->IsValid()) {
+      if (!result->IsTransitionType() && result->IsReadOnly()) {
+        result->NotFound();
+        return;
+      }
+      if (result->type() == CALLBACKS) {
+        return;
+      }
+    }
+  }
+  result->NotFound();
+}
+
+
+void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
+  DescriptorArray* descriptors = map()->instance_descriptors();
+  int number = descriptors->Search(name);
+  if (number != DescriptorArray::kNotFound) {
+    result->DescriptorResult(this, descriptors->GetDetails(number), number);
+  } else {
+    result->NotFound();
+  }
+}
+
+
+void JSObject::LocalLookupRealNamedProperty(String* name,
+                                            LookupResult* result) {
+  if (IsJSGlobalProxy()) {
+    Object* proto = GetPrototype();
+    if (proto->IsNull()) return result->NotFound();
+    ASSERT(proto->IsJSGlobalObject());
+    return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
+  }
+
+  if (HasFastProperties()) {
+    LookupInDescriptor(name, result);
+    if (result->IsValid()) {
+      ASSERT(result->holder() == this && result->type() != NORMAL);
+      // Disallow caching for uninitialized constants. These can only
+      // occur as fields.
+      if (result->IsReadOnly() && result->type() == FIELD &&
+          FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
+        result->DisallowCaching();
+      }
+      return;
+    }
+  } else {
+    int entry = property_dictionary()->FindStringEntry(name);
+    if (entry != DescriptorArray::kNotFound) {
+      // Make sure to disallow caching for uninitialized constants
+      // found in the dictionary-mode objects.
+      if (property_dictionary()->ValueAt(entry)->IsTheHole()) {
+        result->DisallowCaching();
+      }
+      result->DictionaryResult(this, entry);
+      return;
+    }
+    // Slow case object skipped during lookup. Do not use inline caching.
+    result->DisallowCaching();
+  }
+  result->NotFound();
+}
+
+
+void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
+  LocalLookupRealNamedProperty(name, result);
+  if (result->IsProperty()) return;
+
+  LookupRealNamedPropertyInPrototypes(name, result);
+}
+
+
+void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
+                                                   LookupResult* result) {
+  for (Object* pt = GetPrototype();
+       pt != Heap::null_value();
+       pt = JSObject::cast(pt)->GetPrototype()) {
+    JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
+    if (result->IsValid()) {
+      switch (result->type()) {
+        case NORMAL:
+        case FIELD:
+        case CONSTANT_FUNCTION:
+        case CALLBACKS:
+          return;
+        default: break;
+      }
+    }
+  }
+  result->NotFound();
+}
+
+
+// We only need to deal with CALLBACKS and INTERCEPTORS
+Object* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
+                                                   String* name,
+                                                   Object* value) {
+  if (!result->IsProperty()) {
+    LookupCallbackSetterInPrototypes(name, result);
+  }
+
+  if (result->IsProperty()) {
+    if (!result->IsReadOnly()) {
+      switch (result->type()) {
+        case CALLBACKS: {
+          Object* obj = result->GetCallbackObject();
+          if (obj->IsAccessorInfo()) {
+            AccessorInfo* info = AccessorInfo::cast(obj);
+            if (info->all_can_write()) {
+              return SetPropertyWithCallback(result->GetCallbackObject(),
+                                             name,
+                                             value,
+                                             result->holder());
+            }
+          }
+          break;
+        }
+        case INTERCEPTOR: {
+          // Try lookup real named properties. Note that only property can be
+          // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
+          LookupResult r;
+          LookupRealNamedProperty(name, &r);
+          if (r.IsProperty()) {
+            return SetPropertyWithFailedAccessCheck(&r, name, value);
+          }
+          break;
+        }
+        default: {
+          break;
+        }
+      }
+    }
+  }
+
+  Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
+  return value;
+}
+
+
+Object* JSObject::SetProperty(LookupResult* result,
+                              String* name,
+                              Object* value,
+                              PropertyAttributes attributes) {
+  // Make sure that the top context does not change when doing callbacks or
+  // interceptor calls.
+  AssertNoContextChange ncc;
+
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded()
+    && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
+    return SetPropertyWithFailedAccessCheck(result, name, value);
+  }
+
+  if (IsJSGlobalProxy()) {
+    Object* proto = GetPrototype();
+    if (proto->IsNull()) return value;
+    ASSERT(proto->IsJSGlobalObject());
+    return JSObject::cast(proto)->SetProperty(result, name, value, attributes);
+  }
+
+  if (result->IsNotFound() || !result->IsProperty()) {
+    // We could not find a local property so let's check whether there is an
+    // accessor that wants to handle the property.
+    LookupResult accessor_result;
+    LookupCallbackSetterInPrototypes(name, &accessor_result);
+    if (accessor_result.IsValid()) {
+      return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
+                                     name,
+                                     value,
+                                     accessor_result.holder());
+    }
+  }
+  if (result->IsNotFound()) {
+    return AddProperty(name, value, attributes);
+  }
+  if (!result->IsLoaded()) {
+    return SetLazyProperty(result, name, value, attributes);
+  }
+  if (result->IsReadOnly() && result->IsProperty()) return value;
+  // This is a real property that is not read-only, or it is a
+  // transition or null descriptor and there are no setters in the prototypes.
+  switch (result->type()) {
+    case NORMAL:
+      property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
+      return value;
+    case FIELD:
+      return FastPropertyAtPut(result->GetFieldIndex(), value);
+    case MAP_TRANSITION:
+      if (attributes == result->GetAttributes()) {
+        // Only use map transition if the attributes match.
+        return AddFastPropertyUsingMap(result->GetTransitionMap(),
+                                       name,
+                                       value);
+      }
+      return ConvertDescriptorToField(name, value, attributes);
+    case CONSTANT_FUNCTION:
+      if (value == result->GetConstantFunction()) return value;
+      // Only replace the function if necessary.
+      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+    case CALLBACKS:
+      return SetPropertyWithCallback(result->GetCallbackObject(),
+                                     name,
+                                     value,
+                                     result->holder());
+    case INTERCEPTOR:
+      return SetPropertyWithInterceptor(name, value, attributes);
+    case CONSTANT_TRANSITION:
+      // Replace with a MAP_TRANSITION to a new map with a FIELD, even
+      // if the value is a function.
+      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+    case NULL_DESCRIPTOR:
+      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+    default:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+  return value;
+}
+
+
+// Set a real local property, even if it is READ_ONLY.  If the property is not
+// present, add it with attributes NONE.  This code is an exact clone of
+// SetProperty, with the check for IsReadOnly and the check for a
+// callback setter removed.  The two lines looking up the LookupResult
+// result are also added.  If one of the functions is changed, the other
+// should be.
+Object* JSObject::IgnoreAttributesAndSetLocalProperty(
+    String* name,
+    Object* value,
+    PropertyAttributes attributes) {
+  // Make sure that the top context does not change when doing callbacks or
+  // interceptor calls.
+  AssertNoContextChange ncc;
+  // ADDED TO CLONE
+  LookupResult result_struct;
+  LocalLookup(name, &result_struct);
+  LookupResult* result = &result_struct;
+  // END ADDED TO CLONE
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded()
+    && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
+    return SetPropertyWithFailedAccessCheck(result, name, value);
+  }
+  // Check for accessor in prototype chain removed here in clone.
+  if (result->IsNotFound()) {
+    return AddProperty(name, value, attributes);
+  }
+  if (!result->IsLoaded()) {
+    return SetLazyProperty(result, name, value, attributes);
+  }
+  //  Check of IsReadOnly removed from here in clone.
+  switch (result->type()) {
+    case NORMAL:
+      property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
+      return value;
+    case FIELD:
+      return FastPropertyAtPut(result->GetFieldIndex(), value);
+    case MAP_TRANSITION:
+      if (attributes == result->GetAttributes()) {
+        // Only use map transition if the attributes match.
+        return AddFastPropertyUsingMap(result->GetTransitionMap(),
+                                       name,
+                                       value);
+      } else {
+        return ConvertDescriptorToField(name, value, attributes);
+      }
+    case CONSTANT_FUNCTION:
+      if (value == result->GetConstantFunction()) return value;
+      // Only replace the function if necessary.
+      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+    case CALLBACKS:
+      return SetPropertyWithCallback(result->GetCallbackObject(),
+                                     name,
+                                     value,
+                                     result->holder());
+    case INTERCEPTOR:
+      return SetPropertyWithInterceptor(name, value, attributes);
+    case CONSTANT_TRANSITION:
+      // Replace with a MAP_TRANSITION to a new map with a FIELD, even
+      // if the value is a function.
+      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+    case NULL_DESCRIPTOR:
+      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
+    default:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+  return value;
+}
+
+
+PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
+      JSObject* receiver,
+      String* name,
+      bool continue_search) {
+  // Check local property, ignore interceptor.
+  LookupResult result;
+  LocalLookupRealNamedProperty(name, &result);
+  if (result.IsProperty()) return result.GetAttributes();
+
+  if (continue_search) {
+    // Continue searching via the prototype chain.
+    Object* pt = GetPrototype();
+    if (pt != Heap::null_value()) {
+      return JSObject::cast(pt)->
+        GetPropertyAttributeWithReceiver(receiver, name);
+    }
+  }
+  return ABSENT;
+}
+
+
+PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
+      JSObject* receiver,
+      String* name,
+      bool continue_search) {
+  // Make sure that the top context does not change when doing
+  // callbacks or interceptor calls.
+  AssertNoContextChange ncc;
+
+  HandleScope scope;
+  Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
+  Handle<JSObject> receiver_handle(receiver);
+  Handle<JSObject> holder_handle(this);
+  Handle<String> name_handle(name);
+  Handle<Object> data_handle(interceptor->data());
+  v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
+                        v8::Utils::ToLocal(data_handle),
+                        v8::Utils::ToLocal(holder_handle));
+  if (!interceptor->query()->IsUndefined()) {
+    v8::NamedPropertyQuery query =
+        v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
+    LOG(ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
+    v8::Handle<v8::Boolean> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = query(v8::Utils::ToLocal(name_handle), info);
+    }
+    if (!result.IsEmpty()) {
+      // Convert the boolean result to a property attribute
+      // specification.
+      return result->IsTrue() ? NONE : ABSENT;
+    }
+  } else if (!interceptor->getter()->IsUndefined()) {
+    v8::NamedPropertyGetter getter =
+        v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
+    LOG(ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
+    v8::Handle<v8::Value> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = getter(v8::Utils::ToLocal(name_handle), info);
+    }
+    if (!result.IsEmpty()) return NONE;
+  }
+  return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
+                                                            *name_handle,
+                                                            continue_search);
+}
+
+
+PropertyAttributes JSObject::GetPropertyAttributeWithReceiver(
+      JSObject* receiver,
+      String* key) {
+  uint32_t index = 0;
+  if (key->AsArrayIndex(&index)) {
+    if (HasElementWithReceiver(receiver, index)) return NONE;
+    return ABSENT;
+  }
+  // Named property.
+  LookupResult result;
+  Lookup(key, &result);
+  return GetPropertyAttribute(receiver, &result, key, true);
+}
+
+
+PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
+                                                  LookupResult* result,
+                                                  String* name,
+                                                  bool continue_search) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return ABSENT;
+  }
+  if (result->IsValid()) {
+    switch (result->type()) {
+      case NORMAL:  // fall through
+      case FIELD:
+      case CONSTANT_FUNCTION:
+      case CALLBACKS:
+        return result->GetAttributes();
+      case INTERCEPTOR:
+        return result->holder()->
+          GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
+      case MAP_TRANSITION:
+      case CONSTANT_TRANSITION:
+      case NULL_DESCRIPTOR:
+        return ABSENT;
+      default:
+        UNREACHABLE();
+        break;
+    }
+  }
+  return ABSENT;
+}
+
+
+PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
+  // Check whether the name is an array index.
+  uint32_t index = 0;
+  if (name->AsArrayIndex(&index)) {
+    if (HasLocalElement(index)) return NONE;
+    return ABSENT;
+  }
+  // Named property.
+  LookupResult result;
+  LocalLookup(name, &result);
+  return GetPropertyAttribute(this, &result, name, false);
+}
+
+
+Object* JSObject::NormalizeProperties() {
+  if (!HasFastProperties()) return this;
+
+  // Allocate new content
+  Object* obj =
+      Dictionary::Allocate(map()->NumberOfDescribedProperties() * 2 + 4);
+  if (obj->IsFailure()) return obj;
+  Dictionary* dictionary = Dictionary::cast(obj);
+
+  for (DescriptorReader r(map()->instance_descriptors());
+       !r.eos();
+       r.advance()) {
+    PropertyDetails details = r.GetDetails();
+    switch (details.type()) {
+      case CONSTANT_FUNCTION: {
+        PropertyDetails d =
+            PropertyDetails(details.attributes(), NORMAL, details.index());
+        Object* value = r.GetConstantFunction();
+        Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
+        if (result->IsFailure()) return result;
+        dictionary = Dictionary::cast(result);
+        break;
+      }
+      case FIELD: {
+        PropertyDetails d =
+            PropertyDetails(details.attributes(), NORMAL, details.index());
+        Object* value = FastPropertyAt(r.GetFieldIndex());
+        Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
+        if (result->IsFailure()) return result;
+        dictionary = Dictionary::cast(result);
+        break;
+      }
+      case CALLBACKS: {
+        PropertyDetails d =
+            PropertyDetails(details.attributes(), CALLBACKS, details.index());
+        Object* value = r.GetCallbacksObject();
+        Object* result = dictionary->AddStringEntry(r.GetKey(), value, d);
+        if (result->IsFailure()) return result;
+        dictionary = Dictionary::cast(result);
+        break;
+      }
+      case MAP_TRANSITION:
+      case CONSTANT_TRANSITION:
+      case NULL_DESCRIPTOR:
+      case INTERCEPTOR:
+        break;
+      default:
+      case NORMAL:
+        UNREACHABLE();
+        break;
+    }
+  }
+
+  // Copy the next enumeration index from instance descriptor.
+  int index = map()->instance_descriptors()->NextEnumerationIndex();
+  dictionary->SetNextEnumerationIndex(index);
+
+  // Allocate new map.
+  obj = map()->Copy();
+  if (obj->IsFailure()) return obj;
+
+  // We have now sucessfully allocated all the necessary objects.
+  // Changes can now be made with the guarantee that all of them take effect.
+  set_map(Map::cast(obj));
+  map()->set_instance_descriptors(Heap::empty_descriptor_array());
+
+  map()->set_unused_property_fields(0);
+  set_properties(dictionary);
+
+  Counters::props_to_dictionary.Increment();
+
+#ifdef DEBUG
+  if (FLAG_trace_normalization) {
+    PrintF("Object properties have been normalized:\n");
+    Print();
+  }
+#endif
+  return this;
+}
+
+
+Object* JSObject::TransformToFastProperties(int unused_property_fields) {
+  if (HasFastProperties()) return this;
+  return property_dictionary()->
+    TransformPropertiesToFastFor(this, unused_property_fields);
+}
+
+
+Object* JSObject::NormalizeElements() {
+  if (!HasFastElements()) return this;
+
+  // Get number of entries.
+  FixedArray* array = FixedArray::cast(elements());
+
+  // Compute the effective length.
+  int length = IsJSArray() ?
+               Smi::cast(JSArray::cast(this)->length())->value() :
+               array->length();
+  Object* obj = Dictionary::Allocate(length);
+  if (obj->IsFailure()) return obj;
+  Dictionary* dictionary = Dictionary::cast(obj);
+  // Copy entries.
+  for (int i = 0; i < length; i++) {
+    Object* value = array->get(i);
+    if (!value->IsTheHole()) {
+      PropertyDetails details = PropertyDetails(NONE, NORMAL);
+      Object* result = dictionary->AddNumberEntry(i, array->get(i), details);
+      if (result->IsFailure()) return result;
+      dictionary = Dictionary::cast(result);
+    }
+  }
+  // Switch to using the dictionary as the backing storage for elements.
+  set_elements(dictionary);
+
+  Counters::elements_to_dictionary.Increment();
+
+#ifdef DEBUG
+  if (FLAG_trace_normalization) {
+    PrintF("Object elements have been normalized:\n");
+    Print();
+  }
+#endif
+
+  return this;
+}
+
+
+Object* JSObject::DeletePropertyPostInterceptor(String* name) {
+  // Check local property, ignore interceptor.
+  LookupResult result;
+  LocalLookupRealNamedProperty(name, &result);
+  if (!result.IsValid()) return Heap::true_value();
+
+  // Normalize object if needed.
+  Object* obj = NormalizeProperties();
+  if (obj->IsFailure()) return obj;
+
+  ASSERT(!HasFastProperties());
+  // Attempt to remove the property from the property dictionary.
+  Dictionary* dictionary = property_dictionary();
+  int entry = dictionary->FindStringEntry(name);
+  if (entry != -1) return dictionary->DeleteProperty(entry);
+  return Heap::true_value();
+}
+
+
+Object* JSObject::DeletePropertyWithInterceptor(String* name) {
+  HandleScope scope;
+  Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
+  Handle<String> name_handle(name);
+  Handle<JSObject> this_handle(this);
+  if (!interceptor->deleter()->IsUndefined()) {
+    v8::NamedPropertyDeleter deleter =
+        v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
+    Handle<Object> data_handle(interceptor->data());
+    LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
+    v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
+                          v8::Utils::ToLocal(data_handle),
+                          v8::Utils::ToLocal(this_handle));
+    v8::Handle<v8::Boolean> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = deleter(v8::Utils::ToLocal(name_handle), info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (!result.IsEmpty()) {
+      ASSERT(result->IsBoolean());
+      return *v8::Utils::OpenHandle(*result);
+    }
+  }
+  Object* raw_result = this_handle->DeletePropertyPostInterceptor(*name_handle);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return raw_result;
+}
+
+
+Object* JSObject::DeleteElementPostInterceptor(uint32_t index) {
+  if (HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+      static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
+      static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    if (index < length) {
+      FixedArray::cast(elements())->set_the_hole(index);
+    }
+    return Heap::true_value();
+  }
+  ASSERT(!HasFastElements());
+  Dictionary* dictionary = element_dictionary();
+  int entry = dictionary->FindNumberEntry(index);
+  if (entry != -1) return dictionary->DeleteProperty(entry);
+  return Heap::true_value();
+}
+
+
+Object* JSObject::DeleteElementWithInterceptor(uint32_t index) {
+  // Make sure that the top context does not change when doing
+  // callbacks or interceptor calls.
+  AssertNoContextChange ncc;
+  HandleScope scope;
+  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
+  if (interceptor->deleter()->IsUndefined()) return Heap::false_value();
+  v8::IndexedPropertyDeleter deleter =
+      v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
+  Handle<JSObject> this_handle(this);
+  Handle<Object> data_handle(interceptor->data());
+  LOG(ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
+  v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
+                        v8::Utils::ToLocal(data_handle),
+                        v8::Utils::ToLocal(this_handle));
+  v8::Handle<v8::Boolean> result;
+  {
+    // Leaving JavaScript.
+    VMState state(OTHER);
+    result = deleter(index, info);
+  }
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  if (!result.IsEmpty()) {
+    ASSERT(result->IsBoolean());
+    return *v8::Utils::OpenHandle(*result);
+  }
+  Object* raw_result = this_handle->DeleteElementPostInterceptor(index);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return raw_result;
+}
+
+
+Object* JSObject::DeleteElement(uint32_t index) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
+    return Heap::false_value();
+  }
+
+  if (IsJSGlobalProxy()) {
+    Object* proto = GetPrototype();
+    if (proto->IsNull()) return Heap::false_value();
+    ASSERT(proto->IsJSGlobalObject());
+    return JSGlobalObject::cast(proto)->DeleteElement(index);
+  }
+
+  if (HasIndexedInterceptor()) {
+    return DeleteElementWithInterceptor(index);
+  }
+
+  if (HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+      static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
+      static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    if (index < length) {
+      FixedArray::cast(elements())->set_the_hole(index);
+    }
+    return Heap::true_value();
+  } else {
+    Dictionary* dictionary = element_dictionary();
+    int entry = dictionary->FindNumberEntry(index);
+    if (entry != -1) return dictionary->DeleteProperty(entry);
+  }
+  return Heap::true_value();
+}
+
+
+Object* JSObject::DeleteProperty(String* name) {
+  // ECMA-262, 3rd, 8.6.2.5
+  ASSERT(name->IsString());
+
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
+    return Heap::false_value();
+  }
+
+  if (IsJSGlobalProxy()) {
+    Object* proto = GetPrototype();
+    if (proto->IsNull()) return Heap::false_value();
+    ASSERT(proto->IsJSGlobalObject());
+    return JSGlobalObject::cast(proto)->DeleteProperty(name);
+  }
+
+  uint32_t index = 0;
+  if (name->AsArrayIndex(&index)) {
+    return DeleteElement(index);
+  } else {
+    LookupResult result;
+    LocalLookup(name, &result);
+    if (!result.IsValid()) return Heap::true_value();
+    if (result.IsDontDelete()) return Heap::false_value();
+    // Check for interceptor.
+    if (result.type() == INTERCEPTOR) {
+      return DeletePropertyWithInterceptor(name);
+    }
+    if (!result.IsLoaded()) {
+      return JSObject::cast(this)->DeleteLazyProperty(&result, name);
+    }
+    // Normalize object if needed.
+    Object* obj = NormalizeProperties();
+    if (obj->IsFailure()) return obj;
+    // Make sure the properties are normalized before removing the entry.
+    Dictionary* dictionary = property_dictionary();
+    int entry = dictionary->FindStringEntry(name);
+    if (entry != -1) return dictionary->DeleteProperty(entry);
+    return Heap::true_value();
+  }
+}
+
+
+// Check whether this object references another object.
+bool JSObject::ReferencesObject(Object* obj) {
+  AssertNoAllocation no_alloc;
+
+  // Is the object the constructor for this object?
+  if (map()->constructor() == obj) {
+    return true;
+  }
+
+  // Is the object the prototype for this object?
+  if (map()->prototype() == obj) {
+    return true;
+  }
+
+  // Check if the object is among the named properties.
+  Object* key = SlowReverseLookup(obj);
+  if (key != Heap::undefined_value()) {
+    return true;
+  }
+
+  // Check if the object is among the indexed properties.
+  if (HasFastElements()) {
+    int length = IsJSArray()
+        ? Smi::cast(JSArray::cast(this)->length())->value()
+        : FixedArray::cast(elements())->length();
+    for (int i = 0; i < length; i++) {
+      Object* element = FixedArray::cast(elements())->get(i);
+      if (!element->IsTheHole() && element == obj) {
+        return true;
+      }
+    }
+  } else {
+    key = element_dictionary()->SlowReverseLookup(obj);
+    if (key != Heap::undefined_value()) {
+      return true;
+    }
+  }
+
+  // For functions check the context. Boilerplate functions do
+  // not have to be traversed since they have no real context.
+  if (IsJSFunction() && !JSFunction::cast(this)->IsBoilerplate()) {
+    // Get the constructor function for arguments array.
+    JSObject* arguments_boilerplate =
+        Top::context()->global_context()->arguments_boilerplate();
+    JSFunction* arguments_function =
+        JSFunction::cast(arguments_boilerplate->map()->constructor());
+
+    // Get the context and don't check if it is the global context.
+    JSFunction* f = JSFunction::cast(this);
+    Context* context = f->context();
+    if (context->IsGlobalContext()) {
+      return false;
+    }
+
+    // Check the non-special context slots.
+    for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
+      // Only check JS objects.
+      if (context->get(i)->IsJSObject()) {
+        JSObject* ctxobj = JSObject::cast(context->get(i));
+        // If it is an arguments array check the content.
+        if (ctxobj->map()->constructor() == arguments_function) {
+          if (ctxobj->ReferencesObject(obj)) {
+            return true;
+          }
+        } else if (ctxobj == obj) {
+          return true;
+        }
+      }
+    }
+
+    // Check the context extension if any.
+    if (context->has_extension()) {
+      return context->extension()->ReferencesObject(obj);
+    }
+  }
+
+  // No references to object.
+  return false;
+}
+
+
+// Tests for the fast common case for property enumeration:
+// - this object has an enum cache
+// - this object has no elements
+// - no prototype has enumerable properties/elements
+// - neither this object nor any prototype has interceptors
+bool JSObject::IsSimpleEnum() {
+  JSObject* arguments_boilerplate =
+      Top::context()->global_context()->arguments_boilerplate();
+  JSFunction* arguments_function =
+      JSFunction::cast(arguments_boilerplate->map()->constructor());
+  if (IsAccessCheckNeeded()) return false;
+  if (map()->constructor() == arguments_function) return false;
+
+  for (Object* o = this;
+       o != Heap::null_value();
+       o = JSObject::cast(o)->GetPrototype()) {
+    JSObject* curr = JSObject::cast(o);
+    if (!curr->HasFastProperties()) return false;
+    if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
+    if (curr->NumberOfEnumElements() > 0) return false;
+    if (curr->HasNamedInterceptor()) return false;
+    if (curr->HasIndexedInterceptor()) return false;
+    if (curr != this) {
+      FixedArray* curr_fixed_array =
+          FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
+      if (curr_fixed_array->length() > 0) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+
+int Map::NumberOfDescribedProperties() {
+  int result = 0;
+  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
+    if (!r.IsTransition()) result++;
+  }
+  return result;
+}
+
+
+int Map::PropertyIndexFor(String* name) {
+  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
+    if (r.Equals(name)) return r.GetFieldIndex();
+  }
+  return -1;
+}
+
+
+int Map::NextFreePropertyIndex() {
+  int index = -1;
+  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
+    if (r.type() == FIELD) {
+      if (r.GetFieldIndex() > index) index = r.GetFieldIndex();
+    }
+  }
+  return index+1;
+}
+
+
+AccessorDescriptor* Map::FindAccessor(String* name) {
+  for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
+    if (r.Equals(name) && r.type() == CALLBACKS) return r.GetCallbacks();
+  }
+  return NULL;
+}
+
+
+void JSObject::LocalLookup(String* name, LookupResult* result) {
+  ASSERT(name->IsString());
+
+  if (IsJSGlobalProxy()) {
+    Object* proto = GetPrototype();
+    if (proto->IsNull()) return result->NotFound();
+    ASSERT(proto->IsJSGlobalObject());
+    return JSObject::cast(proto)->LocalLookup(name, result);
+  }
+
+  // Do not use inline caching if the object is a non-global object
+  // that requires access checks.
+  if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
+    result->DisallowCaching();
+  }
+
+  // Check __proto__ before interceptor.
+  if (name->Equals(Heap::Proto_symbol())) {
+    result->ConstantResult(this);
+    return;
+  }
+
+  // Check for lookup interceptor except when bootstrapping.
+  if (HasNamedInterceptor() && !Bootstrapper::IsActive()) {
+    result->InterceptorResult(this);
+    return;
+  }
+
+  LocalLookupRealNamedProperty(name, result);
+}
+
+
+void JSObject::Lookup(String* name, LookupResult* result) {
+  // Ecma-262 3rd 8.6.2.4
+  for (Object* current = this;
+       current != Heap::null_value();
+       current = JSObject::cast(current)->GetPrototype()) {
+    JSObject::cast(current)->LocalLookup(name, result);
+    if (result->IsValid() && !result->IsTransitionType()) {
+      return;
+    }
+  }
+  result->NotFound();
+}
+
+
+Object* JSObject::DefineGetterSetter(String* name,
+                                     PropertyAttributes attributes) {
+  // Make sure that the top context does not change when doing callbacks or
+  // interceptor calls.
+  AssertNoContextChange ncc;
+
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
+    return Heap::undefined_value();
+  }
+
+  // TryFlatten before operating on the string.
+  name->TryFlatten();
+
+  // Make sure name is not an index.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) return Heap::undefined_value();
+
+  // Lookup the name.
+  LookupResult result;
+  LocalLookup(name, &result);
+  if (result.IsValid()) {
+    if (result.IsReadOnly()) return Heap::undefined_value();
+    if (result.type() == CALLBACKS) {
+      Object* obj = result.GetCallbackObject();
+      if (obj->IsFixedArray()) return obj;
+    }
+  }
+
+  // Normalize object to make this operation simple.
+  Object* ok = NormalizeProperties();
+  if (ok->IsFailure()) return ok;
+
+  // Allocate the fixed array to hold getter and setter.
+  Object* array = Heap::AllocateFixedArray(2);
+  if (array->IsFailure()) return array;
+
+  // Update the dictionary with the new CALLBACKS property.
+  PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
+  Object* dict =
+      property_dictionary()->SetOrAddStringEntry(name, array, details);
+  if (dict->IsFailure()) return dict;
+
+  // Set the potential new dictionary on the object.
+  set_properties(Dictionary::cast(dict));
+  return array;
+}
+
+
+Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun,
+                                 PropertyAttributes attributes) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return Heap::undefined_value();
+  }
+
+  if (IsJSGlobalProxy()) {
+    Object* proto = GetPrototype();
+    if (proto->IsNull()) return this;
+    ASSERT(proto->IsJSGlobalObject());
+    return JSObject::cast(proto)->DefineAccessor(name, is_getter,
+                                                 fun, attributes);
+  }
+
+  Object* array = DefineGetterSetter(name, attributes);
+  if (array->IsFailure() || array->IsUndefined()) return array;
+  FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
+  return this;
+}
+
+
+Object* JSObject::LookupAccessor(String* name, bool is_getter) {
+  // Make sure that the top context does not change when doing callbacks or
+  // interceptor calls.
+  AssertNoContextChange ncc;
+
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return Heap::undefined_value();
+  }
+
+  // Make sure name is not an index.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) return Heap::undefined_value();
+
+  // Make the lookup and include prototypes.
+  for (Object* obj = this;
+       obj != Heap::null_value();
+       obj = JSObject::cast(obj)->GetPrototype()) {
+    LookupResult result;
+    JSObject::cast(obj)->LocalLookup(name, &result);
+    if (result.IsValid()) {
+      if (result.IsReadOnly()) return Heap::undefined_value();
+      if (result.type() == CALLBACKS) {
+        Object* obj = result.GetCallbackObject();
+        if (obj->IsFixedArray()) {
+          return FixedArray::cast(obj)->get(is_getter
+                                            ? kGetterIndex
+                                            : kSetterIndex);
+        }
+      }
+    }
+  }
+  return Heap::undefined_value();
+}
+
+
+Object* JSObject::SlowReverseLookup(Object* value) {
+  if (HasFastProperties()) {
+    for (DescriptorReader r(map()->instance_descriptors());
+         !r.eos();
+         r.advance()) {
+      if (r.type() == FIELD) {
+        if (FastPropertyAt(r.GetFieldIndex()) == value) {
+          return r.GetKey();
+        }
+      } else if (r.type() == CONSTANT_FUNCTION) {
+        if (r.GetConstantFunction() == value) {
+          return r.GetKey();
+        }
+      }
+    }
+    return Heap::undefined_value();
+  } else {
+    return property_dictionary()->SlowReverseLookup(value);
+  }
+}
+
+
+Object* Map::Copy() {
+  Object* result = Heap::AllocateMap(instance_type(), instance_size());
+  if (result->IsFailure()) return result;
+  Map::cast(result)->set_prototype(prototype());
+  Map::cast(result)->set_constructor(constructor());
+  // Don't copy descriptors, so map transitions always remain a forest.
+  Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array());
+  // Please note instance_type and instance_size are set when allocated.
+  Map::cast(result)->set_inobject_properties(inobject_properties());
+  Map::cast(result)->set_unused_property_fields(unused_property_fields());
+  Map::cast(result)->set_bit_field(bit_field());
+  Map::cast(result)->ClearCodeCache();
+  return result;
+}
+
+
+Object* Map::CopyDropTransitions() {
+  Object* new_map = Copy();
+  if (new_map->IsFailure()) return new_map;
+  Object* descriptors = instance_descriptors()->RemoveTransitions();
+  if (descriptors->IsFailure()) return descriptors;
+  cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
+  return cast(new_map);
+}
+
+
+Object* Map::UpdateCodeCache(String* name, Code* code) {
+  ASSERT(code->ic_state() == MONOMORPHIC);
+  FixedArray* cache = code_cache();
+
+  // When updating the code cache we disregard the type encoded in the
+  // flags. This allows call constant stubs to overwrite call field
+  // stubs, etc.
+  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
+
+  // First check whether we can update existing code cache without
+  // extending it.
+  int length = cache->length();
+  int deleted_index = -1;
+  for (int i = 0; i < length; i += 2) {
+    Object* key = cache->get(i);
+    if (key->IsNull()) {
+      if (deleted_index < 0) deleted_index = i;
+      continue;
+    }
+    if (key->IsUndefined()) {
+      if (deleted_index >= 0) i = deleted_index;
+      cache->set(i + 0, name);
+      cache->set(i + 1, code);
+      return this;
+    }
+    if (name->Equals(String::cast(key))) {
+      Code::Flags found = Code::cast(cache->get(i + 1))->flags();
+      if (Code::RemoveTypeFromFlags(found) == flags) {
+        cache->set(i + 1, code);
+        return this;
+      }
+    }
+  }
+
+  // Reached the end of the code cache.  If there were deleted
+  // elements, reuse the space for the first of them.
+  if (deleted_index >= 0) {
+    cache->set(deleted_index + 0, name);
+    cache->set(deleted_index + 1, code);
+    return this;
+  }
+
+  // Extend the code cache with some new entries (at least one).
+  int new_length = length + ((length >> 1) & ~1) + 2;
+  ASSERT((new_length & 1) == 0);  // must be a multiple of two
+  Object* result = cache->CopySize(new_length);
+  if (result->IsFailure()) return result;
+
+  // Add the (name, code) pair to the new cache.
+  cache = FixedArray::cast(result);
+  cache->set(length + 0, name);
+  cache->set(length + 1, code);
+  set_code_cache(cache);
+  return this;
+}
+
+
+Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
+  FixedArray* cache = code_cache();
+  int length = cache->length();
+  for (int i = 0; i < length; i += 2) {
+    Object* key = cache->get(i);
+    // Skip deleted elements.
+    if (key->IsNull()) continue;
+    if (key->IsUndefined()) return key;
+    if (name->Equals(String::cast(key))) {
+      Code* code = Code::cast(cache->get(i + 1));
+      if (code->flags() == flags) return code;
+    }
+  }
+  return Heap::undefined_value();
+}
+
+
+int Map::IndexInCodeCache(Code* code) {
+  FixedArray* array = code_cache();
+  int len = array->length();
+  for (int i = 0; i < len; i += 2) {
+    if (array->get(i + 1) == code) return i + 1;
+  }
+  return -1;
+}
+
+
+void Map::RemoveFromCodeCache(int index) {
+  FixedArray* array = code_cache();
+  ASSERT(array->length() >= index && array->get(index)->IsCode());
+  // Use null instead of undefined for deleted elements to distinguish
+  // deleted elements from unused elements.  This distinction is used
+  // when looking up in the cache and when updating the cache.
+  array->set_null(index - 1);  // key
+  array->set_null(index);  // code
+}
+
+
+void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) {
+  IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize);
+}
+
+
+static bool HasKey(FixedArray* array, Object* key) {
+  int len0 = array->length();
+  for (int i = 0; i < len0; i++) {
+    Object* element = array->get(i);
+    if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
+    if (element->IsString() &&
+        key->IsString() && String::cast(element)->Equals(String::cast(key))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
+  // Remove array holes from array if any.
+  Object* object = array->RemoveHoles();
+  if (object->IsFailure()) return object;
+  JSArray* compacted_array = JSArray::cast(object);
+
+  // Allocate a temporary fixed array.
+  int compacted_array_length = Smi::cast(compacted_array->length())->value();
+  object = Heap::AllocateFixedArray(compacted_array_length);
+  if (object->IsFailure()) return object;
+  FixedArray* key_array = FixedArray::cast(object);
+
+  // Copy the elements from the JSArray to the temporary fixed array.
+  for (int i = 0; i < compacted_array_length; i++) {
+    key_array->set(i, compacted_array->GetElement(i));
+  }
+
+  // Compute the union of this and the temporary fixed array.
+  return UnionOfKeys(key_array);
+}
+
+
+Object* FixedArray::UnionOfKeys(FixedArray* other) {
+  int len0 = length();
+  int len1 = other->length();
+  // Optimize if either is empty.
+  if (len0 == 0) return other;
+  if (len1 == 0) return this;
+
+  // Compute how many elements are not in this.
+  int extra = 0;
+  for (int y = 0; y < len1; y++) {
+    if (!HasKey(this, other->get(y))) extra++;
+  }
+
+  // Allocate the result
+  Object* obj = Heap::AllocateFixedArray(len0 + extra);
+  if (obj->IsFailure()) return obj;
+  // Fill in the content
+  FixedArray* result = FixedArray::cast(obj);
+  WriteBarrierMode mode = result->GetWriteBarrierMode();
+  for (int i = 0; i < len0; i++) {
+    result->set(i, get(i), mode);
+  }
+  // Fill in the extra keys.
+  int index = 0;
+  for (int y = 0; y < len1; y++) {
+    if (!HasKey(this, other->get(y))) {
+      result->set(len0 + index, other->get(y), mode);
+      index++;
+    }
+  }
+  ASSERT(extra == index);
+  return result;
+}
+
+
+Object* FixedArray::CopySize(int new_length) {
+  if (new_length == 0) return Heap::empty_fixed_array();
+  Object* obj = Heap::AllocateFixedArray(new_length);
+  if (obj->IsFailure()) return obj;
+  FixedArray* result = FixedArray::cast(obj);
+  // Copy the content
+  int len = length();
+  if (new_length < len) len = new_length;
+  result->set_map(map());
+  WriteBarrierMode mode = result->GetWriteBarrierMode();
+  for (int i = 0; i < len; i++) {
+    result->set(i, get(i), mode);
+  }
+  return result;
+}
+
+
+void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
+  WriteBarrierMode mode = dest->GetWriteBarrierMode();
+  for (int index = 0; index < len; index++) {
+    dest->set(dest_pos+index, get(pos+index), mode);
+  }
+}
+
+
+#ifdef DEBUG
+bool FixedArray::IsEqualTo(FixedArray* other) {
+  if (length() != other->length()) return false;
+  for (int i = 0 ; i < length(); ++i) {
+    if (get(i) != other->get(i)) return false;
+  }
+  return true;
+}
+#endif
+
+
+Object* DescriptorArray::Allocate(int number_of_descriptors) {
+  if (number_of_descriptors == 0) {
+    return Heap::empty_descriptor_array();
+  }
+  // Allocate the array of keys.
+  Object* array = Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors));
+  if (array->IsFailure()) return array;
+  // Do not use DescriptorArray::cast on incomplete object.
+  FixedArray* result = FixedArray::cast(array);
+
+  // Allocate the content array and set it in the descriptor array.
+  array = Heap::AllocateFixedArray(number_of_descriptors << 1);
+  if (array->IsFailure()) return array;
+  result->set(kContentArrayIndex, array);
+  result->set(kEnumerationIndexIndex,
+              Smi::FromInt(PropertyDetails::kInitialIndex),
+              SKIP_WRITE_BARRIER);
+  return result;
+}
+
+
+void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
+                                   FixedArray* new_cache) {
+  ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
+  if (HasEnumCache()) {
+    FixedArray::cast(get(kEnumerationIndexIndex))->
+      set(kEnumCacheBridgeCacheIndex, new_cache);
+  } else {
+    if (IsEmpty()) return;  // Do nothing for empty descriptor array.
+    FixedArray::cast(bridge_storage)->
+      set(kEnumCacheBridgeCacheIndex, new_cache);
+    fast_set(FixedArray::cast(bridge_storage),
+             kEnumCacheBridgeEnumIndex,
+             get(kEnumerationIndexIndex));
+    set(kEnumerationIndexIndex, bridge_storage);
+  }
+}
+
+
+Object* DescriptorArray::CopyInsert(Descriptor* descriptor,
+                                    TransitionFlag transition_flag) {
+  // Transitions are only kept when inserting another transition.
+  // This precondition is not required by this function's implementation, but
+  // is currently required by the semantics of maps, so we check it.
+  // Conversely, we filter after replacing, so replacing a transition and
+  // removing all other transitions is not supported.
+  bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
+  ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
+  ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
+
+  // Ensure the key is a symbol.
+  Object* result = descriptor->KeyToSymbol();
+  if (result->IsFailure()) return result;
+
+  int transitions = 0;
+  int null_descriptors = 0;
+  if (remove_transitions) {
+    for (DescriptorReader r(this); !r.eos(); r.advance()) {
+      if (r.IsTransition()) transitions++;
+      if (r.IsNullDescriptor()) null_descriptors++;
+    }
+  } else {
+    for (DescriptorReader r(this); !r.eos(); r.advance()) {
+      if (r.IsNullDescriptor()) null_descriptors++;
+    }
+  }
+  int new_size = number_of_descriptors() - transitions - null_descriptors;
+
+  // If key is in descriptor, we replace it in-place when filtering.
+  int index = Search(descriptor->GetKey());
+  const bool inserting = (index == kNotFound);
+  const bool replacing = !inserting;
+  bool keep_enumeration_index = false;
+  if (inserting) {
+    ++new_size;
+  }
+  if (replacing) {
+    // We are replacing an existing descriptor.  We keep the enumeration
+    // index of a visible property.
+    PropertyType t = PropertyDetails(GetDetails(index)).type();
+    if (t == CONSTANT_FUNCTION ||
+        t == FIELD ||
+        t == CALLBACKS ||
+        t == INTERCEPTOR) {
+      keep_enumeration_index = true;
+    } else if (t == NULL_DESCRIPTOR || remove_transitions) {
+     // Replaced descriptor has been counted as removed if it is null
+     // or a transition that will be replaced.  Adjust count in this case.
+      ++new_size;
+    }
+  }
+  result = Allocate(new_size);
+  if (result->IsFailure()) return result;
+  DescriptorArray* new_descriptors = DescriptorArray::cast(result);
+  // Set the enumeration index in the descriptors and set the enumeration index
+  // in the result.
+  int enumeration_index = NextEnumerationIndex();
+  if (!descriptor->GetDetails().IsTransition()) {
+    if (keep_enumeration_index) {
+      descriptor->SetEnumerationIndex(
+          PropertyDetails(GetDetails(index)).index());
+    } else {
+      descriptor->SetEnumerationIndex(enumeration_index);
+      ++enumeration_index;
+    }
+  }
+  new_descriptors->SetNextEnumerationIndex(enumeration_index);
+
+  // Copy the descriptors, filtering out transitions and null descriptors,
+  // and inserting or replacing a descriptor.
+  DescriptorWriter w(new_descriptors);
+  DescriptorReader r(this);
+  uint32_t descriptor_hash = descriptor->GetKey()->Hash();
+
+  for (; !r.eos(); r.advance()) {
+    if (r.GetKey()->Hash() > descriptor_hash ||
+        r.GetKey() == descriptor->GetKey()) break;
+    if (r.IsNullDescriptor()) continue;
+    if (remove_transitions && r.IsTransition()) continue;
+    w.WriteFrom(&r);
+  }
+  w.Write(descriptor);
+  if (replacing) {
+    ASSERT(r.GetKey() == descriptor->GetKey());
+    r.advance();
+  } else {
+    ASSERT(r.eos() || r.GetKey()->Hash() > descriptor_hash);
+  }
+  for (; !r.eos(); r.advance()) {
+    if (r.IsNullDescriptor()) continue;
+    if (remove_transitions && r.IsTransition()) continue;
+    w.WriteFrom(&r);
+  }
+  ASSERT(w.eos());
+
+  return new_descriptors;
+}
+
+
+Object* DescriptorArray::RemoveTransitions() {
+  // Remove all transitions.  Return a copy of the array with all transitions
+  // removed, or a Failure object if the new array could not be allocated.
+
+  // Compute the size of the map transition entries to be removed.
+  int count_transitions = 0;
+  for (DescriptorReader r(this); !r.eos(); r.advance()) {
+    if (r.IsTransition()) count_transitions++;
+  }
+
+  // Allocate the new descriptor array.
+  Object* result = Allocate(number_of_descriptors() - count_transitions);
+  if (result->IsFailure()) return result;
+  DescriptorArray* new_descriptors = DescriptorArray::cast(result);
+
+  // Copy the content.
+  DescriptorWriter w(new_descriptors);
+  for (DescriptorReader r(this); !r.eos(); r.advance()) {
+    if (!r.IsTransition()) w.WriteFrom(&r);
+  }
+  ASSERT(w.eos());
+
+  return new_descriptors;
+}
+
+
+void DescriptorArray::Sort() {
+  // In-place heap sort.
+  int len = number_of_descriptors();
+
+  // Bottom-up max-heap construction.
+  for (int i = 1; i < len; ++i) {
+    int child_index = i;
+    while (child_index > 0) {
+      int parent_index = ((child_index + 1) >> 1) - 1;
+      uint32_t parent_hash = GetKey(parent_index)->Hash();
+      uint32_t child_hash = GetKey(child_index)->Hash();
+      if (parent_hash < child_hash) {
+        Swap(parent_index, child_index);
+      } else {
+        break;
+      }
+      child_index = parent_index;
+    }
+  }
+
+  // Extract elements and create sorted array.
+  for (int i = len - 1; i > 0; --i) {
+    // Put max element at the back of the array.
+    Swap(0, i);
+    // Sift down the new top element.
+    int parent_index = 0;
+    while (true) {
+      int child_index = ((parent_index + 1) << 1) - 1;
+      if (child_index >= i) break;
+      uint32_t child1_hash = GetKey(child_index)->Hash();
+      uint32_t child2_hash = GetKey(child_index + 1)->Hash();
+      uint32_t parent_hash = GetKey(parent_index)->Hash();
+      if (child_index + 1 >= i || child1_hash > child2_hash) {
+        if (parent_hash > child1_hash) break;
+        Swap(parent_index, child_index);
+        parent_index = child_index;
+      } else {
+        if (parent_hash > child2_hash) break;
+        Swap(parent_index, child_index + 1);
+        parent_index = child_index + 1;
+      }
+    }
+  }
+
+  SLOW_ASSERT(IsSortedNoDuplicates());
+}
+
+
+int DescriptorArray::BinarySearch(String* name, int low, int high) {
+  uint32_t hash = name->Hash();
+
+  while (low <= high) {
+    int mid = (low + high) / 2;
+    String* mid_name = GetKey(mid);
+    uint32_t mid_hash = mid_name->Hash();
+
+    if (mid_hash > hash) {
+      high = mid - 1;
+      continue;
+    }
+    if (mid_hash < hash) {
+      low = mid + 1;
+      continue;
+    }
+    // Found an element with the same hash-code.
+    ASSERT(hash == mid_hash);
+    // There might be more, so we find the first one and
+    // check them all to see if we have a match.
+    if (name == mid_name) return mid;
+    while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
+    for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
+      if (GetKey(mid)->Equals(name)) return mid;
+    }
+    break;
+  }
+  return kNotFound;
+}
+
+
+int DescriptorArray::LinearSearch(String* name, int len) {
+  for (int number = 0; number < len; number++) {
+    if (name->Equals(GetKey(number))) return number;
+  }
+  return kNotFound;
+}
+
+
+#ifdef DEBUG
+bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
+  if (IsEmpty()) return other->IsEmpty();
+  if (other->IsEmpty()) return false;
+  if (length() != other->length()) return false;
+  for (int i = 0; i < length(); ++i) {
+    if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
+  }
+  return GetContentArray()->IsEqualTo(other->GetContentArray());
+}
+#endif
+
+
+static StaticResource<StringInputBuffer> string_input_buffer;
+
+
+bool String::LooksValid() {
+  if (!Heap::Contains(this))
+    return false;
+  switch (representation_tag()) {
+    case kSeqStringTag:
+    case kConsStringTag:
+    case kSlicedStringTag:
+    case kExternalStringTag:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+int String::Utf8Length() {
+  if (is_ascii_representation()) return length();
+  // Attempt to flatten before accessing the string.  It probably
+  // doesn't make Utf8Length faster, but it is very likely that
+  // the string will be accessed later (for example by WriteUtf8)
+  // so it's still a good idea.
+  TryFlatten();
+  Access<StringInputBuffer> buffer(&string_input_buffer);
+  buffer->Reset(0, this);
+  int result = 0;
+  while (buffer->has_more())
+    result += unibrow::Utf8::Length(buffer->GetNext());
+  return result;
+}
+
+
+Vector<const char> String::ToAsciiVector() {
+  ASSERT(IsAsciiRepresentation());
+  ASSERT(IsFlat());
+
+  int offset = 0;
+  int length = this->length();
+  StringRepresentationTag string_tag = representation_tag();
+  String* string = this;
+  if (string_tag == kSlicedStringTag) {
+    SlicedString* sliced = SlicedString::cast(string);
+    offset += sliced->start();
+    string = String::cast(sliced->buffer());
+    string_tag = string->representation_tag();
+  } else if (string_tag == kConsStringTag) {
+    ConsString* cons = ConsString::cast(string);
+    ASSERT(String::cast(cons->second())->length() == 0);
+    string = String::cast(cons->first());
+    string_tag = string->representation_tag();
+  }
+  if (string_tag == kSeqStringTag) {
+    SeqAsciiString* seq = SeqAsciiString::cast(string);
+    char* start = seq->GetChars();
+    return Vector<const char>(start + offset, length);
+  }
+  ASSERT(string_tag == kExternalStringTag);
+  ExternalAsciiString* ext = ExternalAsciiString::cast(string);
+  const char* start = ext->resource()->data();
+  return Vector<const char>(start + offset, length);
+}
+
+
+Vector<const uc16> String::ToUC16Vector() {
+  ASSERT(IsTwoByteStringRepresentation());
+  ASSERT(IsFlat());
+
+  int offset = 0;
+  int length = this->length();
+  StringRepresentationTag string_tag = representation_tag();
+  String* string = this;
+  if (string_tag == kSlicedStringTag) {
+    SlicedString* sliced = SlicedString::cast(string);
+    offset += sliced->start();
+    string = String::cast(sliced->buffer());
+    string_tag = string->representation_tag();
+  } else if (string_tag == kConsStringTag) {
+    ConsString* cons = ConsString::cast(string);
+    ASSERT(String::cast(cons->second())->length() == 0);
+    string = String::cast(cons->first());
+    string_tag = string->representation_tag();
+  }
+  if (string_tag == kSeqStringTag) {
+    SeqTwoByteString* seq = SeqTwoByteString::cast(string);
+    return Vector<const uc16>(seq->GetChars() + offset, length);
+  }
+  ASSERT(string_tag == kExternalStringTag);
+  ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
+  const uc16* start =
+      reinterpret_cast<const uc16*>(ext->resource()->data());
+  return Vector<const uc16>(start + offset, length);
+}
+
+
+SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+                                     RobustnessFlag robust_flag,
+                                     int offset,
+                                     int length,
+                                     int* length_return) {
+  ASSERT(NativeAllocationChecker::allocation_allowed());
+  if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
+    return SmartPointer<char>(NULL);
+  }
+
+  // Negative length means the to the end of the string.
+  if (length < 0) length = kMaxInt - offset;
+
+  // Compute the size of the UTF-8 string. Start at the specified offset.
+  Access<StringInputBuffer> buffer(&string_input_buffer);
+  buffer->Reset(offset, this);
+  int character_position = offset;
+  int utf8_bytes = 0;
+  while (buffer->has_more()) {
+    uint16_t character = buffer->GetNext();
+    if (character_position < offset + length) {
+      utf8_bytes += unibrow::Utf8::Length(character);
+    }
+    character_position++;
+  }
+
+  if (length_return) {
+    *length_return = utf8_bytes;
+  }
+
+  char* result = NewArray<char>(utf8_bytes + 1);
+
+  // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
+  buffer->Rewind();
+  buffer->Seek(offset);
+  character_position = offset;
+  int utf8_byte_position = 0;
+  while (buffer->has_more()) {
+    uint16_t character = buffer->GetNext();
+    if (character_position < offset + length) {
+      if (allow_nulls == DISALLOW_NULLS && character == 0) {
+        character = ' ';
+      }
+      utf8_byte_position +=
+          unibrow::Utf8::Encode(result + utf8_byte_position, character);
+    }
+    character_position++;
+  }
+  result[utf8_byte_position] = 0;
+  return SmartPointer<char>(result);
+}
+
+
+SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+                                     RobustnessFlag robust_flag,
+                                     int* length_return) {
+  return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
+}
+
+
+const uc16* String::GetTwoByteData() {
+  return GetTwoByteData(0);
+}
+
+
+const uc16* String::GetTwoByteData(unsigned start) {
+  ASSERT(!IsAsciiRepresentation());
+  switch (representation_tag()) {
+    case kSeqStringTag:
+      return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
+    case kExternalStringTag:
+      return ExternalTwoByteString::cast(this)->
+        ExternalTwoByteStringGetData(start);
+    case kSlicedStringTag: {
+      SlicedString* sliced_string = SlicedString::cast(this);
+      String* buffer = String::cast(sliced_string->buffer());
+      if (buffer->StringIsConsString()) {
+        ConsString* cons_string = ConsString::cast(buffer);
+        // Flattened string.
+        ASSERT(String::cast(cons_string->second())->length() == 0);
+        buffer = String::cast(cons_string->first());
+      }
+      return buffer->GetTwoByteData(start + sliced_string->start());
+    }
+    case kConsStringTag:
+      UNREACHABLE();
+      return NULL;
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
+  ASSERT(NativeAllocationChecker::allocation_allowed());
+
+  if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
+    return SmartPointer<uc16>();
+  }
+
+  Access<StringInputBuffer> buffer(&string_input_buffer);
+  buffer->Reset(this);
+
+  uc16* result = NewArray<uc16>(length() + 1);
+
+  int i = 0;
+  while (buffer->has_more()) {
+    uint16_t character = buffer->GetNext();
+    result[i++] = character;
+  }
+  result[i] = 0;
+  return SmartPointer<uc16>(result);
+}
+
+
+const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
+  return reinterpret_cast<uc16*>(
+      reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
+}
+
+
+void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
+                                                     unsigned* offset_ptr,
+                                                     unsigned max_chars) {
+  unsigned chars_read = 0;
+  unsigned offset = *offset_ptr;
+  while (chars_read < max_chars) {
+    uint16_t c = *reinterpret_cast<uint16_t*>(
+        reinterpret_cast<char*>(this) -
+            kHeapObjectTag + kHeaderSize + offset * kShortSize);
+    if (c <= kMaxAsciiCharCode) {
+      // Fast case for ASCII characters.   Cursor is an input output argument.
+      if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
+                                                          rbb->util_buffer,
+                                                          rbb->capacity,
+                                                          rbb->cursor)) {
+        break;
+      }
+    } else {
+      if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
+                                                             rbb->util_buffer,
+                                                             rbb->capacity,
+                                                             rbb->cursor)) {
+        break;
+      }
+    }
+    offset++;
+    chars_read++;
+  }
+  *offset_ptr = offset;
+  rbb->remaining += chars_read;
+}
+
+
+const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
+    unsigned* remaining,
+    unsigned* offset_ptr,
+    unsigned max_chars) {
+  const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
+      kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
+  *remaining = max_chars;
+  *offset_ptr += max_chars;
+  return b;
+}
+
+
+// This will iterate unless the block of string data spans two 'halves' of
+// a ConsString, in which case it will recurse.  Since the block of string
+// data to be read has a maximum size this limits the maximum recursion
+// depth to something sane.  Since C++ does not have tail call recursion
+// elimination, the iteration must be explicit. Since this is not an
+// -IntoBuffer method it can delegate to one of the efficient
+// *AsciiStringReadBlock routines.
+const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
+                                                     unsigned* offset_ptr,
+                                                     unsigned max_chars) {
+  ConsString* current = this;
+  unsigned offset = *offset_ptr;
+  int offset_correction = 0;
+
+  while (true) {
+    String* left = String::cast(current->first());
+    unsigned left_length = (unsigned)left->length();
+    if (left_length > offset &&
+        (max_chars <= left_length - offset ||
+         (rbb->capacity <= left_length - offset &&
+          (max_chars = left_length - offset, true)))) {  // comma operator!
+      // Left hand side only - iterate unless we have reached the bottom of
+      // the cons tree.  The assignment on the left of the comma operator is
+      // in order to make use of the fact that the -IntoBuffer routines can
+      // produce at most 'capacity' characters.  This enables us to postpone
+      // the point where we switch to the -IntoBuffer routines (below) in order
+      // to maximize the chances of delegating a big chunk of work to the
+      // efficient *AsciiStringReadBlock routines.
+      if (left->StringIsConsString()) {
+        current = ConsString::cast(left);
+        continue;
+      } else {
+        const unibrow::byte* answer =
+            String::ReadBlock(left, rbb, &offset, max_chars);
+        *offset_ptr = offset + offset_correction;
+        return answer;
+      }
+    } else if (left_length <= offset) {
+      // Right hand side only - iterate unless we have reached the bottom of
+      // the cons tree.
+      String* right = String::cast(current->second());
+      offset -= left_length;
+      offset_correction += left_length;
+      if (right->StringIsConsString()) {
+        current = ConsString::cast(right);
+        continue;
+      } else {
+        const unibrow::byte* answer =
+            String::ReadBlock(right, rbb, &offset, max_chars);
+        *offset_ptr = offset + offset_correction;
+        return answer;
+      }
+    } else {
+      // The block to be read spans two sides of the ConsString, so we call the
+      // -IntoBuffer version, which will recurse.  The -IntoBuffer methods
+      // are able to assemble data from several part strings because they use
+      // the util_buffer to store their data and never return direct pointers
+      // to their storage.  We don't try to read more than the buffer capacity
+      // here or we can get too much recursion.
+      ASSERT(rbb->remaining == 0);
+      ASSERT(rbb->cursor == 0);
+      current->ConsStringReadBlockIntoBuffer(
+          rbb,
+          &offset,
+          max_chars > rbb->capacity ? rbb->capacity : max_chars);
+      *offset_ptr = offset + offset_correction;
+      return rbb->util_buffer;
+    }
+  }
+}
+
+
+const unibrow::byte* SlicedString::SlicedStringReadBlock(ReadBlockBuffer* rbb,
+                                                         unsigned* offset_ptr,
+                                                         unsigned max_chars) {
+  String* backing = String::cast(buffer());
+  unsigned offset = start() + *offset_ptr;
+  unsigned length = backing->length();
+  if (max_chars > length - offset) {
+    max_chars = length - offset;
+  }
+  const unibrow::byte* answer =
+      String::ReadBlock(backing, rbb, &offset, max_chars);
+  *offset_ptr = offset - start();
+  return answer;
+}
+
+
+uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
+  ASSERT(index >= 0 && index < length());
+  return resource()->data()[index];
+}
+
+
+const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
+      unsigned* remaining,
+      unsigned* offset_ptr,
+      unsigned max_chars) {
+  // Cast const char* to unibrow::byte* (signedness difference).
+  const unibrow::byte* b =
+      reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
+  *remaining = max_chars;
+  *offset_ptr += max_chars;
+  return b;
+}
+
+
+const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
+      unsigned start) {
+  return resource()->data() + start;
+}
+
+
+uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
+  ASSERT(index >= 0 && index < length());
+  return resource()->data()[index];
+}
+
+
+void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
+      ReadBlockBuffer* rbb,
+      unsigned* offset_ptr,
+      unsigned max_chars) {
+  unsigned chars_read = 0;
+  unsigned offset = *offset_ptr;
+  const uint16_t* data = resource()->data();
+  while (chars_read < max_chars) {
+    uint16_t c = data[offset];
+    if (c <= kMaxAsciiCharCode) {
+      // Fast case for ASCII characters.   Cursor is an input output argument.
+      if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
+                                                          rbb->util_buffer,
+                                                          rbb->capacity,
+                                                          rbb->cursor))
+        break;
+    } else {
+      if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
+                                                             rbb->util_buffer,
+                                                             rbb->capacity,
+                                                             rbb->cursor))
+        break;
+    }
+    offset++;
+    chars_read++;
+  }
+  *offset_ptr = offset;
+  rbb->remaining += chars_read;
+}
+
+
+void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
+                                                 unsigned* offset_ptr,
+                                                 unsigned max_chars) {
+  unsigned capacity = rbb->capacity - rbb->cursor;
+  if (max_chars > capacity) max_chars = capacity;
+  memcpy(rbb->util_buffer + rbb->cursor,
+         reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
+             *offset_ptr * kCharSize,
+         max_chars);
+  rbb->remaining += max_chars;
+  *offset_ptr += max_chars;
+  rbb->cursor += max_chars;
+}
+
+
+void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
+      ReadBlockBuffer* rbb,
+      unsigned* offset_ptr,
+      unsigned max_chars) {
+  unsigned capacity = rbb->capacity - rbb->cursor;
+  if (max_chars > capacity) max_chars = capacity;
+  memcpy(rbb->util_buffer + rbb->cursor,
+         resource()->data() + *offset_ptr,
+         max_chars);
+  rbb->remaining += max_chars;
+  *offset_ptr += max_chars;
+  rbb->cursor += max_chars;
+}
+
+
+// This method determines the type of string involved and then copies
+// a whole chunk of characters into a buffer, or returns a pointer to a buffer
+// where they can be found.  The pointer is not necessarily valid across a GC
+// (see AsciiStringReadBlock).
+const unibrow::byte* String::ReadBlock(String* input,
+                                       ReadBlockBuffer* rbb,
+                                       unsigned* offset_ptr,
+                                       unsigned max_chars) {
+  ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
+  if (max_chars == 0) {
+    rbb->remaining = 0;
+    return NULL;
+  }
+  switch (input->representation_tag()) {
+    case kSeqStringTag:
+      if (input->is_ascii_representation()) {
+        SeqAsciiString* str = SeqAsciiString::cast(input);
+        return str->SeqAsciiStringReadBlock(&rbb->remaining,
+                                            offset_ptr,
+                                            max_chars);
+      } else {
+        SeqTwoByteString* str = SeqTwoByteString::cast(input);
+        str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
+                                                 offset_ptr,
+                                                 max_chars);
+        return rbb->util_buffer;
+      }
+    case kConsStringTag:
+      return ConsString::cast(input)->ConsStringReadBlock(rbb,
+                                                          offset_ptr,
+                                                          max_chars);
+    case kSlicedStringTag:
+      return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
+                                                              offset_ptr,
+                                                              max_chars);
+    case kExternalStringTag:
+      if (input->is_ascii_representation()) {
+        return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
+            &rbb->remaining,
+            offset_ptr,
+            max_chars);
+      } else {
+        ExternalTwoByteString::cast(input)->
+            ExternalTwoByteStringReadBlockIntoBuffer(rbb,
+                                                     offset_ptr,
+                                                     max_chars);
+        return rbb->util_buffer;
+      }
+    default:
+      break;
+  }
+
+  UNREACHABLE();
+  return 0;
+}
+
+
+void StringInputBuffer::Seek(unsigned pos) {
+  Reset(pos, input_);
+}
+
+
+void SafeStringInputBuffer::Seek(unsigned pos) {
+  Reset(pos, input_);
+}
+
+
+// This method determines the type of string involved and then copies
+// a whole chunk of characters into a buffer.  It can be used with strings
+// that have been glued together to form a ConsString and which must cooperate
+// to fill up a buffer.
+void String::ReadBlockIntoBuffer(String* input,
+                                 ReadBlockBuffer* rbb,
+                                 unsigned* offset_ptr,
+                                 unsigned max_chars) {
+  ASSERT(*offset_ptr <= (unsigned)input->length());
+  if (max_chars == 0) return;
+
+  switch (input->representation_tag()) {
+    case kSeqStringTag:
+      if (input->is_ascii_representation()) {
+        SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
+                                                                 offset_ptr,
+                                                                 max_chars);
+        return;
+      } else {
+        SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
+                                                                     offset_ptr,
+                                                                     max_chars);
+        return;
+      }
+    case kConsStringTag:
+      ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
+                                                             offset_ptr,
+                                                             max_chars);
+      return;
+    case kSlicedStringTag:
+      SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
+                                                                 offset_ptr,
+                                                                 max_chars);
+      return;
+    case kExternalStringTag:
+      if (input->is_ascii_representation()) {
+         ExternalAsciiString::cast(input)->
+             ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
+       } else {
+         ExternalTwoByteString::cast(input)->
+             ExternalTwoByteStringReadBlockIntoBuffer(rbb,
+                                                      offset_ptr,
+                                                      max_chars);
+       }
+       return;
+    default:
+      break;
+  }
+
+  UNREACHABLE();
+  return;
+}
+
+
+const unibrow::byte* String::ReadBlock(String* input,
+                                       unibrow::byte* util_buffer,
+                                       unsigned capacity,
+                                       unsigned* remaining,
+                                       unsigned* offset_ptr) {
+  ASSERT(*offset_ptr <= (unsigned)input->length());
+  unsigned chars = input->length() - *offset_ptr;
+  ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
+  const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
+  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
+  *remaining = rbb.remaining;
+  return answer;
+}
+
+
+const unibrow::byte* String::ReadBlock(String** raw_input,
+                                       unibrow::byte* util_buffer,
+                                       unsigned capacity,
+                                       unsigned* remaining,
+                                       unsigned* offset_ptr) {
+  Handle<String> input(raw_input);
+  ASSERT(*offset_ptr <= (unsigned)input->length());
+  unsigned chars = input->length() - *offset_ptr;
+  if (chars > capacity) chars = capacity;
+  ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
+  ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
+  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
+  *remaining = rbb.remaining;
+  return rbb.util_buffer;
+}
+
+
+// This will iterate unless the block of string data spans two 'halves' of
+// a ConsString, in which case it will recurse.  Since the block of string
+// data to be read has a maximum size this limits the maximum recursion
+// depth to something sane.  Since C++ does not have tail call recursion
+// elimination, the iteration must be explicit.
+void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
+                                               unsigned* offset_ptr,
+                                               unsigned max_chars) {
+  ConsString* current = this;
+  unsigned offset = *offset_ptr;
+  int offset_correction = 0;
+
+  while (true) {
+    String* left = String::cast(current->first());
+    unsigned left_length = (unsigned)left->length();
+    if (left_length > offset &&
+      max_chars <= left_length - offset) {
+      // Left hand side only - iterate unless we have reached the bottom of
+      // the cons tree.
+      if (left->StringIsConsString()) {
+        current = ConsString::cast(left);
+        continue;
+      } else {
+        String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
+        *offset_ptr = offset + offset_correction;
+        return;
+      }
+    } else if (left_length <= offset) {
+      // Right hand side only - iterate unless we have reached the bottom of
+      // the cons tree.
+      offset -= left_length;
+      offset_correction += left_length;
+      String* right = String::cast(current->second());
+      if (right->StringIsConsString()) {
+        current = ConsString::cast(right);
+        continue;
+      } else {
+        String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
+        *offset_ptr = offset + offset_correction;
+        return;
+      }
+    } else {
+      // The block to be read spans two sides of the ConsString, so we recurse.
+      // First recurse on the left.
+      max_chars -= left_length - offset;
+      String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
+      // We may have reached the max or there may not have been enough space
+      // in the buffer for the characters in the left hand side.
+      if (offset == left_length) {
+        // Recurse on the right.
+        String* right = String::cast(current->second());
+        offset -= left_length;
+        offset_correction += left_length;
+        String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
+      }
+      *offset_ptr = offset + offset_correction;
+      return;
+    }
+  }
+}
+
+
+void SlicedString::SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
+                                                   unsigned* offset_ptr,
+                                                   unsigned max_chars) {
+  String* backing = String::cast(buffer());
+  unsigned offset = start() + *offset_ptr;
+  unsigned length = backing->length();
+  if (max_chars > length - offset) {
+    max_chars = length - offset;
+  }
+  String::ReadBlockIntoBuffer(backing, rbb, &offset, max_chars);
+  *offset_ptr = offset - start();
+}
+
+
+void ConsString::ConsStringIterateBody(ObjectVisitor* v) {
+  IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize);
+}
+
+
+uint16_t ConsString::ConsStringGet(int index) {
+  ASSERT(index >= 0 && index < this->length());
+
+  // Check for a flattened cons string
+  if (String::cast(second())->length() == 0) {
+    return String::cast(first())->Get(index);
+  }
+
+  String* string = String::cast(this);
+
+  while (true) {
+    if (string->StringIsConsString()) {
+      ConsString* cons_string = ConsString::cast(string);
+      String* left = String::cast(cons_string->first());
+      if (left->length() > index) {
+        string = left;
+      } else {
+        index -= left->length();
+        string = String::cast(cons_string->second());
+      }
+    } else {
+      return string->Get(index);
+    }
+  }
+
+  UNREACHABLE();
+  return 0;
+}
+
+
+Object* SlicedString::SlicedStringFlatten() {
+  // The SlicedString constructor should ensure that there are no
+  // SlicedStrings that are constructed directly on top of other
+  // SlicedStrings.
+  String* buf = String::cast(buffer());
+  ASSERT(!buf->StringIsSlicedString());
+  if (buf->StringIsConsString()) {
+    Object* ok = buf->Flatten();
+    if (ok->IsFailure()) return ok;
+  }
+  return this;
+}
+
+
+template <typename sinkchar>
+void String::WriteToFlat(String* src,
+                         sinkchar* sink,
+                         int f,
+                         int t) {
+  String* source = src;
+  int from = f;
+  int to = t;
+  while (true) {
+    ASSERT(0 <= from && from <= to && to <= source->length());
+    switch (source->full_representation_tag()) {
+      case kAsciiStringTag | kExternalStringTag: {
+        CopyChars(sink,
+                  ExternalAsciiString::cast(source)->resource()->data() + from,
+                  to - from);
+        return;
+      }
+      case kTwoByteStringTag | kExternalStringTag: {
+        const uc16* data =
+            ExternalTwoByteString::cast(source)->resource()->data();
+        CopyChars(sink,
+                  data + from,
+                  to - from);
+        return;
+      }
+      case kAsciiStringTag | kSeqStringTag: {
+        CopyChars(sink,
+                  SeqAsciiString::cast(source)->GetChars() + from,
+                  to - from);
+        return;
+      }
+      case kTwoByteStringTag | kSeqStringTag: {
+        CopyChars(sink,
+                  SeqTwoByteString::cast(source)->GetChars() + from,
+                  to - from);
+        return;
+      }
+      case kAsciiStringTag | kSlicedStringTag:
+      case kTwoByteStringTag | kSlicedStringTag: {
+        SlicedString* sliced_string = SlicedString::cast(source);
+        int start = sliced_string->start();
+        from += start;
+        to += start;
+        source = String::cast(sliced_string->buffer());
+        break;
+      }
+      case kAsciiStringTag | kConsStringTag:
+      case kTwoByteStringTag | kConsStringTag: {
+        ConsString* cons_string = ConsString::cast(source);
+        String* first = String::cast(cons_string->first());
+        int boundary = first->length();
+        if (to - boundary >= boundary - from) {
+          // Right hand side is longer.  Recurse over left.
+          if (from < boundary) {
+            WriteToFlat(first, sink, from, boundary);
+            sink += boundary - from;
+            from = 0;
+          } else {
+            from -= boundary;
+          }
+          to -= boundary;
+          source = String::cast(cons_string->second());
+        } else {
+          // Left hand side is longer.  Recurse over right.
+          if (to > boundary) {
+            String* second = String::cast(cons_string->second());
+            WriteToFlat(second,
+                        sink + boundary - from,
+                        0,
+                        to - boundary);
+            to = boundary;
+          }
+          source = first;
+        }
+        break;
+      }
+    }
+  }
+}
+
+
+void SlicedString::SlicedStringIterateBody(ObjectVisitor* v) {
+  IteratePointer(v, kBufferOffset);
+}
+
+
+uint16_t SlicedString::SlicedStringGet(int index) {
+  ASSERT(index >= 0 && index < this->length());
+  // Delegate to the buffer string.
+  return String::cast(buffer())->Get(start() + index);
+}
+
+
+template <typename IteratorA, typename IteratorB>
+static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
+  // General slow case check.  We know that the ia and ib iterators
+  // have the same length.
+  while (ia->has_more()) {
+    uc32 ca = ia->GetNext();
+    uc32 cb = ib->GetNext();
+    if (ca != cb)
+      return false;
+  }
+  return true;
+}
+
+
+// Compares the contents of two strings by reading and comparing
+// int-sized blocks of characters.
+template <typename Char>
+static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
+  int length = a.length();
+  ASSERT_EQ(length, b.length());
+  const Char* pa = a.start();
+  const Char* pb = b.start();
+  int i = 0;
+#ifndef CAN_READ_UNALIGNED
+  // If this architecture isn't comfortable reading unaligned ints
+  // then we have to check that the strings are aligned before
+  // comparing them blockwise.
+  const int kAlignmentMask = sizeof(uint32_t) - 1;  // NOLINT
+  uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
+  uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
+  if ((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask) == 0) {
+#endif
+    const int kStepSize = sizeof(int) / sizeof(Char);  // NOLINT
+    int endpoint = length - kStepSize;
+    // Compare blocks until we reach near the end of the string.
+    for (; i <= endpoint; i += kStepSize) {
+      uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
+      uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
+      if (wa != wb) {
+        return false;
+      }
+    }
+#ifndef CAN_READ_UNALIGNED
+  }
+#endif
+  // Compare the remaining characters that didn't fit into a block.
+  for (; i < length; i++) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+static StringInputBuffer string_compare_buffer_b;
+
+
+template <typename IteratorA>
+static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
+  if (b->IsFlat()) {
+    if (b->IsAsciiRepresentation()) {
+      VectorIterator<char> ib(b->ToAsciiVector());
+      return CompareStringContents(ia, &ib);
+    } else {
+      VectorIterator<uc16> ib(b->ToUC16Vector());
+      return CompareStringContents(ia, &ib);
+    }
+  } else {
+    string_compare_buffer_b.Reset(0, b);
+    return CompareStringContents(ia, &string_compare_buffer_b);
+  }
+}
+
+
+static StringInputBuffer string_compare_buffer_a;
+
+
+bool String::SlowEquals(String* other) {
+  // Fast check: negative check with lengths.
+  int len = length();
+  if (len != other->length()) return false;
+  if (len == 0) return true;
+
+  // Fast check: if hash code is computed for both strings
+  // a fast negative check can be performed.
+  if (HasHashCode() && other->HasHashCode()) {
+    if (Hash() != other->Hash()) return false;
+  }
+
+  if (this->IsSeqAsciiString() && other->IsSeqAsciiString()) {
+    const char* str1 = SeqAsciiString::cast(this)->GetChars();
+    const char* str2 = SeqAsciiString::cast(other)->GetChars();
+    return CompareRawStringContents(Vector<const char>(str1, len),
+                                    Vector<const char>(str2, len));
+  }
+
+  if (this->IsFlat()) {
+    if (this->IsAsciiRepresentation()) {
+      Vector<const char> vec1 = this->ToAsciiVector();
+      if (other->IsFlat()) {
+        if (other->IsAsciiRepresentation()) {
+          Vector<const char> vec2 = other->ToAsciiVector();
+          return CompareRawStringContents(vec1, vec2);
+        } else {
+          VectorIterator<char> buf1(vec1);
+          VectorIterator<uc16> ib(other->ToUC16Vector());
+          return CompareStringContents(&buf1, &ib);
+        }
+      } else {
+        VectorIterator<char> buf1(vec1);
+        string_compare_buffer_b.Reset(0, other);
+        return CompareStringContents(&buf1, &string_compare_buffer_b);
+      }
+    } else {
+      Vector<const uc16> vec1 = this->ToUC16Vector();
+      if (other->IsFlat()) {
+        if (other->IsAsciiRepresentation()) {
+          VectorIterator<uc16> buf1(vec1);
+          VectorIterator<char> ib(other->ToAsciiVector());
+          return CompareStringContents(&buf1, &ib);
+        } else {
+          Vector<const uc16> vec2(other->ToUC16Vector());
+          return CompareRawStringContents(vec1, vec2);
+        }
+      } else {
+        VectorIterator<uc16> buf1(vec1);
+        string_compare_buffer_b.Reset(0, other);
+        return CompareStringContents(&buf1, &string_compare_buffer_b);
+      }
+    }
+  } else {
+    string_compare_buffer_a.Reset(0, this);
+    return CompareStringContentsPartial(&string_compare_buffer_a, other);
+  }
+}
+
+
+bool String::MarkAsUndetectable() {
+  if (this->IsSymbol()) return false;
+
+  Map* map = this->map();
+  if (map == Heap::short_string_map()) {
+    this->set_map(Heap::undetectable_short_string_map());
+    return true;
+  } else if (map == Heap::medium_string_map()) {
+    this->set_map(Heap::undetectable_medium_string_map());
+    return true;
+  } else if (map == Heap::long_string_map()) {
+    this->set_map(Heap::undetectable_long_string_map());
+    return true;
+  } else if (map == Heap::short_ascii_string_map()) {
+    this->set_map(Heap::undetectable_short_ascii_string_map());
+    return true;
+  } else if (map == Heap::medium_ascii_string_map()) {
+    this->set_map(Heap::undetectable_medium_ascii_string_map());
+    return true;
+  } else if (map == Heap::long_ascii_string_map()) {
+    this->set_map(Heap::undetectable_long_ascii_string_map());
+    return true;
+  }
+  // Rest cannot be marked as undetectable
+  return false;
+}
+
+
+bool String::IsEqualTo(Vector<const char> str) {
+  int slen = length();
+  Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
+  decoder->Reset(str.start(), str.length());
+  int i;
+  for (i = 0; i < slen && decoder->has_more(); i++) {
+    uc32 r = decoder->GetNext();
+    if (Get(i) != r) return false;
+  }
+  return i == slen && !decoder->has_more();
+}
+
+
+uint32_t String::ComputeAndSetHash() {
+  // Should only be call if hash code has not yet been computed.
+  ASSERT(!(length_field() & kHashComputedMask));
+
+  // Compute the hash code.
+  StringInputBuffer buffer(this);
+  uint32_t field = ComputeLengthAndHashField(&buffer, length());
+
+  // Store the hash code in the object.
+  set_length_field(field);
+
+  // Check the hash code is there.
+  ASSERT(length_field() & kHashComputedMask);
+  return field >> kHashShift;
+}
+
+
+bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
+                               uint32_t* index,
+                               int length) {
+  if (length == 0 || length > kMaxArrayIndexSize) return false;
+  uc32 ch = buffer->GetNext();
+
+  // If the string begins with a '0' character, it must only consist
+  // of it to be a legal array index.
+  if (ch == '0') {
+    *index = 0;
+    return length == 1;
+  }
+
+  // Convert string to uint32 array index; character by character.
+  int d = ch - '0';
+  if (d < 0 || d > 9) return false;
+  uint32_t result = d;
+  while (buffer->has_more()) {
+    d = buffer->GetNext() - '0';
+    if (d < 0 || d > 9) return false;
+    // Check that the new result is below the 32 bit limit.
+    if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
+    result = (result * 10) + d;
+  }
+
+  *index = result;
+  return true;
+}
+
+
+bool String::SlowAsArrayIndex(uint32_t* index) {
+  if (length() <= kMaxCachedArrayIndexLength) {
+    Hash();  // force computation of hash code
+    uint32_t field = length_field();
+    if ((field & kIsArrayIndexMask) == 0) return false;
+    *index = (field & ((1 << kShortLengthShift) - 1)) >> kLongLengthShift;
+    return true;
+  } else {
+    StringInputBuffer buffer(this);
+    return ComputeArrayIndex(&buffer, index, length());
+  }
+}
+
+
+static inline uint32_t HashField(uint32_t hash, bool is_array_index) {
+  uint32_t result =
+      (hash << String::kLongLengthShift) | String::kHashComputedMask;
+  if (is_array_index) result |= String::kIsArrayIndexMask;
+  return result;
+}
+
+
+uint32_t StringHasher::GetHashField() {
+  ASSERT(is_valid());
+  if (length_ <= String::kMaxShortStringSize) {
+    uint32_t payload;
+    if (is_array_index()) {
+      payload = v8::internal::HashField(array_index(), true);
+    } else {
+      payload = v8::internal::HashField(GetHash(), false);
+    }
+    return (payload & 0x00FFFFFF) | (length_ << String::kShortLengthShift);
+  } else if (length_ <= String::kMaxMediumStringSize) {
+    uint32_t payload = v8::internal::HashField(GetHash(), false);
+    return (payload & 0x0000FFFF) | (length_ << String::kMediumLengthShift);
+  } else {
+    return v8::internal::HashField(length_, false);
+  }
+}
+
+
+uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
+                                           int length) {
+  StringHasher hasher(length);
+
+  // Very long strings have a trivial hash that doesn't inspect the
+  // string contents.
+  if (hasher.has_trivial_hash()) {
+    return hasher.GetHashField();
+  }
+
+  // Do the iterative array index computation as long as there is a
+  // chance this is an array index.
+  while (buffer->has_more() && hasher.is_array_index()) {
+    hasher.AddCharacter(buffer->GetNext());
+  }
+
+  // Process the remaining characters without updating the array
+  // index.
+  while (buffer->has_more()) {
+    hasher.AddCharacterNoIndex(buffer->GetNext());
+  }
+
+  return hasher.GetHashField();
+}
+
+
+Object* String::Slice(int start, int end) {
+  if (start == 0 && end == length()) return this;
+  int representation = representation_tag();
+  if (representation == kSlicedStringTag) {
+    // Translate slices of a SlicedString into slices of the
+    // underlying string buffer.
+    SlicedString* str = SlicedString::cast(this);
+    return Heap::AllocateSlicedString(String::cast(str->buffer()),
+                                      str->start() + start,
+                                      str->start() + end);
+  }
+  Object* answer = Heap::AllocateSlicedString(this, start, end);
+  if (answer->IsFailure()) {
+    return answer;
+  }
+  // Due to the way we retry after GC on allocation failure we are not allowed
+  // to fail on allocation after this point.  This is the one-allocation rule.
+
+  // Try to flatten a cons string that is under the sliced string.
+  // This is to avoid memory leaks and possible stack overflows caused by
+  // building 'towers' of sliced strings on cons strings.
+  // This may fail due to an allocation failure (when a GC is needed), but it
+  // will succeed often enough to avoid the problem.  We only have to do this
+  // if Heap::AllocateSlicedString actually returned a SlicedString.  It will
+  // return flat strings for small slices for efficiency reasons.
+  if (String::cast(answer)->StringIsSlicedString() &&
+      representation == kConsStringTag) {
+    TryFlatten();
+    // If the flatten succeeded we might as well make the sliced string point
+    // to the flat string rather than the cons string.
+    if (String::cast(ConsString::cast(this)->second())->length() == 0) {
+      SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first());
+    }
+  }
+  return answer;
+}
+
+
+void String::PrintOn(FILE* file) {
+  int length = this->length();
+  for (int i = 0; i < length; i++) {
+    fprintf(file, "%c", Get(i));
+  }
+}
+
+
+void Map::MapIterateBody(ObjectVisitor* v) {
+  // Assumes all Object* members are contiguously allocated!
+  IteratePointers(v, kPrototypeOffset, kCodeCacheOffset + kPointerSize);
+}
+
+
+Object* JSFunction::SetInstancePrototype(Object* value) {
+  ASSERT(value->IsJSObject());
+
+  if (has_initial_map()) {
+    initial_map()->set_prototype(value);
+  } else {
+    // Put the value in the initial map field until an initial map is
+    // needed.  At that point, a new initial map is created and the
+    // prototype is put into the initial map where it belongs.
+    set_prototype_or_initial_map(value);
+  }
+  return value;
+}
+
+
+
+Object* JSFunction::SetPrototype(Object* value) {
+  Object* construct_prototype = value;
+
+  // If the value is not a JSObject, store the value in the map's
+  // constructor field so it can be accessed.  Also, set the prototype
+  // used for constructing objects to the original object prototype.
+  // See ECMA-262 13.2.2.
+  if (!value->IsJSObject()) {
+    // Copy the map so this does not affect unrelated functions.
+    // Remove map transitions because they point to maps with a
+    // different prototype.
+    Object* new_map = map()->CopyDropTransitions();
+    if (new_map->IsFailure()) return new_map;
+    set_map(Map::cast(new_map));
+    map()->set_constructor(value);
+    map()->set_non_instance_prototype(true);
+    construct_prototype =
+        Top::context()->global_context()->initial_object_prototype();
+  } else {
+    map()->set_non_instance_prototype(false);
+  }
+
+  return SetInstancePrototype(construct_prototype);
+}
+
+
+Object* JSFunction::SetInstanceClassName(String* name) {
+  shared()->set_instance_class_name(name);
+  return this;
+}
+
+
+Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
+  return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
+}
+
+
+void Oddball::OddballIterateBody(ObjectVisitor* v) {
+  // Assumes all Object* members are contiguously allocated!
+  IteratePointers(v, kToStringOffset, kToNumberOffset + kPointerSize);
+}
+
+
+Object* Oddball::Initialize(const char* to_string, Object* to_number) {
+  Object* symbol = Heap::LookupAsciiSymbol(to_string);
+  if (symbol->IsFailure()) return symbol;
+  set_to_string(String::cast(symbol));
+  set_to_number(to_number);
+  return this;
+}
+
+
+bool SharedFunctionInfo::HasSourceCode() {
+  return !script()->IsUndefined() &&
+         !Script::cast(script())->source()->IsUndefined();
+}
+
+
+Object* SharedFunctionInfo::GetSourceCode() {
+  HandleScope scope;
+  if (script()->IsUndefined()) return Heap::undefined_value();
+  Object* source = Script::cast(script())->source();
+  if (source->IsUndefined()) return Heap::undefined_value();
+  return *SubString(Handle<String>(String::cast(source)),
+                    start_position(), end_position());
+}
+
+
+// Support function for printing the source code to a StringStream
+// without any allocation in the heap.
+void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
+                                         int max_length) {
+  // For some native functions there is no source.
+  if (script()->IsUndefined() ||
+      Script::cast(script())->source()->IsUndefined()) {
+    accumulator->Add("<No Source>");
+    return;
+  }
+
+  // Get the slice of the source for this function.
+  // Don't use String::cast because we don't want more assertion errors while
+  // we are already creating a stack dump.
+  String* script_source =
+      reinterpret_cast<String*>(Script::cast(script())->source());
+
+  if (!script_source->LooksValid()) {
+    accumulator->Add("<Invalid Source>");
+    return;
+  }
+
+  if (!is_toplevel()) {
+    accumulator->Add("function ");
+    Object* name = this->name();
+    if (name->IsString() && String::cast(name)->length() > 0) {
+      accumulator->PrintName(name);
+    }
+  }
+
+  int len = end_position() - start_position();
+  if (len > max_length) {
+    accumulator->Put(script_source,
+                     start_position(),
+                     start_position() + max_length);
+    accumulator->Add("...\n");
+  } else {
+    accumulator->Put(script_source, start_position(), end_position());
+  }
+}
+
+
+void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
+  IteratePointers(v, kNameOffset, kCodeOffset + kPointerSize);
+  IteratePointers(v, kInstanceClassNameOffset, kScriptOffset + kPointerSize);
+  IteratePointer(v, kDebugInfoOffset);
+}
+
+
+void ObjectVisitor::BeginCodeIteration(Code* code) {
+  ASSERT(code->ic_flag() == Code::IC_TARGET_IS_OBJECT);
+}
+
+
+void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
+  ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+  VisitPointer(rinfo->target_object_address());
+}
+
+
+void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
+  ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) && rinfo->is_call_instruction());
+  VisitPointer(rinfo->call_object_address());
+}
+
+
+// Convert relocatable targets from address to code object address. This is
+// mainly IC call targets but for debugging straight-line code can be replaced
+// with a call instruction which also has to be relocated.
+void Code::ConvertICTargetsFromAddressToObject() {
+  ASSERT(ic_flag() == IC_TARGET_IS_ADDRESS);
+
+  for (RelocIterator it(this, RelocInfo::kCodeTargetMask);
+       !it.done(); it.next()) {
+    Address ic_addr = it.rinfo()->target_address();
+    ASSERT(ic_addr != NULL);
+    HeapObject* code = HeapObject::FromAddress(ic_addr - Code::kHeaderSize);
+    ASSERT(code->IsHeapObject());
+    it.rinfo()->set_target_object(code);
+  }
+
+  if (Debug::has_break_points()) {
+    for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
+         !it.done();
+         it.next()) {
+      if (it.rinfo()->is_call_instruction()) {
+        Address addr = it.rinfo()->call_address();
+        ASSERT(addr != NULL);
+        HeapObject* code = HeapObject::FromAddress(addr - Code::kHeaderSize);
+        ASSERT(code->IsHeapObject());
+        it.rinfo()->set_call_object(code);
+      }
+    }
+  }
+  set_ic_flag(IC_TARGET_IS_OBJECT);
+}
+
+
+void Code::CodeIterateBody(ObjectVisitor* v) {
+  v->BeginCodeIteration(this);
+
+  int mode_mask = RelocInfo::kCodeTargetMask |
+                  RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
+                  RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
+                  RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
+                  RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
+
+  for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
+    RelocInfo::Mode rmode = it.rinfo()->rmode();
+    if (rmode == RelocInfo::EMBEDDED_OBJECT) {
+      v->VisitPointer(it.rinfo()->target_object_address());
+    } else if (RelocInfo::IsCodeTarget(rmode)) {
+      v->VisitCodeTarget(it.rinfo());
+    } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+      v->VisitExternalReference(it.rinfo()->target_reference_address());
+    } else if (Debug::has_break_points() &&
+               RelocInfo::IsJSReturn(rmode) &&
+               it.rinfo()->is_call_instruction()) {
+      v->VisitDebugTarget(it.rinfo());
+    } else if (rmode == RelocInfo::RUNTIME_ENTRY) {
+      v->VisitRuntimeEntry(it.rinfo());
+    }
+  }
+
+  ScopeInfo<>::IterateScopeInfo(this, v);
+
+  v->EndCodeIteration(this);
+}
+
+
+void Code::ConvertICTargetsFromObjectToAddress() {
+  ASSERT(ic_flag() == IC_TARGET_IS_OBJECT);
+
+  for (RelocIterator it(this, RelocInfo::kCodeTargetMask);
+       !it.done(); it.next()) {
+    // We cannot use the safe cast (Code::cast) here, because we may be in
+    // the middle of relocating old objects during GC and the map pointer in
+    // the code object may be mangled
+    Code* code = reinterpret_cast<Code*>(it.rinfo()->target_object());
+    ASSERT((code != NULL) && code->IsHeapObject());
+    it.rinfo()->set_target_address(code->instruction_start());
+  }
+
+  if (Debug::has_break_points()) {
+    for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
+         !it.done();
+         it.next()) {
+      if (it.rinfo()->is_call_instruction()) {
+        Code* code = reinterpret_cast<Code*>(it.rinfo()->call_object());
+        ASSERT((code != NULL) && code->IsHeapObject());
+        it.rinfo()->set_call_address(code->instruction_start());
+      }
+    }
+  }
+  set_ic_flag(IC_TARGET_IS_ADDRESS);
+}
+
+
+void Code::Relocate(int delta) {
+  for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
+    it.rinfo()->apply(delta);
+  }
+  CPU::FlushICache(instruction_start(), instruction_size());
+}
+
+
+void Code::CopyFrom(const CodeDesc& desc) {
+  // copy code
+  memmove(instruction_start(), desc.buffer, desc.instr_size);
+
+  // fill gap with zero bytes
+  { byte* p = instruction_start() + desc.instr_size;
+    byte* q = relocation_start();
+    while (p < q) {
+      *p++ = 0;
+    }
+  }
+
+  // copy reloc info
+  memmove(relocation_start(),
+          desc.buffer + desc.buffer_size - desc.reloc_size,
+          desc.reloc_size);
+
+  // unbox handles and relocate
+  int delta = instruction_start() - desc.buffer;
+  int mode_mask = RelocInfo::kCodeTargetMask |
+                  RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
+                  RelocInfo::kApplyMask;
+  for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
+    RelocInfo::Mode mode = it.rinfo()->rmode();
+    if (mode == RelocInfo::EMBEDDED_OBJECT) {
+      Object** p = reinterpret_cast<Object**>(it.rinfo()->target_object());
+      it.rinfo()->set_target_object(*p);
+    } else if (RelocInfo::IsCodeTarget(mode)) {
+      // rewrite code handles in inline cache targets to direct
+      // pointers to the first instruction in the code object
+      Object** p = reinterpret_cast<Object**>(it.rinfo()->target_object());
+      Code* code = Code::cast(*p);
+      it.rinfo()->set_target_address(code->instruction_start());
+    } else {
+      it.rinfo()->apply(delta);
+    }
+  }
+  CPU::FlushICache(instruction_start(), instruction_size());
+}
+
+
+// Locate the source position which is closest to the address in the code. This
+// is using the source position information embedded in the relocation info.
+// The position returned is relative to the beginning of the script where the
+// source for this function is found.
+int Code::SourcePosition(Address pc) {
+  int distance = kMaxInt;
+  int position = RelocInfo::kNoPosition;  // Initially no position found.
+  // Run through all the relocation info to find the best matching source
+  // position. All the code needs to be considered as the sequence of the
+  // instructions in the code does not necessarily follow the same order as the
+  // source.
+  RelocIterator it(this, RelocInfo::kPositionMask);
+  while (!it.done()) {
+    // Only look at positions after the current pc.
+    if (it.rinfo()->pc() < pc) {
+      // Get position and distance.
+      int dist = pc - it.rinfo()->pc();
+      int pos = it.rinfo()->data();
+      // If this position is closer than the current candidate or if it has the
+      // same distance as the current candidate and the position is higher then
+      // this position is the new candidate.
+      if ((dist < distance) ||
+          (dist == distance && pos > position)) {
+        position = pos;
+        distance = dist;
+      }
+    }
+    it.next();
+  }
+  return position;
+}
+
+
+// Same as Code::SourcePosition above except it only looks for statement
+// positions.
+int Code::SourceStatementPosition(Address pc) {
+  // First find the position as close as possible using all position
+  // information.
+  int position = SourcePosition(pc);
+  // Now find the closest statement position before the position.
+  int statement_position = 0;
+  RelocIterator it(this, RelocInfo::kPositionMask);
+  while (!it.done()) {
+    if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
+      int p = it.rinfo()->data();
+      if (statement_position < p && p <= position) {
+        statement_position = p;
+      }
+    }
+    it.next();
+  }
+  return statement_position;
+}
+
+
+#ifdef ENABLE_DISASSEMBLER
+// Identify kind of code.
+const char* Code::Kind2String(Kind kind) {
+  switch (kind) {
+    case FUNCTION: return "FUNCTION";
+    case STUB: return "STUB";
+    case BUILTIN: return "BUILTIN";
+    case LOAD_IC: return "LOAD_IC";
+    case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
+    case STORE_IC: return "STORE_IC";
+    case KEYED_STORE_IC: return "KEYED_STORE_IC";
+    case CALL_IC: return "CALL_IC";
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+const char* Code::ICState2String(InlineCacheState state) {
+  switch (state) {
+    case UNINITIALIZED: return "UNINITIALIZED";
+    case PREMONOMORPHIC: return "PREMONOMORPHIC";
+    case MONOMORPHIC: return "MONOMORPHIC";
+    case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
+    case MEGAMORPHIC: return "MEGAMORPHIC";
+    case DEBUG_BREAK: return "DEBUG_BREAK";
+    case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+void Code::Disassemble() {
+  PrintF("kind = %s", Kind2String(kind()));
+
+  PrintF("\nInstructions (size = %d)\n", instruction_size());
+  Disassembler::Decode(NULL, this);
+  PrintF("\n");
+
+  PrintF("RelocInfo (size = %d)\n", relocation_size());
+  for (RelocIterator it(this); !it.done(); it.next())
+    it.rinfo()->Print();
+  PrintF("\n");
+}
+#endif  // ENABLE_DISASSEMBLER
+
+
+void JSObject::SetFastElements(FixedArray* elems) {
+#ifdef DEBUG
+  // Check the provided array is filled with the_hole.
+  uint32_t len = static_cast<uint32_t>(elems->length());
+  for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole());
+#endif
+  WriteBarrierMode mode = elems->GetWriteBarrierMode();
+  if (HasFastElements()) {
+    FixedArray* old_elements = FixedArray::cast(elements());
+    uint32_t old_length = static_cast<uint32_t>(old_elements->length());
+    // Fill out the new array with this content and array holes.
+    for (uint32_t i = 0; i < old_length; i++) {
+      elems->set(i, old_elements->get(i), mode);
+    }
+  } else {
+    Dictionary* dictionary = Dictionary::cast(elements());
+    for (int i = 0; i < dictionary->Capacity(); i++) {
+      Object* key = dictionary->KeyAt(i);
+      if (key->IsNumber()) {
+        uint32_t entry = static_cast<uint32_t>(key->Number());
+        elems->set(entry, dictionary->ValueAt(i), mode);
+      }
+    }
+  }
+  set_elements(elems);
+}
+
+
+Object* JSObject::SetSlowElements(Object* len) {
+  uint32_t new_length = static_cast<uint32_t>(len->Number());
+
+  if (!HasFastElements()) {
+    if (IsJSArray()) {
+      uint32_t old_length =
+          static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
+      element_dictionary()->RemoveNumberEntries(new_length, old_length),
+      JSArray::cast(this)->set_length(len);
+    }
+    return this;
+  }
+
+  // Make sure we never try to shrink dense arrays into sparse arrays.
+  ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
+                               new_length);
+  Object* obj = NormalizeElements();
+  if (obj->IsFailure()) return obj;
+
+  // Update length for JSArrays.
+  if (IsJSArray()) JSArray::cast(this)->set_length(len);
+  return this;
+}
+
+
+Object* JSArray::Initialize(int capacity) {
+  ASSERT(capacity >= 0);
+  set_length(Smi::FromInt(0), SKIP_WRITE_BARRIER);
+  FixedArray* new_elements;
+  if (capacity == 0) {
+    new_elements = Heap::empty_fixed_array();
+  } else {
+    Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+    if (obj->IsFailure()) return obj;
+    new_elements = FixedArray::cast(obj);
+  }
+  set_elements(new_elements);
+  return this;
+}
+
+
+// Computes the new capacity when expanding the elements of a JSObject.
+static int NewElementsCapacity(int old_capacity) {
+  // (old_capacity + 50%) + 16
+  return old_capacity + (old_capacity >> 1) + 16;
+}
+
+
+static Object* ArrayLengthRangeError() {
+  HandleScope scope;
+  return Top::Throw(*Factory::NewRangeError("invalid_array_length",
+                                            HandleVector<Object>(NULL, 0)));
+}
+
+
+Object* JSObject::SetElementsLength(Object* len) {
+  Object* smi_length = len->ToSmi();
+  if (smi_length->IsSmi()) {
+    int value = Smi::cast(smi_length)->value();
+    if (value < 0) return ArrayLengthRangeError();
+    if (HasFastElements()) {
+      int old_capacity = FixedArray::cast(elements())->length();
+      if (value <= old_capacity) {
+        if (IsJSArray()) {
+          int old_length = FastD2I(JSArray::cast(this)->length()->Number());
+          // NOTE: We may be able to optimize this by removing the
+          // last part of the elements backing storage array and
+          // setting the capacity to the new size.
+          for (int i = value; i < old_length; i++) {
+            FixedArray::cast(elements())->set_the_hole(i);
+          }
+          JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER);
+        }
+        return this;
+      }
+      int min = NewElementsCapacity(old_capacity);
+      int new_capacity = value > min ? value : min;
+      if (new_capacity <= kMaxFastElementsLength ||
+          !ShouldConvertToSlowElements(new_capacity)) {
+        Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
+        if (obj->IsFailure()) return obj;
+        if (IsJSArray()) JSArray::cast(this)->set_length(smi_length,
+                                                         SKIP_WRITE_BARRIER);
+        SetFastElements(FixedArray::cast(obj));
+        return this;
+      }
+    } else {
+      if (IsJSArray()) {
+        if (value == 0) {
+          // If the length of a slow array is reset to zero, we clear
+          // the array and flush backing storage. This has the added
+          // benefit that the array returns to fast mode.
+          initialize_elements();
+        } else {
+          // Remove deleted elements.
+          uint32_t old_length =
+              static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
+          element_dictionary()->RemoveNumberEntries(value, old_length);
+        }
+        JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER);
+      }
+      return this;
+    }
+  }
+
+  // General slow case.
+  if (len->IsNumber()) {
+    uint32_t length;
+    if (Array::IndexFromObject(len, &length)) {
+      return SetSlowElements(len);
+    } else {
+      return ArrayLengthRangeError();
+    }
+  }
+
+  // len is not a number so make the array size one and
+  // set only element to len.
+  Object* obj = Heap::AllocateFixedArray(1);
+  if (obj->IsFailure()) return obj;
+  FixedArray::cast(obj)->set(0, len);
+  if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1),
+                                                   SKIP_WRITE_BARRIER);
+  set_elements(FixedArray::cast(obj));
+  return this;
+}
+
+
+bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
+  if (HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+        static_cast<uint32_t>(
+            Smi::cast(JSArray::cast(this)->length())->value()) :
+        static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    if ((index < length) &&
+        !FixedArray::cast(elements())->get(index)->IsTheHole()) {
+      return true;
+    }
+  } else {
+    if (element_dictionary()->FindNumberEntry(index) != -1) return true;
+  }
+
+  // Handle [] on String objects.
+  if (this->IsStringObjectWithCharacterAt(index)) return true;
+
+  Object* pt = GetPrototype();
+  if (pt == Heap::null_value()) return false;
+  return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
+}
+
+
+bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
+  // Make sure that the top context does not change when doing
+  // callbacks or interceptor calls.
+  AssertNoContextChange ncc;
+  HandleScope scope;
+  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
+  Handle<JSObject> receiver_handle(receiver);
+  Handle<JSObject> holder_handle(this);
+  Handle<Object> data_handle(interceptor->data());
+  v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
+                        v8::Utils::ToLocal(data_handle),
+                        v8::Utils::ToLocal(holder_handle));
+  if (!interceptor->query()->IsUndefined()) {
+    v8::IndexedPropertyQuery query =
+        v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
+    LOG(ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
+    v8::Handle<v8::Boolean> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = query(index, info);
+    }
+    if (!result.IsEmpty()) return result->IsTrue();
+  } else if (!interceptor->getter()->IsUndefined()) {
+    v8::IndexedPropertyGetter getter =
+        v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
+    LOG(ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
+    v8::Handle<v8::Value> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = getter(index, info);
+    }
+    if (!result.IsEmpty()) return !result->IsUndefined();
+  }
+  return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
+}
+
+
+bool JSObject::HasLocalElement(uint32_t index) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return false;
+  }
+
+  // Check for lookup interceptor
+  if (HasIndexedInterceptor()) {
+    return HasElementWithInterceptor(this, index);
+  }
+
+  // Handle [] on String objects.
+  if (this->IsStringObjectWithCharacterAt(index)) return true;
+
+  if (HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+        static_cast<uint32_t>(
+            Smi::cast(JSArray::cast(this)->length())->value()) :
+        static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    return (index < length) &&
+           !FixedArray::cast(elements())->get(index)->IsTheHole();
+  } else {
+    return element_dictionary()->FindNumberEntry(index) != -1;
+  }
+}
+
+
+bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return false;
+  }
+
+  // Check for lookup interceptor
+  if (HasIndexedInterceptor()) {
+    return HasElementWithInterceptor(receiver, index);
+  }
+
+  if (HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+        static_cast<uint32_t>(
+            Smi::cast(JSArray::cast(this)->length())->value()) :
+        static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    if ((index < length) &&
+        !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
+  } else {
+    if (element_dictionary()->FindNumberEntry(index) != -1) return true;
+  }
+
+  // Handle [] on String objects.
+  if (this->IsStringObjectWithCharacterAt(index)) return true;
+
+  Object* pt = GetPrototype();
+  if (pt == Heap::null_value()) return false;
+  return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
+}
+
+
+Object* JSObject::SetElementPostInterceptor(uint32_t index, Object* value) {
+  if (HasFastElements()) return SetFastElement(index, value);
+
+  // Dictionary case.
+  ASSERT(!HasFastElements());
+
+  FixedArray* elms = FixedArray::cast(elements());
+  Object* result = Dictionary::cast(elms)->AtNumberPut(index, value);
+  if (result->IsFailure()) return result;
+  if (elms != FixedArray::cast(result)) {
+    set_elements(FixedArray::cast(result));
+  }
+
+  if (IsJSArray()) {
+    return JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
+  }
+
+  return value;
+}
+
+
+Object* JSObject::SetElementWithInterceptor(uint32_t index, Object* value) {
+  // Make sure that the top context does not change when doing
+  // callbacks or interceptor calls.
+  AssertNoContextChange ncc;
+  HandleScope scope;
+  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
+  Handle<JSObject> this_handle(this);
+  Handle<Object> value_handle(value);
+  if (!interceptor->setter()->IsUndefined()) {
+    v8::IndexedPropertySetter setter =
+        v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
+    Handle<Object> data_handle(interceptor->data());
+    LOG(ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
+    v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
+                          v8::Utils::ToLocal(data_handle),
+                          v8::Utils::ToLocal(this_handle));
+    v8::Handle<v8::Value> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = setter(index, v8::Utils::ToLocal(value_handle), info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (!result.IsEmpty()) return *value_handle;
+  }
+  Object* raw_result =
+      this_handle->SetElementPostInterceptor(index, *value_handle);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return raw_result;
+}
+
+
+// Adding n elements in fast case is O(n*n).
+// Note: revisit design to have dual undefined values to capture absent
+// elements.
+Object* JSObject::SetFastElement(uint32_t index, Object* value) {
+  ASSERT(HasFastElements());
+
+  FixedArray* elms = FixedArray::cast(elements());
+  uint32_t elms_length = static_cast<uint32_t>(elms->length());
+
+  // Check whether there is extra space in fixed array..
+  if (index < elms_length) {
+    elms->set(index, value);
+    if (IsJSArray()) {
+      // Update the length of the array if needed.
+      uint32_t array_length = 0;
+      CHECK(Array::IndexFromObject(JSArray::cast(this)->length(),
+                                   &array_length));
+      if (index >= array_length) {
+        JSArray::cast(this)->set_length(Smi::FromInt(index + 1),
+                                        SKIP_WRITE_BARRIER);
+      }
+    }
+    return value;
+  }
+
+  // Allow gap in fast case.
+  if ((index - elms_length) < kMaxGap) {
+    // Try allocating extra space.
+    int new_capacity = NewElementsCapacity(index+1);
+    if (new_capacity <= kMaxFastElementsLength ||
+        !ShouldConvertToSlowElements(new_capacity)) {
+      ASSERT(static_cast<uint32_t>(new_capacity) > index);
+      Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
+      if (obj->IsFailure()) return obj;
+      SetFastElements(FixedArray::cast(obj));
+      if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(index + 1),
+                                                       SKIP_WRITE_BARRIER);
+      FixedArray::cast(elements())->set(index, value);
+      return value;
+    }
+  }
+
+  // Otherwise default to slow case.
+  Object* obj = NormalizeElements();
+  if (obj->IsFailure()) return obj;
+  ASSERT(!HasFastElements());
+  return SetElement(index, value);
+}
+
+Object* JSObject::SetElement(uint32_t index, Object* value) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
+    return value;
+  }
+
+  if (IsJSGlobalProxy()) {
+    Object* proto = GetPrototype();
+    if (proto->IsNull()) return value;
+    ASSERT(proto->IsJSGlobalObject());
+    return JSObject::cast(proto)->SetElement(index, value);
+  }
+
+  // Check for lookup interceptor
+  if (HasIndexedInterceptor()) {
+    return SetElementWithInterceptor(index, value);
+  }
+
+  // Fast case.
+  if (HasFastElements()) return SetFastElement(index, value);
+
+  // Dictionary case.
+  ASSERT(!HasFastElements());
+
+  // Insert element in the dictionary.
+  FixedArray* elms = FixedArray::cast(elements());
+  Dictionary* dictionary = Dictionary::cast(elms);
+  Object* result = dictionary->AtNumberPut(index, value);
+  if (result->IsFailure()) return result;
+  if (elms != FixedArray::cast(result)) {
+    set_elements(FixedArray::cast(result));
+  }
+
+  // Update the array length if this JSObject is an array.
+  if (IsJSArray()) {
+    JSArray* array = JSArray::cast(this);
+    Object* return_value = array->JSArrayUpdateLengthFromIndex(index, value);
+    if (return_value->IsFailure()) return return_value;
+  }
+
+  // Attempt to put this object back in fast case.
+  if (ShouldConvertToFastElements()) {
+    uint32_t new_length = 0;
+    if (IsJSArray()) {
+      CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length));
+    } else {
+      new_length = Dictionary::cast(elements())->max_number_key() + 1;
+    }
+    Object* obj = Heap::AllocateFixedArrayWithHoles(new_length);
+    if (obj->IsFailure()) return obj;
+    SetFastElements(FixedArray::cast(obj));
+#ifdef DEBUG
+    if (FLAG_trace_normalization) {
+      PrintF("Object elements are fast case again:\n");
+      Print();
+    }
+#endif
+  }
+
+  return value;
+}
+
+
+Object* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) {
+  uint32_t old_len = 0;
+  CHECK(Array::IndexFromObject(length(), &old_len));
+  // Check to see if we need to update the length. For now, we make
+  // sure that the length stays within 32-bits (unsigned).
+  if (index >= old_len && index != 0xffffffff) {
+    Object* len =
+        Heap::NumberFromDouble(static_cast<double>(index) + 1);
+    if (len->IsFailure()) return len;
+    set_length(len);
+  }
+  return value;
+}
+
+
+Object* JSObject::GetElementPostInterceptor(JSObject* receiver,
+                                            uint32_t index) {
+  // Get element works for both JSObject and JSArray since
+  // JSArray::length cannot change.
+  if (HasFastElements()) {
+    FixedArray* elms = FixedArray::cast(elements());
+    if (index < static_cast<uint32_t>(elms->length())) {
+      Object* value = elms->get(index);
+      if (!value->IsTheHole()) return value;
+    }
+  } else {
+    Dictionary* dictionary = element_dictionary();
+    int entry = dictionary->FindNumberEntry(index);
+    if (entry != -1) {
+      return dictionary->ValueAt(entry);
+    }
+  }
+
+  // Continue searching via the prototype chain.
+  Object* pt = GetPrototype();
+  if (pt == Heap::null_value()) return Heap::undefined_value();
+  return pt->GetElementWithReceiver(receiver, index);
+}
+
+
+Object* JSObject::GetElementWithInterceptor(JSObject* receiver,
+                                            uint32_t index) {
+  // Make sure that the top context does not change when doing
+  // callbacks or interceptor calls.
+  AssertNoContextChange ncc;
+  HandleScope scope;
+  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
+  Handle<JSObject> this_handle(receiver);
+  Handle<JSObject> holder_handle(this);
+
+  if (!interceptor->getter()->IsUndefined()) {
+    Handle<Object> data_handle(interceptor->data());
+    v8::IndexedPropertyGetter getter =
+        v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
+    LOG(ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
+    v8::AccessorInfo info(v8::Utils::ToLocal(this_handle),
+                          v8::Utils::ToLocal(data_handle),
+                          v8::Utils::ToLocal(holder_handle));
+    v8::Handle<v8::Value> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = getter(index, info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+  }
+
+  Object* raw_result =
+      holder_handle->GetElementPostInterceptor(*this_handle, index);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return raw_result;
+}
+
+
+Object* JSObject::GetElementWithReceiver(JSObject* receiver, uint32_t index) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayIndexedAccess(this, index, v8::ACCESS_GET)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
+    return Heap::undefined_value();
+  }
+
+  if (HasIndexedInterceptor()) {
+    return GetElementWithInterceptor(receiver, index);
+  }
+
+  // Get element works for both JSObject and JSArray since
+  // JSArray::length cannot change.
+  if (HasFastElements()) {
+    FixedArray* elms = FixedArray::cast(elements());
+    if (index < static_cast<uint32_t>(elms->length())) {
+      Object* value = elms->get(index);
+      if (!value->IsTheHole()) return value;
+    }
+  } else {
+    Dictionary* dictionary = element_dictionary();
+    int entry = dictionary->FindNumberEntry(index);
+    if (entry != -1) {
+      return dictionary->ValueAt(entry);
+    }
+  }
+
+  Object* pt = GetPrototype();
+  if (pt == Heap::null_value()) return Heap::undefined_value();
+  return pt->GetElementWithReceiver(receiver, index);
+}
+
+
+bool JSObject::HasDenseElements() {
+  int capacity = 0;
+  int number_of_elements = 0;
+
+  if (HasFastElements()) {
+    FixedArray* elms = FixedArray::cast(elements());
+    capacity = elms->length();
+    for (int i = 0; i < capacity; i++) {
+      if (!elms->get(i)->IsTheHole()) number_of_elements++;
+    }
+  } else {
+    Dictionary* dictionary = Dictionary::cast(elements());
+    capacity = dictionary->Capacity();
+    number_of_elements = dictionary->NumberOfElements();
+  }
+
+  if (capacity == 0) return true;
+  return (number_of_elements > (capacity / 2));
+}
+
+
+bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
+  ASSERT(HasFastElements());
+  // Keep the array in fast case if the current backing storage is
+  // almost filled and if the new capacity is no more than twice the
+  // old capacity.
+  int elements_length = FixedArray::cast(elements())->length();
+  return !HasDenseElements() || ((new_capacity / 2) > elements_length);
+}
+
+
+bool JSObject::ShouldConvertToFastElements() {
+  ASSERT(!HasFastElements());
+  Dictionary* dictionary = Dictionary::cast(elements());
+  // If the elements are sparse, we should not go back to fast case.
+  if (!HasDenseElements()) return false;
+  // If an element has been added at a very high index in the elements
+  // dictionary, we cannot go back to fast case.
+  if (dictionary->requires_slow_elements()) return false;
+  // An object requiring access checks is never allowed to have fast
+  // elements.  If it had fast elements we would skip security checks.
+  if (IsAccessCheckNeeded()) return false;
+  // If the dictionary backing storage takes up roughly half as much
+  // space as a fast-case backing storage would the array should have
+  // fast elements.
+  uint32_t length = 0;
+  if (IsJSArray()) {
+    CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &length));
+  } else {
+    length = dictionary->max_number_key();
+  }
+  return static_cast<uint32_t>(dictionary->Capacity()) >=
+      (length / (2 * Dictionary::kElementSize));
+}
+
+
+Object* Dictionary::RemoveHoles() {
+  int capacity = Capacity();
+  Object* obj = Allocate(NumberOfElements());
+  if (obj->IsFailure()) return obj;
+  Dictionary* dict = Dictionary::cast(obj);
+  uint32_t pos = 0;
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k)) {
+      dict->AddNumberEntry(pos++, ValueAt(i), DetailsAt(i));
+    }
+  }
+  return dict;
+}
+
+
+void Dictionary::CopyValuesTo(FixedArray* elements) {
+  int pos = 0;
+  int capacity = Capacity();
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k)) elements->set(pos++, ValueAt(i));
+  }
+  ASSERT(pos == elements->length());
+}
+
+
+Object* JSArray::RemoveHoles() {
+  if (HasFastElements()) {
+    int len = Smi::cast(length())->value();
+    int pos = 0;
+    FixedArray* elms = FixedArray::cast(elements());
+    for (int index = 0; index < len; index++) {
+      Object* e = elms->get(index);
+      if (!e->IsTheHole()) {
+        if (index != pos) elms->set(pos, e);
+        pos++;
+      }
+    }
+    set_length(Smi::FromInt(pos), SKIP_WRITE_BARRIER);
+    for (int index = pos; index < len; index++) {
+      elms->set_the_hole(index);
+    }
+    return this;
+  }
+
+  // Compact the sparse array if possible.
+  Dictionary* dict = element_dictionary();
+  int length = dict->NumberOfElements();
+
+  // Try to make this a fast array again.
+  if (length <= kMaxFastElementsLength) {
+    Object* obj = Heap::AllocateFixedArray(length);
+    if (obj->IsFailure()) return obj;
+    dict->CopyValuesTo(FixedArray::cast(obj));
+    set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER);
+    set_elements(FixedArray::cast(obj));
+    return this;
+  }
+
+  // Make another dictionary with smaller indices.
+  Object* obj = dict->RemoveHoles();
+  if (obj->IsFailure()) return obj;
+  set_length(Smi::FromInt(length), SKIP_WRITE_BARRIER);
+  set_elements(Dictionary::cast(obj));
+  return this;
+}
+
+
+InterceptorInfo* JSObject::GetNamedInterceptor() {
+  ASSERT(map()->has_named_interceptor());
+  JSFunction* constructor = JSFunction::cast(map()->constructor());
+  Object* template_info = constructor->shared()->function_data();
+  Object* result =
+      FunctionTemplateInfo::cast(template_info)->named_property_handler();
+  return InterceptorInfo::cast(result);
+}
+
+
+InterceptorInfo* JSObject::GetIndexedInterceptor() {
+  ASSERT(map()->has_indexed_interceptor());
+  JSFunction* constructor = JSFunction::cast(map()->constructor());
+  Object* template_info = constructor->shared()->function_data();
+  Object* result =
+      FunctionTemplateInfo::cast(template_info)->indexed_property_handler();
+  return InterceptorInfo::cast(result);
+}
+
+
+Object* JSObject::GetPropertyPostInterceptor(JSObject* receiver,
+                                             String* name,
+                                             PropertyAttributes* attributes) {
+  // Check local property in holder, ignore interceptor.
+  LookupResult result;
+  LocalLookupRealNamedProperty(name, &result);
+  if (result.IsValid()) return GetProperty(receiver, &result, name, attributes);
+  // Continue searching via the prototype chain.
+  Object* pt = GetPrototype();
+  *attributes = ABSENT;
+  if (pt == Heap::null_value()) return Heap::undefined_value();
+  return pt->GetPropertyWithReceiver(receiver, name, attributes);
+}
+
+
+Object* JSObject::GetPropertyWithInterceptor(JSObject* receiver,
+                                             String* name,
+                                             PropertyAttributes* attributes) {
+  HandleScope scope;
+  Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
+  Handle<JSObject> receiver_handle(receiver);
+  Handle<JSObject> holder_handle(this);
+  Handle<String> name_handle(name);
+  Handle<Object> data_handle(interceptor->data());
+
+  if (!interceptor->getter()->IsUndefined()) {
+    v8::NamedPropertyGetter getter =
+        v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
+    LOG(ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
+    v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle),
+                          v8::Utils::ToLocal(data_handle),
+                          v8::Utils::ToLocal(holder_handle));
+    v8::Handle<v8::Value> result;
+    {
+      // Leaving JavaScript.
+      VMState state(OTHER);
+      result = getter(v8::Utils::ToLocal(name_handle), info);
+    }
+    RETURN_IF_SCHEDULED_EXCEPTION();
+    if (!result.IsEmpty()) {
+      *attributes = NONE;
+      return *v8::Utils::OpenHandle(*result);
+    }
+  }
+
+  Object* raw_result = holder_handle->GetPropertyPostInterceptor(
+      *receiver_handle,
+      *name_handle,
+      attributes);
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return raw_result;
+}
+
+
+bool JSObject::HasRealNamedProperty(String* key) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return false;
+  }
+
+  LookupResult result;
+  LocalLookupRealNamedProperty(key, &result);
+  if (result.IsValid()) {
+    switch (result.type()) {
+      case NORMAL:    // fall through.
+      case FIELD:     // fall through.
+      case CALLBACKS:  // fall through.
+      case CONSTANT_FUNCTION:
+        return true;
+      case INTERCEPTOR:
+      case MAP_TRANSITION:
+      case CONSTANT_TRANSITION:
+      case NULL_DESCRIPTOR:
+        return false;
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  return false;
+}
+
+
+bool JSObject::HasRealElementProperty(uint32_t index) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return false;
+  }
+
+  // Handle [] on String objects.
+  if (this->IsStringObjectWithCharacterAt(index)) return true;
+
+  if (HasFastElements()) {
+    uint32_t length = IsJSArray() ?
+        static_cast<uint32_t>(
+            Smi::cast(JSArray::cast(this)->length())->value()) :
+        static_cast<uint32_t>(FixedArray::cast(elements())->length());
+    return (index < length) &&
+        !FixedArray::cast(elements())->get(index)->IsTheHole();
+  }
+  return element_dictionary()->FindNumberEntry(index) != -1;
+}
+
+
+bool JSObject::HasRealNamedCallbackProperty(String* key) {
+  // Check access rights if needed.
+  if (IsAccessCheckNeeded() &&
+      !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+    Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+    return false;
+  }
+
+  LookupResult result;
+  LocalLookupRealNamedProperty(key, &result);
+  return result.IsValid() && (result.type() == CALLBACKS);
+}
+
+
+int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
+  if (HasFastProperties()) {
+    int result = 0;
+    for (DescriptorReader r(map()->instance_descriptors());
+         !r.eos();
+         r.advance()) {
+      PropertyDetails details = r.GetDetails();
+      if (!details.IsTransition() && (details.attributes() & filter) == 0) {
+        result++;
+      }
+    }
+    return result;
+  } else {
+    return property_dictionary()->NumberOfElementsFilterAttributes(filter);
+  }
+}
+
+
+int JSObject::NumberOfEnumProperties() {
+  return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
+}
+
+
+void FixedArray::Swap(int i, int j) {
+  Object* temp = get(i);
+  set(i, get(j));
+  set(j, temp);
+}
+
+
+static void InsertionSortPairs(FixedArray* content, FixedArray* smis) {
+  int len = smis->length();
+  for (int i = 1; i < len; i++) {
+    int j = i;
+    while (j > 0 &&
+           Smi::cast(smis->get(j-1))->value() >
+               Smi::cast(smis->get(j))->value()) {
+      smis->Swap(j-1, j);
+      content->Swap(j-1, j);
+      j--;
+    }
+  }
+}
+
+
+void HeapSortPairs(FixedArray* content, FixedArray* smis) {
+  // In-place heap sort.
+  ASSERT(content->length() == smis->length());
+  int len = smis->length();
+
+  // Bottom-up max-heap construction.
+  for (int i = 1; i < len; ++i) {
+    int child_index = i;
+    while (child_index > 0) {
+      int parent_index = ((child_index + 1) >> 1) - 1;
+      int parent_value = Smi::cast(smis->get(parent_index))->value();
+      int child_value = Smi::cast(smis->get(child_index))->value();
+      if (parent_value < child_value) {
+        content->Swap(parent_index, child_index);
+        smis->Swap(parent_index, child_index);
+      } else {
+        break;
+      }
+      child_index = parent_index;
+    }
+  }
+
+  // Extract elements and create sorted array.
+  for (int i = len - 1; i > 0; --i) {
+    // Put max element at the back of the array.
+    content->Swap(0, i);
+    smis->Swap(0, i);
+    // Sift down the new top element.
+    int parent_index = 0;
+    while (true) {
+      int child_index = ((parent_index + 1) << 1) - 1;
+      if (child_index >= i) break;
+      uint32_t child1_value = Smi::cast(smis->get(child_index))->value();
+      uint32_t child2_value = Smi::cast(smis->get(child_index + 1))->value();
+      uint32_t parent_value = Smi::cast(smis->get(parent_index))->value();
+      if (child_index + 1 >= i || child1_value > child2_value) {
+        if (parent_value > child1_value) break;
+        content->Swap(parent_index, child_index);
+        smis->Swap(parent_index, child_index);
+        parent_index = child_index;
+      } else {
+        if (parent_value > child2_value) break;
+        content->Swap(parent_index, child_index + 1);
+        smis->Swap(parent_index, child_index + 1);
+        parent_index = child_index + 1;
+      }
+    }
+  }
+}
+
+
+// Sort this array and the smis as pairs wrt. the (distinct) smis.
+void FixedArray::SortPairs(FixedArray* smis) {
+  ASSERT(this->length() == smis->length());
+  int len = smis->length();
+  // For small arrays, simply use insertion sort.
+  if (len <= 10) {
+    InsertionSortPairs(this, smis);
+    return;
+  }
+  // Check the range of indices.
+  int min_index = Smi::cast(smis->get(0))->value();
+  int max_index = min_index;
+  int i;
+  for (i = 1; i < len; i++) {
+    if (Smi::cast(smis->get(i))->value() < min_index) {
+      min_index = Smi::cast(smis->get(i))->value();
+    } else if (Smi::cast(smis->get(i))->value() > max_index) {
+      max_index = Smi::cast(smis->get(i))->value();
+    }
+  }
+  if (max_index - min_index + 1 == len) {
+    // Indices form a contiguous range, unless there are duplicates.
+    // Do an in-place linear time sort assuming distinct smis, but
+    // avoid hanging in case they are not.
+    for (i = 0; i < len; i++) {
+      int p;
+      int j = 0;
+      // While the current element at i is not at its correct position p,
+      // swap the elements at these two positions.
+      while ((p = Smi::cast(smis->get(i))->value() - min_index) != i &&
+             j++ < len) {
+        this->Swap(i, p);
+        smis->Swap(i, p);
+      }
+    }
+  } else {
+    HeapSortPairs(this, smis);
+    return;
+  }
+}
+
+
+// Fill in the names of local properties into the supplied storage. The main
+// purpose of this function is to provide reflection information for the object
+// mirrors.
+void JSObject::GetLocalPropertyNames(FixedArray* storage) {
+  ASSERT(storage->length() ==
+         NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE)));
+  int index = 0;
+  if (HasFastProperties()) {
+    for (DescriptorReader r(map()->instance_descriptors());
+         !r.eos();
+         r.advance()) {
+      if (!r.IsTransition()) {
+        storage->set(index++, r.GetKey());
+      }
+    }
+    ASSERT(storage->length() == index);
+  } else {
+    property_dictionary()->CopyKeysTo(storage);
+  }
+}
+
+
+int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
+  return GetLocalElementKeys(NULL, filter);
+}
+
+
+int JSObject::NumberOfEnumElements() {
+  return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
+}
+
+
+int JSObject::GetLocalElementKeys(FixedArray* storage,
+                                  PropertyAttributes filter) {
+  int counter = 0;
+  if (HasFastElements()) {
+    int length = IsJSArray()
+        ? Smi::cast(JSArray::cast(this)->length())->value()
+        : FixedArray::cast(elements())->length();
+    for (int i = 0; i < length; i++) {
+      if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
+        if (storage) {
+          storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER);
+        }
+        counter++;
+      }
+    }
+    ASSERT(!storage || storage->length() >= counter);
+  } else {
+    if (storage) {
+      element_dictionary()->CopyKeysTo(storage, filter);
+    }
+    counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
+  }
+
+  if (this->IsJSValue()) {
+    Object* val = JSValue::cast(this)->value();
+    if (val->IsString()) {
+      String* str = String::cast(val);
+      if (storage) {
+        for (int i = 0; i < str->length(); i++) {
+          storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER);
+        }
+      }
+      counter += str->length();
+    }
+  }
+  ASSERT(!storage || storage->length() == counter);
+  return counter;
+}
+
+
+int JSObject::GetEnumElementKeys(FixedArray* storage) {
+  return GetLocalElementKeys(storage,
+                             static_cast<PropertyAttributes>(DONT_ENUM));
+}
+
+
+// The NumberKey uses carries the uint32_t as key.
+// This avoids allocation in HasProperty.
+class NumberKey : public HashTableKey {
+ public:
+  explicit NumberKey(uint32_t number) : number_(number) { }
+
+ private:
+  bool IsMatch(Object* number) {
+    return number_ == ToUint32(number);
+  }
+
+  // Thomas Wang, Integer Hash Functions.
+  // http://www.concentric.net/~Ttwang/tech/inthash.htm
+  static uint32_t ComputeHash(uint32_t key) {
+    uint32_t hash = key;
+    hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
+    hash = hash ^ (hash >> 12);
+    hash = hash + (hash << 2);
+    hash = hash ^ (hash >> 4);
+    hash = hash * 2057;  // hash = (hash + (hash << 3)) + (hash << 11);
+    hash = hash ^ (hash >> 16);
+    return hash;
+  }
+
+  uint32_t Hash() { return ComputeHash(number_); }
+
+  HashFunction GetHashFunction() { return NumberHash; }
+
+  Object* GetObject() {
+    return Heap::NumberFromDouble(number_);
+  }
+
+  static uint32_t NumberHash(Object* obj) {
+    return ComputeHash(ToUint32(obj));
+  }
+
+  static uint32_t ToUint32(Object* obj) {
+    ASSERT(obj->IsNumber());
+    return static_cast<uint32_t>(obj->Number());
+  }
+
+  bool IsStringKey() { return false; }
+
+  uint32_t number_;
+};
+
+
+// StringKey simply carries a string object as key.
+class StringKey : public HashTableKey {
+ public:
+  explicit StringKey(String* string) : string_(string) { }
+
+  bool IsMatch(Object* string) {
+    return string_->Equals(String::cast(string));
+  }
+
+  uint32_t Hash() { return StringHash(string_); }
+
+  HashFunction GetHashFunction() { return StringHash; }
+
+  Object* GetObject() { return string_; }
+
+  static uint32_t StringHash(Object* obj) {
+    return String::cast(obj)->Hash();
+  }
+
+  bool IsStringKey() { return true; }
+
+  String* string_;
+};
+
+// RegExpKey carries the source and flags of a regular expression as key.
+class RegExpKey : public HashTableKey {
+ public:
+  RegExpKey(String* string, JSRegExp::Flags flags)
+    : string_(string),
+      flags_(Smi::FromInt(flags.value())) { }
+
+  bool IsMatch(Object* obj) {
+    FixedArray* val = FixedArray::cast(obj);
+    return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
+        && (flags_ == val->get(JSRegExp::kFlagsIndex));
+  }
+
+  uint32_t Hash() { return RegExpHash(string_, flags_); }
+
+  HashFunction GetHashFunction() { return RegExpObjectHash; }
+
+  Object* GetObject() {
+    // Plain hash maps, which is where regexp keys are used, don't
+    // use this function.
+    UNREACHABLE();
+    return NULL;
+  }
+
+  static uint32_t RegExpObjectHash(Object* obj) {
+    FixedArray* val = FixedArray::cast(obj);
+    return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
+                      Smi::cast(val->get(JSRegExp::kFlagsIndex)));
+  }
+
+  static uint32_t RegExpHash(String* string, Smi* flags) {
+    return string->Hash() + flags->value();
+  }
+
+  bool IsStringKey() { return false; }
+
+  String* string_;
+  Smi* flags_;
+};
+
+// Utf8SymbolKey carries a vector of chars as key.
+class Utf8SymbolKey : public HashTableKey {
+ public:
+  explicit Utf8SymbolKey(Vector<const char> string)
+      : string_(string), length_field_(0) { }
+
+  bool IsMatch(Object* string) {
+    return String::cast(string)->IsEqualTo(string_);
+  }
+
+  HashFunction GetHashFunction() {
+    return StringHash;
+  }
+
+  uint32_t Hash() {
+    if (length_field_ != 0) return length_field_ >> String::kHashShift;
+    unibrow::Utf8InputBuffer<> buffer(string_.start(),
+                                      static_cast<unsigned>(string_.length()));
+    chars_ = buffer.Length();
+    length_field_ = String::ComputeLengthAndHashField(&buffer, chars_);
+    return length_field_ >> String::kHashShift;
+  }
+
+  Object* GetObject() {
+    if (length_field_ == 0) Hash();
+    unibrow::Utf8InputBuffer<> buffer(string_.start(),
+                                      static_cast<unsigned>(string_.length()));
+    return Heap::AllocateSymbol(&buffer, chars_, length_field_);
+  }
+
+  static uint32_t StringHash(Object* obj) {
+    return String::cast(obj)->Hash();
+  }
+
+  bool IsStringKey() { return true; }
+
+  Vector<const char> string_;
+  uint32_t length_field_;
+  int chars_;  // Caches the number of characters when computing the hash code.
+};
+
+
+// SymbolKey carries a string/symbol object as key.
+class SymbolKey : public HashTableKey {
+ public:
+  explicit SymbolKey(String* string) : string_(string) { }
+
+  HashFunction GetHashFunction() {
+    return StringHash;
+  }
+
+  bool IsMatch(Object* string) {
+    return String::cast(string)->Equals(string_);
+  }
+
+  uint32_t Hash() { return string_->Hash(); }
+
+  Object* GetObject() {
+    // If the string is a cons string, attempt to flatten it so that
+    // symbols will most often be flat strings.
+    if (string_->IsConsString()) {
+      ConsString* cons_string = ConsString::cast(string_);
+      cons_string->TryFlatten();
+      if (cons_string->second() == Heap::empty_string()) {
+        string_ = String::cast(cons_string->first());
+      }
+    }
+    // Transform string to symbol if possible.
+    Map* map = Heap::SymbolMapForString(string_);
+    if (map != NULL) {
+      string_->set_map(map);
+      return string_;
+    }
+    // Otherwise allocate a new symbol.
+    StringInputBuffer buffer(string_);
+    return Heap::AllocateSymbol(&buffer,
+                                string_->length(),
+                                string_->length_field());
+  }
+
+  static uint32_t StringHash(Object* obj) {
+    return String::cast(obj)->Hash();
+  }
+
+  bool IsStringKey() { return true; }
+
+  String* string_;
+};
+
+
+template<int prefix_size, int element_size>
+void HashTable<prefix_size, element_size>::IteratePrefix(ObjectVisitor* v) {
+  IteratePointers(v, 0, kElementsStartOffset);
+}
+
+
+template<int prefix_size, int element_size>
+void HashTable<prefix_size, element_size>::IterateElements(ObjectVisitor* v) {
+  IteratePointers(v,
+                  kElementsStartOffset,
+                  kHeaderSize + length() * kPointerSize);
+}
+
+
+template<int prefix_size, int element_size>
+Object* HashTable<prefix_size, element_size>::Allocate(int at_least_space_for) {
+  int capacity = RoundUpToPowerOf2(at_least_space_for);
+  if (capacity < 4) capacity = 4;  // Guarantee min capacity.
+  Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity));
+  if (!obj->IsFailure()) {
+    HashTable::cast(obj)->SetNumberOfElements(0);
+    HashTable::cast(obj)->SetCapacity(capacity);
+  }
+  return obj;
+}
+
+
+// Find entry for key otherwise return -1.
+template <int prefix_size, int element_size>
+int HashTable<prefix_size, element_size>::FindEntry(HashTableKey* key) {
+  uint32_t nof = NumberOfElements();
+  if (nof == 0) return -1;  // Bail out if empty.
+
+  uint32_t capacity = Capacity();
+  uint32_t hash = key->Hash();
+  uint32_t entry = GetProbe(hash, 0, capacity);
+
+  Object* element = KeyAt(entry);
+  uint32_t passed_elements = 0;
+  if (!element->IsNull()) {
+    if (!element->IsUndefined() && key->IsMatch(element)) return entry;
+    if (++passed_elements == nof) return -1;
+  }
+  for (uint32_t i = 1; !element->IsUndefined(); i++) {
+    entry = GetProbe(hash, i, capacity);
+    element = KeyAt(entry);
+    if (!element->IsNull()) {
+      if (!element->IsUndefined() && key->IsMatch(element)) return entry;
+      if (++passed_elements == nof) return -1;
+    }
+  }
+  return -1;
+}
+
+
+template<int prefix_size, int element_size>
+Object* HashTable<prefix_size, element_size>::EnsureCapacity(
+    int n, HashTableKey* key) {
+  int capacity = Capacity();
+  int nof = NumberOfElements() + n;
+  // Make sure 20% is free
+  if (nof + (nof >> 2) <= capacity) return this;
+
+  Object* obj = Allocate(nof * 2);
+  if (obj->IsFailure()) return obj;
+  HashTable* table = HashTable::cast(obj);
+  WriteBarrierMode mode = table->GetWriteBarrierMode();
+
+  // Copy prefix to new array.
+  for (int i = kPrefixStartIndex; i < kPrefixStartIndex + prefix_size; i++) {
+    table->set(i, get(i), mode);
+  }
+  // Rehash the elements.
+  uint32_t (*Hash)(Object* key) = key->GetHashFunction();
+  for (int i = 0; i < capacity; i++) {
+    uint32_t from_index = EntryToIndex(i);
+    Object* key = get(from_index);
+    if (IsKey(key)) {
+      uint32_t insertion_index =
+          EntryToIndex(table->FindInsertionEntry(key, Hash(key)));
+      for (int j = 0; j < element_size; j++) {
+        table->set(insertion_index + j, get(from_index + j), mode);
+      }
+    }
+  }
+  table->SetNumberOfElements(NumberOfElements());
+  return table;
+}
+
+
+template<int prefix_size, int element_size>
+uint32_t HashTable<prefix_size, element_size>::FindInsertionEntry(
+      Object* key,
+      uint32_t hash) {
+  uint32_t capacity = Capacity();
+  uint32_t entry = GetProbe(hash, 0, capacity);
+  Object* element = KeyAt(entry);
+
+  for (uint32_t i = 1; !(element->IsUndefined() || element->IsNull()); i++) {
+    entry = GetProbe(hash, i, capacity);
+    element = KeyAt(entry);
+  }
+
+  return entry;
+}
+
+
+// Force instantiation of SymbolTable's base class
+template class HashTable<0, 1>;
+
+
+// Force instantiation of Dictionary's base class
+template class HashTable<2, 3>;
+
+
+// Force instantiation of EvalCache's base class
+template class HashTable<0, 2>;
+
+
+Object* SymbolTable::LookupString(String* string, Object** s) {
+  SymbolKey key(string);
+  return LookupKey(&key, s);
+}
+
+
+bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
+  SymbolKey key(string);
+  int entry = FindEntry(&key);
+  if (entry == -1) {
+    return false;
+  } else {
+    String* result = String::cast(KeyAt(entry));
+    ASSERT(result->is_symbol());
+    *symbol = result;
+    return true;
+  }
+}
+
+
+Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
+  Utf8SymbolKey key(str);
+  return LookupKey(&key, s);
+}
+
+
+Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
+  int entry = FindEntry(key);
+
+  // Symbol already in table.
+  if (entry != -1) {
+    *s = KeyAt(entry);
+    return this;
+  }
+
+  // Adding new symbol. Grow table if needed.
+  Object* obj = EnsureCapacity(1, key);
+  if (obj->IsFailure()) return obj;
+
+  // Create symbol object.
+  Object* symbol = key->GetObject();
+  if (symbol->IsFailure()) return symbol;
+
+  // If the symbol table grew as part of EnsureCapacity, obj is not
+  // the current symbol table and therefore we cannot use
+  // SymbolTable::cast here.
+  SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
+
+  // Add the new symbol and return it along with the symbol table.
+  entry = table->FindInsertionEntry(symbol, key->Hash());
+  table->set(EntryToIndex(entry), symbol);
+  table->ElementAdded();
+  *s = symbol;
+  return table;
+}
+
+
+Object* CompilationCacheTable::Lookup(String* src) {
+  StringKey key(src);
+  int entry = FindEntry(&key);
+  if (entry == -1) return Heap::undefined_value();
+  return get(EntryToIndex(entry) + 1);
+}
+
+
+Object* CompilationCacheTable::LookupRegExp(String* src,
+                                            JSRegExp::Flags flags) {
+  RegExpKey key(src, flags);
+  int entry = FindEntry(&key);
+  if (entry == -1) return Heap::undefined_value();
+  return get(EntryToIndex(entry) + 1);
+}
+
+
+Object* CompilationCacheTable::Put(String* src, Object* value) {
+  StringKey key(src);
+  Object* obj = EnsureCapacity(1, &key);
+  if (obj->IsFailure()) return obj;
+
+  CompilationCacheTable* cache =
+      reinterpret_cast<CompilationCacheTable*>(obj);
+  int entry = cache->FindInsertionEntry(src, key.Hash());
+  cache->set(EntryToIndex(entry), src);
+  cache->set(EntryToIndex(entry) + 1, value);
+  cache->ElementAdded();
+  return cache;
+}
+
+
+Object* CompilationCacheTable::PutRegExp(String* src,
+                                         JSRegExp::Flags flags,
+                                         FixedArray* value) {
+  RegExpKey key(src, flags);
+  Object* obj = EnsureCapacity(1, &key);
+  if (obj->IsFailure()) return obj;
+
+  CompilationCacheTable* cache =
+      reinterpret_cast<CompilationCacheTable*>(obj);
+  int entry = cache->FindInsertionEntry(value, key.Hash());
+  cache->set(EntryToIndex(entry), value);
+  cache->set(EntryToIndex(entry) + 1, value);
+  cache->ElementAdded();
+  return cache;
+}
+
+
+// SymbolsKey used for HashTable where key is array of symbols.
+class SymbolsKey : public HashTableKey {
+ public:
+  explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
+
+  bool IsMatch(Object* symbols) {
+    FixedArray* o = FixedArray::cast(symbols);
+    int len = symbols_->length();
+    if (o->length() != len) return false;
+    for (int i = 0; i < len; i++) {
+      if (o->get(i) != symbols_->get(i)) return false;
+    }
+    return true;
+  }
+
+  uint32_t Hash() { return SymbolsHash(symbols_); }
+
+  HashFunction GetHashFunction() { return SymbolsHash; }
+
+  Object* GetObject() { return symbols_; }
+
+  static uint32_t SymbolsHash(Object* obj) {
+    FixedArray* symbols = FixedArray::cast(obj);
+    int len = symbols->length();
+    uint32_t hash = 0;
+    for (int i = 0; i < len; i++) {
+      hash ^= String::cast(symbols->get(i))->Hash();
+    }
+    return hash;
+  }
+
+  bool IsStringKey() { return false; }
+
+ private:
+  FixedArray* symbols_;
+};
+
+
+// MapNameKeys are used as keys in lookup caches.
+class MapNameKey : public HashTableKey {
+ public:
+  MapNameKey(Map* map, String* name)
+    : map_(map), name_(name) { }
+
+  bool IsMatch(Object* other) {
+    if (!other->IsFixedArray()) return false;
+    FixedArray* pair = FixedArray::cast(other);
+    Map* map = Map::cast(pair->get(0));
+    if (map != map_) return false;
+    String* name = String::cast(pair->get(1));
+    return name->Equals(name_);
+  }
+
+  typedef uint32_t (*HashFunction)(Object* obj);
+
+  virtual HashFunction GetHashFunction() { return MapNameHash; }
+
+  static uint32_t MapNameHashHelper(Map* map, String* name) {
+    return reinterpret_cast<uint32_t>(map) ^ name->Hash();
+  }
+
+  static uint32_t MapNameHash(Object* obj) {
+    FixedArray* pair = FixedArray::cast(obj);
+    Map* map = Map::cast(pair->get(0));
+    String* name = String::cast(pair->get(1));
+    return MapNameHashHelper(map, name);
+  }
+
+  virtual uint32_t Hash() {
+    return MapNameHashHelper(map_, name_);
+  }
+
+  virtual Object* GetObject() {
+    Object* obj = Heap::AllocateFixedArray(2);
+    if (obj->IsFailure()) return obj;
+    FixedArray* pair = FixedArray::cast(obj);
+    pair->set(0, map_);
+    pair->set(1, name_);
+    return pair;
+  }
+
+  virtual bool IsStringKey() { return false; }
+
+ private:
+  Map* map_;
+  String* name_;
+};
+
+
+Object* MapCache::Lookup(FixedArray* array) {
+  SymbolsKey key(array);
+  int entry = FindEntry(&key);
+  if (entry == -1) return Heap::undefined_value();
+  return get(EntryToIndex(entry) + 1);
+}
+
+
+Object* MapCache::Put(FixedArray* array, Map* value) {
+  SymbolsKey key(array);
+  Object* obj = EnsureCapacity(1, &key);
+  if (obj->IsFailure()) return obj;
+
+  MapCache* cache = reinterpret_cast<MapCache*>(obj);
+  int entry = cache->FindInsertionEntry(array, key.Hash());
+  cache->set(EntryToIndex(entry), array);
+  cache->set(EntryToIndex(entry) + 1, value);
+  cache->ElementAdded();
+  return cache;
+}
+
+
+int LookupCache::Lookup(Map* map, String* name) {
+  MapNameKey key(map, name);
+  int entry = FindEntry(&key);
+  if (entry == -1) return kNotFound;
+  return Smi::cast(get(EntryToIndex(entry) + 1))->value();
+}
+
+
+Object* LookupCache::Put(Map* map, String* name, int value) {
+  MapNameKey key(map, name);
+  Object* obj = EnsureCapacity(1, &key);
+  if (obj->IsFailure()) return obj;
+  Object* k = key.GetObject();
+  if (k->IsFailure()) return k;
+
+  LookupCache* cache = reinterpret_cast<LookupCache*>(obj);
+  int entry = cache->FindInsertionEntry(k, key.Hash());
+  int index = EntryToIndex(entry);
+  cache->set(index, k);
+  cache->set(index + 1, Smi::FromInt(value), SKIP_WRITE_BARRIER);
+  cache->ElementAdded();
+  return cache;
+}
+
+
+Object* Dictionary::Allocate(int at_least_space_for) {
+  Object* obj = DictionaryBase::Allocate(at_least_space_for);
+  // Initialize the next enumeration index.
+  if (!obj->IsFailure()) {
+    Dictionary::cast(obj)->
+        SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
+  }
+  return obj;
+}
+
+
+Object* Dictionary::GenerateNewEnumerationIndices() {
+  int length = NumberOfElements();
+
+  // Allocate and initialize iteration order array.
+  Object* obj = Heap::AllocateFixedArray(length);
+  if (obj->IsFailure()) return obj;
+  FixedArray* iteration_order = FixedArray::cast(obj);
+  for (int i = 0; i < length; i++) {
+    iteration_order->set(i, Smi::FromInt(i), SKIP_WRITE_BARRIER);
+  }
+
+  // Allocate array with enumeration order.
+  obj = Heap::AllocateFixedArray(length);
+  if (obj->IsFailure()) return obj;
+  FixedArray* enumeration_order = FixedArray::cast(obj);
+
+  // Fill the enumeration order array with property details.
+  int capacity = Capacity();
+  int pos = 0;
+  for (int i = 0; i < capacity; i++) {
+    if (IsKey(KeyAt(i))) {
+      enumeration_order->set(pos++,
+                             Smi::FromInt(DetailsAt(i).index()),
+                             SKIP_WRITE_BARRIER);
+    }
+  }
+
+  // Sort the arrays wrt. enumeration order.
+  iteration_order->SortPairs(enumeration_order);
+
+  // Overwrite the enumeration_order with the enumeration indices.
+  for (int i = 0; i < length; i++) {
+    int index = Smi::cast(iteration_order->get(i))->value();
+    int enum_index = PropertyDetails::kInitialIndex + i;
+    enumeration_order->set(index,
+                           Smi::FromInt(enum_index),
+                           SKIP_WRITE_BARRIER);
+  }
+
+  // Update the dictionary with new indices.
+  capacity = Capacity();
+  pos = 0;
+  for (int i = 0; i < capacity; i++) {
+    if (IsKey(KeyAt(i))) {
+      int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
+      PropertyDetails details = DetailsAt(i);
+      PropertyDetails new_details =
+          PropertyDetails(details.attributes(), details.type(), enum_index);
+      DetailsAtPut(i, new_details);
+    }
+  }
+
+  // Set the next enumeration index.
+  SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
+  return this;
+}
+
+
+Object* Dictionary::EnsureCapacity(int n, HashTableKey* key) {
+  // Check whether there are enough enumeration indices to add n elements.
+  if (key->IsStringKey() &&
+      !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
+    // If not, we generate new indices for the properties.
+    Object* result = GenerateNewEnumerationIndices();
+    if (result->IsFailure()) return result;
+  }
+  return DictionaryBase::EnsureCapacity(n, key);
+}
+
+
+void Dictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
+  // Do nothing if the interval [from, to) is empty.
+  if (from >= to) return;
+
+  int removed_entries = 0;
+  Object* sentinel = Heap::null_value();
+  int capacity = Capacity();
+  for (int i = 0; i < capacity; i++) {
+    Object* key = KeyAt(i);
+    if (key->IsNumber()) {
+      uint32_t number = static_cast<uint32_t>(key->Number());
+      if (from <= number && number < to) {
+        SetEntry(i, sentinel, sentinel, Smi::FromInt(0));
+        removed_entries++;
+      }
+    }
+  }
+
+  // Update the number of elements.
+  SetNumberOfElements(NumberOfElements() - removed_entries);
+}
+
+
+Object* Dictionary::DeleteProperty(int entry) {
+  PropertyDetails details = DetailsAt(entry);
+  if (details.IsDontDelete()) return Heap::false_value();
+  SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0));
+  ElementRemoved();
+  return Heap::true_value();
+}
+
+
+int Dictionary::FindStringEntry(String* key) {
+  StringKey k(key);
+  return FindEntry(&k);
+}
+
+
+int Dictionary::FindNumberEntry(uint32_t index) {
+  NumberKey k(index);
+  return FindEntry(&k);
+}
+
+
+Object* Dictionary::AtPut(HashTableKey* key, Object* value) {
+  int entry = FindEntry(key);
+
+  // If the entry is present set the value;
+  if (entry != -1) {
+    ValueAtPut(entry, value);
+    return this;
+  }
+
+  // Check whether the dictionary should be extended.
+  Object* obj = EnsureCapacity(1, key);
+  if (obj->IsFailure()) return obj;
+  Object* k = key->GetObject();
+  if (k->IsFailure()) return k;
+  PropertyDetails details = PropertyDetails(NONE, NORMAL);
+  Dictionary::cast(obj)->AddEntry(k, value, details, key->Hash());
+  return obj;
+}
+
+
+Object* Dictionary::Add(HashTableKey* key, Object* value,
+                        PropertyDetails details) {
+  // Check whether the dictionary should be extended.
+  Object* obj = EnsureCapacity(1, key);
+  if (obj->IsFailure()) return obj;
+  // Compute the key object.
+  Object* k = key->GetObject();
+  if (k->IsFailure()) return k;
+  Dictionary::cast(obj)->AddEntry(k, value, details, key->Hash());
+  return obj;
+}
+
+
+// Add a key, value pair to the dictionary.
+void Dictionary::AddEntry(Object* key,
+                          Object* value,
+                          PropertyDetails details,
+                          uint32_t hash) {
+  uint32_t entry = FindInsertionEntry(key, hash);
+  // Insert element at empty or deleted entry
+  if (details.index() == 0 && key->IsString()) {
+    // Assign an enumeration index to the property and update
+    // SetNextEnumerationIndex.
+    int index = NextEnumerationIndex();
+    details = PropertyDetails(details.attributes(), details.type(), index);
+    SetNextEnumerationIndex(index + 1);
+  }
+  SetEntry(entry, key, value, details);
+  ASSERT(KeyAt(entry)->IsNumber() || KeyAt(entry)->IsString());
+  ElementAdded();
+}
+
+
+void Dictionary::UpdateMaxNumberKey(uint32_t key) {
+  // If the dictionary requires slow elements an element has already
+  // been added at a high index.
+  if (requires_slow_elements()) return;
+  // Check if this index is high enough that we should require slow
+  // elements.
+  if (key > kRequiresSlowElementsLimit) {
+    set(kMaxNumberKeyIndex,
+        Smi::FromInt(kRequiresSlowElementsMask),
+        SKIP_WRITE_BARRIER);
+    return;
+  }
+  // Update max key value.
+  Object* max_index_object = get(kMaxNumberKeyIndex);
+  if (!max_index_object->IsSmi() || max_number_key() < key) {
+    set(kMaxNumberKeyIndex,
+        Smi::FromInt(key << kRequiresSlowElementsTagSize),
+        SKIP_WRITE_BARRIER);
+  }
+}
+
+
+Object* Dictionary::AddStringEntry(String* key,
+                                   Object* value,
+                                   PropertyDetails details) {
+  StringKey k(key);
+  SLOW_ASSERT(FindEntry(&k) == -1);
+  return Add(&k, value, details);
+}
+
+
+Object* Dictionary::AddNumberEntry(uint32_t key,
+                                   Object* value,
+                                   PropertyDetails details) {
+  NumberKey k(key);
+  UpdateMaxNumberKey(key);
+  SLOW_ASSERT(FindEntry(&k) == -1);
+  return Add(&k, value, details);
+}
+
+
+Object* Dictionary::AtStringPut(String* key, Object* value) {
+  StringKey k(key);
+  return AtPut(&k, value);
+}
+
+
+Object* Dictionary::AtNumberPut(uint32_t key, Object* value) {
+  NumberKey k(key);
+  UpdateMaxNumberKey(key);
+  return AtPut(&k, value);
+}
+
+
+Object* Dictionary::SetOrAddStringEntry(String* key,
+                                        Object* value,
+                                        PropertyDetails details) {
+  StringKey k(key);
+  int entry = FindEntry(&k);
+  if (entry == -1) return AddStringEntry(key, value, details);
+  // Preserve enumeration index.
+  details = PropertyDetails(details.attributes(),
+                            details.type(),
+                            DetailsAt(entry).index());
+  SetEntry(entry, key, value, details);
+  return this;
+}
+
+
+int Dictionary::NumberOfElementsFilterAttributes(PropertyAttributes filter) {
+  int capacity = Capacity();
+  int result = 0;
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k)) {
+      PropertyAttributes attr = DetailsAt(i).attributes();
+      if ((attr & filter) == 0) result++;
+    }
+  }
+  return result;
+}
+
+
+int Dictionary::NumberOfEnumElements() {
+  return NumberOfElementsFilterAttributes(
+      static_cast<PropertyAttributes>(DONT_ENUM));
+}
+
+
+void Dictionary::CopyKeysTo(FixedArray* storage, PropertyAttributes filter) {
+  ASSERT(storage->length() >= NumberOfEnumElements());
+  int capacity = Capacity();
+  int index = 0;
+  for (int i = 0; i < capacity; i++) {
+     Object* k = KeyAt(i);
+     if (IsKey(k)) {
+       PropertyAttributes attr = DetailsAt(i).attributes();
+       if ((attr & filter) == 0) storage->set(index++, k);
+     }
+  }
+  ASSERT(storage->length() >= index);
+}
+
+
+void Dictionary::CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array) {
+  ASSERT(storage->length() >= NumberOfEnumElements());
+  int capacity = Capacity();
+  int index = 0;
+  for (int i = 0; i < capacity; i++) {
+     Object* k = KeyAt(i);
+     if (IsKey(k)) {
+       PropertyDetails details = DetailsAt(i);
+       if (!details.IsDontEnum()) {
+         storage->set(index, k);
+         sort_array->set(index,
+                         Smi::FromInt(details.index()),
+                         SKIP_WRITE_BARRIER);
+         index++;
+       }
+     }
+  }
+  storage->SortPairs(sort_array);
+  ASSERT(storage->length() >= index);
+}
+
+
+void Dictionary::CopyKeysTo(FixedArray* storage) {
+  ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
+      static_cast<PropertyAttributes>(NONE)));
+  int capacity = Capacity();
+  int index = 0;
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k)) {
+      storage->set(index++, k);
+    }
+  }
+  ASSERT(storage->length() >= index);
+}
+
+
+// Backwards lookup (slow).
+Object* Dictionary::SlowReverseLookup(Object* value) {
+  int capacity = Capacity();
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k) && ValueAt(i) == value) {
+      return k;
+    }
+  }
+  return Heap::undefined_value();
+}
+
+
+Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj,
+                                                 int unused_property_fields) {
+  // Make sure we preserve dictionary representation if there are too many
+  // descriptors.
+  if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
+
+  // Figure out if it is necessary to generate new enumeration indices.
+  int max_enumeration_index =
+      NextEnumerationIndex() +
+          (DescriptorArray::kMaxNumberOfDescriptors - NumberOfElements());
+  if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
+    Object* result = GenerateNewEnumerationIndices();
+    if (result->IsFailure()) return result;
+  }
+
+  int instance_descriptor_length = 0;
+  int number_of_fields = 0;
+
+  // Compute the length of the instance descriptor.
+  int capacity = Capacity();
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k)) {
+      Object* value = ValueAt(i);
+      PropertyType type = DetailsAt(i).type();
+      ASSERT(type != FIELD);
+      instance_descriptor_length++;
+      if (type == NORMAL && !value->IsJSFunction()) number_of_fields += 1;
+    }
+  }
+
+  // Allocate the instance descriptor.
+  Object* descriptors_unchecked =
+      DescriptorArray::Allocate(instance_descriptor_length);
+  if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
+  DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
+
+  int number_of_allocated_fields = number_of_fields + unused_property_fields;
+
+  // Allocate the fixed array for the fields.
+  Object* fields = Heap::AllocateFixedArray(number_of_allocated_fields);
+  if (fields->IsFailure()) return fields;
+
+  // Fill in the instance descriptor and the fields.
+  DescriptorWriter w(descriptors);
+  int current_offset = 0;
+  for (int i = 0; i < capacity; i++) {
+    Object* k = KeyAt(i);
+    if (IsKey(k)) {
+      Object* value = ValueAt(i);
+      // Ensure the key is a symbol before writing into the instance descriptor.
+      Object* key = Heap::LookupSymbol(String::cast(k));
+      if (key->IsFailure()) return key;
+      PropertyDetails details = DetailsAt(i);
+      PropertyType type = details.type();
+      if (value->IsJSFunction()) {
+        ConstantFunctionDescriptor d(String::cast(key),
+                                     JSFunction::cast(value),
+                                     details.attributes(),
+                                     details.index());
+        w.Write(&d);
+      } else if (type == NORMAL) {
+        FixedArray::cast(fields)->set(current_offset, value);
+        FieldDescriptor d(String::cast(key),
+                          current_offset++,
+                          details.attributes(),
+                          details.index());
+        w.Write(&d);
+      } else if (type == CALLBACKS) {
+        CallbacksDescriptor d(String::cast(key),
+                              value,
+                              details.attributes(),
+                              details.index());
+        w.Write(&d);
+      } else {
+        UNREACHABLE();
+      }
+    }
+  }
+  ASSERT(current_offset == number_of_fields);
+
+  descriptors->Sort();
+  // Allocate new map.
+  Object* new_map = obj->map()->Copy();
+  if (new_map->IsFailure()) return new_map;
+
+  // Transform the object.
+  obj->set_map(Map::cast(new_map));
+  obj->map()->set_instance_descriptors(descriptors);
+  obj->map()->set_unused_property_fields(unused_property_fields);
+
+  obj->set_properties(FixedArray::cast(fields));
+  ASSERT(obj->IsJSObject());
+
+  descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
+  // Check it really works.
+  ASSERT(obj->HasFastProperties());
+  return obj;
+}
+
+
+// Check if there is a break point at this code position.
+bool DebugInfo::HasBreakPoint(int code_position) {
+  // Get the break point info object for this code position.
+  Object* break_point_info = GetBreakPointInfo(code_position);
+
+  // If there is no break point info object or no break points in the break
+  // point info object there is no break point at this code position.
+  if (break_point_info->IsUndefined()) return false;
+  return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
+}
+
+
+// Get the break point info object for this code position.
+Object* DebugInfo::GetBreakPointInfo(int code_position) {
+  // Find the index of the break point info object for this code position.
+  int index = GetBreakPointInfoIndex(code_position);
+
+  // Return the break point info object if any.
+  if (index == kNoBreakPointInfo) return Heap::undefined_value();
+  return BreakPointInfo::cast(break_points()->get(index));
+}
+
+
+// Clear a break point at the specified code position.
+void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
+                                int code_position,
+                                Handle<Object> break_point_object) {
+  Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
+  if (break_point_info->IsUndefined()) return;
+  BreakPointInfo::ClearBreakPoint(
+      Handle<BreakPointInfo>::cast(break_point_info),
+      break_point_object);
+}
+
+
+void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
+                              int code_position,
+                              int source_position,
+                              int statement_position,
+                              Handle<Object> break_point_object) {
+  Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
+  if (!break_point_info->IsUndefined()) {
+    BreakPointInfo::SetBreakPoint(
+        Handle<BreakPointInfo>::cast(break_point_info),
+        break_point_object);
+    return;
+  }
+
+  // Adding a new break point for a code position which did not have any
+  // break points before. Try to find a free slot.
+  int index = kNoBreakPointInfo;
+  for (int i = 0; i < debug_info->break_points()->length(); i++) {
+    if (debug_info->break_points()->get(i)->IsUndefined()) {
+      index = i;
+      break;
+    }
+  }
+  if (index == kNoBreakPointInfo) {
+    // No free slot - extend break point info array.
+    Handle<FixedArray> old_break_points =
+        Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
+    debug_info->set_break_points(*Factory::NewFixedArray(
+        old_break_points->length() +
+            Debug::kEstimatedNofBreakPointsInFunction));
+    Handle<FixedArray> new_break_points =
+        Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
+    for (int i = 0; i < old_break_points->length(); i++) {
+      new_break_points->set(i, old_break_points->get(i));
+    }
+    index = old_break_points->length();
+  }
+  ASSERT(index != kNoBreakPointInfo);
+
+  // Allocate new BreakPointInfo object and set the break point.
+  Handle<BreakPointInfo> new_break_point_info =
+      Handle<BreakPointInfo>::cast(Factory::NewStruct(BREAK_POINT_INFO_TYPE));
+  new_break_point_info->set_code_position(Smi::FromInt(code_position));
+  new_break_point_info->set_source_position(Smi::FromInt(source_position));
+  new_break_point_info->
+      set_statement_position(Smi::FromInt(statement_position));
+  new_break_point_info->set_break_point_objects(Heap::undefined_value());
+  BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
+  debug_info->break_points()->set(index, *new_break_point_info);
+}
+
+
+// Get the break point objects for a code position.
+Object* DebugInfo::GetBreakPointObjects(int code_position) {
+  Object* break_point_info = GetBreakPointInfo(code_position);
+  if (break_point_info->IsUndefined()) {
+    return Heap::undefined_value();
+  }
+  return BreakPointInfo::cast(break_point_info)->break_point_objects();
+}
+
+
+// Get the total number of break points.
+int DebugInfo::GetBreakPointCount() {
+  if (break_points()->IsUndefined()) return 0;
+  int count = 0;
+  for (int i = 0; i < break_points()->length(); i++) {
+    if (!break_points()->get(i)->IsUndefined()) {
+      BreakPointInfo* break_point_info =
+          BreakPointInfo::cast(break_points()->get(i));
+      count += break_point_info->GetBreakPointCount();
+    }
+  }
+  return count;
+}
+
+
+Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
+                                      Handle<Object> break_point_object) {
+  if (debug_info->break_points()->IsUndefined()) return Heap::undefined_value();
+  for (int i = 0; i < debug_info->break_points()->length(); i++) {
+    if (!debug_info->break_points()->get(i)->IsUndefined()) {
+      Handle<BreakPointInfo> break_point_info =
+          Handle<BreakPointInfo>(BreakPointInfo::cast(
+              debug_info->break_points()->get(i)));
+      if (BreakPointInfo::HasBreakPointObject(break_point_info,
+                                              break_point_object)) {
+        return *break_point_info;
+      }
+    }
+  }
+  return Heap::undefined_value();
+}
+
+
+// Find the index of the break point info object for the specified code
+// position.
+int DebugInfo::GetBreakPointInfoIndex(int code_position) {
+  if (break_points()->IsUndefined()) return kNoBreakPointInfo;
+  for (int i = 0; i < break_points()->length(); i++) {
+    if (!break_points()->get(i)->IsUndefined()) {
+      BreakPointInfo* break_point_info =
+          BreakPointInfo::cast(break_points()->get(i));
+      if (break_point_info->code_position()->value() == code_position) {
+        return i;
+      }
+    }
+  }
+  return kNoBreakPointInfo;
+}
+
+
+// Remove the specified break point object.
+void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
+                                     Handle<Object> break_point_object) {
+  // If there are no break points just ignore.
+  if (break_point_info->break_point_objects()->IsUndefined()) return;
+  // If there is a single break point clear it if it is the same.
+  if (!break_point_info->break_point_objects()->IsFixedArray()) {
+    if (break_point_info->break_point_objects() == *break_point_object) {
+      break_point_info->set_break_point_objects(Heap::undefined_value());
+    }
+    return;
+  }
+  // If there are multiple break points shrink the array
+  ASSERT(break_point_info->break_point_objects()->IsFixedArray());
+  Handle<FixedArray> old_array =
+      Handle<FixedArray>(
+          FixedArray::cast(break_point_info->break_point_objects()));
+  Handle<FixedArray> new_array =
+      Factory::NewFixedArray(old_array->length() - 1);
+  int found_count = 0;
+  for (int i = 0; i < old_array->length(); i++) {
+    if (old_array->get(i) == *break_point_object) {
+      ASSERT(found_count == 0);
+      found_count++;
+    } else {
+      new_array->set(i - found_count, old_array->get(i));
+    }
+  }
+  // If the break point was found in the list change it.
+  if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
+}
+
+
+// Add the specified break point object.
+void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
+                                   Handle<Object> break_point_object) {
+  // If there was no break point objects before just set it.
+  if (break_point_info->break_point_objects()->IsUndefined()) {
+    break_point_info->set_break_point_objects(*break_point_object);
+    return;
+  }
+  // If the break point object is the same as before just ignore.
+  if (break_point_info->break_point_objects() == *break_point_object) return;
+  // If there was one break point object before replace with array.
+  if (!break_point_info->break_point_objects()->IsFixedArray()) {
+    Handle<FixedArray> array = Factory::NewFixedArray(2);
+    array->set(0, break_point_info->break_point_objects());
+    array->set(1, *break_point_object);
+    break_point_info->set_break_point_objects(*array);
+    return;
+  }
+  // If there was more than one break point before extend array.
+  Handle<FixedArray> old_array =
+      Handle<FixedArray>(
+          FixedArray::cast(break_point_info->break_point_objects()));
+  Handle<FixedArray> new_array =
+      Factory::NewFixedArray(old_array->length() + 1);
+  for (int i = 0; i < old_array->length(); i++) {
+    // If the break point was there before just ignore.
+    if (old_array->get(i) == *break_point_object) return;
+    new_array->set(i, old_array->get(i));
+  }
+  // Add the new break point.
+  new_array->set(old_array->length(), *break_point_object);
+  break_point_info->set_break_point_objects(*new_array);
+}
+
+
+bool BreakPointInfo::HasBreakPointObject(
+    Handle<BreakPointInfo> break_point_info,
+    Handle<Object> break_point_object) {
+  // No break point.
+  if (break_point_info->break_point_objects()->IsUndefined()) return false;
+  // Single beak point.
+  if (!break_point_info->break_point_objects()->IsFixedArray()) {
+    return break_point_info->break_point_objects() == *break_point_object;
+  }
+  // Multiple break points.
+  FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
+  for (int i = 0; i < array->length(); i++) {
+    if (array->get(i) == *break_point_object) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// Get the number of break points.
+int BreakPointInfo::GetBreakPointCount() {
+  // No break point.
+  if (break_point_objects()->IsUndefined()) return 0;
+  // Single beak point.
+  if (!break_point_objects()->IsFixedArray()) return 1;
+  // Multiple break points.
+  return FixedArray::cast(break_point_objects())->length();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/objects.h b/regexp2000/src/objects.h
new file mode 100644 (file)
index 0000000..b20f93c
--- /dev/null
@@ -0,0 +1,4132 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_OBJECTS_H_
+#define V8_OBJECTS_H_
+
+#include "builtins.h"
+#include "code-stubs.h"
+#include "smart-pointer.h"
+#include "unicode-inl.h"
+
+//
+// All object types in the V8 JavaScript are described in this file.
+//
+// Inheritance hierarchy:
+//   - Object
+//     - Smi          (immediate small integer)
+//     - Failure      (immediate for marking failed operation)
+//     - HeapObject   (superclass for everything allocated in the heap)
+//       - JSObject
+//         - JSArray
+//         - JSRegExp
+//         - JSFunction
+//         - GlobalObject
+//           - JSGlobalObject
+//           - JSBuiltinsObject
+//         _ JSGlobalProxy
+//         - JSValue
+//         - Script
+//       - Array
+//         - ByteArray
+//         - FixedArray
+//           - DescriptorArray
+//           - HashTable
+//             - Dictionary
+//             - SymbolTable
+//             - CompilationCacheTable
+//             - MapCache
+//             - LookupCache
+//           - Context
+//           - GlobalContext
+//       - String
+//         - SeqString
+//           - SeqAsciiString
+//           - SeqTwoByteString
+//         - ConsString
+//         - SlicedString
+//         - ExternalString
+//           - ExternalAsciiString
+//           - ExternalTwoByteString
+//       - HeapNumber
+//       - Code
+//       - Map
+//       - Oddball
+//       - Proxy
+//       - SharedFunctionInfo
+//       - Struct
+//         - AccessorInfo
+//         - AccessCheckInfo
+//         - InterceptorInfo
+//         - CallHandlerInfo
+//         - FunctionTemplateInfo
+//         - ObjectTemplateInfo
+//         - SignatureInfo
+//         - TypeSwitchInfo
+//         - DebugInfo
+//         - BreakPointInfo
+//
+// Formats of Object*:
+//  Smi:        [31 bit signed int] 0
+//  HeapObject: [32 bit direct pointer] (4 byte aligned) | 01
+//  Failure:    [30 bit signed int] 11
+
+
+// Ecma-262 3rd 8.6.1
+enum PropertyAttributes {
+  NONE              = v8::None,
+  READ_ONLY         = v8::ReadOnly,
+  DONT_ENUM         = v8::DontEnum,
+  DONT_DELETE       = v8::DontDelete,
+  ABSENT            = 16  // Used in runtime to indicate a property is absent.
+  // ABSENT can never be stored in or returned from a descriptor's attributes
+  // bitfield.  It is only used as a return value meaning the attributes of
+  // a non-existent property.
+};
+
+namespace v8 { namespace internal {
+
+
+// PropertyDetails captures type and attributes for a property.
+// They are used both in property dictionaries and instance descriptors.
+class PropertyDetails BASE_EMBEDDED {
+ public:
+
+  PropertyDetails(PropertyAttributes attributes,
+                  PropertyType type,
+                  int index = 0) {
+    ASSERT(TypeField::is_valid(type));
+    ASSERT(AttributesField::is_valid(attributes));
+    ASSERT(IndexField::is_valid(index));
+
+    value_ = TypeField::encode(type)
+        | AttributesField::encode(attributes)
+        | IndexField::encode(index);
+
+    ASSERT(type == this->type());
+    ASSERT(attributes == this->attributes());
+    ASSERT(index == this->index());
+  }
+
+  // Conversion for storing details as Object*.
+  inline PropertyDetails(Smi* smi);
+  inline Smi* AsSmi();
+
+  PropertyType type() { return TypeField::decode(value_); }
+
+  bool IsTransition() {
+    PropertyType t = type();
+    ASSERT(t != INTERCEPTOR);
+    return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
+  }
+
+  PropertyAttributes attributes() { return AttributesField::decode(value_); }
+
+  int index() { return IndexField::decode(value_); }
+
+  static bool IsValidIndex(int index) { return IndexField::is_valid(index); }
+
+  bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; }
+  bool IsDontDelete() { return (attributes() & DONT_DELETE) != 0; }
+  bool IsDontEnum() { return (attributes() & DONT_ENUM) != 0; }
+
+  // Bit fields in value_ (type, shift, size). Must be public so the
+  // constants can be embedded in generated code.
+  class TypeField:       public BitField<PropertyType,       0, 3> {};
+  class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
+  class IndexField:      public BitField<uint32_t,           6, 32-6> {};
+
+  static const int kInitialIndex = 1;
+
+ private:
+  uint32_t value_;
+};
+
+// Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER.
+enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
+
+// All Maps have a field instance_type containing a InstanceType.
+// It describes the type of the instances.
+//
+// As an example, a JavaScript object is a heap object and its map
+// instance_type is JS_OBJECT_TYPE.
+//
+// The names of the string instance types are intended to systematically
+// mirror their encoding in the instance_type field of the map.  The length
+// (SHORT, MEDIUM, or LONG) is always mentioned.  The default encoding is
+// considered TWO_BYTE.  It is not mentioned in the name.  ASCII encoding is
+// mentioned explicitly in the name.  Likewise, the default representation is
+// considered sequential.  It is not mentioned in the name.  The other
+// representations (eg, CONS, SLICED, EXTERNAL) are explicitly mentioned.
+// Finally, the string is either a SYMBOL_TYPE (if it is a symbol) or a
+// STRING_TYPE (if it is not a symbol).
+//
+// NOTE: The following things are some that depend on the string types having
+// instance_types that are less than those of all other types:
+// HeapObject::Size, HeapObject::IterateBody, the typeof operator, and
+// Object::IsString.
+//
+// NOTE: Everything following JS_VALUE_TYPE is considered a
+// JSObject for GC purposes. The first four entries here have typeof
+// 'object', whereas JS_FUNCTION_TYPE has typeof 'function'.
+#define INSTANCE_TYPE_LIST(V)                   \
+  V(SHORT_SYMBOL_TYPE)                          \
+  V(MEDIUM_SYMBOL_TYPE)                         \
+  V(LONG_SYMBOL_TYPE)                           \
+  V(SHORT_ASCII_SYMBOL_TYPE)                    \
+  V(MEDIUM_ASCII_SYMBOL_TYPE)                   \
+  V(LONG_ASCII_SYMBOL_TYPE)                     \
+  V(SHORT_CONS_SYMBOL_TYPE)                     \
+  V(MEDIUM_CONS_SYMBOL_TYPE)                    \
+  V(LONG_CONS_SYMBOL_TYPE)                      \
+  V(SHORT_CONS_ASCII_SYMBOL_TYPE)               \
+  V(MEDIUM_CONS_ASCII_SYMBOL_TYPE)              \
+  V(LONG_CONS_ASCII_SYMBOL_TYPE)                \
+  V(SHORT_SLICED_SYMBOL_TYPE)                   \
+  V(MEDIUM_SLICED_SYMBOL_TYPE)                  \
+  V(LONG_SLICED_SYMBOL_TYPE)                    \
+  V(SHORT_SLICED_ASCII_SYMBOL_TYPE)             \
+  V(MEDIUM_SLICED_ASCII_SYMBOL_TYPE)            \
+  V(LONG_SLICED_ASCII_SYMBOL_TYPE)              \
+  V(SHORT_EXTERNAL_SYMBOL_TYPE)                 \
+  V(MEDIUM_EXTERNAL_SYMBOL_TYPE)                \
+  V(LONG_EXTERNAL_SYMBOL_TYPE)                  \
+  V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE)           \
+  V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE)          \
+  V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE)            \
+  V(SHORT_STRING_TYPE)                          \
+  V(MEDIUM_STRING_TYPE)                         \
+  V(LONG_STRING_TYPE)                           \
+  V(SHORT_ASCII_STRING_TYPE)                    \
+  V(MEDIUM_ASCII_STRING_TYPE)                   \
+  V(LONG_ASCII_STRING_TYPE)                     \
+  V(SHORT_CONS_STRING_TYPE)                     \
+  V(MEDIUM_CONS_STRING_TYPE)                    \
+  V(LONG_CONS_STRING_TYPE)                      \
+  V(SHORT_CONS_ASCII_STRING_TYPE)               \
+  V(MEDIUM_CONS_ASCII_STRING_TYPE)              \
+  V(LONG_CONS_ASCII_STRING_TYPE)                \
+  V(SHORT_SLICED_STRING_TYPE)                   \
+  V(MEDIUM_SLICED_STRING_TYPE)                  \
+  V(LONG_SLICED_STRING_TYPE)                    \
+  V(SHORT_SLICED_ASCII_STRING_TYPE)             \
+  V(MEDIUM_SLICED_ASCII_STRING_TYPE)            \
+  V(LONG_SLICED_ASCII_STRING_TYPE)              \
+  V(SHORT_EXTERNAL_STRING_TYPE)                 \
+  V(MEDIUM_EXTERNAL_STRING_TYPE)                \
+  V(LONG_EXTERNAL_STRING_TYPE)                  \
+  V(SHORT_EXTERNAL_ASCII_STRING_TYPE)           \
+  V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE)          \
+  V(LONG_EXTERNAL_ASCII_STRING_TYPE)            \
+  V(LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE)    \
+                                                \
+  V(MAP_TYPE)                                   \
+  V(HEAP_NUMBER_TYPE)                           \
+  V(FIXED_ARRAY_TYPE)                           \
+  V(CODE_TYPE)                                  \
+  V(ODDBALL_TYPE)                               \
+  V(PROXY_TYPE)                                 \
+  V(BYTE_ARRAY_TYPE)                            \
+  V(FILLER_TYPE)                                \
+                                                \
+  V(ACCESSOR_INFO_TYPE)                         \
+  V(ACCESS_CHECK_INFO_TYPE)                     \
+  V(INTERCEPTOR_INFO_TYPE)                      \
+  V(SHARED_FUNCTION_INFO_TYPE)                  \
+  V(CALL_HANDLER_INFO_TYPE)                     \
+  V(FUNCTION_TEMPLATE_INFO_TYPE)                \
+  V(OBJECT_TEMPLATE_INFO_TYPE)                  \
+  V(SIGNATURE_INFO_TYPE)                        \
+  V(TYPE_SWITCH_INFO_TYPE)                      \
+  V(DEBUG_INFO_TYPE)                            \
+  V(BREAK_POINT_INFO_TYPE)                      \
+  V(SCRIPT_TYPE)                                \
+                                                \
+  V(JS_VALUE_TYPE)                              \
+  V(JS_OBJECT_TYPE)                             \
+  V(JS_GLOBAL_OBJECT_TYPE)                      \
+  V(JS_BUILTINS_OBJECT_TYPE)                    \
+  V(JS_GLOBAL_PROXY_TYPE)                       \
+  V(JS_ARRAY_TYPE)                              \
+  V(JS_REGEXP_TYPE)                             \
+                                                \
+  V(JS_FUNCTION_TYPE)                           \
+
+
+// Since string types are not consecutive, this macro is used to
+// iterate over them.
+#define STRING_TYPE_LIST(V)                                                    \
+  V(SHORT_SYMBOL_TYPE, SeqTwoByteString::kHeaderSize, short_symbol)            \
+  V(MEDIUM_SYMBOL_TYPE, SeqTwoByteString::kHeaderSize, medium_symbol)          \
+  V(LONG_SYMBOL_TYPE, SeqTwoByteString::kHeaderSize, long_symbol)              \
+  V(SHORT_ASCII_SYMBOL_TYPE, SeqAsciiString::kHeaderSize, short_ascii_symbol)  \
+  V(MEDIUM_ASCII_SYMBOL_TYPE, SeqAsciiString::kHeaderSize, medium_ascii_symbol)\
+  V(LONG_ASCII_SYMBOL_TYPE, SeqAsciiString::kHeaderSize, long_ascii_symbol)    \
+  V(SHORT_CONS_SYMBOL_TYPE, ConsString::kSize, short_cons_symbol)              \
+  V(MEDIUM_CONS_SYMBOL_TYPE, ConsString::kSize, medium_cons_symbol)            \
+  V(LONG_CONS_SYMBOL_TYPE, ConsString::kSize, long_cons_symbol)                \
+  V(SHORT_CONS_ASCII_SYMBOL_TYPE, ConsString::kSize, short_cons_ascii_symbol)  \
+  V(MEDIUM_CONS_ASCII_SYMBOL_TYPE, ConsString::kSize, medium_cons_ascii_symbol)\
+  V(LONG_CONS_ASCII_SYMBOL_TYPE, ConsString::kSize, long_cons_ascii_symbol)    \
+  V(SHORT_SLICED_SYMBOL_TYPE, SlicedString::kSize, short_sliced_symbol)        \
+  V(MEDIUM_SLICED_SYMBOL_TYPE, SlicedString::kSize, medium_sliced_symbol)      \
+  V(LONG_SLICED_SYMBOL_TYPE, SlicedString::kSize, long_sliced_symbol)          \
+  V(SHORT_SLICED_ASCII_SYMBOL_TYPE,                                            \
+    SlicedString::kSize,                                                       \
+    short_sliced_ascii_symbol)                                                 \
+  V(MEDIUM_SLICED_ASCII_SYMBOL_TYPE,                                           \
+    SlicedString::kSize,                                                       \
+    medium_sliced_ascii_symbol)                                                \
+  V(LONG_SLICED_ASCII_SYMBOL_TYPE,                                             \
+    SlicedString::kSize,                                                       \
+    long_sliced_ascii_symbol)                                                  \
+  V(SHORT_EXTERNAL_SYMBOL_TYPE,                                                \
+    ExternalTwoByteString::kSize,                                              \
+    short_external_symbol)                                                     \
+  V(MEDIUM_EXTERNAL_SYMBOL_TYPE,                                               \
+    ExternalTwoByteString::kSize,                                              \
+    medium_external_symbol)                                                    \
+  V(LONG_EXTERNAL_SYMBOL_TYPE,                                                 \
+    ExternalTwoByteString::kSize,                                              \
+    long_external_symbol)                                                      \
+  V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE,                                          \
+    ExternalAsciiString::kSize,                                                \
+    short_external_ascii_symbol)                                               \
+  V(MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE,                                         \
+    ExternalAsciiString::kSize,                                                \
+    medium_external_ascii_symbol)                                              \
+  V(LONG_EXTERNAL_ASCII_SYMBOL_TYPE,                                           \
+    ExternalAsciiString::kSize,                                                \
+    long_external_ascii_symbol)                                                \
+  V(SHORT_STRING_TYPE, SeqTwoByteString::kHeaderSize, short_string)            \
+  V(MEDIUM_STRING_TYPE, SeqTwoByteString::kHeaderSize, medium_string)          \
+  V(LONG_STRING_TYPE, SeqTwoByteString::kHeaderSize, long_string)              \
+  V(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize, short_ascii_string)  \
+  V(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize, medium_ascii_string)\
+  V(LONG_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize, long_ascii_string)    \
+  V(SHORT_CONS_STRING_TYPE, ConsString::kSize, short_cons_string)              \
+  V(MEDIUM_CONS_STRING_TYPE, ConsString::kSize, medium_cons_string)            \
+  V(LONG_CONS_STRING_TYPE, ConsString::kSize, long_cons_string)                \
+  V(SHORT_CONS_ASCII_STRING_TYPE, ConsString::kSize, short_cons_ascii_string)  \
+  V(MEDIUM_CONS_ASCII_STRING_TYPE, ConsString::kSize, medium_cons_ascii_string)\
+  V(LONG_CONS_ASCII_STRING_TYPE, ConsString::kSize, long_cons_ascii_string)    \
+  V(SHORT_SLICED_STRING_TYPE, SlicedString::kSize, short_sliced_string)        \
+  V(MEDIUM_SLICED_STRING_TYPE, SlicedString::kSize, medium_sliced_string)      \
+  V(LONG_SLICED_STRING_TYPE, SlicedString::kSize, long_sliced_string)          \
+  V(SHORT_SLICED_ASCII_STRING_TYPE,                                            \
+    SlicedString::kSize,                                                       \
+    short_sliced_ascii_string)                                                 \
+  V(MEDIUM_SLICED_ASCII_STRING_TYPE,                                           \
+    SlicedString::kSize,                                                       \
+    medium_sliced_ascii_string)                                                \
+  V(LONG_SLICED_ASCII_STRING_TYPE,                                             \
+    SlicedString::kSize,                                                       \
+    long_sliced_ascii_string)                                                  \
+  V(SHORT_EXTERNAL_STRING_TYPE,                                                \
+    ExternalTwoByteString::kSize,                                              \
+    short_external_string)                                                     \
+  V(MEDIUM_EXTERNAL_STRING_TYPE,                                               \
+    ExternalTwoByteString::kSize,                                              \
+    medium_external_string)                                                    \
+  V(LONG_EXTERNAL_STRING_TYPE,                                                 \
+    ExternalTwoByteString::kSize,                                              \
+    long_external_string)                                                      \
+  V(SHORT_EXTERNAL_ASCII_STRING_TYPE,                                          \
+    ExternalAsciiString::kSize,                                                \
+    short_external_ascii_string)                                               \
+  V(MEDIUM_EXTERNAL_ASCII_STRING_TYPE,                                         \
+    ExternalAsciiString::kSize,                                                \
+    medium_external_ascii_string)                                              \
+  V(LONG_EXTERNAL_ASCII_STRING_TYPE,                                           \
+    ExternalAsciiString::kSize,                                                \
+    long_external_ascii_string)
+
+// A struct is a simple object a set of object-valued fields.  Including an
+// object type in this causes the compiler to generate most of the boilerplate
+// code for the class including allocation and garbage collection routines,
+// casts and predicates.  All you need to define is the class, methods and
+// object verification routines.  Easy, no?
+//
+// Note that for subtle reasons related to the ordering or numerical values of
+// type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST
+// manually.
+#define STRUCT_LIST(V)                                                    \
+  V(ACCESSOR_INFO, AccessorInfo, accessor_info)                           \
+  V(ACCESS_CHECK_INFO, AccessCheckInfo, access_check_info)                \
+  V(INTERCEPTOR_INFO, InterceptorInfo, interceptor_info)                  \
+  V(CALL_HANDLER_INFO, CallHandlerInfo, call_handler_info)                \
+  V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info) \
+  V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info)       \
+  V(SIGNATURE_INFO, SignatureInfo, signature_info)                        \
+  V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_info)                   \
+  V(DEBUG_INFO, DebugInfo, debug_info)                                    \
+  V(BREAK_POINT_INFO, BreakPointInfo, break_point_info)                   \
+  V(SCRIPT, Script, script)
+
+
+// We use the full 8 bits of the instance_type field to encode heap object
+// instance types.  The high-order bit (bit 7) is set if the object is not a
+// string, and cleared if it is a string.
+const uint32_t kIsNotStringMask = 0x80;
+const uint32_t kStringTag = 0x0;
+const uint32_t kNotStringTag = 0x80;
+
+// If bit 7 is clear, bits 5 and 6 are the string's size (short, medium, or
+// long).
+const uint32_t kStringSizeMask = 0x60;
+const uint32_t kShortStringTag = 0x0;
+const uint32_t kMediumStringTag = 0x20;
+const uint32_t kLongStringTag = 0x40;
+
+// If bit 7 is clear, bit 4 indicates that the string is a symbol (if set) or
+// not (if cleared).
+const uint32_t kIsSymbolMask = 0x10;
+const uint32_t kNotSymbolTag = 0x0;
+const uint32_t kSymbolTag = 0x10;
+
+// If bit 7 is clear, and the string representation is a sequential string,
+// then bit 3 indicates whether the string consists of two-byte characters or
+// one-byte characters.
+const uint32_t kStringEncodingMask = 0x8;
+const uint32_t kTwoByteStringTag = 0x0;
+const uint32_t kAsciiStringTag = 0x8;
+
+// If bit 7 is clear, the low-order 3 bits indicate the representation
+// of the string.
+const uint32_t kStringRepresentationMask = 0x07;
+enum StringRepresentationTag {
+  kSeqStringTag = 0x0,
+  kConsStringTag = 0x1,
+  kSlicedStringTag = 0x2,
+  kExternalStringTag = 0x3
+};
+
+enum InstanceType {
+  SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
+  MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
+  LONG_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSeqStringTag,
+  SHORT_ASCII_SYMBOL_TYPE =
+      kShortStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
+  MEDIUM_ASCII_SYMBOL_TYPE =
+      kMediumStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
+  LONG_ASCII_SYMBOL_TYPE =
+      kLongStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
+  SHORT_CONS_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kConsStringTag,
+  MEDIUM_CONS_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kConsStringTag,
+  LONG_CONS_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kConsStringTag,
+  SHORT_CONS_ASCII_SYMBOL_TYPE =
+      kShortStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
+  MEDIUM_CONS_ASCII_SYMBOL_TYPE =
+      kMediumStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
+  LONG_CONS_ASCII_SYMBOL_TYPE =
+      kLongStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
+  SHORT_SLICED_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSlicedStringTag,
+  MEDIUM_SLICED_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSlicedStringTag,
+  LONG_SLICED_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSlicedStringTag,
+  SHORT_SLICED_ASCII_SYMBOL_TYPE =
+      kShortStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
+  MEDIUM_SLICED_ASCII_SYMBOL_TYPE =
+      kMediumStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
+  LONG_SLICED_ASCII_SYMBOL_TYPE =
+      kLongStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
+  SHORT_EXTERNAL_SYMBOL_TYPE =
+      kShortStringTag | kSymbolTag | kExternalStringTag,
+  MEDIUM_EXTERNAL_SYMBOL_TYPE =
+      kMediumStringTag | kSymbolTag | kExternalStringTag,
+  LONG_EXTERNAL_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kExternalStringTag,
+  SHORT_EXTERNAL_ASCII_SYMBOL_TYPE =
+      kShortStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
+  MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE =
+      kMediumStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
+  LONG_EXTERNAL_ASCII_SYMBOL_TYPE =
+      kLongStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
+  SHORT_STRING_TYPE = kShortStringTag | kSeqStringTag,
+  MEDIUM_STRING_TYPE = kMediumStringTag | kSeqStringTag,
+  LONG_STRING_TYPE = kLongStringTag | kSeqStringTag,
+  SHORT_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSeqStringTag,
+  MEDIUM_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSeqStringTag,
+  LONG_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSeqStringTag,
+  SHORT_CONS_STRING_TYPE = kShortStringTag | kConsStringTag,
+  MEDIUM_CONS_STRING_TYPE = kMediumStringTag | kConsStringTag,
+  LONG_CONS_STRING_TYPE = kLongStringTag | kConsStringTag,
+  SHORT_CONS_ASCII_STRING_TYPE =
+      kShortStringTag | kAsciiStringTag | kConsStringTag,
+  MEDIUM_CONS_ASCII_STRING_TYPE =
+      kMediumStringTag | kAsciiStringTag | kConsStringTag,
+  LONG_CONS_ASCII_STRING_TYPE =
+      kLongStringTag | kAsciiStringTag | kConsStringTag,
+  SHORT_SLICED_STRING_TYPE = kShortStringTag | kSlicedStringTag,
+  MEDIUM_SLICED_STRING_TYPE = kMediumStringTag | kSlicedStringTag,
+  LONG_SLICED_STRING_TYPE = kLongStringTag | kSlicedStringTag,
+  SHORT_SLICED_ASCII_STRING_TYPE =
+      kShortStringTag | kAsciiStringTag | kSlicedStringTag,
+  MEDIUM_SLICED_ASCII_STRING_TYPE =
+      kMediumStringTag | kAsciiStringTag | kSlicedStringTag,
+  LONG_SLICED_ASCII_STRING_TYPE =
+      kLongStringTag | kAsciiStringTag | kSlicedStringTag,
+  SHORT_EXTERNAL_STRING_TYPE = kShortStringTag | kExternalStringTag,
+  MEDIUM_EXTERNAL_STRING_TYPE = kMediumStringTag | kExternalStringTag,
+  LONG_EXTERNAL_STRING_TYPE = kLongStringTag | kExternalStringTag,
+  SHORT_EXTERNAL_ASCII_STRING_TYPE =
+      kShortStringTag | kAsciiStringTag | kExternalStringTag,
+  MEDIUM_EXTERNAL_ASCII_STRING_TYPE =
+      kMediumStringTag | kAsciiStringTag | kExternalStringTag,
+  LONG_EXTERNAL_ASCII_STRING_TYPE =
+      kLongStringTag | kAsciiStringTag | kExternalStringTag,
+  LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE = LONG_EXTERNAL_ASCII_STRING_TYPE,
+
+  MAP_TYPE = kNotStringTag,
+  HEAP_NUMBER_TYPE,
+  FIXED_ARRAY_TYPE,
+  CODE_TYPE,
+  ODDBALL_TYPE,
+  PROXY_TYPE,
+  BYTE_ARRAY_TYPE,
+  FILLER_TYPE,
+  SMI_TYPE,
+
+  ACCESSOR_INFO_TYPE,
+  ACCESS_CHECK_INFO_TYPE,
+  INTERCEPTOR_INFO_TYPE,
+  SHARED_FUNCTION_INFO_TYPE,
+  CALL_HANDLER_INFO_TYPE,
+  FUNCTION_TEMPLATE_INFO_TYPE,
+  OBJECT_TEMPLATE_INFO_TYPE,
+  SIGNATURE_INFO_TYPE,
+  TYPE_SWITCH_INFO_TYPE,
+  DEBUG_INFO_TYPE,
+  BREAK_POINT_INFO_TYPE,
+  SCRIPT_TYPE,
+
+  JS_VALUE_TYPE,
+  JS_OBJECT_TYPE,
+  JS_GLOBAL_OBJECT_TYPE,
+  JS_BUILTINS_OBJECT_TYPE,
+  JS_GLOBAL_PROXY_TYPE,
+  JS_ARRAY_TYPE,
+  JS_REGEXP_TYPE,
+
+  JS_FUNCTION_TYPE,
+
+  // Pseudo-types
+  FIRST_NONSTRING_TYPE = MAP_TYPE,
+  FIRST_TYPE = 0x0,
+  INVALID_TYPE = FIRST_TYPE - 1,
+  LAST_TYPE = JS_FUNCTION_TYPE,
+  // Boundaries for testing the type is a JavaScript "object".  Note that
+  // function objects are not counted as objects, even though they are
+  // implemented as such; only values whose typeof is "object" are included.
+  FIRST_JS_OBJECT_TYPE = JS_VALUE_TYPE,
+  LAST_JS_OBJECT_TYPE = JS_REGEXP_TYPE
+};
+
+
+enum CompareResult {
+  LESS      = -1,
+  EQUAL     =  0,
+  GREATER   =  1,
+
+  NOT_EQUAL = GREATER
+};
+
+
+#define DECL_BOOLEAN_ACCESSORS(name)   \
+  inline bool name();                  \
+  inline void set_##name(bool value);  \
+
+
+#define DECL_ACCESSORS(name, type)    \
+  inline type* name();                \
+  inline void set_##name(type* value, \
+                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
+
+
+class StringStream;
+class ObjectVisitor;
+
+struct ValueInfo : public Malloced {
+  ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { }
+  InstanceType type;
+  Object* ptr;
+  const char* str;
+  double number;
+};
+
+
+// A template-ized version of the IsXXX functions.
+template <class C> static inline bool Is(Object* obj);
+
+
+// Object is the abstract superclass for all classes in the
+// object hierarchy.
+// Object does not use any virtual functions to avoid the
+// allocation of the C++ vtable.
+// Since Smi and Failure are subclasses of Object no
+// data members can be present in Object.
+class Object BASE_EMBEDDED {
+ public:
+  // Type testing.
+  inline bool IsSmi();
+  inline bool IsHeapObject();
+  inline bool IsHeapNumber();
+  inline bool IsString();
+  inline bool IsSeqString();
+  inline bool IsAsciiStringRepresentation();
+  inline bool IsTwoByteStringRepresentation();
+  inline bool IsSeqAsciiString();
+  inline bool IsSeqTwoByteString();
+  inline bool IsConsString();
+  inline bool IsSlicedString();
+  inline bool IsExternalString();
+  inline bool IsExternalAsciiString();
+  inline bool IsExternalTwoByteString();
+  inline bool IsShortString();
+  inline bool IsMediumString();
+  inline bool IsLongString();
+  inline bool IsSymbol();
+  inline bool IsNumber();
+  inline bool IsByteArray();
+  inline bool IsFailure();
+  inline bool IsRetryAfterGC();
+  inline bool IsOutOfMemoryFailure();
+  inline bool IsException();
+  inline bool IsJSObject();
+  inline bool IsMap();
+  inline bool IsFixedArray();
+  inline bool IsDescriptorArray();
+  inline bool IsContext();
+  inline bool IsGlobalContext();
+  inline bool IsJSFunction();
+  inline bool IsCode();
+  inline bool IsOddball();
+  inline bool IsSharedFunctionInfo();
+  inline bool IsJSValue();
+  inline bool IsProxy();
+  inline bool IsBoolean();
+  inline bool IsJSArray();
+  inline bool IsJSRegExp();
+  inline bool IsHashTable();
+  inline bool IsDictionary();
+  inline bool IsSymbolTable();
+  inline bool IsCompilationCacheTable();
+  inline bool IsMapCache();
+  inline bool IsLookupCache();
+  inline bool IsPrimitive();
+  inline bool IsGlobalObject();
+  inline bool IsJSGlobalObject();
+  inline bool IsJSBuiltinsObject();
+  inline bool IsJSGlobalProxy();
+  inline bool IsUndetectableObject();
+  inline bool IsAccessCheckNeeded();
+
+  // Returns true if this object is an instance of the specified
+  // function template.
+  bool IsInstanceOf(FunctionTemplateInfo* type);
+
+  inline bool IsStruct();
+#define DECLARE_STRUCT_PREDICATE(NAME, Name, name) inline bool Is##Name();
+  STRUCT_LIST(DECLARE_STRUCT_PREDICATE)
+#undef DECLARE_STRUCT_PREDICATE
+
+  // Oddball testing.
+  INLINE(bool IsUndefined());
+  INLINE(bool IsTheHole());
+  INLINE(bool IsNull());
+  INLINE(bool IsTrue());
+  INLINE(bool IsFalse());
+
+  // Extract the number.
+  inline double Number();
+
+  inline bool HasSpecificClassOf(String* name);
+
+  Object* ToObject();             // ECMA-262 9.9.
+  Object* ToBoolean();            // ECMA-262 9.2.
+
+  // Convert to a JSObject if needed.
+  // global_context is used when creating wrapper object.
+  Object* ToObject(Context* global_context);
+
+  // Converts this to a Smi if possible.
+  // Failure is returned otherwise.
+  inline Object* ToSmi();
+
+  void Lookup(String* name, LookupResult* result);
+
+  // Property access.
+  inline Object* GetProperty(String* key);
+  inline Object* GetProperty(String* key, PropertyAttributes* attributes);
+  Object* GetPropertyWithReceiver(Object* receiver,
+                                  String* key,
+                                  PropertyAttributes* attributes);
+  Object* GetProperty(Object* receiver,
+                      LookupResult* result,
+                      String* key,
+                      PropertyAttributes* attributes);
+  Object* GetPropertyWithCallback(Object* receiver,
+                                  Object* structure,
+                                  String* name,
+                                  Object* holder);
+
+  inline Object* GetElement(uint32_t index);
+  Object* GetElementWithReceiver(Object* receiver, uint32_t index);
+
+  // Return the object's prototype (might be Heap::null_value()).
+  Object* GetPrototype();
+
+  // Returns true if this is a JSValue containing a string and the index is
+  // < the length of the string.  Used to implement [] on strings.
+  inline bool IsStringObjectWithCharacterAt(uint32_t index);
+
+#ifdef DEBUG
+  // Prints this object with details.
+  void Print();
+  void PrintLn();
+  // Verifies the object.
+  void Verify();
+
+  // Verify a pointer is a valid object pointer.
+  static void VerifyPointer(Object* p);
+#endif
+
+  // Prints this object without details.
+  void ShortPrint();
+
+  // Prints this object without details to a message accumulator.
+  void ShortPrint(StringStream* accumulator);
+
+  // Casting: This cast is only needed to satisfy macros in objects-inl.h.
+  static Object* cast(Object* value) { return value; }
+
+  // Layout description.
+  static const int kHeaderSize = 0;  // Object does not take up any space.
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
+};
+
+
+// Smi represents integer Numbers that can be stored in 31 bits.
+// Smis are immediate which means they are NOT allocated in the heap.
+// The this pointer has the following format: [31 bit signed int] 0
+// Smi stands for small integer.
+class Smi: public Object {
+ public:
+  // Returns the integer value.
+  inline int value();
+
+  // Convert a value to a Smi object.
+  static inline Smi* FromInt(int value);
+
+  // Returns whether value can be represented in a Smi.
+  static inline bool IsValid(int value);
+
+  // Casting.
+  static inline Smi* cast(Object* object);
+
+  // Dispatched behavior.
+  void SmiPrint();
+  void SmiPrint(StringStream* accumulator);
+#ifdef DEBUG
+  void SmiVerify();
+#endif
+
+  // Min and max limits for Smi values.
+  static const int kMinValue = -(1 << (kBitsPerPointer - (kSmiTagSize + 1)));
+  static const int kMaxValue = (1 << (kBitsPerPointer - (kSmiTagSize + 1))) - 1;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Smi);
+};
+
+
+// Failure is used for reporing out of memory situations and
+// propagating exceptions through the runtime system.  Failure objects
+// are transient and cannot occur as part of the objects graph.
+//
+// Failures are a single word, encoded as follows:
+// +-------------------------+---+--+--+
+// |rrrrrrrrrrrrrrrrrrrrrrrrr|sss|tt|11|
+// +-------------------------+---+--+--+
+//
+// The low two bits, 0-1, are the failure tag, 11.  The next two bits,
+// 2-3, are a failure type tag 'tt' with possible values:
+//   00 RETRY_AFTER_GC
+//   01 EXCEPTION
+//   10 INTERNAL_ERROR
+//   11 OUT_OF_MEMORY_EXCEPTION
+//
+// The next three bits, 4-6, are an allocation space tag 'sss'.  The
+// allocation space tag is 000 for all failure types except
+// RETRY_AFTER_GC.  For RETRY_AFTER_GC, the possible values are
+// (the encoding is found in globals.h):
+//   000 NEW_SPACE
+//   001 OLD_SPACE
+//   010 CODE_SPACE
+//   011 MAP_SPACE
+//   100 LO_SPACE
+//
+// The remaining bits is the number of words requested by the
+// allocation request that failed, and is zeroed except for
+// RETRY_AFTER_GC failures.  The 25 bits (on a 32 bit platform) gives
+// a representable range of 2^27 bytes (128MB).
+
+// Failure type tag info.
+const int kFailureTypeTagSize = 2;
+const int kFailureTypeTagMask = (1 << kFailureTypeTagSize) - 1;
+
+class Failure: public Object {
+ public:
+  // RuntimeStubs assumes EXCEPTION = 1 in the compiler-generated code.
+  enum Type {
+    RETRY_AFTER_GC = 0,
+    EXCEPTION = 1,       // Returning this marker tells the real exception
+                         // is in Top::pending_exception.
+    INTERNAL_ERROR = 2,
+    OUT_OF_MEMORY_EXCEPTION = 3
+  };
+
+  inline Type type() const;
+
+  // Returns the space that needs to be collected for RetryAfterGC failures.
+  inline AllocationSpace allocation_space() const;
+
+  // Returns the number of bytes requested (up to the representable maximum)
+  // for RetryAfterGC failures.
+  inline int requested() const;
+
+  inline bool IsInternalError() const;
+  inline bool IsOutOfMemoryException() const;
+
+  static Failure* RetryAfterGC(int requested_bytes, AllocationSpace space);
+  static inline Failure* RetryAfterGC(int requested_bytes);  // NEW_SPACE
+  static inline Failure* Exception();
+  static inline Failure* InternalError();
+  static inline Failure* OutOfMemoryException();
+  // Casting.
+  static inline Failure* cast(Object* object);
+
+  // Dispatched behavior.
+  void FailurePrint();
+  void FailurePrint(StringStream* accumulator);
+#ifdef DEBUG
+  void FailureVerify();
+#endif
+
+ private:
+  inline int value() const;
+  static inline Failure* Construct(Type type, int value = 0);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Failure);
+};
+
+
+// Heap objects typically have a map pointer in their first word.  However,
+// during GC other data (eg, mark bits, forwarding addresses) is sometimes
+// encoded in the first word.  The class MapWord is an abstraction of the
+// value in a heap object's first word.
+class MapWord BASE_EMBEDDED {
+ public:
+  // Normal state: the map word contains a map pointer.
+
+  // Create a map word from a map pointer.
+  static inline MapWord FromMap(Map* map);
+
+  // View this map word as a map pointer.
+  inline Map* ToMap();
+
+
+  // Scavenge collection: the map word of live objects in the from space
+  // contains a forwarding address (a heap object pointer in the to space).
+
+  // True if this map word is a forwarding address for a scavenge
+  // collection.  Only valid during a scavenge collection (specifically,
+  // when all map words are heap object pointers, ie. not during a full GC).
+  inline bool IsForwardingAddress();
+
+  // Create a map word from a forwarding address.
+  static inline MapWord FromForwardingAddress(HeapObject* object);
+
+  // View this map word as a forwarding address.
+  inline HeapObject* ToForwardingAddress();
+
+
+  // Marking phase of full collection: the map word of live objects is
+  // marked, and may be marked as overflowed (eg, the object is live, its
+  // children have not been visited, and it does not fit in the marking
+  // stack).
+
+  // True if this map word's mark bit is set.
+  inline bool IsMarked();
+
+  // Return this map word but with its mark bit set.
+  inline void SetMark();
+
+  // Return this map word but with its mark bit cleared.
+  inline void ClearMark();
+
+  // True if this map word's overflow bit is set.
+  inline bool IsOverflowed();
+
+  // Return this map word but with its overflow bit set.
+  inline void SetOverflow();
+
+  // Return this map word but with its overflow bit cleared.
+  inline void ClearOverflow();
+
+
+  // Compacting phase of a full compacting collection: the map word of live
+  // objects contains an encoding of the original map address along with the
+  // forwarding address (represented as an offset from the first live object
+  // in the same page as the (old) object address).
+
+  // Create a map word from a map address and a forwarding address offset.
+  static inline MapWord EncodeAddress(Address map_address, int offset);
+
+  // Return the map address encoded in this map word.
+  inline Address DecodeMapAddress(MapSpace* map_space);
+
+  // Return the forwarding offset encoded in this map word.
+  inline int DecodeOffset();
+
+
+  // During serialization: the map word is used to hold an encoded
+  // address, and possibly a mark bit (set and cleared with SetMark
+  // and ClearMark).
+
+  // Create a map word from an encoded address.
+  static inline MapWord FromEncodedAddress(Address address);
+
+  inline Address ToEncodedAddress();
+
+ private:
+  // HeapObject calls the private constructor and directly reads the value.
+  friend class HeapObject;
+
+  explicit MapWord(uintptr_t value) : value_(value) {}
+
+  uintptr_t value_;
+
+  // Bits used by the marking phase of the garbage collector.
+  //
+  // The first word of a heap object is normall a map pointer. The last two
+  // bits are tagged as '01' (kHeapObjectTag). We reuse the last two bits to
+  // mark an object as live and/or overflowed:
+  //   last bit = 0, marked as alive
+  //   second bit = 1, overflowed
+  // An object is only marked as overflowed when it is marked as live while
+  // the marking stack is overflowed.
+  static const int kMarkingBit = 0;  // marking bit
+  static const int kMarkingMask = (1 << kMarkingBit);  // marking mask
+  static const int kOverflowBit = 1;  // overflow bit
+  static const int kOverflowMask = (1 << kOverflowBit);  // overflow mask
+
+  // Forwarding pointers and map pointer encoding
+  //  31             21 20              10 9               0
+  // +-----------------+------------------+-----------------+
+  // |forwarding offset|page offset of map|page index of map|
+  // +-----------------+------------------+-----------------+
+  //  11 bits           11 bits            10 bits
+  static const int kMapPageIndexBits = 10;
+  static const int kMapPageOffsetBits = 11;
+  static const int kForwardingOffsetBits = 11;
+
+  static const int kMapPageIndexShift = 0;
+  static const int kMapPageOffsetShift =
+      kMapPageIndexShift + kMapPageIndexBits;
+  static const int kForwardingOffsetShift =
+      kMapPageOffsetShift + kMapPageOffsetBits;
+
+  // 0x000003FF
+  static const uint32_t kMapPageIndexMask =
+      (1 << kMapPageOffsetShift) - 1;
+
+  // 0x001FFC00
+  static const uint32_t kMapPageOffsetMask =
+      ((1 << kForwardingOffsetShift) - 1) & ~kMapPageIndexMask;
+
+  // 0xFFE00000
+  static const uint32_t kForwardingOffsetMask =
+      ~(kMapPageIndexMask | kMapPageOffsetMask);
+};
+
+
+// HeapObject is the superclass for all classes describing heap allocated
+// objects.
+class HeapObject: public Object {
+ public:
+  // [map]: Contains a map which contains the object's reflective
+  // information.
+  inline Map* map();
+  inline void set_map(Map* value);
+
+  // During garbage collection, the map word of a heap object does not
+  // necessarily contain a map pointer.
+  inline MapWord map_word();
+  inline void set_map_word(MapWord map_word);
+
+  // Converts an address to a HeapObject pointer.
+  static inline HeapObject* FromAddress(Address address);
+
+  // Returns the address of this HeapObject.
+  inline Address address();
+
+  // Iterates over pointers contained in the object (including the Map)
+  void Iterate(ObjectVisitor* v);
+
+  // Iterates over all pointers contained in the object except the
+  // first map pointer.  The object type is given in the first
+  // parameter. This function does not access the map pointer in the
+  // object, and so is safe to call while the map pointer is modified.
+  void IterateBody(InstanceType type, int object_size, ObjectVisitor* v);
+
+  // This method only applies to struct objects.  Iterates over all the fields
+  // of this struct.
+  void IterateStructBody(int object_size, ObjectVisitor* v);
+
+  // Returns the heap object's size in bytes
+  inline int Size();
+
+  // Given a heap object's map pointer, returns the heap size in bytes
+  // Useful when the map pointer field is used for other purposes.
+  // GC internal.
+  inline int SizeFromMap(Map* map);
+
+  // Support for the marking heap objects during the marking phase of GC.
+  // True if the object is marked live.
+  inline bool IsMarked();
+
+  // Mutate this object's map pointer to indicate that the object is live.
+  inline void SetMark();
+
+  // Mutate this object's map pointer to remove the indication that the
+  // object is live (ie, partially restore the map pointer).
+  inline void ClearMark();
+
+  // True if this object is marked as overflowed.  Overflowed objects have
+  // been reached and marked during marking of the heap, but their children
+  // have not necessarily been marked and they have not been pushed on the
+  // marking stack.
+  inline bool IsOverflowed();
+
+  // Mutate this object's map pointer to indicate that the object is
+  // overflowed.
+  inline void SetOverflow();
+
+  // Mutate this object's map pointer to remove the indication that the
+  // object is overflowed (ie, partially restore the map pointer).
+  inline void ClearOverflow();
+
+  static inline Object* GetHeapObjectField(HeapObject* obj, int index);
+
+  // Casting.
+  static inline HeapObject* cast(Object* obj);
+
+  // Return the write barrier mode for this.
+  inline WriteBarrierMode GetWriteBarrierMode();
+
+  // Dispatched behavior.
+  void HeapObjectShortPrint(StringStream* accumulator);
+#ifdef DEBUG
+  void HeapObjectPrint();
+  void HeapObjectVerify();
+  inline void VerifyObjectField(int offset);
+
+  void PrintHeader(const char* id);
+
+  // Verify a pointer is a valid HeapObject pointer that points to object
+  // areas in the heap.
+  static void VerifyHeapPointer(Object* p);
+#endif
+
+  // Layout description.
+  // First field in a heap object is map.
+  static const int kMapOffset = Object::kHeaderSize;
+  static const int kHeaderSize = kMapOffset + kPointerSize;
+
+ protected:
+  // helpers for calling an ObjectVisitor to iterate over pointers in the
+  // half-open range [start, end) specified as integer offsets
+  inline void IteratePointers(ObjectVisitor* v, int start, int end);
+  // as above, for the single element at "offset"
+  inline void IteratePointer(ObjectVisitor* v, int offset);
+
+  // Computes the object size from the map.
+  // Should only be used from SizeFromMap.
+  int SlowSizeFromMap(Map* map);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(HeapObject);
+};
+
+
+// The HeapNumber class describes heap allocated numbers that cannot be
+// represented in a Smi (small integer)
+class HeapNumber: public HeapObject {
+ public:
+  // [value]: number value.
+  inline double value();
+  inline void set_value(double value);
+
+  // Casting.
+  static inline HeapNumber* cast(Object* obj);
+
+  // Dispatched behavior.
+  Object* HeapNumberToBoolean();
+  void HeapNumberPrint();
+  void HeapNumberPrint(StringStream* accumulator);
+#ifdef DEBUG
+  void HeapNumberVerify();
+#endif
+
+  // Layout description.
+  static const int kValueOffset = HeapObject::kHeaderSize;
+  static const int kSize = kValueOffset + kDoubleSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(HeapNumber);
+};
+
+
+// The JSObject describes real heap allocated JavaScript objects with
+// properties.
+// Note that the map of JSObject changes during execution to enable inline
+// caching.
+class JSObject: public HeapObject {
+ public:
+  // [properties]: Backing storage for properties.
+  // properties is a FixedArray in the fast case, and a Dictionary in the
+  // slow case.
+  DECL_ACCESSORS(properties, FixedArray)  // Get and set fast properties.
+  inline void initialize_properties();
+  inline bool HasFastProperties();
+  inline Dictionary* property_dictionary();  // Gets slow properties.
+
+  // [elements]: The elements (properties with names that are integers).
+  // elements is a FixedArray in the fast case, and a Dictionary in the slow
+  // case.
+  DECL_ACCESSORS(elements, FixedArray)  // Get and set fast elements.
+  inline void initialize_elements();
+  inline bool HasFastElements();
+  inline Dictionary* element_dictionary();  // Gets slow elements.
+
+  Object* SetProperty(String* key,
+                      Object* value,
+                      PropertyAttributes attributes);
+  Object* SetProperty(LookupResult* result,
+                      String* key,
+                      Object* value,
+                      PropertyAttributes attributes);
+  Object* SetPropertyWithFailedAccessCheck(LookupResult* result,
+                                           String* name,
+                                           Object* value);
+  Object* SetPropertyWithCallback(Object* structure,
+                                  String* name,
+                                  Object* value,
+                                  JSObject* holder);
+  Object* SetPropertyWithInterceptor(String* name,
+                                     Object* value,
+                                     PropertyAttributes attributes);
+  Object* SetPropertyPostInterceptor(String* name,
+                                     Object* value,
+                                     PropertyAttributes attributes);
+  Object* IgnoreAttributesAndSetLocalProperty(String* key,
+                                              Object* value,
+                                              PropertyAttributes attributes);
+
+  // Sets a property that currently has lazy loading.
+  Object* SetLazyProperty(LookupResult* result,
+                          String* name,
+                          Object* value,
+                          PropertyAttributes attributes);
+
+  // Returns the class name ([[Class]] property in the specification).
+  String* class_name();
+
+  // Retrieve interceptors.
+  InterceptorInfo* GetNamedInterceptor();
+  InterceptorInfo* GetIndexedInterceptor();
+
+  inline PropertyAttributes GetPropertyAttribute(String* name);
+  PropertyAttributes GetPropertyAttributeWithReceiver(JSObject* receiver,
+                                                      String* name);
+  PropertyAttributes GetLocalPropertyAttribute(String* name);
+
+  Object* DefineAccessor(String* name, bool is_getter, JSFunction* fun,
+                         PropertyAttributes attributes);
+  Object* LookupAccessor(String* name, bool is_getter);
+
+  // Used from Object::GetProperty().
+  Object* GetPropertyWithFailedAccessCheck(Object* receiver,
+                                           LookupResult* result,
+                                           String* name);
+  Object* GetPropertyWithInterceptor(JSObject* receiver,
+                                     String* name,
+                                     PropertyAttributes* attributes);
+  Object* GetPropertyPostInterceptor(JSObject* receiver,
+                                     String* name,
+                                     PropertyAttributes* attributes);
+  Object* GetLazyProperty(Object* receiver,
+                          LookupResult* result,
+                          String* name,
+                          PropertyAttributes* attributes);
+
+  bool HasProperty(String* name) {
+    return GetPropertyAttribute(name) != ABSENT;
+  }
+
+  bool HasLocalProperty(String* name) {
+    return GetLocalPropertyAttribute(name) != ABSENT;
+  }
+
+  Object* DeleteProperty(String* name);
+  Object* DeleteElement(uint32_t index);
+  Object* DeleteLazyProperty(LookupResult* result, String* name);
+
+  // Tests for the fast common case for property enumeration.
+  bool IsSimpleEnum();
+
+  // Do we want to keep the elements in fast case when increasing the
+  // capacity?
+  bool ShouldConvertToSlowElements(int new_capacity);
+  // Returns true if the backing storage for the slow-case elements of
+  // this object takes up nearly as much space as a fast-case backing
+  // storage would.  In that case the JSObject should have fast
+  // elements.
+  bool ShouldConvertToFastElements();
+
+  // Return the object's prototype (might be Heap::null_value()).
+  inline Object* GetPrototype();
+
+  // Tells whether the index'th element is present.
+  inline bool HasElement(uint32_t index);
+  bool HasElementWithReceiver(JSObject* receiver, uint32_t index);
+  bool HasLocalElement(uint32_t index);
+
+  bool HasElementWithInterceptor(JSObject* receiver, uint32_t index);
+  bool HasElementPostInterceptor(JSObject* receiver, uint32_t index);
+
+  Object* SetFastElement(uint32_t index, Object* value);
+
+  // Set the index'th array element.
+  // A Failure object is returned if GC is needed.
+  Object* SetElement(uint32_t index, Object* value);
+
+  // Returns the index'th element.
+  // The undefined object if index is out of bounds.
+  Object* GetElementWithReceiver(JSObject* receiver, uint32_t index);
+
+  void SetFastElements(FixedArray* elements);
+  Object* SetSlowElements(Object* length);
+
+  // Lookup interceptors are used for handling properties controlled by host
+  // objects.
+  inline bool HasNamedInterceptor();
+  inline bool HasIndexedInterceptor();
+
+  // Support functions for v8 api (needed for correct interceptor behavior).
+  bool HasRealNamedProperty(String* key);
+  bool HasRealElementProperty(uint32_t index);
+  bool HasRealNamedCallbackProperty(String* key);
+
+  // Initializes the array to a certain length
+  Object* SetElementsLength(Object* length);
+
+  // Get the header size for a JSObject.  Used to compute the index of
+  // internal fields as well as the number of internal fields.
+  inline int GetHeaderSize();
+
+  inline int GetInternalFieldCount();
+  inline Object* GetInternalField(int index);
+  inline void SetInternalField(int index, Object* value);
+
+  // Lookup a property.  If found, the result is valid and has
+  // detailed information.
+  void LocalLookup(String* name, LookupResult* result);
+  void Lookup(String* name, LookupResult* result);
+
+  // The following lookup functions skip interceptors.
+  void LocalLookupRealNamedProperty(String* name, LookupResult* result);
+  void LookupRealNamedProperty(String* name, LookupResult* result);
+  void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result);
+  void LookupCallbackSetterInPrototypes(String* name, LookupResult* result);
+
+  // Returns the number of properties on this object filtering out properties
+  // with the specified attributes (ignoring interceptors).
+  int NumberOfLocalProperties(PropertyAttributes filter);
+  // Returns the number of enumerable properties (ignoring interceptors).
+  int NumberOfEnumProperties();
+  // Fill in details for properties into storage.
+  void GetLocalPropertyNames(FixedArray* storage);
+
+  // Returns the number of properties on this object filtering out properties
+  // with the specified attributes (ignoring interceptors).
+  int NumberOfLocalElements(PropertyAttributes filter);
+  // Returns the number of enumerable elements (ignoring interceptors).
+  int NumberOfEnumElements();
+  // Returns the number of elements on this object filtering out elements
+  // with the specified attributes (ignoring interceptors).
+  int GetLocalElementKeys(FixedArray* storage, PropertyAttributes filter);
+  // Count and fill in the enumerable elements into storage.
+  // (storage->length() == NumberOfEnumElements()).
+  // If storage is NULL, will count the elements without adding
+  // them to any storage.
+  // Returns the number of enumerable elements.
+  int GetEnumElementKeys(FixedArray* storage);
+
+  // Add a property to a fast-case object using a map transition to
+  // new_map.
+  Object* AddFastPropertyUsingMap(Map* new_map,
+                                  String* name,
+                                  Object* value);
+
+  // Add a constant function property to a fast-case object.
+  // This leaves a CONSTANT_TRANSITION in the old map, and
+  // if it is called on a second object with this map, a
+  // normal property is added instead, with a map transition.
+  // This avoids the creation of many maps with the same constant
+  // function, all orphaned.
+  Object* AddConstantFunctionProperty(String* name,
+                                      JSFunction* function,
+                                      PropertyAttributes attributes);
+
+  Object* ReplaceSlowProperty(String* name,
+                              Object* value,
+                              PropertyAttributes attributes);
+
+  // Converts a descriptor of any other type to a real field,
+  // backed by the properties array.  Descriptors of visible
+  // types, such as CONSTANT_FUNCTION, keep their enumeration order.
+  // Converts the descriptor on the original object's map to a
+  // map transition, and the the new field is on the object's new map.
+  Object* ConvertDescriptorToFieldAndMapTransition(
+      String* name,
+      Object* new_value,
+      PropertyAttributes attributes);
+
+  // Converts a descriptor of any other type to a real field,
+  // backed by the properties array.  Descriptors of visible
+  // types, such as CONSTANT_FUNCTION, keep their enumeration order.
+  Object* ConvertDescriptorToField(String* name,
+                                   Object* new_value,
+                                   PropertyAttributes attributes);
+
+  // Add a property to a fast-case object.
+  Object* AddFastProperty(String* name,
+                          Object* value,
+                          PropertyAttributes attributes);
+
+  // Add a property to a slow-case object.
+  Object* AddSlowProperty(String* name,
+                          Object* value,
+                          PropertyAttributes attributes);
+
+  // Add a property to an object.
+  Object* AddProperty(String* name,
+                      Object* value,
+                      PropertyAttributes attributes);
+
+  // Convert the object to use the canonical dictionary
+  // representation.
+  Object* NormalizeProperties();
+  Object* NormalizeElements();
+
+  // Transform slow named properties to fast variants.
+  // Returns failure if allocation failed.
+  Object* TransformToFastProperties(int unused_property_fields);
+
+  // Access fast-case object properties at index.
+  inline Object* FastPropertyAt(int index);
+  inline Object* FastPropertyAtPut(int index, Object* value);
+
+  // Access to set in object properties.
+  inline Object* InObjectPropertyAtPut(int index,
+                                       Object* value,
+                                       WriteBarrierMode mode
+                                       = UPDATE_WRITE_BARRIER);
+
+  // initializes the body after properties slot, properties slot is
+  // initialized by set_properties
+  // Note: this call does not update write barrier, it is caller's
+  // reponsibility to ensure that *v* can be collected without WB here.
+  inline void InitializeBody(int object_size);
+
+  // Check whether this object references another object
+  bool ReferencesObject(Object* obj);
+
+  // Casting.
+  static inline JSObject* cast(Object* obj);
+
+  // Dispatched behavior.
+  void JSObjectIterateBody(int object_size, ObjectVisitor* v);
+  void JSObjectShortPrint(StringStream* accumulator);
+#ifdef DEBUG
+  void JSObjectPrint();
+  void JSObjectVerify();
+  void PrintProperties();
+  void PrintElements();
+
+  // Structure for collecting spill information about JSObjects.
+  class SpillInformation {
+   public:
+    void Clear();
+    void Print();
+    int number_of_objects_;
+    int number_of_objects_with_fast_properties_;
+    int number_of_objects_with_fast_elements_;
+    int number_of_fast_used_fields_;
+    int number_of_fast_unused_fields_;
+    int number_of_slow_used_properties_;
+    int number_of_slow_unused_properties_;
+    int number_of_fast_used_elements_;
+    int number_of_fast_unused_elements_;
+    int number_of_slow_used_elements_;
+    int number_of_slow_unused_elements_;
+  };
+
+  void IncrementSpillStatistics(SpillInformation* info);
+#endif
+  Object* SlowReverseLookup(Object* value);
+
+  static const uint32_t kMaxGap = 1024;
+  static const int kMaxFastElementsLength = 5000;
+  static const int kMaxFastProperties = 8;
+  static const int kMaxInstanceSize = 255 * kPointerSize;
+  // When extending the backing storage for property values, we increase
+  // its size by more than the 1 entry necessary, so sequentially adding fields
+  // to the same object requires fewer allocations and copies.
+  static const int kFieldsAdded = 3;
+
+  // Layout description.
+  static const int kPropertiesOffset = HeapObject::kHeaderSize;
+  static const int kElementsOffset = kPropertiesOffset + kPointerSize;
+  static const int kHeaderSize = kElementsOffset + kPointerSize;
+
+  Object* GetElementWithInterceptor(JSObject* receiver, uint32_t index);
+
+ private:
+  Object* SetElementWithInterceptor(uint32_t index, Object* value);
+  Object* SetElementPostInterceptor(uint32_t index, Object* value);
+
+  Object* GetElementPostInterceptor(JSObject* receiver, uint32_t index);
+
+  Object* DeletePropertyPostInterceptor(String* name);
+  Object* DeletePropertyWithInterceptor(String* name);
+
+  Object* DeleteElementPostInterceptor(uint32_t index);
+  Object* DeleteElementWithInterceptor(uint32_t index);
+
+  PropertyAttributes GetPropertyAttributePostInterceptor(JSObject* receiver,
+                                                         String* name,
+                                                         bool continue_search);
+  PropertyAttributes GetPropertyAttributeWithInterceptor(JSObject* receiver,
+                                                         String* name,
+                                                         bool continue_search);
+  PropertyAttributes GetPropertyAttribute(JSObject* receiver,
+                                          LookupResult* result,
+                                          String* name,
+                                          bool continue_search);
+
+  // Returns true if most of the elements backing storage is used.
+  bool HasDenseElements();
+
+  Object* DefineGetterSetter(String* name, PropertyAttributes attributes);
+
+  void LookupInDescriptor(String* name, LookupResult* result);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject);
+};
+
+
+// Abstract super class arrays. It provides length behavior.
+class Array: public HeapObject {
+ public:
+  // [length]: length of the array.
+  inline int length();
+  inline void set_length(int value);
+
+  // Convert an object to an array index.
+  // Returns true if the conversion succeeded.
+  static inline bool IndexFromObject(Object* object, uint32_t* index);
+
+  // Layout descriptor.
+  static const int kLengthOffset = HeapObject::kHeaderSize;
+  static const int kHeaderSize = kLengthOffset + kIntSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Array);
+};
+
+
+// FixedArray describes fixed sized arrays where element
+// type is Object*.
+
+class FixedArray: public Array {
+ public:
+
+  // Setter and getter for elements.
+  inline Object* get(int index);
+  inline void set(int index, Object* value);
+
+  // Setter with barrier mode.
+  inline void set(int index, Object* value, WriteBarrierMode mode);
+
+  // Setters for frequently used oddballs located in old space.
+  inline void set_undefined(int index);
+  inline void set_null(int index);
+  inline void set_the_hole(int index);
+
+  // Copy operations.
+  inline Object* Copy();
+  Object* CopySize(int new_length);
+
+  // Add the elements of a JSArray to this FixedArray.
+  Object* AddKeysFromJSArray(JSArray* array);
+
+  // Compute the union of this and other.
+  Object* UnionOfKeys(FixedArray* other);
+
+  // Copy a sub array from the receiver to dest.
+  void CopyTo(int pos, FixedArray* dest, int dest_pos, int len);
+
+  // Garbage collection support.
+  static int SizeFor(int length) { return kHeaderSize + length * kPointerSize; }
+
+  // Casting.
+  static inline FixedArray* cast(Object* obj);
+
+  // Dispatched behavior.
+  int FixedArraySize() { return SizeFor(length()); }
+  void FixedArrayIterateBody(ObjectVisitor* v);
+#ifdef DEBUG
+  void FixedArrayPrint();
+  void FixedArrayVerify();
+  // Checks if two FixedArrays have identical contents.
+  bool IsEqualTo(FixedArray* other);
+#endif
+
+  // Swap two elements.
+  void Swap(int i, int j);
+
+  // Sort this array and the smis as pairs wrt. the smis.
+  void SortPairs(FixedArray* smis);
+
+ protected:
+  // Set operation on FixedArray without using write barriers.
+  static inline void fast_set(FixedArray* array, int index, Object* value);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FixedArray);
+};
+
+
+// DescriptorArrays are fixed arrays used to hold instance descriptors.
+// The format of the these objects is:
+//   [0]: point to a fixed array with (value, detail) pairs.
+//   [1]: next enumeration index (Smi), or pointer to small fixed array:
+//          [0]: next enumeration index (Smi)
+//          [1]: pointer to fixed array with enum cache
+//   [2]: first key
+//   [length() - 1]: last key
+//
+class DescriptorArray: public FixedArray {
+ public:
+  // Is this the singleton empty_descriptor_array?
+  inline bool IsEmpty();
+  // Returns the number of descriptors in the array.
+  int number_of_descriptors() {
+    return IsEmpty() ? 0 : length() - kFirstIndex;
+  }
+
+  int NextEnumerationIndex() {
+    if (IsEmpty()) return PropertyDetails::kInitialIndex;
+    Object* obj = get(kEnumerationIndexIndex);
+    if (obj->IsSmi()) {
+      return Smi::cast(obj)->value();
+    } else {
+      Object* index = FixedArray::cast(obj)->get(kEnumCacheBridgeEnumIndex);
+      return Smi::cast(index)->value();
+    }
+  }
+
+  // Set next enumeration index and flush any enum cache.
+  void SetNextEnumerationIndex(int value) {
+    if (!IsEmpty()) {
+      fast_set(this, kEnumerationIndexIndex, Smi::FromInt(value));
+    }
+  }
+  bool HasEnumCache() {
+    return !IsEmpty() && !get(kEnumerationIndexIndex)->IsSmi();
+  }
+
+  Object* GetEnumCache() {
+    ASSERT(HasEnumCache());
+    FixedArray* bridge = FixedArray::cast(get(kEnumerationIndexIndex));
+    return bridge->get(kEnumCacheBridgeCacheIndex);
+  }
+
+  // Initialize or change the enum cache,
+  // using the supplied storage for the small "bridge".
+  void SetEnumCache(FixedArray* bridge_storage, FixedArray* new_cache);
+
+  // Accessors for fetching instance descriptor at descriptor number..
+  inline String* GetKey(int descriptor_number);
+  inline Object* GetValue(int descriptor_number);
+  inline Smi* GetDetails(int descriptor_number);
+
+  // Accessor for complete descriptor.
+  inline void Get(int descriptor_number, Descriptor* desc);
+  inline void Set(int descriptor_number, Descriptor* desc);
+
+  // Copy the descriptor array, insert a new descriptor and optionally
+  // remove map transitions.  If the descriptor is already present, it is
+  // replaced.  If a replaced descriptor is a real property (not a transition
+  // or null), its enumeration index is kept as is.
+  // If adding a real property, map transitions must be removed.  If adding
+  // a transition, they must not be removed.  All null descriptors are removed.
+  Object* CopyInsert(Descriptor* descriptor, TransitionFlag transition_flag);
+
+  // Remove all transitions.  Return  a copy of the array with all transitions
+  // removed, or a Failure object if the new array could not be allocated.
+  Object* RemoveTransitions();
+
+  // Sort the instance descriptors by the hash codes of their keys.
+  void Sort();
+
+  // Search the instance descriptors for given name.
+  inline int Search(String* name);
+
+  // Tells whether the name is present int the array.
+  bool Contains(String* name) { return kNotFound != Search(name); }
+
+  // Perform a binary search in the instance descriptors represented
+  // by this fixed array.  low and high are descriptor indices.  If there
+  // are three instance descriptors in this array it should be called
+  // with low=0 and high=2.
+  int BinarySearch(String* name, int low, int high);
+
+  // Perform a linear search in the instance descriptors represented
+  // by this fixed array.  len is the number of descriptor indeces that are
+  // valid.  Does not require the descriptors to be sorted.
+  int LinearSearch(String* name, int len);
+
+  // Allocates a DescriptorArray, but returns the singleton
+  // empty descriptor array object if number_of_descriptors is 0.
+  static Object* Allocate(int number_of_descriptors);
+
+  // Casting.
+  static inline DescriptorArray* cast(Object* obj);
+
+  // Constant for denoting key was not found.
+  static const int kNotFound = -1;
+
+  static const int kContentArrayIndex = 0;
+  static const int kEnumerationIndexIndex = 1;
+  static const int kFirstIndex = 2;
+
+  // The length of the "bridge" to the enum cache.
+  static const int kEnumCacheBridgeLength = 2;
+  static const int kEnumCacheBridgeEnumIndex = 0;
+  static const int kEnumCacheBridgeCacheIndex = 1;
+
+  // Layout description.
+  static const int kContentArrayOffset = FixedArray::kHeaderSize;
+  static const int kEnumerationIndexOffset = kContentArrayOffset + kPointerSize;
+  static const int kFirstOffset = kEnumerationIndexOffset + kPointerSize;
+
+  // Layout description for the bridge array.
+  static const int kEnumCacheBridgeEnumOffset = FixedArray::kHeaderSize;
+  static const int kEnumCacheBridgeCacheOffset =
+    kEnumCacheBridgeEnumOffset + kPointerSize;
+
+#ifdef DEBUG
+  // Print all the descriptors.
+  void PrintDescriptors();
+
+  // Is the descriptor array sorted and without duplicates?
+  bool IsSortedNoDuplicates();
+
+  // Are two DescriptorArrays equal?
+  bool IsEqualTo(DescriptorArray* other);
+#endif
+
+  // The maximum number of descriptors we want in a descriptor array (should
+  // fit in a page).
+  static const int kMaxNumberOfDescriptors = 1024 + 512;
+
+ private:
+  // Conversion from descriptor number to array indices.
+  static int ToKeyIndex(int descriptor_number) {
+    return descriptor_number+kFirstIndex;
+  }
+  static int ToValueIndex(int descriptor_number) {
+    return descriptor_number << 1;
+  }
+  static int ToDetailsIndex(int descriptor_number) {
+    return( descriptor_number << 1) + 1;
+  }
+
+  // Swap operation on FixedArray without using write barriers.
+  static inline void fast_swap(FixedArray* array, int first, int second);
+
+  // Swap descriptor first and second.
+  inline void Swap(int first, int second);
+
+  FixedArray* GetContentArray() {
+    return FixedArray::cast(get(kContentArrayIndex));
+  }
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DescriptorArray);
+};
+
+
+// HashTable is a subclass of FixedArray that implements a hash table
+// that uses open addressing and quadratic probing.
+//
+// In order for the quadratic probing to work, elements that have not
+// yet been used and elements that have been deleted are
+// distinguished.  Probing continues when deleted elements are
+// encountered and stops when unused elements are encountered.
+//
+// - Elements with key == undefined have not been used yet.
+// - Elements with key == null have been deleted.
+//
+// The hash table class is parameterized with a prefix size and with
+// the size, including the key size, of the elements held in the hash
+// table.  The prefix size indicates an amount of memory in the
+// beginning of the backing storage that can be used for non-element
+// information by subclasses.
+
+// HashTableKey is an abstract superclass keys.
+class HashTableKey {
+ public:
+  // Returns whether the other object matches this key.
+  virtual bool IsMatch(Object* other) = 0;
+  typedef uint32_t (*HashFunction)(Object* obj);
+  // Returns the hash function used for this key.
+  virtual HashFunction GetHashFunction() = 0;
+  // Returns the hash value for this key.
+  virtual uint32_t Hash() = 0;
+  // Returns the key object for storing into the dictionary.
+  // If allocations fails a failure object is returned.
+  virtual Object* GetObject() = 0;
+  virtual bool IsStringKey() = 0;
+  // Required.
+  virtual ~HashTableKey() {}
+};
+
+
+template<int prefix_size, int element_size>
+class HashTable: public FixedArray {
+ public:
+  // Returns the number of elements in the dictionary.
+  int NumberOfElements() {
+    return Smi::cast(get(kNumberOfElementsIndex))->value();
+  }
+
+  // Returns the capacity of the dictionary.
+  int Capacity() {
+    return Smi::cast(get(kCapacityIndex))->value();
+  }
+
+  // ElementAdded should be called whenever an element is added to a
+  // dictionary.
+  void ElementAdded() { SetNumberOfElements(NumberOfElements() + 1); }
+
+  // ElementRemoved should be called whenever an element is removed from
+  // a dictionary.
+  void ElementRemoved() { SetNumberOfElements(NumberOfElements() - 1); }
+  void ElementsRemoved(int n) { SetNumberOfElements(NumberOfElements() - n); }
+
+  // Returns a new array for dictionary usage. Might return Failure.
+  static Object* Allocate(int at_least_space_for);
+
+  // Returns the key at entry.
+  Object* KeyAt(int entry) { return get(EntryToIndex(entry)); }
+
+  // Tells wheter k is a real key.  Null and undefined are not allowed
+  // as keys and can be used to indicate missing or deleted elements.
+  bool IsKey(Object* k) {
+    return !k->IsNull() && !k->IsUndefined();
+  }
+
+  // Garbage collection support.
+  void IteratePrefix(ObjectVisitor* visitor);
+  void IterateElements(ObjectVisitor* visitor);
+
+  // Casting.
+  static inline HashTable* cast(Object* obj);
+
+  // Compute the probe offset (quadratic probing).
+  INLINE(static uint32_t GetProbeOffset(uint32_t n)) {
+    return (n + n * n) >> 1;
+  }
+
+  static const int kNumberOfElementsIndex = 0;
+  static const int kCapacityIndex         = 1;
+  static const int kPrefixStartIndex      = 2;
+  static const int kElementsStartIndex    = kPrefixStartIndex + prefix_size;
+  static const int kElementSize           = element_size;
+  static const int kElementsStartOffset   =
+      kHeaderSize + kElementsStartIndex * kPointerSize;
+
+ protected:
+  // Find entry for key otherwise return -1.
+  int FindEntry(HashTableKey* key);
+
+  // Find the entry at which to insert element with the given key that
+  // has the given hash value.
+  uint32_t FindInsertionEntry(Object* key, uint32_t hash);
+
+  // Returns the index for an entry (of the key)
+  static inline int EntryToIndex(int entry) {
+    return (entry * kElementSize) + kElementsStartIndex;
+  }
+
+  // Update the number of elements in the dictionary.
+  void SetNumberOfElements(int nof) {
+    fast_set(this, kNumberOfElementsIndex, Smi::FromInt(nof));
+  }
+
+  // Sets the capacity of the hash table.
+  void SetCapacity(int capacity) {
+    // To scale a computed hash code to fit within the hash table, we
+    // use bit-wise AND with a mask, so the capacity must be positive
+    // and non-zero.
+    ASSERT(capacity > 0);
+    fast_set(this, kCapacityIndex, Smi::FromInt(capacity));
+  }
+
+
+  // Returns probe entry.
+  static uint32_t GetProbe(uint32_t hash, uint32_t number, uint32_t size) {
+    ASSERT(IsPowerOf2(size));
+    return (hash + GetProbeOffset(number)) & (size - 1);
+  }
+
+  // Ensure enough space for n additional elements.
+  Object* EnsureCapacity(int n, HashTableKey* key);
+};
+
+
+// SymbolTable.
+//
+// No special elements in the prefix and the element size is 1
+// because only the symbol itself (the key) needs to be stored.
+class SymbolTable: public HashTable<0, 1> {
+ public:
+  // Find symbol in the symbol table.  If it is not there yet, it is
+  // added.  The return value is the symbol table which might have
+  // been enlarged.  If the return value is not a failure, the symbol
+  // pointer *s is set to the symbol found.
+  Object* LookupSymbol(Vector<const char> str, Object** s);
+  Object* LookupString(String* key, Object** s);
+
+  // Looks up a symbol that is equal to the given string and returns
+  // true if it is found, assigning the symbol to the given output
+  // parameter.
+  bool LookupSymbolIfExists(String* str, String** symbol);
+
+  // Casting.
+  static inline SymbolTable* cast(Object* obj);
+
+ private:
+  Object* LookupKey(HashTableKey* key, Object** s);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable);
+};
+
+
+// MapCache.
+//
+// Maps keys that are a fixed array of symbols to a map.
+// Used for canonicalize maps for object literals.
+class MapCache: public HashTable<0, 2> {
+ public:
+  // Find cached value for a string key, otherwise return null.
+  Object* Lookup(FixedArray* key);
+  Object* Put(FixedArray* key, Map* value);
+  static inline MapCache* cast(Object* obj);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MapCache);
+};
+
+
+// LookupCache.
+//
+// Maps a key consisting of a map and a name to an index within a
+// fast-case properties array.
+//
+// LookupCaches are used to avoid repeatedly searching instance
+// descriptors.
+class LookupCache: public HashTable<0, 2> {
+ public:
+  int Lookup(Map* map, String* name);
+  Object* Put(Map* map, String* name, int offset);
+  static inline LookupCache* cast(Object* obj);
+
+  // Constant returned by Lookup when the key was not found.
+  static const int kNotFound = -1;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(LookupCache);
+};
+
+
+// Dictionary for keeping properties and elements in slow case.
+//
+// One element in the prefix is used for storing non-element
+// information about the dictionary.
+//
+// The rest of the array embeds triples of (key, value, details).
+// if key == undefined the triple is empty.
+// if key == null the triple has been deleted.
+// otherwise key contains the name of a property.
+class DictionaryBase: public HashTable<2, 3> {};
+
+class Dictionary: public DictionaryBase {
+ public:
+  // Returns the value at entry.
+  Object* ValueAt(int entry) { return get(EntryToIndex(entry)+1); }
+
+  // Set the value for entry.
+  void ValueAtPut(int entry, Object* value) {
+    set(EntryToIndex(entry)+1, value);
+  }
+
+  // Returns the property details for the property at entry.
+  PropertyDetails DetailsAt(int entry) {
+    return PropertyDetails(Smi::cast(get(EntryToIndex(entry) + 2)));
+  }
+
+  // Set the details for entry.
+  void DetailsAtPut(int entry, PropertyDetails value) {
+    set(EntryToIndex(entry) + 2, value.AsSmi());
+  }
+
+  // Remove all entries were key is a number and (from <= key && key < to).
+  void RemoveNumberEntries(uint32_t from, uint32_t to);
+
+  // Sorting support
+  Object* RemoveHoles();
+  void CopyValuesTo(FixedArray* elements);
+
+  // Casting.
+  static inline Dictionary* cast(Object* obj);
+
+  // Find entry for string key otherwise return -1.
+  int FindStringEntry(String* key);
+
+  // Find entry for number key otherwise return -1.
+  int FindNumberEntry(uint32_t index);
+
+  // Delete a property from the dictionary.
+  Object* DeleteProperty(int entry);
+
+  // Type specific at put (default NONE attributes is used when adding).
+  Object* AtStringPut(String* key, Object* value);
+  Object* AtNumberPut(uint32_t key, Object* value);
+
+  Object* AddStringEntry(String* key, Object* value, PropertyDetails details);
+  Object* AddNumberEntry(uint32_t key, Object* value, PropertyDetails details);
+
+  // Set and existing string entry or add a new one if needed.
+  Object* SetOrAddStringEntry(String* key,
+                              Object* value,
+                              PropertyDetails details);
+
+  // Returns the number of elements in the dictionary filtering out properties
+  // with the specified attributes.
+  int NumberOfElementsFilterAttributes(PropertyAttributes filter);
+
+  // Returns the number of enumerable elements in the dictionary.
+  int NumberOfEnumElements();
+
+  // Copies keys to preallocated fixed array.
+  void CopyKeysTo(FixedArray* storage, PropertyAttributes filter);
+  // Copies enumerable keys to preallocated fixed array.
+  void CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array);
+  // Fill in details for properties into storage.
+  void CopyKeysTo(FixedArray* storage);
+
+  // Returns the value at entry.
+  static int ValueIndexFor(int entry) { return EntryToIndex(entry)+1; }
+
+  // For transforming properties of a JSObject.
+  Object* TransformPropertiesToFastFor(JSObject* obj,
+                                       int unused_property_fields);
+
+  // If slow elements are required we will never go back to fast-case
+  // for the elements kept in this dictionary.  We require slow
+  // elements if an element has been added at an index larger than
+  // kRequiresSlowElementsLimit.
+  inline bool requires_slow_elements();
+
+  // Get the value of the max number key that has been added to this
+  // dictionary.  max_number_key can only be called if
+  // requires_slow_elements returns false.
+  inline uint32_t max_number_key();
+
+  // Accessors for next enumeration index.
+  void SetNextEnumerationIndex(int index) {
+    fast_set(this, kNextEnumerationIndexIndex, Smi::FromInt(index));
+  }
+
+  int NextEnumerationIndex() {
+    return Smi::cast(get(kNextEnumerationIndexIndex))->value();
+  }
+
+  // Returns a new array for dictionary usage. Might return Failure.
+  static Object* Allocate(int at_least_space_for);
+
+  // Ensure enough space for n additional elements.
+  Object* EnsureCapacity(int n, HashTableKey* key);
+
+#ifdef DEBUG
+  void Print();
+#endif
+  // Returns the key (slow).
+  Object* SlowReverseLookup(Object* value);
+
+  // Bit masks.
+  static const int kRequiresSlowElementsMask = 1;
+  static const int kRequiresSlowElementsTagSize = 1;
+  static const uint32_t kRequiresSlowElementsLimit = (1 << 29) - 1;
+
+ private:
+  // Generic at put operation.
+  Object* AtPut(HashTableKey* key, Object* value);
+
+  Object* Add(HashTableKey* key, Object* value, PropertyDetails details);
+
+  // Add entry to dictionary.
+  void AddEntry(Object* key,
+                Object* value,
+                PropertyDetails details,
+                uint32_t hash);
+
+  // Sets the entry to (key, value) pair.
+  inline void SetEntry(int entry,
+                       Object* key,
+                       Object* value,
+                       PropertyDetails details);
+
+  void UpdateMaxNumberKey(uint32_t key);
+
+  // Generate new enumneration indices to avoid enumeration insdex overflow.
+  Object* GenerateNewEnumerationIndices();
+
+  static const int kMaxNumberKeyIndex = kPrefixStartIndex;
+  static const int kNextEnumerationIndexIndex = kMaxNumberKeyIndex + 1;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary);
+};
+
+
+// ByteArray represents fixed sized byte arrays.  Used by the outside world,
+// such as PCRE, and also by the memory allocator and garbage collector to
+// fill in free blocks in the heap.
+class ByteArray: public Array {
+ public:
+  // Setter and getter.
+  inline byte get(int index);
+  inline void set(int index, byte value);
+
+  // Treat contents as an int array.
+  inline int get_int(int index);
+
+  static int SizeFor(int length) {
+    return kHeaderSize + OBJECT_SIZE_ALIGN(length);
+  }
+  // We use byte arrays for free blocks in the heap.  Given a desired size in
+  // bytes that is a multiple of the word size and big enough to hold a byte
+  // array, this function returns the number of elements a byte array should
+  // have.
+  static int LengthFor(int size_in_bytes) {
+    ASSERT(IsAligned(size_in_bytes, kPointerSize));
+    ASSERT(size_in_bytes >= kHeaderSize);
+    return size_in_bytes - kHeaderSize;
+  }
+
+  // Returns data start address.
+  inline Address GetDataStartAddress();
+
+  // Returns a pointer to the ByteArray object for a given data start address.
+  static inline ByteArray* FromDataStartAddress(Address address);
+
+  // Casting.
+  static inline ByteArray* cast(Object* obj);
+
+  // Dispatched behavior.
+  int ByteArraySize() { return SizeFor(length()); }
+#ifdef DEBUG
+  void ByteArrayPrint();
+  void ByteArrayVerify();
+#endif
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArray);
+};
+
+
+// Code describes objects with on-the-fly generated machine code.
+class Code: public HeapObject {
+ public:
+  // Opaque data type for encapsulating code flags like kind, inline
+  // cache state, and arguments count.
+  enum Flags { };
+
+  enum Kind {
+    FUNCTION,
+    STUB,
+    BUILTIN,
+    LOAD_IC,
+    KEYED_LOAD_IC,
+    CALL_IC,
+    STORE_IC,
+    KEYED_STORE_IC,
+
+    // Pseudo-kinds.
+    FIRST_IC_KIND = LOAD_IC,
+    LAST_IC_KIND = KEYED_STORE_IC
+  };
+
+  enum {
+    NUMBER_OF_KINDS = LAST_IC_KIND + 1
+  };
+
+  // A state indicates that inline cache in this Code object contains
+  // objects or relative instruction addresses.
+  enum ICTargetState {
+    IC_TARGET_IS_ADDRESS,
+    IC_TARGET_IS_OBJECT
+  };
+
+#ifdef ENABLE_DISASSEMBLER
+  // Printing
+  static const char* Kind2String(Kind kind);
+  static const char* ICState2String(InlineCacheState state);
+  void Disassemble();
+#endif  // ENABLE_DISASSEMBLER
+
+  // [instruction_size]: Size of the native instructions
+  inline int instruction_size();
+  inline void set_instruction_size(int value);
+
+  // [relocation_size]: Size of relocation information.
+  inline int relocation_size();
+  inline void set_relocation_size(int value);
+
+  // [sinfo_size]: Size of scope information.
+  inline int sinfo_size();
+  inline void set_sinfo_size(int value);
+
+  // [flags]: Various code flags.
+  inline Flags flags();
+  inline void set_flags(Flags flags);
+
+  // [flags]: Access to specific code flags.
+  inline Kind kind();
+  inline InlineCacheState ic_state();  // only valid for IC stubs
+  inline PropertyType type();  // only valid for monomorphic IC stubs
+  inline int arguments_count();  // only valid for call IC stubs
+
+  // Testers for IC stub kinds.
+  inline bool is_inline_cache_stub();
+  inline bool is_load_stub() { return kind() == LOAD_IC; }
+  inline bool is_keyed_load_stub() { return kind() == KEYED_LOAD_IC; }
+  inline bool is_store_stub() { return kind() == STORE_IC; }
+  inline bool is_keyed_store_stub() { return kind() == KEYED_STORE_IC; }
+  inline bool is_call_stub() { return kind() == CALL_IC; }
+
+  // [ic_flag]: State of inline cache targets. The flag is set to the
+  // object variant in ConvertICTargetsFromAddressToObject, and set to
+  // the address variant in ConvertICTargetsFromObjectToAddress.
+  inline ICTargetState ic_flag();
+  inline void set_ic_flag(ICTargetState value);
+
+  // [major_key]: For kind STUB, the major key.
+  inline CodeStub::Major major_key();
+  inline void set_major_key(CodeStub::Major major);
+
+  // Flags operations.
+  static inline Flags ComputeFlags(Kind kind,
+                                   InlineCacheState ic_state = UNINITIALIZED,
+                                   PropertyType type = NORMAL,
+                                   int argc = -1);
+
+  static inline Flags ComputeMonomorphicFlags(Kind kind,
+                                              PropertyType type,
+                                              int argc = -1);
+
+  static inline Kind ExtractKindFromFlags(Flags flags);
+  static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
+  static inline PropertyType ExtractTypeFromFlags(Flags flags);
+  static inline int ExtractArgumentsCountFromFlags(Flags flags);
+  static inline Flags RemoveTypeFromFlags(Flags flags);
+
+
+  // Returns the address of the first instruction.
+  inline byte* instruction_start();
+
+  // Returns the size of the instructions, padding, and relocation information.
+  inline int body_size();
+
+  // Returns the address of the first relocation info (read backwards!).
+  inline byte* relocation_start();
+
+  // Code entry point.
+  inline byte* entry();
+
+  // Returns true if pc is inside this object's instructions.
+  inline bool contains(byte* pc);
+
+  // Returns the adddress of the scope information.
+  inline byte* sinfo_start();
+
+  // Convert inline cache target from address to code object before GC.
+  void ConvertICTargetsFromAddressToObject();
+
+  // Convert inline cache target from code object to address after GC
+  void ConvertICTargetsFromObjectToAddress();
+
+  // Relocate the code by delta bytes. Called to signal that this code
+  // object has been moved by delta bytes.
+  void Relocate(int delta);
+
+  // Migrate code described by desc.
+  void CopyFrom(const CodeDesc& desc);
+
+  // Returns the object size for a given body and sinfo size (Used for
+  // allocation).
+  static int SizeFor(int body_size, int sinfo_size) {
+    ASSERT_SIZE_TAG_ALIGNED(body_size);
+    ASSERT_SIZE_TAG_ALIGNED(sinfo_size);
+    return kHeaderSize + body_size + sinfo_size;
+  }
+
+  // Locating source position.
+  int SourcePosition(Address pc);
+  int SourceStatementPosition(Address pc);
+
+  // Casting.
+  static inline Code* cast(Object* obj);
+
+  // Dispatched behavior.
+  int CodeSize() { return SizeFor(body_size(), sinfo_size()); }
+  void CodeIterateBody(ObjectVisitor* v);
+#ifdef DEBUG
+  void CodePrint();
+  void CodeVerify();
+#endif
+
+  // Layout description.
+  static const int kInstructionSizeOffset = HeapObject::kHeaderSize;
+  static const int kRelocationSizeOffset = kInstructionSizeOffset + kIntSize;
+  static const int kSInfoSizeOffset = kRelocationSizeOffset + kIntSize;
+  static const int kFlagsOffset = kSInfoSizeOffset + kIntSize;
+  static const int kKindSpecificFlagsOffset  = kFlagsOffset + kIntSize;
+  static const int kHeaderSize = kKindSpecificFlagsOffset + kIntSize;
+
+  // Byte offsets within kKindSpecificFlagsOffset.
+  static const int kICFlagOffset = kKindSpecificFlagsOffset + 0;
+  static const int kStubMajorKeyOffset = kKindSpecificFlagsOffset + 1;
+
+  // Flags layout.
+  static const int kFlagsICStateShift        = 0;
+  static const int kFlagsKindShift           = 3;
+  static const int kFlagsTypeShift           = 6;
+  static const int kFlagsArgumentsCountShift = 9;
+
+  static const int kFlagsICStateMask        = 0x00000007;  // 000000111
+  static const int kFlagsKindMask           = 0x00000038;  // 000111000
+  static const int kFlagsTypeMask           = 0x000001C0;  // 111000000
+  static const int kFlagsArgumentsCountMask = 0xFFFFFE00;
+
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
+};
+
+
+// All heap objects have a Map that describes their structure.
+//  A Map contains information about:
+//  - Size information about the object
+//  - How to iterate over an object (for garbage collection)
+class Map: public HeapObject {
+ public:
+  // instance size.
+  inline int instance_size();
+  inline void set_instance_size(int value);
+
+  // Count of properties allocated in the object.
+  inline int inobject_properties();
+  inline void set_inobject_properties(int value);
+
+  // instance type.
+  inline InstanceType instance_type();
+  inline void set_instance_type(InstanceType value);
+
+  // tells how many unused property fields are available in the instance.
+  // (only used for JSObject in fast mode).
+  inline int unused_property_fields();
+  inline void set_unused_property_fields(int value);
+
+  // bit field.
+  inline byte bit_field();
+  inline void set_bit_field(byte value);
+
+  // Tells whether the object in the prototype property will be used
+  // for instances created from this function.  If the prototype
+  // property is set to a value that is not a JSObject, the prototype
+  // property will not be used to create instances of the function.
+  // See ECMA-262, 13.2.2.
+  inline void set_non_instance_prototype(bool value);
+  inline bool has_non_instance_prototype();
+
+  // Tells whether the instance with this map should be ignored by the
+  // __proto__ accessor.
+  inline void set_is_hidden_prototype() {
+    set_bit_field(bit_field() | (1 << kIsHiddenPrototype));
+  }
+
+  inline bool is_hidden_prototype() {
+    return ((1 << kIsHiddenPrototype) & bit_field()) != 0;
+  }
+
+  // Tells whether the instance has a named interceptor.
+  inline void set_has_named_interceptor() {
+    set_bit_field(bit_field() | (1 << kHasNamedInterceptor));
+  }
+
+  inline bool has_named_interceptor() {
+    return ((1 << kHasNamedInterceptor) & bit_field()) != 0;
+  }
+
+  // Tells whether the instance has a named interceptor.
+  inline void set_has_indexed_interceptor() {
+    set_bit_field(bit_field() | (1 << kHasIndexedInterceptor));
+  }
+
+  inline bool has_indexed_interceptor() {
+    return ((1 << kHasIndexedInterceptor) & bit_field()) != 0;
+  }
+
+  // Tells whether the instance is undetectable.
+  // An undetectable object is a special class of JSObject: 'typeof' operator
+  // returns undefined, ToBoolean returns false. Otherwise it behaves like
+  // a normal JS object.  It is useful for implementing undetectable
+  // document.all in Firefox & Safari.
+  // See https://bugzilla.mozilla.org/show_bug.cgi?id=248549.
+  inline void set_is_undetectable() {
+    set_bit_field(bit_field() | (1 << kIsUndetectable));
+  }
+
+  inline bool is_undetectable() {
+    return ((1 << kIsUndetectable) & bit_field()) != 0;
+  }
+
+  // Tells whether the instance has a call-as-function handler.
+  inline void set_has_instance_call_handler() {
+    set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
+  }
+
+  inline bool has_instance_call_handler() {
+    return ((1 << kHasInstanceCallHandler) & bit_field()) != 0;
+  }
+
+  // Tells whether the instance needs security checks when accessing its
+  // properties.
+  inline void set_is_access_check_needed() {
+    set_bit_field(bit_field() | (1 << kIsAccessCheckNeeded));
+  }
+
+  inline bool is_access_check_needed() {
+    return ((1 << kIsAccessCheckNeeded) & bit_field()) != 0;
+  }
+
+  // [prototype]: implicit prototype object.
+  DECL_ACCESSORS(prototype, Object)
+
+  // [constructor]: points back to the function responsible for this map.
+  DECL_ACCESSORS(constructor, Object)
+
+  // [instance descriptors]: describes the object.
+  DECL_ACCESSORS(instance_descriptors, DescriptorArray)
+
+  // [stub cache]: contains stubs compiled for this map.
+  DECL_ACCESSORS(code_cache, FixedArray)
+
+  // Returns a copy of the map.
+  Object* Copy();
+
+  // Returns a copy of the map, with all transitions dropped from the
+  // instance descriptors.
+  Object* CopyDropTransitions();
+
+  // Returns the property index for name (only valid for FAST MODE).
+  int PropertyIndexFor(String* name);
+
+  // Returns the next free property index (only valid for FAST MODE).
+  int NextFreePropertyIndex();
+
+  // Returns the number of properties described in instance_descriptors.
+  int NumberOfDescribedProperties();
+
+  // Casting.
+  static inline Map* cast(Object* obj);
+
+  // Locate an accessor in the instance descriptor.
+  AccessorDescriptor* FindAccessor(String* name);
+
+  // Code cache operations.
+
+  // Clears the code cache.
+  inline void ClearCodeCache();
+
+  // Update code cache.
+  Object* UpdateCodeCache(String* name, Code* code);
+
+  // Returns the found code or undefined if absent.
+  Object* FindInCodeCache(String* name, Code::Flags flags);
+
+  // Returns the non-negative index of the code object if it is in the
+  // cache and -1 otherwise.
+  int IndexInCodeCache(Code* code);
+
+  // Removes a code object from the code cache at the given index.
+  void RemoveFromCodeCache(int index);
+
+  // Dispatched behavior.
+  void MapIterateBody(ObjectVisitor* v);
+#ifdef DEBUG
+  void MapPrint();
+  void MapVerify();
+#endif
+
+  // Layout description.
+  static const int kInstanceSizesOffset = HeapObject::kHeaderSize;
+  static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize;
+  static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize;
+  static const int kConstructorOffset = kPrototypeOffset + kPointerSize;
+  static const int kInstanceDescriptorsOffset =
+      kConstructorOffset + kPointerSize;
+  static const int kCodeCacheOffset = kInstanceDescriptorsOffset + kPointerSize;
+  static const int kSize = kCodeCacheOffset + kIntSize;
+
+  // Byte offsets within kInstanceSizesOffset.
+  static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
+  static const int kInObjectPropertiesOffset = kInstanceSizesOffset + 1;
+  // The bytes at positions 2 and 3 are not in use at the moment.
+
+
+  // Byte offsets within kInstanceAttributesOffset attributes.
+  static const int kInstanceTypeOffset = kInstanceAttributesOffset + 0;
+  static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1;
+  static const int kBitFieldOffset = kInstanceAttributesOffset + 2;
+  // The  byte at position 3 is not in use at the moment.
+
+  // Bit positions for bit field.
+  static const int kUnused = 0;  // To be used for marking recently used maps.
+  static const int kHasNonInstancePrototype = 1;
+  static const int kIsHiddenPrototype = 2;
+  static const int kHasNamedInterceptor = 3;
+  static const int kHasIndexedInterceptor = 4;
+  static const int kIsUndetectable = 5;
+  static const int kHasInstanceCallHandler = 6;
+  static const int kIsAccessCheckNeeded = 7;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
+};
+
+
+// An abstract superclass, a marker class really, for simple structure classes.
+// It doesn't carry much functionality but allows struct classes to me
+// identified in the type system.
+class Struct: public HeapObject {
+ public:
+  inline void InitializeBody(int object_size);
+  static inline Struct* cast(Object* that);
+};
+
+
+// Script types.
+enum ScriptType {
+  SCRIPT_TYPE_NATIVE,
+  SCRIPT_TYPE_EXTENSION,
+  SCRIPT_TYPE_NORMAL
+};
+
+
+// Script describes a script which has been added to the VM.
+class Script: public Struct {
+ public:
+  // [source]: the script source.
+  DECL_ACCESSORS(source, Object)
+
+  // [name]: the script name.
+  DECL_ACCESSORS(name, Object)
+
+  // [line_offset]: script line offset in resource from where it was extracted.
+  DECL_ACCESSORS(line_offset, Smi)
+
+  // [column_offset]: script column offset in resource from where it was
+  // extracted.
+  DECL_ACCESSORS(column_offset, Smi)
+
+  // [wrapper]: the wrapper cache.
+  DECL_ACCESSORS(wrapper, Proxy)
+
+  // [type]: the script type.
+  DECL_ACCESSORS(type, Smi)
+
+  static inline Script* cast(Object* obj);
+
+#ifdef DEBUG
+  void ScriptPrint();
+  void ScriptVerify();
+#endif
+
+  static const int kSourceOffset = HeapObject::kHeaderSize;
+  static const int kNameOffset = kSourceOffset + kPointerSize;
+  static const int kLineOffsetOffset = kNameOffset + kPointerSize;
+  static const int kColumnOffsetOffset = kLineOffsetOffset + kPointerSize;
+  static const int kWrapperOffset = kColumnOffsetOffset + kPointerSize;
+  static const int kTypeOffset = kWrapperOffset + kPointerSize;
+  static const int kSize = kTypeOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Script);
+};
+
+
+// SharedFunctionInfo describes the JSFunction information that can be
+// shared by multiple instances of the function.
+class SharedFunctionInfo: public HeapObject {
+ public:
+  // [name]: Function name.
+  DECL_ACCESSORS(name, Object)
+
+  // [code]: Function code.
+  DECL_ACCESSORS(code, Code)
+
+  // Returns if this function has been compiled to native code yet.
+  inline bool is_compiled();
+
+  // [length]: The function length - usually the number of declared parameters.
+  // Use up to 2^30 parameters.
+  inline int length();
+  inline void set_length(int value);
+
+  // [formal parameter count]: The declared number of parameters.
+  inline int formal_parameter_count();
+  inline void set_formal_parameter_count(int value);
+
+  // Set the formal parameter count so the function code will be
+  // called without using argument adaptor frames.
+  inline void DontAdaptArguments();
+
+  // [expected_nof_properties]: Expected number of properties for the function.
+  inline int expected_nof_properties();
+  inline void set_expected_nof_properties(int value);
+
+  // [instance class name]: class name for instances.
+  DECL_ACCESSORS(instance_class_name, Object)
+
+  // [function data]: This field has been added for make benefit the API.
+  // In the long run we don't want all functions to have this field but
+  // we can fix that when we have a better model for storing hidden data
+  // on objects.
+  DECL_ACCESSORS(function_data, Object)
+
+  // [lazy load data]: If the function has lazy loading, this field
+  // contains contexts and other data needed to load it.
+  DECL_ACCESSORS(lazy_load_data, Object)
+
+  // [script info]: Script from which the function originates.
+  DECL_ACCESSORS(script, Object)
+
+  // [start_position_and_type]: Field used to store both the source code
+  // position, whether or not the function is a function expression,
+  // and whether or not the function is a toplevel function. The two
+  // least significants bit indicates whether the function is an
+  // expression and the rest contains the source code position.
+  inline int start_position_and_type();
+  inline void set_start_position_and_type(int value);
+
+  // [debug info]: Debug information.
+  DECL_ACCESSORS(debug_info, Object)
+
+  // Position of the 'function' token in the script source.
+  inline int function_token_position();
+  inline void set_function_token_position(int function_token_position);
+
+  // Position of this function in the script source.
+  inline int start_position();
+  inline void set_start_position(int start_position);
+
+  // End position of this function in the script source.
+  inline int end_position();
+  inline void set_end_position(int end_position);
+
+  // Is this function a function expression in the source code.
+  inline bool is_expression();
+  inline void set_is_expression(bool value);
+
+  // Is this function a top-level function. Used for accessing the
+  // caller of functions. Top-level functions (scripts, evals) are
+  // returned as null; see JSFunction::GetCallerAccessor(...).
+  inline bool is_toplevel();
+  inline void set_is_toplevel(bool value);
+
+  // [source code]: Source code for the function.
+  bool HasSourceCode();
+  Object* GetSourceCode();
+
+  // Dispatched behavior.
+  void SharedFunctionInfoIterateBody(ObjectVisitor* v);
+  // Set max_length to -1 for unlimited length.
+  void SourceCodePrint(StringStream* accumulator, int max_length);
+#ifdef DEBUG
+  void SharedFunctionInfoPrint();
+  void SharedFunctionInfoVerify();
+#endif
+
+  // Casting.
+  static inline SharedFunctionInfo* cast(Object* obj);
+
+  // Constants.
+  static const int kDontAdaptArgumentsSentinel = -1;
+
+  // Layout description.
+  static const int kNameOffset = HeapObject::kHeaderSize;
+  static const int kCodeOffset = kNameOffset + kPointerSize;
+  static const int kLengthOffset = kCodeOffset + kPointerSize;
+  static const int kFormalParameterCountOffset = kLengthOffset + kIntSize;
+  static const int kExpectedNofPropertiesOffset =
+      kFormalParameterCountOffset + kIntSize;
+  static const int kInstanceClassNameOffset =
+      kExpectedNofPropertiesOffset + kIntSize;
+  static const int kExternalReferenceDataOffset =
+      kInstanceClassNameOffset + kPointerSize;
+  static const int kLazyLoadDataOffset =
+      kExternalReferenceDataOffset + kPointerSize;
+  static const int kScriptOffset = kLazyLoadDataOffset + kPointerSize;
+  static const int kStartPositionAndTypeOffset = kScriptOffset + kPointerSize;
+  static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize;
+  static const int kFunctionTokenPositionOffset = kEndPositionOffset + kIntSize;
+  static const int kDebugInfoOffset = kFunctionTokenPositionOffset + kIntSize;
+  static const int kSize = kDebugInfoOffset + kPointerSize;
+
+ private:
+  // Bit positions in length_and_flg.
+  // The least significant bit is used as the flag.
+  static const int kFlagBit         = 0;
+  static const int kLengthShift     = 1;
+  static const int kLengthMask      = ~((1 << kLengthShift) - 1);
+
+  // Bit positions in start_position_and_type.
+  // The source code start position is in the 30 most significant bits of
+  // the start_position_and_type field.
+  static const int kIsExpressionBit = 0;
+  static const int kIsTopLevelBit   = 1;
+  static const int kStartPositionShift = 2;
+  static const int kStartPositionMask = ~((1 << kStartPositionShift) - 1);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
+};
+
+
+// JSFunction describes JavaScript functions.
+class JSFunction: public JSObject {
+ public:
+  // [prototype_or_initial_map]:
+  DECL_ACCESSORS(prototype_or_initial_map, Object)
+
+  // [shared_function_info]: The information about the function that
+  // can be shared by instances.
+  DECL_ACCESSORS(shared, SharedFunctionInfo)
+
+  // [context]: The context for this function.
+  inline Context* context();
+  inline Object* unchecked_context();
+  inline void set_context(Object* context);
+
+  // [code]: The generated code object for this function.  Executed
+  // when the function is invoked, e.g. foo() or new foo(). See
+  // [[Call]] and [[Construct]] description in ECMA-262, section
+  // 8.6.2, page 27.
+  inline Code* code();
+  inline void set_code(Code* value);
+
+  // Tells whether this function is a context-independent boilerplate
+  // function.
+  inline bool IsBoilerplate();
+
+  // Tells whether this function needs to be loaded.
+  inline bool IsLoaded();
+
+  // [literals]: Fixed array holding the materialized literals.
+  //
+  // If the function contains object, regexp or array literals, the
+  // literals array prefix contains the object, regexp, and array
+  // function to be used when creating these literals.  This is
+  // necessary so that we do not dynamically lookup the object, regexp
+  // or array functions.  Performing a dynamic lookup, we might end up
+  // using the functions from a new context that we should not have
+  // access to.
+  DECL_ACCESSORS(literals, FixedArray)
+
+  // The initial map for an object created by this constructor.
+  inline Map* initial_map();
+  inline void set_initial_map(Map* value);
+  inline bool has_initial_map();
+
+  // Get and set the prototype property on a JSFunction. If the
+  // function has an initial map the prototype is set on the initial
+  // map. Otherwise, the prototype is put in the initial map field
+  // until an initial map is needed.
+  inline bool has_prototype();
+  inline bool has_instance_prototype();
+  inline Object* prototype();
+  inline Object* instance_prototype();
+  Object* SetInstancePrototype(Object* value);
+  Object* SetPrototype(Object* value);
+
+  // Accessor for this function's initial map's [[class]]
+  // property. This is primarily used by ECMA native functions.  This
+  // method sets the class_name field of this function's initial map
+  // to a given value. It creates an initial map if this function does
+  // not have one. Note that this method does not copy the initial map
+  // if it has one already, but simply replaces it with the new value.
+  // Instances created afterwards will have a map whose [[class]] is
+  // set to 'value', but there is no guarantees on instances created
+  // before.
+  Object* SetInstanceClassName(String* name);
+
+  // Returns if this function has been compiled to native code yet.
+  inline bool is_compiled();
+
+  // Casting.
+  static inline JSFunction* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef DEBUG
+  void JSFunctionPrint();
+  void JSFunctionVerify();
+#endif
+
+  // Returns the number of allocated literals.
+  inline int NumberOfLiterals();
+
+  // Retrieve the global context from a function's literal array.
+  static Context* GlobalContextFromLiterals(FixedArray* literals);
+
+  // Layout descriptors.
+  static const int kPrototypeOrInitialMapOffset = JSObject::kHeaderSize;
+  static const int kSharedFunctionInfoOffset =
+      kPrototypeOrInitialMapOffset + kPointerSize;
+  static const int kContextOffset = kSharedFunctionInfoOffset + kPointerSize;
+  static const int kLiteralsOffset = kContextOffset + kPointerSize;
+  static const int kSize = kLiteralsOffset + kPointerSize;
+
+  // Layout of the literals array.
+  static const int kLiteralsPrefixSize = 1;
+  static const int kLiteralGlobalContextIndex = 0;
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSFunction);
+};
+
+
+// JSGlobalProxy's prototype must be a JSGlobalObject or null,
+// and the prototype is hidden. JSGlobalProxy always delegates
+// property accesses to its prototype if the prototype is not null.
+//
+// A JSGlobalProxy can be reinitialized which will preserve its identity.
+//
+// Accessing a JSGlobalProxy requires security check.
+
+class JSGlobalProxy : public JSObject {
+ public:
+  // [context]: the owner global context of this proxy object.
+  // It is null value if this object is not used by any context.
+  DECL_ACCESSORS(context, Object)
+
+  // Casting.
+  static inline JSGlobalProxy* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef DEBUG
+  void JSGlobalProxyPrint();
+  void JSGlobalProxyVerify();
+#endif
+
+  // Layout description.
+  static const int kContextOffset = JSObject::kHeaderSize;
+  static const int kSize = kContextOffset + kPointerSize;
+
+ private:
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalProxy);
+};
+
+
+// Forward declaration.
+class JSBuiltinsObject;
+
+// Common super class for JavaScript global objects and the special
+// builtins global objects.
+class GlobalObject: public JSObject {
+ public:
+  // [builtins]: the object holding the runtime routines written in JS.
+  DECL_ACCESSORS(builtins, JSBuiltinsObject)
+
+  // [global context]: the global context corresponding to this global objet.
+  DECL_ACCESSORS(global_context, Context)
+
+  // [global receiver]: the global receiver object of the context
+  DECL_ACCESSORS(global_receiver, JSObject)
+
+  // Casting.
+  static inline GlobalObject* cast(Object* obj);
+
+  // Layout description.
+  static const int kBuiltinsOffset = JSObject::kHeaderSize;
+  static const int kGlobalContextOffset = kBuiltinsOffset + kPointerSize;
+  static const int kGlobalReceiverOffset = kGlobalContextOffset + kPointerSize;
+  static const int kHeaderSize = kGlobalReceiverOffset + kPointerSize;
+
+ private:
+  friend class AGCCVersionRequiresThisClassToHaveAFriendSoHereItIs;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(GlobalObject);
+};
+
+
+// JavaScript global object.
+class JSGlobalObject: public GlobalObject {
+ public:
+  // Casting.
+  static inline JSGlobalObject* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef DEBUG
+  void JSGlobalObjectPrint();
+  void JSGlobalObjectVerify();
+#endif
+
+  // Layout description.
+  static const int kSize = GlobalObject::kHeaderSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalObject);
+};
+
+
+// Builtins global object which holds the runtime routines written in
+// JavaScript.
+class JSBuiltinsObject: public GlobalObject {
+ public:
+  // Accessors for the runtime routines written in JavaScript.
+  inline Object* javascript_builtin(Builtins::JavaScript id);
+  inline void set_javascript_builtin(Builtins::JavaScript id, Object* value);
+
+  // Casting.
+  static inline JSBuiltinsObject* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef DEBUG
+  void JSBuiltinsObjectPrint();
+  void JSBuiltinsObjectVerify();
+#endif
+
+  // Layout description.  The size of the builtins object includes
+  // room for one pointer per runtime routine written in javascript.
+  static const int kJSBuiltinsCount = Builtins::id_count;
+  static const int kJSBuiltinsOffset = GlobalObject::kHeaderSize;
+  static const int kSize =
+      kJSBuiltinsOffset + (kJSBuiltinsCount * kPointerSize);
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSBuiltinsObject);
+};
+
+
+// Representation for JS Wrapper objects, String, Number, Boolean, Date, etc.
+class JSValue: public JSObject {
+ public:
+  // [value]: the object being wrapped.
+  DECL_ACCESSORS(value, Object)
+
+  // Casting.
+  static inline JSValue* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef DEBUG
+  void JSValuePrint();
+  void JSValueVerify();
+#endif
+
+  // Layout description.
+  static const int kValueOffset = JSObject::kHeaderSize;
+  static const int kSize = kValueOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSValue);
+};
+
+// Regular expressions
+class JSRegExp: public JSObject {
+ public:
+  // Meaning of Type:
+  // NOT_COMPILED: Initial value. No data has been stored in the JSRegExp yet.
+  // JSCRE: A complex regexp meant for JSCRE.
+  // ATOM: A simple string to match against using an indexOf-operation.
+  enum Type { NOT_COMPILED, JSCRE, ATOM };
+  enum Flag { NONE = 0, GLOBAL = 1, IGNORE_CASE = 2, MULTILINE = 4 };
+
+  class Flags {
+   public:
+    explicit Flags(uint32_t value) : value_(value) { }
+    bool is_global() { return (value_ & GLOBAL) != 0; }
+    bool is_ignore_case() { return (value_ & IGNORE_CASE) != 0; }
+    bool is_multiline() { return (value_ & MULTILINE) != 0; }
+    uint32_t value() { return value_; }
+   private:
+    uint32_t value_;
+  };
+
+  DECL_ACCESSORS(data, Object)
+
+  inline Type TypeTag();
+  inline Object* DataAt(int index);
+
+  static inline JSRegExp* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef DEBUG
+  void JSRegExpPrint();
+  void JSRegExpVerify();
+#endif
+
+  static const int kDataOffset = JSObject::kHeaderSize;
+  static const int kSize = kDataOffset + kIntSize;
+
+  static const int kTagIndex = 0;
+  static const int kSourceIndex = kTagIndex + 1;
+  static const int kFlagsIndex = kSourceIndex + 1;
+  // These two are the same since the same entry is shared for
+  // different purposes in different types of regexps.
+  static const int kAtomPatternIndex = kFlagsIndex + 1;
+  static const int kJscreDataIndex = kFlagsIndex + 1;
+  static const int kDataSize = kAtomPatternIndex + 1;
+};
+
+
+class CompilationCacheTable: public HashTable<0, 2> {
+ public:
+  // Find cached value for a string key, otherwise return null.
+  Object* Lookup(String* src);
+  Object* LookupRegExp(String* source, JSRegExp::Flags flags);
+  Object* Put(String* src, Object* value);
+  Object* PutRegExp(String* src, JSRegExp::Flags flags, FixedArray* value);
+
+  static inline CompilationCacheTable* cast(Object* obj);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheTable);
+};
+
+
+enum AllowNullsFlag {ALLOW_NULLS, DISALLOW_NULLS};
+enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL};
+
+
+class StringHasher {
+ public:
+  inline StringHasher(int length);
+
+  // Returns true if the hash of this string can be computed without
+  // looking at the contents.
+  inline bool has_trivial_hash();
+
+  // Add a character to the hash and update the array index calculation.
+  inline void AddCharacter(uc32 c);
+
+  // Adds a character to the hash but does not update the array index
+  // calculation.  This can only be called when it has been verified
+  // that the input is not an array index.
+  inline void AddCharacterNoIndex(uc32 c);
+
+  // Returns the value to store in the hash field of a string with
+  // the given length and contents.
+  uint32_t GetHashField();
+
+  // Returns true if the characters seen so far make up a legal array
+  // index.
+  bool is_array_index() { return is_array_index_; }
+
+  bool is_valid() { return is_valid_; }
+
+  void invalidate() { is_valid_ = false; }
+
+ private:
+
+  uint32_t array_index() {
+    ASSERT(is_array_index());
+    return array_index_;
+  }
+
+  inline uint32_t GetHash();
+
+  int length_;
+  uint32_t raw_running_hash_;
+  uint32_t array_index_;
+  bool is_array_index_;
+  bool is_first_char_;
+  bool is_valid_;
+};
+
+
+// The String abstract class captures JavaScript string values:
+//
+// Ecma-262:
+//  4.3.16 String Value
+//    A string value is a member of the type String and is a finite
+//    ordered sequence of zero or more 16-bit unsigned integer values.
+//
+// All string values have a length field.
+class String: public HeapObject {
+ public:
+  // Get and set the length of the string.
+  inline int length();
+  inline void set_length(int value);
+
+  // Get and set the uninterpreted length field of the string.  Notice
+  // that the length field is also used to cache the hash value of
+  // strings.  In order to get or set the actual length of the string
+  // use the length() and set_length methods.
+  inline uint32_t length_field();
+  inline void set_length_field(uint32_t value);
+
+  // Get and set individual two byte chars in the string.
+  inline void Set(int index, uint16_t value);
+  // Get individual two byte char in the string.  Repeated calls
+  // to this method are not efficient unless the string is flat.
+  inline uint16_t Get(int index);
+
+  // Flatten the top level ConsString that is hiding behind this
+  // string.  This is a no-op unless the string is a ConsString or a
+  // SlicedString.  Flatten mutates the ConsString and might return a
+  // failure.
+  Object* Flatten();
+  // Try to flatten the string.  Do not allow handling of allocation
+  // failures.  After calling TryFlatten, the string could still be a
+  // ConsString.
+  inline void TryFlatten();
+
+  // Is this string an ascii string.
+  inline bool IsAsciiRepresentation();
+
+  // Specialization of this function from Object that skips the
+  // string check.
+  inline bool IsSeqAsciiString();
+
+  // Fast testing routines that assume the receiver is a string and
+  // just check whether it is a certain kind of string.
+  inline bool StringIsSlicedString();
+  inline bool StringIsConsString();
+
+  Vector<const char> ToAsciiVector();
+  Vector<const uc16> ToUC16Vector();
+
+  // Mark the string as an undetectable object. It only applies to
+  // ascii and two byte string types.
+  bool MarkAsUndetectable();
+
+  // Slice the string and return a substring.
+  Object* Slice(int from, int to);
+
+  // String equality operations.
+  inline bool Equals(String* other);
+  bool IsEqualTo(Vector<const char> str);
+
+  // Return a UTF8 representation of the string.  The string is null
+  // terminated but may optionally contain nulls.  Length is returned
+  // in length_output if length_output is not a null pointer  The string
+  // should be nearly flat, otherwise the performance of this method may
+  // be very slow (quadratic in the length).  Setting robustness_flag to
+  // 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(
+      AllowNullsFlag allow_nulls = DISALLOW_NULLS,
+      RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL,
+      int* length_output = 0);
+
+  int Utf8Length();
+
+  // Return a 16 bit Unicode representation of the string.
+  // The string should be nearly flat, otherwise the performance of
+  // of this method may be very bad.  Setting robustness_flag to
+  // 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(
+      RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL);
+
+  // Tells whether the hash code has been computed.
+  inline bool HasHashCode();
+
+  // Returns a hash value used for the property table
+  inline uint32_t Hash();
+
+  static uint32_t ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
+                                            int length);
+
+  static bool ComputeArrayIndex(unibrow::CharacterStream* buffer,
+                                uint32_t* index,
+                                int length);
+
+  // Conversion.
+  inline bool AsArrayIndex(uint32_t* index);
+
+  // Casting.
+  static inline String* cast(Object* obj);
+
+  void PrintOn(FILE* out);
+
+  // Get the size tag.
+  inline uint32_t size_tag();
+  static inline uint32_t map_size_tag(Map* map);
+
+  // True if the string is a symbol.
+  inline bool is_symbol();
+  static inline bool is_symbol_map(Map* map);
+
+  // True if the string is ASCII.
+  inline bool is_ascii_representation();
+  static inline bool is_ascii_representation_map(Map* map);
+
+  // Get the representation tag.
+  inline StringRepresentationTag representation_tag();
+  // Get the representation and ASCII tag.
+  inline int full_representation_tag();
+  static inline StringRepresentationTag map_representation_tag(Map* map);
+
+  // For use during stack traces.  Performs rudimentary sanity check.
+  bool LooksValid();
+
+  // Dispatched behavior.
+  void StringShortPrint(StringStream* accumulator);
+#ifdef DEBUG
+  void StringPrint();
+  void StringVerify();
+#endif
+  inline bool IsFlat();
+
+  // Layout description.
+  static const int kLengthOffset = HeapObject::kHeaderSize;
+  static const int kSize = kLengthOffset + kIntSize;
+
+  // Limits on sizes of different types of strings.
+  static const int kMaxShortStringSize = 255;
+  static const int kMaxMediumStringSize = 65535;
+
+  static const int kMaxArrayIndexSize = 10;
+
+  // Max ascii char code.
+  static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar;
+
+  // Minimum length for a cons or sliced string.
+  static const int kMinNonFlatLength = 13;
+
+  // Mask constant for checking if a string has a computed hash code
+  // and if it is an array index.  The least significant bit indicates
+  // whether a hash code has been computed.  If the hash code has been
+  // computed the 2nd bit tells whether the string can be used as an
+  // array index.
+  static const int kHashComputedMask = 1;
+  static const int kIsArrayIndexMask = 1 << 1;
+  static const int kNofLengthBitFields = 2;
+
+  // Array index strings this short can keep their index in the hash
+  // field.
+  static const int kMaxCachedArrayIndexLength = 6;
+
+  // Shift constants for retriving length and hash code from
+  // length/hash field.
+  static const int kHashShift = kNofLengthBitFields;
+  static const int kShortLengthShift = 3 * kBitsPerByte;
+  static const int kMediumLengthShift = 2 * kBitsPerByte;
+  static const int kLongLengthShift = kHashShift;
+
+  // Limit for truncation in short printing.
+  static const int kMaxShortPrintLength = 1024;
+
+  // Support for regular expressions.
+  const uc16* GetTwoByteData();
+  const uc16* GetTwoByteData(unsigned start);
+
+  // Support for StringInputBuffer
+  static const unibrow::byte* ReadBlock(String* input,
+                                        unibrow::byte* util_buffer,
+                                        unsigned capacity,
+                                        unsigned* remaining,
+                                        unsigned* offset);
+  static const unibrow::byte* ReadBlock(String** input,
+                                        unibrow::byte* util_buffer,
+                                        unsigned capacity,
+                                        unsigned* remaining,
+                                        unsigned* offset);
+
+  // Helper function for flattening strings.
+  template <typename sinkchar>
+  static void WriteToFlat(String* source,
+                          sinkchar* sink,
+                          int from,
+                          int to);
+
+ protected:
+  class ReadBlockBuffer {
+   public:
+    ReadBlockBuffer(unibrow::byte* util_buffer_,
+                    unsigned cursor_,
+                    unsigned capacity_,
+                    unsigned remaining_) :
+      util_buffer(util_buffer_),
+      cursor(cursor_),
+      capacity(capacity_),
+      remaining(remaining_) {
+    }
+    unibrow::byte* util_buffer;
+    unsigned       cursor;
+    unsigned       capacity;
+    unsigned       remaining;
+  };
+
+  // NOTE: If you call StringInputBuffer routines on strings that are
+  // too deeply nested trees of cons and slice strings, then this
+  // routine will overflow the stack. Strings that are merely deeply
+  // nested trees of cons strings do not have a problem apart from
+  // performance.
+
+  static inline const unibrow::byte* ReadBlock(String* input,
+                                               ReadBlockBuffer* buffer,
+                                               unsigned* offset,
+                                               unsigned max_chars);
+  static void ReadBlockIntoBuffer(String* input,
+                                  ReadBlockBuffer* buffer,
+                                  unsigned* offset_ptr,
+                                  unsigned max_chars);
+
+ private:
+  // Slow case of String::Equals.  This implementation works on any strings
+  // but it is most efficient on strings that are almost flat.
+  bool SlowEquals(String* other);
+
+  // Slow case of AsArrayIndex.
+  bool SlowAsArrayIndex(uint32_t* index);
+
+  // Compute and set the hash code.
+  uint32_t ComputeAndSetHash();
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(String);
+};
+
+
+// The SeqString abstract class captures sequential string values.
+class SeqString: public String {
+ public:
+
+  // Casting.
+  static inline SeqString* cast(Object* obj);
+
+  // Dispatched behaviour.
+  // For regexp code.
+  uint16_t* SeqStringGetTwoByteAddress();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString);
+};
+
+
+// The AsciiString class captures sequential ascii string objects.
+// Each character in the AsciiString is an ascii character.
+class SeqAsciiString: public SeqString {
+ public:
+  // Dispatched behavior.
+  inline uint16_t SeqAsciiStringGet(int index);
+  inline void SeqAsciiStringSet(int index, uint16_t value);
+
+  // Get the address of the characters in this string.
+  inline Address GetCharsAddress();
+
+  inline char* GetChars();
+
+  // Casting
+  static inline SeqAsciiString* cast(Object* obj);
+
+  // Garbage collection support.  This method is called by the
+  // garbage collector to compute the actual size of an AsciiString
+  // instance.
+  inline int SeqAsciiStringSize(Map* map);
+
+  // Computes the size for an AsciiString instance of a given length.
+  static int SizeFor(int length) {
+    return kHeaderSize + OBJECT_SIZE_ALIGN(length * kCharSize);
+  }
+
+  // Layout description.
+  static const int kHeaderSize = String::kSize;
+
+  // Support for StringInputBuffer.
+  inline void SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                                unsigned* offset,
+                                                unsigned chars);
+  inline const unibrow::byte* SeqAsciiStringReadBlock(unsigned* remaining,
+                                                      unsigned* offset,
+                                                      unsigned chars);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SeqAsciiString);
+};
+
+
+// The TwoByteString class captures sequential unicode string objects.
+// Each character in the TwoByteString is a two-byte uint16_t.
+class SeqTwoByteString: public SeqString {
+ public:
+  // Dispatched behavior.
+  inline uint16_t SeqTwoByteStringGet(int index);
+  inline void SeqTwoByteStringSet(int index, uint16_t value);
+
+  // Get the address of the characters in this string.
+  inline Address GetCharsAddress();
+
+  inline uc16* GetChars();
+
+  // For regexp code.
+  const uint16_t* SeqTwoByteStringGetData(unsigned start);
+
+  // Casting
+  static inline SeqTwoByteString* cast(Object* obj);
+
+  // Garbage collection support.  This method is called by the
+  // garbage collector to compute the actual size of a TwoByteString
+  // instance.
+  inline int SeqTwoByteStringSize(Map* map);
+
+  // Computes the size for a TwoByteString instance of a given length.
+  static int SizeFor(int length) {
+    return kHeaderSize + OBJECT_SIZE_ALIGN(length * kShortSize);
+  }
+
+  // Layout description.
+  static const int kHeaderSize = String::kSize;
+
+  // Support for StringInputBuffer.
+  inline void SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                                  unsigned* offset_ptr,
+                                                  unsigned chars);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SeqTwoByteString);
+};
+
+
+// The ConsString class describes string values built by using the
+// addition operator on strings.  A ConsString is a pair where the
+// first and second components are pointers to other string values.
+// One or both components of a ConsString can be pointers to other
+// ConsStrings, creating a binary tree of ConsStrings where the leaves
+// are non-ConsString string values.  The string value represented by
+// a ConsString can be obtained by concatenating the leaf string
+// values in a left-to-right depth-first traversal of the tree.
+class ConsString: public String {
+ public:
+  // First object of the cons cell.
+  inline Object* first();
+  inline void set_first(Object* first,
+                        WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
+  // Second object of the cons cell.
+  inline Object* second();
+  inline void set_second(Object* second,
+                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
+  // Dispatched behavior.
+  uint16_t ConsStringGet(int index);
+
+  // Casting.
+  static inline ConsString* cast(Object* obj);
+
+  // Garbage collection support.  This method is called during garbage
+  // collection to iterate through the heap pointers in the body of
+  // the ConsString.
+  void ConsStringIterateBody(ObjectVisitor* v);
+
+  // Layout description.
+  static const int kFirstOffset = String::kSize;
+  static const int kSecondOffset = kFirstOffset + kPointerSize;
+  static const int kSize = kSecondOffset + kPointerSize;
+
+  // Support for StringInputBuffer.
+  inline const unibrow::byte* ConsStringReadBlock(ReadBlockBuffer* buffer,
+                                                  unsigned* offset_ptr,
+                                                  unsigned chars);
+  inline void ConsStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                            unsigned* offset_ptr,
+                                            unsigned chars);
+
+  // Minimum length for a cons string.
+  static const int kMinLength = 13;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ConsString);
+};
+
+
+// The SlicedString class describes string values that are slices of
+// some other string.  SlicedStrings consist of a reference to an
+// underlying heap-allocated string value, a start index, and the
+// length field common to all strings.
+class SlicedString: public String {
+ public:
+  // The underlying string buffer.
+  inline Object* buffer();
+  inline void set_buffer(Object* buffer);
+
+  // The start index of the slice.
+  inline int start();
+  inline void set_start(int start);
+
+  // Dispatched behavior.
+  uint16_t SlicedStringGet(int index);
+
+  // Flatten any ConsString hiding behind this SlicedString.
+  Object* SlicedStringFlatten();
+
+  // Casting.
+  static inline SlicedString* cast(Object* obj);
+
+  // Garbage collection support.
+  void SlicedStringIterateBody(ObjectVisitor* v);
+
+  // Layout description
+  static const int kBufferOffset = String::kSize;
+  static const int kStartOffset = kBufferOffset + kPointerSize;
+  static const int kSize = kStartOffset + kIntSize;
+
+  // Support for StringInputBuffer.
+  inline const unibrow::byte* SlicedStringReadBlock(ReadBlockBuffer* buffer,
+                                                    unsigned* offset_ptr,
+                                                    unsigned chars);
+  inline void SlicedStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                              unsigned* offset_ptr,
+                                              unsigned chars);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SlicedString);
+};
+
+
+// The ExternalString class describes string values that are backed by
+// a string resource that lies outside the V8 heap.  ExternalStrings
+// consist of the length field common to all strings, a pointer to the
+// external resource.  It is important to ensure (externally) that the
+// resource is not deallocated while the ExternalString is live in the
+// V8 heap.
+//
+// The API expects that all ExternalStrings are created through the
+// API.  Therefore, ExternalStrings should not be used internally.
+class ExternalString: public String {
+ public:
+  // Casting
+  static inline ExternalString* cast(Object* obj);
+
+  // Layout description.
+  static const int kResourceOffset = String::kSize;
+  static const int kSize = kResourceOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalString);
+};
+
+
+// The ExternalAsciiString class is an external string backed by an
+// ASCII string.
+class ExternalAsciiString: public ExternalString {
+ public:
+  typedef v8::String::ExternalAsciiStringResource Resource;
+
+  // The underlying resource.
+  inline Resource* resource();
+  inline void set_resource(Resource* buffer);
+
+  // Dispatched behavior.
+  uint16_t ExternalAsciiStringGet(int index);
+
+  // Casting.
+  static inline ExternalAsciiString* cast(Object* obj);
+
+  // Support for StringInputBuffer.
+  const unibrow::byte* ExternalAsciiStringReadBlock(unsigned* remaining,
+                                                    unsigned* offset,
+                                                    unsigned chars);
+  inline void ExternalAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                                     unsigned* offset,
+                                                     unsigned chars);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalAsciiString);
+};
+
+
+// The ExternalTwoByteString class is an external string backed by a UTF-16
+// encoded string.
+class ExternalTwoByteString: public ExternalString {
+ public:
+  typedef v8::String::ExternalStringResource Resource;
+
+  // The underlying string resource.
+  inline Resource* resource();
+  inline void set_resource(Resource* buffer);
+
+  // Dispatched behavior.
+  uint16_t ExternalTwoByteStringGet(int index);
+
+  // For regexp code.
+  const uint16_t* ExternalTwoByteStringGetData(unsigned start);
+
+  // Casting.
+  static inline ExternalTwoByteString* cast(Object* obj);
+
+  // Support for StringInputBuffer.
+  void ExternalTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer,
+                                                unsigned* offset_ptr,
+                                                unsigned chars);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString);
+};
+
+
+// Note that StringInputBuffers are not valid across a GC!  To fix this
+// it would have to store a String Handle instead of a String* and
+// AsciiStringReadBlock would have to be modified to use memcpy.
+//
+// StringInputBuffer is able to traverse any string regardless of how
+// deeply nested a sequence of ConsStrings it is made of.  However,
+// performance will be better if deep strings are flattened before they
+// are traversed.  Since flattening requires memory allocation this is
+// not always desirable, however (esp. in debugging situations).
+class StringInputBuffer: public unibrow::InputBuffer<String, String*, 1024> {
+ public:
+  virtual void Seek(unsigned pos);
+  inline StringInputBuffer(): unibrow::InputBuffer<String, String*, 1024>() {}
+  inline StringInputBuffer(String* backing):
+      unibrow::InputBuffer<String, String*, 1024>(backing) {}
+};
+
+
+class SafeStringInputBuffer
+  : public unibrow::InputBuffer<String, String**, 256> {
+ public:
+  virtual void Seek(unsigned pos);
+  inline SafeStringInputBuffer()
+      : unibrow::InputBuffer<String, String**, 256>() {}
+  inline SafeStringInputBuffer(String** backing)
+      : unibrow::InputBuffer<String, String**, 256>(backing) {}
+};
+
+
+template <typename T>
+class VectorIterator {
+ public:
+  VectorIterator(T* d, int l) : data_(Vector<const T>(d, l)), index_(0) { }
+  explicit VectorIterator(Vector<const T> data) : data_(data), index_(0) { }
+  T GetNext() { return data_[index_++]; }
+  bool has_more() { return index_ < data_.length(); }
+ private:
+  Vector<const T> data_;
+  int index_;
+};
+
+
+// The Oddball describes objects null, undefined, true, and false.
+class Oddball: public HeapObject {
+ public:
+  // [to_string]: Cached to_string computed at startup.
+  DECL_ACCESSORS(to_string, String)
+
+  // [to_number]: Cached to_number computed at startup.
+  DECL_ACCESSORS(to_number, Object)
+
+  // Casting.
+  static inline Oddball* cast(Object* obj);
+
+  // Dispatched behavior.
+  void OddballIterateBody(ObjectVisitor* v);
+#ifdef DEBUG
+  void OddballVerify();
+#endif
+
+  // Initialize the fields.
+  Object* Initialize(const char* to_string, Object* to_number);
+
+  // Layout description.
+  static const int kToStringOffset = HeapObject::kHeaderSize;
+  static const int kToNumberOffset = kToStringOffset + kPointerSize;
+  static const int kSize = kToNumberOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Oddball);
+};
+
+
+// Proxy describes objects pointing from JavaScript to C structures.
+// Since they cannot contain references to JS HeapObjects they can be
+// placed in old_data_space.
+class Proxy: public HeapObject {
+ public:
+  // [proxy]: field containing the address.
+  inline Address proxy();
+  inline void set_proxy(Address value);
+
+  // Casting.
+  static inline Proxy* cast(Object* obj);
+
+  // Dispatched behavior.
+  inline void ProxyIterateBody(ObjectVisitor* v);
+#ifdef DEBUG
+  void ProxyPrint();
+  void ProxyVerify();
+#endif
+
+  // Layout description.
+
+  static const int kProxyOffset = HeapObject::kHeaderSize;
+  static const int kSize = kProxyOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Proxy);
+};
+
+
+// The JSArray describes JavaScript Arrays
+//  Such an array can be in one of two modes:
+//    - fast, backing storage is a FixedArray and length <= elements.length();
+//       Please note: push and pop can be used to grow and shrink the array.
+//    - slow, backing storage is a HashTable with numbers as keys.
+class JSArray: public JSObject {
+ public:
+  // [length]: The length property.
+  DECL_ACCESSORS(length, Object)
+
+  Object* JSArrayUpdateLengthFromIndex(uint32_t index, Object* value);
+
+  // Initialize the array with the given capacity. The function may
+  // fail due to out-of-memory situations, but only if the requested
+  // capacity is non-zero.
+  Object* Initialize(int capacity);
+
+  // Set the content of the array to the content of storage.
+  inline void SetContent(FixedArray* storage);
+
+  // Support for sorting
+  Object* RemoveHoles();
+
+  // Casting.
+  static inline JSArray* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef DEBUG
+  void JSArrayPrint();
+  void JSArrayVerify();
+#endif
+
+  // Layout description.
+  static const int kLengthOffset = JSObject::kHeaderSize;
+  static const int kSize = kLengthOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSArray);
+};
+
+
+// An accesor must have a getter, but can have no setter.
+//
+// When setting a property, V8 searches accessors in prototypes.
+// If an accessor was found and it does not have a setter,
+// the request is ignored.
+//
+// To allow shadow an accessor property, the accessor can
+// have READ_ONLY property attribute so that a new value
+// is added to the local object to shadow the accessor
+// in prototypes.
+class AccessorInfo: public Struct {
+ public:
+  DECL_ACCESSORS(getter, Object)
+  DECL_ACCESSORS(setter, Object)
+  DECL_ACCESSORS(data, Object)
+  DECL_ACCESSORS(name, Object)
+  DECL_ACCESSORS(flag, Smi)
+
+  inline bool all_can_read();
+  inline void set_all_can_read(bool value);
+
+  inline bool all_can_write();
+  inline void set_all_can_write(bool value);
+
+  inline PropertyAttributes property_attributes();
+  inline void set_property_attributes(PropertyAttributes attributes);
+
+  static inline AccessorInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void AccessorInfoPrint();
+  void AccessorInfoVerify();
+#endif
+
+  static const int kGetterOffset = HeapObject::kHeaderSize;
+  static const int kSetterOffset = kGetterOffset + kPointerSize;
+  static const int kDataOffset = kSetterOffset + kPointerSize;
+  static const int kNameOffset = kDataOffset + kPointerSize;
+  static const int kFlagOffset = kNameOffset + kPointerSize;
+  static const int kSize = kFlagOffset + kPointerSize;
+
+ private:
+  // Bit positions in flag.
+  static const int kAllCanReadBit  = 0;
+  static const int kAllCanWriteBit = 1;
+  class AttributesField: public BitField<PropertyAttributes, 2, 3> {};
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorInfo);
+};
+
+
+class AccessCheckInfo: public Struct {
+ public:
+  DECL_ACCESSORS(named_callback, Object)
+  DECL_ACCESSORS(indexed_callback, Object)
+  DECL_ACCESSORS(data, Object)
+
+  static inline AccessCheckInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void AccessCheckInfoPrint();
+  void AccessCheckInfoVerify();
+#endif
+
+  static const int kNamedCallbackOffset   = HeapObject::kHeaderSize;
+  static const int kIndexedCallbackOffset = kNamedCallbackOffset + kPointerSize;
+  static const int kDataOffset = kIndexedCallbackOffset + kPointerSize;
+  static const int kSize = kDataOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(AccessCheckInfo);
+};
+
+
+class InterceptorInfo: public Struct {
+ public:
+  DECL_ACCESSORS(getter, Object)
+  DECL_ACCESSORS(setter, Object)
+  DECL_ACCESSORS(query, Object)
+  DECL_ACCESSORS(deleter, Object)
+  DECL_ACCESSORS(enumerator, Object)
+  DECL_ACCESSORS(data, Object)
+
+  static inline InterceptorInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void InterceptorInfoPrint();
+  void InterceptorInfoVerify();
+#endif
+
+  static const int kGetterOffset = HeapObject::kHeaderSize;
+  static const int kSetterOffset = kGetterOffset + kPointerSize;
+  static const int kQueryOffset = kSetterOffset + kPointerSize;
+  static const int kDeleterOffset = kQueryOffset + kPointerSize;
+  static const int kEnumeratorOffset = kDeleterOffset + kPointerSize;
+  static const int kDataOffset = kEnumeratorOffset + kPointerSize;
+  static const int kSize = kDataOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
+};
+
+
+class CallHandlerInfo: public Struct {
+ public:
+  DECL_ACCESSORS(callback, Object)
+  DECL_ACCESSORS(data, Object)
+
+  static inline CallHandlerInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void CallHandlerInfoPrint();
+  void CallHandlerInfoVerify();
+#endif
+
+  static const int kCallbackOffset = HeapObject::kHeaderSize;
+  static const int kDataOffset = kCallbackOffset + kPointerSize;
+  static const int kSize = kDataOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CallHandlerInfo);
+};
+
+
+class TemplateInfo: public Struct {
+ public:
+  DECL_ACCESSORS(tag, Object)
+  DECL_ACCESSORS(property_list, Object)
+
+#ifdef DEBUG
+  void TemplateInfoVerify();
+#endif
+
+  static const int kTagOffset          = HeapObject::kHeaderSize;
+  static const int kPropertyListOffset = kTagOffset + kPointerSize;
+  static const int kHeaderSize         = kPropertyListOffset + kPointerSize;
+ protected:
+  friend class AGCCVersionRequiresThisClassToHaveAFriendSoHereItIs;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TemplateInfo);
+};
+
+
+class FunctionTemplateInfo: public TemplateInfo {
+ public:
+  DECL_ACCESSORS(serial_number, Object)
+  DECL_ACCESSORS(call_code, Object)
+  DECL_ACCESSORS(property_accessors, Object)
+  DECL_ACCESSORS(prototype_template, Object)
+  DECL_ACCESSORS(parent_template, Object)
+  DECL_ACCESSORS(named_property_handler, Object)
+  DECL_ACCESSORS(indexed_property_handler, Object)
+  DECL_ACCESSORS(instance_template, Object)
+  DECL_ACCESSORS(class_name, Object)
+  DECL_ACCESSORS(signature, Object)
+  DECL_ACCESSORS(instance_call_handler, Object)
+  DECL_ACCESSORS(access_check_info, Object)
+  DECL_ACCESSORS(flag, Smi)
+
+  // Following properties use flag bits.
+  DECL_BOOLEAN_ACCESSORS(hidden_prototype)
+  DECL_BOOLEAN_ACCESSORS(undetectable)
+  // If the bit is set, object instances created by this function
+  // requires access check.
+  DECL_BOOLEAN_ACCESSORS(needs_access_check)
+
+  static inline FunctionTemplateInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void FunctionTemplateInfoPrint();
+  void FunctionTemplateInfoVerify();
+#endif
+
+  static const int kSerialNumberOffset = TemplateInfo::kHeaderSize;
+  static const int kCallCodeOffset = kSerialNumberOffset + kPointerSize;
+  static const int kPropertyAccessorsOffset = kCallCodeOffset + kPointerSize;
+  static const int kPrototypeTemplateOffset =
+      kPropertyAccessorsOffset + kPointerSize;
+  static const int kParentTemplateOffset =
+      kPrototypeTemplateOffset + kPointerSize;
+  static const int kNamedPropertyHandlerOffset =
+      kParentTemplateOffset + kPointerSize;
+  static const int kIndexedPropertyHandlerOffset =
+      kNamedPropertyHandlerOffset + kPointerSize;
+  static const int kInstanceTemplateOffset =
+      kIndexedPropertyHandlerOffset + kPointerSize;
+  static const int kClassNameOffset = kInstanceTemplateOffset + kPointerSize;
+  static const int kSignatureOffset = kClassNameOffset + kPointerSize;
+  static const int kInstanceCallHandlerOffset = kSignatureOffset + kPointerSize;
+  static const int kAccessCheckInfoOffset =
+      kInstanceCallHandlerOffset + kPointerSize;
+  static const int kFlagOffset = kAccessCheckInfoOffset + kPointerSize;
+  static const int kSize = kFlagOffset + kPointerSize;
+
+ private:
+  // Bit position in the flag, from least significant bit position.
+  static const int kHiddenPrototypeBit   = 0;
+  static const int kUndetectableBit      = 1;
+  static const int kNeedsAccessCheckBit  = 2;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo);
+};
+
+
+class ObjectTemplateInfo: public TemplateInfo {
+ public:
+  DECL_ACCESSORS(constructor, Object)
+  DECL_ACCESSORS(internal_field_count, Object)
+
+  static inline ObjectTemplateInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void ObjectTemplateInfoPrint();
+  void ObjectTemplateInfoVerify();
+#endif
+
+  static const int kConstructorOffset = TemplateInfo::kHeaderSize;
+  static const int kInternalFieldCountOffset =
+      kConstructorOffset + kPointerSize;
+  static const int kSize = kInternalFieldCountOffset + kHeaderSize;
+};
+
+
+class SignatureInfo: public Struct {
+ public:
+  DECL_ACCESSORS(receiver, Object)
+  DECL_ACCESSORS(args, Object)
+
+  static inline SignatureInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void SignatureInfoPrint();
+  void SignatureInfoVerify();
+#endif
+
+  static const int kReceiverOffset = Struct::kHeaderSize;
+  static const int kArgsOffset     = kReceiverOffset + kPointerSize;
+  static const int kSize           = kArgsOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SignatureInfo);
+};
+
+
+class TypeSwitchInfo: public Struct {
+ public:
+  DECL_ACCESSORS(types, Object)
+
+  static inline TypeSwitchInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void TypeSwitchInfoPrint();
+  void TypeSwitchInfoVerify();
+#endif
+
+  static const int kTypesOffset = Struct::kHeaderSize;
+  static const int kSize        = kTypesOffset + kPointerSize;
+};
+
+
+// The DebugInfo class holds additional information for a function beeing
+// debugged.
+class DebugInfo: public Struct {
+ public:
+  // The shared function info for the source beeing debugged.
+  DECL_ACCESSORS(shared, SharedFunctionInfo)
+  // Code object for the original code.
+  DECL_ACCESSORS(original_code, Code)
+  // Code object for the patched code. This code object is the code object
+  // currently active for the function.
+  DECL_ACCESSORS(code, Code)
+  // Fixed array holding status information for each active break point.
+  DECL_ACCESSORS(break_points, FixedArray)
+
+  // Check if there is a break point at a code position.
+  bool HasBreakPoint(int code_position);
+  // Get the break point info object for a code position.
+  Object* GetBreakPointInfo(int code_position);
+  // Clear a break point.
+  static void ClearBreakPoint(Handle<DebugInfo> debug_info,
+                              int code_position,
+                              Handle<Object> break_point_object);
+  // Set a break point.
+  static void SetBreakPoint(Handle<DebugInfo> debug_info, int code_position,
+                            int source_position, int statement_position,
+                            Handle<Object> break_point_object);
+  // Get the break point objects for a code position.
+  Object* GetBreakPointObjects(int code_position);
+  // Find the break point info holding this break point object.
+  static Object* FindBreakPointInfo(Handle<DebugInfo> debug_info,
+                                    Handle<Object> break_point_object);
+  // Get the number of break points for this function.
+  int GetBreakPointCount();
+
+  static inline DebugInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void DebugInfoPrint();
+  void DebugInfoVerify();
+#endif
+
+  static const int kSharedFunctionInfoIndex = Struct::kHeaderSize;
+  static const int kOriginalCodeIndex = kSharedFunctionInfoIndex + kPointerSize;
+  static const int kPatchedCodeIndex = kOriginalCodeIndex + kPointerSize;
+  static const int kActiveBreakPointsCountIndex =
+      kPatchedCodeIndex + kPointerSize;
+  static const int kBreakPointsStateIndex =
+      kActiveBreakPointsCountIndex + kPointerSize;
+  static const int kSize = kBreakPointsStateIndex + kPointerSize;
+
+ private:
+  static const int kNoBreakPointInfo = -1;
+
+  // Lookup the index in the break_points array for a code position.
+  int GetBreakPointInfoIndex(int code_position);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DebugInfo);
+};
+
+
+// The BreakPointInfo class holds information for break points set in a
+// function. The DebugInfo object holds a BreakPointInfo object for each code
+// position with one or more break points.
+class BreakPointInfo: public Struct {
+ public:
+  // The position in the code for the break point.
+  DECL_ACCESSORS(code_position, Smi)
+  // The position in the source for the break position.
+  DECL_ACCESSORS(source_position, Smi)
+  // The position in the source for the last statement before this break
+  // position.
+  DECL_ACCESSORS(statement_position, Smi)
+  // List of related JavaScript break points.
+  DECL_ACCESSORS(break_point_objects, Object)
+
+  // Removes a break point.
+  static void ClearBreakPoint(Handle<BreakPointInfo> info,
+                              Handle<Object> break_point_object);
+  // Set a break point.
+  static void SetBreakPoint(Handle<BreakPointInfo> info,
+                            Handle<Object> break_point_object);
+  // Check if break point info has this break point object.
+  static bool HasBreakPointObject(Handle<BreakPointInfo> info,
+                                  Handle<Object> break_point_object);
+  // Get the number of break points for this code position.
+  int GetBreakPointCount();
+
+  static inline BreakPointInfo* cast(Object* obj);
+
+#ifdef DEBUG
+  void BreakPointInfoPrint();
+  void BreakPointInfoVerify();
+#endif
+
+  static const int kCodePositionIndex = Struct::kHeaderSize;
+  static const int kSourcePositionIndex = kCodePositionIndex + kPointerSize;
+  static const int kStatementPositionIndex =
+      kSourcePositionIndex + kPointerSize;
+  static const int kBreakPointObjectsIndex =
+      kStatementPositionIndex + kPointerSize;
+  static const int kSize = kBreakPointObjectsIndex + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BreakPointInfo);
+};
+
+
+#undef DECL_BOOLEAN_ACCESSORS
+#undef DECL_ACCESSORS
+
+
+// Abstract base class for visiting, and optionally modifying, the
+// pointers contained in Objects. Used in GC and serialization/deserialization.
+class ObjectVisitor BASE_EMBEDDED {
+ public:
+  virtual ~ObjectVisitor() {}
+
+  // Visits a contiguous arrays of pointers in the half-open range
+  // [start, end). Any or all of the values may be modified on return.
+  virtual void VisitPointers(Object** start, Object** end) = 0;
+
+  // To allow lazy clearing of inline caches the visitor has
+  // a rich interface for iterating over Code objects..
+
+  // Called prior to visiting the body of a Code object.
+  virtual void BeginCodeIteration(Code* code);
+
+  // Visits a code target in the instruction stream.
+  virtual void VisitCodeTarget(RelocInfo* rinfo);
+
+  // Visits a runtime entry in the instruction stream.
+  virtual void VisitRuntimeEntry(RelocInfo* rinfo) {}
+
+  // Visits a debug call target in the instruction stream.
+  virtual void VisitDebugTarget(RelocInfo* rinfo);
+
+  // Called after completing  visiting the body of a Code object.
+  virtual void EndCodeIteration(Code* code) {}
+
+  // Handy shorthand for visiting a single pointer.
+  virtual void VisitPointer(Object** p) { VisitPointers(p, p + 1); }
+
+  // Visits a contiguous arrays of external references (references to the C++
+  // heap) in the half-open range [start, end). Any or all of the values
+  // may be modified on return.
+  virtual void VisitExternalReferences(Address* start, Address* end) {}
+
+  inline void VisitExternalReference(Address* p) {
+    VisitExternalReferences(p, p + 1);
+  }
+
+#ifdef DEBUG
+  // Intended for serialization/deserialization checking: insert, or
+  // check for the presence of, a tag at this position in the stream.
+  virtual void Synchronize(const char* tag) {}
+#endif
+};
+
+
+// BooleanBit is a helper class for setting and getting a bit in an
+// integer or Smi.
+class BooleanBit : public AllStatic {
+ public:
+  static inline bool get(Smi* smi, int bit_position) {
+    return get(smi->value(), bit_position);
+  }
+
+  static inline bool get(int value, int bit_position) {
+    return (value & (1 << bit_position)) != 0;
+  }
+
+  static inline Smi* set(Smi* smi, int bit_position, bool v) {
+    return Smi::FromInt(set(smi->value(), bit_position, v));
+  }
+
+  static inline int set(int value, int bit_position, bool v) {
+    if (v) {
+      value |= (1 << bit_position);
+    } else {
+      value &= ~(1 << bit_position);
+    }
+    return value;
+  }
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_OBJECTS_H_
diff --git a/regexp2000/src/parser.cc b/regexp2000/src/parser.cc
new file mode 100644 (file)
index 0000000..faca81b
--- /dev/null
@@ -0,0 +1,3982 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "ast.h"
+#include "bootstrapper.h"
+#include "platform.h"
+#include "runtime.h"
+#include "parser.h"
+#include "scopes.h"
+#include "string-stream.h"
+
+namespace v8 { namespace internal {
+
+class ParserFactory;
+class ParserLog;
+class TemporaryScope;
+template <typename T> class ZoneListWrapper;
+
+
+class Parser {
+ public:
+  Parser(Handle<Script> script, bool allow_natives_syntax,
+         v8::Extension* extension, bool is_pre_parsing,
+         ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data);
+  virtual ~Parser() { }
+
+  // Pre-parse the program from the character stream; returns true on
+  // success, false if a stack-overflow happened during parsing.
+  bool PreParseProgram(unibrow::CharacterStream* stream);
+
+  void ReportMessage(const char* message, Vector<const char*> args);
+  virtual void ReportMessageAt(Scanner::Location loc,
+                               const char* message,
+                               Vector<const char*> args) = 0;
+
+
+  // Returns NULL if parsing failed.
+  FunctionLiteral* ParseProgram(Handle<String> source,
+                                unibrow::CharacterStream* stream,
+                                bool in_global_context);
+  FunctionLiteral* ParseLazy(Handle<String> source,
+                             Handle<String> name,
+                             int start_position, bool is_expression);
+
+ protected:
+
+  enum Mode {
+    PARSE_LAZILY,
+    PARSE_EAGERLY
+  };
+
+  // Report syntax error
+  void ReportUnexpectedToken(Token::Value token);
+
+  Handle<Script> script_;
+  Scanner scanner_;
+
+  Scope* top_scope_;
+  int with_nesting_level_;
+
+  TemporaryScope* temp_scope_;
+  Mode mode_;
+  List<Node*>* target_stack_;  // for break, continue statements
+  bool allow_natives_syntax_;
+  v8::Extension* extension_;
+  ParserFactory* factory_;
+  ParserLog* log_;
+  bool is_pre_parsing_;
+  ScriptDataImpl* pre_data_;
+
+  bool inside_with() const  { return with_nesting_level_ > 0; }
+  ParserFactory* factory() const  { return factory_; }
+  ParserLog* log() const { return log_; }
+  Scanner& scanner()  { return scanner_; }
+  Mode mode() const  { return mode_; }
+  ScriptDataImpl* pre_data() const  { return pre_data_; }
+
+  // All ParseXXX functions take as the last argument an *ok parameter
+  // which is set to false if parsing failed; it is unchanged otherwise.
+  // By making the 'exception handling' explicit, we are forced to check
+  // for failure at the call sites.
+  void* ParseSourceElements(ZoneListWrapper<Statement>* processor,
+                            int end_token, bool* ok);
+  Statement* ParseStatement(ZoneStringList* labels, bool* ok);
+  Statement* ParseFunctionDeclaration(bool* ok);
+  Statement* ParseNativeDeclaration(bool* ok);
+  Block* ParseBlock(ZoneStringList* labels, bool* ok);
+  Block* ParseVariableStatement(bool* ok);
+  Block* ParseVariableDeclarations(bool accept_IN, Expression** var, bool* ok);
+  Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
+                                                bool* ok);
+  IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok);
+  Statement* ParseContinueStatement(bool* ok);
+  Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok);
+  Statement* ParseReturnStatement(bool* ok);
+  Block* WithHelper(Expression* obj, ZoneStringList* labels, bool* ok);
+  Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
+  CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
+  SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
+  LoopStatement* ParseDoStatement(ZoneStringList* labels, bool* ok);
+  LoopStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok);
+  Statement* ParseForStatement(ZoneStringList* labels, bool* ok);
+  Statement* ParseThrowStatement(bool* ok);
+  Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
+  TryStatement* ParseTryStatement(bool* ok);
+  DebuggerStatement* ParseDebuggerStatement(bool* ok);
+
+  Expression* ParseExpression(bool accept_IN, bool* ok);
+  Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);
+  Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
+  Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
+  Expression* ParseUnaryExpression(bool* ok);
+  Expression* ParsePostfixExpression(bool* ok);
+  Expression* ParseLeftHandSideExpression(bool* ok);
+  Expression* ParseNewExpression(bool* ok);
+  Expression* ParseMemberExpression(bool* ok);
+  Expression* ParseMemberWithNewPrefixesExpression(List<int>* new_prefixes,
+                                                   bool* ok);
+  Expression* ParsePrimaryExpression(bool* ok);
+  Expression* ParseArrayLiteral(bool* ok);
+  Expression* ParseObjectLiteral(bool* ok);
+  Expression* ParseRegExpLiteral(bool seen_equal, bool* ok);
+
+  // Decide if a property should be the object boilerplate.
+  bool IsBoilerplateProperty(ObjectLiteral::Property* property);
+  // If the property is CONSTANT type, it returns the literal value,
+  // otherwise, it return undefined literal as the placeholder
+  // in the object literal boilerplate.
+  Literal* GetBoilerplateValue(ObjectLiteral::Property* property);
+
+  enum FunctionLiteralType {
+    EXPRESSION,
+    DECLARATION,
+    NESTED
+  };
+
+  ZoneList<Expression*>* ParseArguments(bool* ok);
+  FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name,
+                                        int function_token_position,
+                                        FunctionLiteralType type,
+                                        bool* ok);
+
+
+  // Magical syntax support.
+  Expression* ParseV8Intrinsic(bool* ok);
+
+  INLINE(Token::Value peek()) { return scanner_.peek(); }
+  INLINE(Token::Value Next()) { return scanner_.Next(); }
+  INLINE(void Consume(Token::Value token));
+  void Expect(Token::Value token, bool* ok);
+  void ExpectSemicolon(bool* ok);
+
+  // Get odd-ball literals.
+  Literal* GetLiteralUndefined();
+  Literal* GetLiteralTheHole();
+  Literal* GetLiteralNumber(double value);
+
+  Handle<String> ParseIdentifier(bool* ok);
+  Handle<String> ParseIdentifierOrGetOrSet(bool* is_get,
+                                           bool* is_set,
+                                           bool* ok);
+
+  // Parser support
+  virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
+                                 FunctionLiteral* fun,
+                                 bool resolve,
+                                 bool* ok) = 0;
+
+  bool TargetStackContainsLabel(Handle<String> label);
+  BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok);
+  IterationStatement* LookupContinueTarget(Handle<String> label, bool* ok);
+
+  void RegisterLabelUse(Label* label, int index);
+
+  // Create a number literal.
+  Literal* NewNumberLiteral(double value);
+
+  // Generate AST node that throw a ReferenceError with the given type.
+  Expression* NewThrowReferenceError(Handle<String> type);
+
+  // Generate AST node that throw a SyntaxError with the given
+  // type. The first argument may be null (in the handle sense) in
+  // which case no arguments are passed to the constructor.
+  Expression* NewThrowSyntaxError(Handle<String> type, Handle<Object> first);
+
+  // Generate AST node that throw a TypeError with the given
+  // type. Both arguments must be non-null (in the handle sense).
+  Expression* NewThrowTypeError(Handle<String> type,
+                                Handle<Object> first,
+                                Handle<Object> second);
+
+  // Generic AST generator for throwing errors from compiled code.
+  Expression* NewThrowError(Handle<String> constructor,
+                            Handle<String> type,
+                            Vector< Handle<Object> > arguments);
+
+  friend class Target;
+  friend class TargetScope;
+  friend class LexicalScope;
+  friend class TemporaryScope;
+};
+
+
+class RegExpParser {
+ public:
+  RegExpParser(unibrow::CharacterStream* in,
+               Handle<String>* error,
+               bool multiline_mode);
+  RegExpTree* ParsePattern(bool* ok);
+  RegExpTree* ParseDisjunction(bool* ok);
+  RegExpTree* ParseAlternative(bool* ok);
+  RegExpTree* ParseTerm(bool* ok);
+  RegExpTree* ParseAtom(bool* ok);
+  RegExpTree* ParseGroup(bool* ok);
+  RegExpTree* ParseCharacterClass(bool* ok);
+
+  // Parses a {...,...} quantifier and stores the range in the given
+  // out parameters.
+  void* ParseIntervalQuantifier(int* min_out, int* max_out, bool* ok);
+
+  // Parses and returns a single escaped character.  The character
+  // must not be 'b' or 'B' since they are usually handle specially.
+  uc32 ParseCharacterEscape(bool* ok);
+
+  // Checks whether the following is a length-digit hexadecimal number,
+  // and sets the value if it is.
+  bool ParseHexEscape(int length, uc32* value);
+
+  uc32 ParseControlEscape(bool* ok);
+  uc32 ParseOctalLiteral(bool* ok);
+
+  // Tries to parse the input as a backreference.  If successful it
+  // stores the result in the output parameter and returns true.  If
+  // it fails it will push back the characters read so the same characters
+  // can be reparsed.
+  bool ParseBackreferenceIndex(int* index_out);
+
+  CharacterRange ParseClassAtom(bool* ok);
+  RegExpTree* ReportError(Vector<const char> message, bool* ok);
+  void Advance();
+  void Advance(int dist);
+  // Pushes a read character (or potentially some other character) back
+  // on the input stream. After pushing it back, it becomes the character
+  // returned by current(). There is a limited amount of push-back buffer.
+  // A function using PushBack should check that it doesn't push back more
+  // than kMaxPushback characters, and it should not push back more characters
+  // than it has read, or that it knows had been read prior to calling it.
+  void PushBack(uc32 character);
+  bool CanPushBack();
+  static const uc32 kEndMarker = unibrow::Utf8::kBadChar;
+ private:
+  uc32 current() { return current_; }
+  uc32 next() { return next_; }
+  bool has_more() { return has_more_; }
+  bool has_next() { return has_next_; }
+  unibrow::CharacterStream* in() { return in_; }
+  uc32 current_;
+  uc32 next_;
+  bool has_more_;
+  bool has_next_;
+  bool multiline_mode_;
+  int captures_seen_;
+  unibrow::CharacterStream* in_;
+  Handle<String>* error_;
+  static const int kMaxPushback = 5;
+  int pushback_count_;
+  uc32 pushback_buffer_[kMaxPushback];
+};
+
+
+// A temporary scope stores information during parsing, just like
+// a plain scope.  However, temporary scopes are not kept around
+// after parsing or referenced by syntax trees so they can be stack-
+// allocated and hence used by the pre-parser.
+class TemporaryScope BASE_EMBEDDED {
+ public:
+  explicit TemporaryScope(Parser* parser);
+  ~TemporaryScope();
+
+  int NextMaterializedLiteralIndex() {
+    int next_index =
+        materialized_literal_count_ + JSFunction::kLiteralsPrefixSize;
+    materialized_literal_count_++;
+    return next_index;
+  }
+  int materialized_literal_count() { return materialized_literal_count_; }
+
+  void set_contains_array_literal() { contains_array_literal_ = true; }
+  bool contains_array_literal() { return contains_array_literal_; }
+
+  void AddProperty() { expected_property_count_++; }
+  int expected_property_count() { return expected_property_count_; }
+ private:
+  // Captures the number of nodes that need materialization in the
+  // function.  regexp literals, and boilerplate for object literals.
+  int materialized_literal_count_;
+
+  // Captures whether or not the function contains array literals.  If
+  // the function contains array literals, we have to allocate space
+  // for the array constructor in the literals array of the function.
+  // This array constructor is used when creating the actual array
+  // literals.
+  bool contains_array_literal_;
+
+  // Properties count estimation.
+  int expected_property_count_;
+
+  // Bookkeeping
+  Parser* parser_;
+  TemporaryScope* parent_;
+
+  friend class Parser;
+};
+
+
+TemporaryScope::TemporaryScope(Parser* parser)
+  : materialized_literal_count_(0),
+    contains_array_literal_(false),
+    expected_property_count_(0),
+    parser_(parser),
+    parent_(parser->temp_scope_) {
+  parser->temp_scope_ = this;
+}
+
+
+TemporaryScope::~TemporaryScope() {
+  parser_->temp_scope_ = parent_;
+}
+
+
+// A zone list wrapper lets code either access a access a zone list
+// or appear to do so while actually ignoring all operations.
+template <typename T>
+class ZoneListWrapper {
+ public:
+  ZoneListWrapper() : list_(NULL) { }
+  explicit ZoneListWrapper(int size) : list_(new ZoneList<T*>(size)) { }
+  void Add(T* that) { if (list_) list_->Add(that); }
+  int length() { return list_->length(); }
+  ZoneList<T*>* elements() { return list_; }
+  T* at(int index) { return list_->at(index); }
+ private:
+  ZoneList<T*>* list_;
+};
+
+
+// Allocation macro that should be used to allocate objects that must
+// only be allocated in real parsing mode.  Note that in preparse mode
+// not only is the syntax tree not created but the constructor
+// arguments are not evaulated.
+#define NEW(expr) (is_pre_parsing_ ? NULL : new expr)
+
+
+class ParserFactory BASE_EMBEDDED {
+ public:
+  explicit ParserFactory(bool is_pre_parsing) :
+      is_pre_parsing_(is_pre_parsing) { }
+
+  virtual ~ParserFactory() { }
+
+  virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
+
+  virtual Handle<String> LookupSymbol(const char* string, int length) {
+    return Handle<String>();
+  }
+
+  virtual Handle<String> EmptySymbol() {
+    return Handle<String>();
+  }
+
+  virtual Expression* NewProperty(Expression* obj, Expression* key, int pos) {
+    if (obj == VariableProxySentinel::this_proxy()) {
+      return Property::this_property();
+    } else {
+      return ValidLeftHandSideSentinel::instance();
+    }
+  }
+
+  virtual Expression* NewCall(Expression* expression,
+                              ZoneList<Expression*>* arguments,
+                              bool is_eval, int pos) {
+    return Call::sentinel();
+  }
+
+  virtual Statement* EmptyStatement() {
+    return NULL;
+  }
+
+  template <typename T> ZoneListWrapper<T> NewList(int size) {
+    return is_pre_parsing_ ? ZoneListWrapper<T>() : ZoneListWrapper<T>(size);
+  }
+
+ private:
+  bool is_pre_parsing_;
+};
+
+
+class ParserLog BASE_EMBEDDED {
+ public:
+  virtual ~ParserLog() { }
+
+  // Records the occurrence of a function.  The returned object is
+  // only guaranteed to be valid until the next function has been
+  // logged.
+  virtual FunctionEntry LogFunction(int start) { return FunctionEntry(); }
+
+  virtual void LogError() { }
+};
+
+
+class AstBuildingParserFactory : public ParserFactory {
+ public:
+  AstBuildingParserFactory() : ParserFactory(false) { }
+
+  virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
+
+  virtual Handle<String> LookupSymbol(const char* string, int length) {
+    return Factory::LookupSymbol(Vector<const char>(string, length));
+  }
+
+  virtual Handle<String> EmptySymbol() {
+    return Factory::empty_symbol();
+  }
+
+  virtual Expression* NewProperty(Expression* obj, Expression* key, int pos) {
+    return new Property(obj, key, pos);
+  }
+
+  virtual Expression* NewCall(Expression* expression,
+                              ZoneList<Expression*>* arguments,
+                              bool is_eval, int pos) {
+    return new Call(expression, arguments, is_eval, pos);
+  }
+
+  virtual Statement* EmptyStatement() {
+    // Use a statically allocated empty statement singleton to avoid
+    // allocating lots and lots of empty statements.
+    static v8::internal::EmptyStatement empty;
+    return &empty;
+  }
+};
+
+
+class ParserRecorder: public ParserLog {
+ public:
+  ParserRecorder();
+  virtual FunctionEntry LogFunction(int start);
+  virtual void LogError() { }
+  virtual void LogMessage(Scanner::Location loc,
+                          const char* message,
+                          Vector<const char*> args);
+  void WriteString(Vector<const char> str);
+  static const char* ReadString(unsigned* start, int* chars);
+  List<unsigned>* store() { return &store_; }
+ private:
+  bool has_error_;
+  List<unsigned> store_;
+};
+
+
+FunctionEntry ScriptDataImpl::GetFunctionEnd(int start) {
+  if (nth(last_entry_).start_pos() > start) {
+    // If the last entry we looked up is higher than what we're
+    // looking for then it's useless and we reset it.
+    last_entry_ = 0;
+  }
+  for (int i = last_entry_; i < EntryCount(); i++) {
+    FunctionEntry entry = nth(i);
+    if (entry.start_pos() == start) {
+      last_entry_ = i;
+      return entry;
+    }
+  }
+  return FunctionEntry();
+}
+
+
+bool ScriptDataImpl::SanityCheck() {
+  if (store_.length() < static_cast<int>(ScriptDataImpl::kHeaderSize))
+    return false;
+  if (magic() != ScriptDataImpl::kMagicNumber)
+    return false;
+  if (version() != ScriptDataImpl::kCurrentVersion)
+    return false;
+  return true;
+}
+
+
+int ScriptDataImpl::EntryCount() {
+  return (store_.length() - kHeaderSize) / FunctionEntry::kSize;
+}
+
+
+FunctionEntry ScriptDataImpl::nth(int n) {
+  int offset = kHeaderSize + n * FunctionEntry::kSize;
+  return FunctionEntry(Vector<unsigned>(store_.start() + offset,
+                                        FunctionEntry::kSize));
+}
+
+
+ParserRecorder::ParserRecorder()
+  : has_error_(false), store_(4) {
+  Vector<unsigned> preamble = store()->AddBlock(0, ScriptDataImpl::kHeaderSize);
+  preamble[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber;
+  preamble[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion;
+  preamble[ScriptDataImpl::kHasErrorOffset] = false;
+}
+
+
+void ParserRecorder::WriteString(Vector<const char> str) {
+  store()->Add(str.length());
+  for (int i = 0; i < str.length(); i++)
+    store()->Add(str[i]);
+}
+
+
+const char* ParserRecorder::ReadString(unsigned* start, int* chars) {
+  int length = start[0];
+  char* result = NewArray<char>(length + 1);
+  for (int i = 0; i < length; i++)
+    result[i] = start[i + 1];
+  result[length] = '\0';
+  if (chars != NULL) *chars = length;
+  return result;
+}
+
+
+void ParserRecorder::LogMessage(Scanner::Location loc, const char* message,
+                                Vector<const char*> args) {
+  if (has_error_) return;
+  store()->Rewind(ScriptDataImpl::kHeaderSize);
+  store()->at(ScriptDataImpl::kHasErrorOffset) = true;
+  store()->Add(loc.beg_pos);
+  store()->Add(loc.end_pos);
+  store()->Add(args.length());
+  WriteString(CStrVector(message));
+  for (int i = 0; i < args.length(); i++)
+    WriteString(CStrVector(args[i]));
+}
+
+
+Scanner::Location ScriptDataImpl::MessageLocation() {
+  int beg_pos = Read(0);
+  int end_pos = Read(1);
+  return Scanner::Location(beg_pos, end_pos);
+}
+
+
+const char* ScriptDataImpl::BuildMessage() {
+  unsigned* start = ReadAddress(3);
+  return ParserRecorder::ReadString(start, NULL);
+}
+
+
+Vector<const char*> ScriptDataImpl::BuildArgs() {
+  int arg_count = Read(2);
+  const char** array = NewArray<const char*>(arg_count);
+  int pos = ScriptDataImpl::kHeaderSize + Read(3);
+  for (int i = 0; i < arg_count; i++) {
+    int count = 0;
+    array[i] = ParserRecorder::ReadString(ReadAddress(pos), &count);
+    pos += count + 1;
+  }
+  return Vector<const char*>(array, arg_count);
+}
+
+
+unsigned ScriptDataImpl::Read(int position) {
+  return store_[ScriptDataImpl::kHeaderSize + position];
+}
+
+
+unsigned* ScriptDataImpl::ReadAddress(int position) {
+  return &store_[ScriptDataImpl::kHeaderSize + position];
+}
+
+
+FunctionEntry ParserRecorder::LogFunction(int start) {
+  if (has_error_) return FunctionEntry();
+  FunctionEntry result(store()->AddBlock(0, FunctionEntry::kSize));
+  result.set_start_pos(start);
+  return result;
+}
+
+
+class AstBuildingParser : public Parser {
+ public:
+  AstBuildingParser(Handle<Script> script, bool allow_natives_syntax,
+                    v8::Extension* extension, ScriptDataImpl* pre_data)
+      : Parser(script, allow_natives_syntax, extension, false,
+               factory(), log(), pre_data) { }
+  virtual void ReportMessageAt(Scanner::Location loc, const char* message,
+                               Vector<const char*> args);
+  virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
+                                 FunctionLiteral* fun, bool resolve, bool* ok);
+  AstBuildingParserFactory* factory() { return &factory_; }
+  ParserLog* log() { return &log_; }
+
+ private:
+  ParserLog log_;
+  AstBuildingParserFactory factory_;
+};
+
+
+class PreParser : public Parser {
+ public:
+  PreParser(Handle<Script> script, bool allow_natives_syntax,
+            v8::Extension* extension)
+      : Parser(script, allow_natives_syntax, extension, true,
+               factory(), recorder(), NULL)
+      , factory_(true) { }
+  virtual void ReportMessageAt(Scanner::Location loc, const char* message,
+                               Vector<const char*> args);
+  virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
+                                 FunctionLiteral* fun, bool resolve, bool* ok);
+  ParserFactory* factory() { return &factory_; }
+  ParserRecorder* recorder() { return &recorder_; }
+
+ private:
+  ParserRecorder recorder_;
+  ParserFactory factory_;
+};
+
+
+Scope* AstBuildingParserFactory::NewScope(Scope* parent, Scope::Type type,
+                                          bool inside_with) {
+  Scope* result = new Scope(parent, type);
+  result->Initialize(inside_with);
+  return result;
+}
+
+
+Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type,
+                               bool inside_with) {
+  ASSERT(parent != NULL);
+  parent->type_ = type;
+  return parent;
+}
+
+
+VariableProxy* PreParser::Declare(Handle<String> name, Variable::Mode mode,
+                                  FunctionLiteral* fun, bool resolve,
+                                  bool* ok) {
+  return NULL;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// Target is a support class to facilitate manipulation of the
+// Parser's target_stack_ (the stack of potential 'break' and
+// 'continue' statement targets). Upon construction, a new target is
+// added; it is removed upon destruction.
+
+class Target BASE_EMBEDDED {
+ public:
+  Target(Parser* parser, Node* node) : parser_(parser) {
+    parser_->target_stack_->Add(node);
+  }
+
+  ~Target() {
+    parser_->target_stack_->RemoveLast();
+  }
+
+ private:
+  Parser* parser_;
+};
+
+
+class TargetScope BASE_EMBEDDED {
+ public:
+  explicit TargetScope(Parser* parser)
+      : parser_(parser), previous_(parser->target_stack_), stack_(0) {
+    parser_->target_stack_ = &stack_;
+  }
+
+  ~TargetScope() {
+    ASSERT(stack_.is_empty());
+    parser_->target_stack_ = previous_;
+  }
+
+ private:
+  Parser* parser_;
+  List<Node*>* previous_;
+  List<Node*> stack_;
+};
+
+
+// ----------------------------------------------------------------------------
+// LexicalScope is a support class to facilitate manipulation of the
+// Parser's scope stack. The constructor sets the parser's top scope
+// to the incoming scope, and the destructor resets it.
+
+class LexicalScope BASE_EMBEDDED {
+ public:
+  LexicalScope(Parser* parser, Scope* scope)
+    : parser_(parser),
+      prev_scope_(parser->top_scope_),
+      prev_level_(parser->with_nesting_level_) {
+    parser_->top_scope_ = scope;
+    parser_->with_nesting_level_ = 0;
+  }
+
+  ~LexicalScope() {
+    parser_->top_scope_ = prev_scope_;
+    parser_->with_nesting_level_ = prev_level_;
+  }
+
+ private:
+  Parser* parser_;
+  Scope* prev_scope_;
+  int prev_level_;
+};
+
+
+// ----------------------------------------------------------------------------
+// The CHECK_OK macro is a convenient macro to enforce error
+// handling for functions that may fail (by returning !*ok).
+//
+// CAUTION: This macro appends extra statements after a call,
+// thus it must never be used where only a single statement
+// is correct (e.g. an if statement branch w/o braces)!
+
+#define CHECK_OK  ok);   \
+  if (!*ok) return NULL; \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+
+// ----------------------------------------------------------------------------
+// Implementation of Parser
+
+Parser::Parser(Handle<Script> script,
+               bool allow_natives_syntax,
+               v8::Extension* extension,
+               bool is_pre_parsing,
+               ParserFactory* factory,
+               ParserLog* log,
+               ScriptDataImpl* pre_data)
+    : script_(script),
+      scanner_(is_pre_parsing),
+      top_scope_(NULL),
+      with_nesting_level_(0),
+      temp_scope_(NULL),
+      target_stack_(NULL),
+      allow_natives_syntax_(allow_natives_syntax),
+      extension_(extension),
+      factory_(factory),
+      log_(log),
+      is_pre_parsing_(is_pre_parsing),
+      pre_data_(pre_data) {
+}
+
+
+bool Parser::PreParseProgram(unibrow::CharacterStream* stream) {
+  StatsRateScope timer(&Counters::pre_parse);
+  StackGuard guard;
+  AssertNoZoneAllocation assert_no_zone_allocation;
+  AssertNoAllocation assert_no_allocation;
+  NoHandleAllocation no_handle_allocation;
+  scanner_.Init(Handle<String>(), stream, 0);
+  ASSERT(target_stack_ == NULL);
+  mode_ = PARSE_EAGERLY;
+  DummyScope top_scope;
+  LexicalScope scope(this, &top_scope);
+  TemporaryScope temp_scope(this);
+  ZoneListWrapper<Statement> processor;
+  bool ok = true;
+  ParseSourceElements(&processor, Token::EOS, &ok);
+  return !scanner().stack_overflow();
+}
+
+
+FunctionLiteral* Parser::ParseProgram(Handle<String> source,
+                                      unibrow::CharacterStream* stream,
+                                      bool in_global_context) {
+  ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
+
+  StatsRateScope timer(&Counters::parse);
+  Counters::total_parse_size.Increment(source->length());
+
+  // Initialize parser state.
+  source->TryFlatten();
+  scanner_.Init(source, stream, 0);
+  ASSERT(target_stack_ == NULL);
+
+  // Compute the parsing mode.
+  mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
+  if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
+
+  Scope::Type type =
+    in_global_context
+      ? Scope::GLOBAL_SCOPE
+      : Scope::EVAL_SCOPE;
+  Handle<String> no_name = factory()->EmptySymbol();
+
+  FunctionLiteral* result = NULL;
+  { Scope* scope = factory()->NewScope(top_scope_, type, inside_with());
+    LexicalScope lexical_scope(this, scope);
+    TemporaryScope temp_scope(this);
+    ZoneListWrapper<Statement> body(16);
+    bool ok = true;
+    ParseSourceElements(&body, Token::EOS, &ok);
+    if (ok) {
+      result = NEW(FunctionLiteral(no_name, top_scope_,
+                                   body.elements(),
+                                   temp_scope.materialized_literal_count(),
+                                   temp_scope.contains_array_literal(),
+                                   temp_scope.expected_property_count(),
+                                   0, 0, source->length(), false));
+    } else if (scanner().stack_overflow()) {
+      Top::StackOverflow();
+    }
+  }
+
+  // Make sure the target stack is empty.
+  ASSERT(target_stack_ == NULL);
+
+  // If there was a syntax error we have to get rid of the AST
+  // and it is not safe to do so before the scope has been deleted.
+  if (result == NULL) zone_scope.DeleteOnExit();
+  return result;
+}
+
+
+FunctionLiteral* Parser::ParseLazy(Handle<String> source,
+                                   Handle<String> name,
+                                   int start_position,
+                                   bool is_expression) {
+  ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
+  StatsRateScope timer(&Counters::parse_lazy);
+  Counters::total_parse_size.Increment(source->length());
+  SafeStringInputBuffer buffer(source.location());
+
+  // Initialize parser state.
+  source->TryFlatten();
+  scanner_.Init(source, &buffer, start_position);
+  ASSERT(target_stack_ == NULL);
+  mode_ = PARSE_EAGERLY;
+
+  // Place holder for the result.
+  FunctionLiteral* result = NULL;
+
+  {
+    // Parse the function literal.
+    Handle<String> no_name = factory()->EmptySymbol();
+    Scope* scope =
+        factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
+    LexicalScope lexical_scope(this, scope);
+    TemporaryScope temp_scope(this);
+
+    FunctionLiteralType type = is_expression ? EXPRESSION : DECLARATION;
+    bool ok = true;
+    result = ParseFunctionLiteral(name, RelocInfo::kNoPosition, type, &ok);
+    // Make sure the results agree.
+    ASSERT(ok == (result != NULL));
+    // The only errors should be stack overflows.
+    ASSERT(ok || scanner_.stack_overflow());
+  }
+
+  // Make sure the target stack is empty.
+  ASSERT(target_stack_ == NULL);
+
+  // If there was a stack overflow we have to get rid of AST and it is
+  // not safe to do before scope has been deleted.
+  if (result == NULL) {
+    Top::StackOverflow();
+    zone_scope.DeleteOnExit();
+  }
+  return result;
+}
+
+
+void Parser::ReportMessage(const char* type, Vector<const char*> args) {
+  Scanner::Location source_location = scanner_.location();
+  ReportMessageAt(source_location, type, args);
+}
+
+
+void AstBuildingParser::ReportMessageAt(Scanner::Location source_location,
+                                        const char* type,
+                                        Vector<const char*> args) {
+  MessageLocation location(script_,
+                           source_location.beg_pos, source_location.end_pos);
+  Handle<JSArray> array = Factory::NewJSArray(args.length());
+  for (int i = 0; i < args.length(); i++) {
+    SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i])));
+  }
+  Handle<Object> result = Factory::NewSyntaxError(type, array);
+  Top::Throw(*result, &location);
+}
+
+
+void PreParser::ReportMessageAt(Scanner::Location source_location,
+                                const char* type,
+                                Vector<const char*> args) {
+  recorder()->LogMessage(source_location, type, args);
+}
+
+
+void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor,
+                                  int end_token,
+                                  bool* ok) {
+  // SourceElements ::
+  //   (Statement)* <end_token>
+
+  // Allocate a target stack to use for this set of source
+  // elements. This way, all scripts and functions get their own
+  // target stack thus avoiding illegal breaks and continues across
+  // functions.
+  TargetScope scope(this);
+
+  ASSERT(processor != NULL);
+  while (peek() != end_token) {
+    Statement* stat = ParseStatement(NULL, CHECK_OK);
+    if (stat && !stat->IsEmpty()) processor->Add(stat);
+  }
+  return 0;
+}
+
+
+Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
+  // Statement ::
+  //   Block
+  //   VariableStatement
+  //   EmptyStatement
+  //   ExpressionStatement
+  //   IfStatement
+  //   IterationStatement
+  //   ContinueStatement
+  //   BreakStatement
+  //   ReturnStatement
+  //   WithStatement
+  //   LabelledStatement
+  //   SwitchStatement
+  //   ThrowStatement
+  //   TryStatement
+  //   DebuggerStatement
+
+  // Note: Since labels can only be used by 'break' and 'continue'
+  // statements, which themselves are only valid within blocks,
+  // iterations or 'switch' statements (i.e., BreakableStatements),
+  // labels can be simply ignored in all other cases; except for
+  // trivial labelled break statements 'label: break label' which is
+  // parsed into an empty statement.
+
+  // Keep the source position of the statement
+  int statement_pos = scanner().peek_location().beg_pos;
+  Statement* stmt = NULL;
+  switch (peek()) {
+    case Token::LBRACE:
+      return ParseBlock(labels, ok);
+
+    case Token::CONST:  // fall through
+    case Token::VAR:
+      stmt = ParseVariableStatement(ok);
+      break;
+
+    case Token::SEMICOLON:
+      Next();
+      return factory()->EmptyStatement();
+
+    case Token::IF:
+      stmt = ParseIfStatement(labels, ok);
+      break;
+
+    case Token::DO:
+      stmt = ParseDoStatement(labels, ok);
+      break;
+
+    case Token::WHILE:
+      stmt = ParseWhileStatement(labels, ok);
+      break;
+
+    case Token::FOR:
+      stmt = ParseForStatement(labels, ok);
+      break;
+
+    case Token::CONTINUE:
+      stmt = ParseContinueStatement(ok);
+      break;
+
+    case Token::BREAK:
+      stmt = ParseBreakStatement(labels, ok);
+      break;
+
+    case Token::RETURN:
+      stmt = ParseReturnStatement(ok);
+      break;
+
+    case Token::WITH:
+      stmt = ParseWithStatement(labels, ok);
+      break;
+
+    case Token::SWITCH:
+      stmt = ParseSwitchStatement(labels, ok);
+      break;
+
+    case Token::THROW:
+      stmt = ParseThrowStatement(ok);
+      break;
+
+    case Token::TRY: {
+      // NOTE: It is somewhat complicated to have labels on
+      // try-statements. When breaking out of a try-finally statement,
+      // one must take great care not to treat it as a
+      // fall-through. It is much easier just to wrap the entire
+      // try-statement in a statement block and put the labels there
+      Block* result = NEW(Block(labels, 1, false));
+      Target target(this, result);
+      TryStatement* statement = ParseTryStatement(CHECK_OK);
+      if (result) result->AddStatement(statement);
+      return result;
+    }
+
+    case Token::FUNCTION:
+      return ParseFunctionDeclaration(ok);
+
+    case Token::NATIVE:
+      return ParseNativeDeclaration(ok);
+
+    case Token::DEBUGGER:
+      stmt = ParseDebuggerStatement(ok);
+      break;
+
+    default:
+      stmt = ParseExpressionOrLabelledStatement(labels, ok);
+  }
+
+  // Store the source position of the statement
+  if (stmt != NULL) stmt->set_statement_pos(statement_pos);
+  return stmt;
+}
+
+
+VariableProxy* AstBuildingParser::Declare(Handle<String> name,
+                                          Variable::Mode mode,
+                                          FunctionLiteral* fun,
+                                          bool resolve,
+                                          bool* ok) {
+  Variable* var = NULL;
+  // If we are inside a function, a declaration of a variable
+  // is a truly local variable, and the scope of the variable
+  // is always the function scope.
+
+  // If a function scope exists, then we can statically declare this
+  // variable and also set its mode. In any case, a Declaration node
+  // will be added to the scope so that the declaration can be added
+  // to the corresponding activation frame at runtime if necessary.
+  // For instance declarations inside an eval scope need to be added
+  // to the calling function context.
+  if (top_scope_->is_function_scope()) {
+    // Declare the variable in the function scope.
+    var = top_scope_->Lookup(name);
+    if (var == NULL) {
+      // Declare the name.
+      var = top_scope_->Declare(name, mode);
+    } else {
+      // The name was declared before; check for conflicting
+      // re-declarations. If the previous declaration was a const or the
+      // current declaration is a const then we have a conflict. There is
+      // similar code in runtime.cc in the Declare functions.
+      if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) {
+        // We only have vars and consts in declarations.
+        ASSERT(var->mode() == Variable::VAR ||
+               var->mode() == Variable::CONST);
+        const char* type = (var->mode() == Variable::VAR) ? "var" : "const";
+        Handle<String> type_string =
+            Factory::NewStringFromUtf8(CStrVector(type), TENURED);
+        Expression* expression =
+            NewThrowTypeError(Factory::redeclaration_symbol(),
+                              type_string, name);
+        top_scope_->SetIllegalRedeclaration(expression);
+      }
+    }
+  }
+
+  // We add a declaration node for every declaration. The compiler
+  // will only generate code if necessary. In particular, declarations
+  // for inner local variables that do not represent functions won't
+  // result in any generated code.
+  //
+  // Note that we always add an unresolved proxy even if it's not
+  // used, simply because we don't know in this method (w/o extra
+  // parameters) if the proxy is needed or not. The proxy will be
+  // bound during variable resolution time unless it was pre-bound
+  // below.
+  //
+  // WARNING: This will lead to multiple declaration nodes for the
+  // same variable if it is declared several times. This is not a
+  // 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 = top_scope_->NewUnresolved(name, inside_with());
+  top_scope_->AddDeclaration(NEW(Declaration(proxy, mode, fun)));
+
+  // For global const variables we bind the proxy to a variable.
+  if (mode == Variable::CONST && top_scope_->is_global_scope()) {
+    ASSERT(resolve);  // should be set by all callers
+    var = NEW(Variable(top_scope_, name, Variable::CONST, true, false));
+  }
+
+  // If requested and we have a local variable, bind the proxy to the variable
+  // at parse-time. This is used for functions (and consts) declared inside
+  // statements: the corresponding function (or const) variable must be in the
+  // function scope and not a statement-local scope, e.g. as provided with a
+  // 'with' statement:
+  //
+  //   with (obj) {
+  //     function f() {}
+  //   }
+  //
+  // which is translated into:
+  //
+  //   with (obj) {
+  //     // in this case this is not: 'var f; f = function () {};'
+  //     var f = function () {};
+  //   }
+  //
+  // Note that if 'f' is accessed from inside the 'with' statement, it
+  // will be allocated in the context (because we must be able to look
+  // it up dynamically) but it will also be accessed statically, i.e.,
+  // with a context slot index and a context chain length for this
+  // initialization code. Thus, inside the 'with' statement, we need
+  // both access to the static and the dynamic context chain; the
+  // runtime needs to provide both.
+  if (resolve && var != NULL) proxy->BindTo(var);
+
+  return proxy;
+}
+
+
+// Language extension which is only enabled for source files loaded
+// through the API's extension mechanism.  A native function
+// declaration is resolved by looking up the function through a
+// callback provided by the extension.
+Statement* Parser::ParseNativeDeclaration(bool* ok) {
+  if (extension_ == NULL) {
+    ReportUnexpectedToken(Token::NATIVE);
+    *ok = false;
+    return NULL;
+  }
+
+  Expect(Token::NATIVE, CHECK_OK);
+  Expect(Token::FUNCTION, CHECK_OK);
+  Handle<String> name = ParseIdentifier(CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  bool done = (peek() == Token::RPAREN);
+  while (!done) {
+    ParseIdentifier(CHECK_OK);
+    done = (peek() == Token::RPAREN);
+    if (!done) Expect(Token::COMMA, CHECK_OK);
+  }
+  Expect(Token::RPAREN, CHECK_OK);
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  if (is_pre_parsing_) return NULL;
+
+  // Make sure that the function containing the native declaration
+  // isn't lazily compiled. The extension structures are only
+  // accessible while parsing the first time not when reparsing
+  // because of lazy compilation.
+  top_scope_->ForceEagerCompilation();
+
+  // Compute the function template for the native function.
+  v8::Handle<v8::FunctionTemplate> fun_template =
+      extension_->GetNativeFunction(v8::Utils::ToLocal(name));
+  ASSERT(!fun_template.IsEmpty());
+
+  // Instantiate the function and create a boilerplate function from it.
+  Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction());
+  const int literals = fun->NumberOfLiterals();
+  Handle<Code> code = Handle<Code>(fun->shared()->code());
+  Handle<JSFunction> boilerplate =
+      Factory::NewFunctionBoilerplate(name, literals, false, code);
+
+  // Copy the function data to the boilerplate. Used by
+  // builtins.cc:HandleApiCall to perform argument type checks and to
+  // find the right native code to call.
+  boilerplate->shared()->set_function_data(fun->shared()->function_data());
+  int parameters = fun->shared()->formal_parameter_count();
+  boilerplate->shared()->set_formal_parameter_count(parameters);
+
+  // TODO(1240846): It's weird that native function declarations are
+  // introduced dynamically when we meet their declarations, whereas
+  // other functions are setup when entering the surrounding scope.
+  FunctionBoilerplateLiteral* lit =
+      NEW(FunctionBoilerplateLiteral(boilerplate));
+  VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK);
+  return NEW(ExpressionStatement(
+      new Assignment(Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)));
+}
+
+
+Statement* Parser::ParseFunctionDeclaration(bool* ok) {
+  // Parse a function literal. We may or may not have a function name.
+  // If we have a name we use it as the variable name for the function
+  // (a function declaration) and not as the function name of a function
+  // expression.
+
+  Expect(Token::FUNCTION, CHECK_OK);
+  int function_token_position = scanner().location().beg_pos;
+
+  Handle<String> name;
+  if (peek() == Token::IDENTIFIER) name = ParseIdentifier(CHECK_OK);
+  FunctionLiteral* fun = ParseFunctionLiteral(name, function_token_position,
+                                              DECLARATION, CHECK_OK);
+
+  if (name.is_null()) {
+    // We don't have a name - it is always an anonymous function
+    // expression.
+    return NEW(ExpressionStatement(fun));
+  } else {
+    // We have a name so even if we're not at the top-level of the
+    // global or a function scope, we treat is as such and introduce
+    // the function with it's initial value upon entering the
+    // corresponding scope.
+    Declare(name, Variable::VAR, fun, true, CHECK_OK);
+    return factory()->EmptyStatement();
+  }
+}
+
+
+Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
+  // Block ::
+  //   '{' Statement* '}'
+
+  // Note that a Block does not introduce a new execution scope!
+  // (ECMA-262, 3rd, 12.2)
+  //
+  // Construct block expecting 16 statements.
+  Block* result = NEW(Block(labels, 16, false));
+  Target target(this, result);
+  Expect(Token::LBRACE, CHECK_OK);
+  while (peek() != Token::RBRACE) {
+    Statement* stat = ParseStatement(NULL, CHECK_OK);
+    if (stat && !stat->IsEmpty()) result->AddStatement(stat);
+  }
+  Expect(Token::RBRACE, CHECK_OK);
+  return result;
+}
+
+
+Block* Parser::ParseVariableStatement(bool* ok) {
+  // VariableStatement ::
+  //   VariableDeclarations ';'
+
+  Expression* dummy;  // to satisfy the ParseVariableDeclarations() signature
+  Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+  return result;
+}
+
+
+// If the variable declaration declares exactly one non-const
+// variable, then *var is set to that variable. In all other cases,
+// *var is untouched; in particular, it is the caller's responsibility
+// to initialize it properly. This mechanism is used for the parsing
+// of 'for-in' loops.
+Block* Parser::ParseVariableDeclarations(bool accept_IN,
+                                         Expression** var,
+                                         bool* ok) {
+  // VariableDeclarations ::
+  //   ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
+
+  Variable::Mode mode = Variable::VAR;
+  bool is_const = false;
+  if (peek() == Token::VAR) {
+    Consume(Token::VAR);
+  } else if (peek() == Token::CONST) {
+    Consume(Token::CONST);
+    mode = Variable::CONST;
+    is_const = true;
+  } else {
+    UNREACHABLE();  // by current callers
+  }
+
+  // The scope of a variable/const declared anywhere inside a function
+  // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
+  // transform a source-level variable/const declaration into a (Function)
+  // Scope declaration, and rewrite the source-level initialization into an
+  // assignment statement. We use a block to collect multiple assignments.
+  //
+  // We mark the block as initializer block because we don't want the
+  // rewriter to add a '.result' assignment to such a block (to get compliant
+  // behavior for code such as print(eval('var x = 7')), and for cosmetic
+  // reasons when pretty-printing. Also, unless an assignment (initialization)
+  // is inside an initializer block, it is ignored.
+  //
+  // Create new block with one expected declaration.
+  Block* block = NEW(Block(NULL, 1, true));
+  VariableProxy* last_var = NULL;  // the last variable declared
+  int nvars = 0;  // the number of variables declared
+  do {
+    // Parse variable name.
+    if (nvars > 0) Consume(Token::COMMA);
+    Handle<String> name = ParseIdentifier(CHECK_OK);
+
+    // Declare variable.
+    // Note that we *always* must treat the initial value via a separate init
+    // assignment for variables and constants because the value must be assigned
+    // when the variable is encountered in the source. But the variable/constant
+    // is declared (and set to 'undefined') upon entering the function within
+    // which the variable or constant is declared. Only function variables have
+    // an initial value in the declaration (because they are initialized upon
+    // entering the function).
+    //
+    // If we have a const declaration, in an inner scope, the proxy is always
+    // bound to the declared variable (independent of possibly surrounding with
+    // statements).
+    last_var = Declare(name, mode, NULL,
+                       is_const /* always bound for CONST! */,
+                       CHECK_OK);
+    nvars++;
+
+    // Parse initialization expression if present and/or needed. A
+    // declaration of the form:
+    //
+    //    var v = x;
+    //
+    // is syntactic sugar for:
+    //
+    //    var v; v = x;
+    //
+    // In particular, we need to re-lookup 'v' as it may be a
+    // different 'v' than the 'v' in the declaration (if we are inside
+    // a 'with' statement that makes a object property with name 'v'
+    // visible).
+    //
+    // However, note that const declarations are different! A const
+    // declaration of the form:
+    //
+    //   const c = x;
+    //
+    // is *not* syntactic sugar for:
+    //
+    //   const c; c = x;
+    //
+    // The "variable" c initialized to x is the same as the declared
+    // one - there is no re-lookup (see the last parameter of the
+    // Declare() call above).
+
+    Expression* value = NULL;
+    int position = -1;
+    if (peek() == Token::ASSIGN) {
+      Expect(Token::ASSIGN, CHECK_OK);
+      position = scanner().location().beg_pos;
+      value = ParseAssignmentExpression(accept_IN, CHECK_OK);
+    }
+
+    // Make sure that 'const c' actually initializes 'c' to undefined
+    // even though it seems like a stupid thing to do.
+    if (value == NULL && is_const) {
+      value = GetLiteralUndefined();
+    }
+
+    // Global variable declarations must be compiled in a specific
+    // way. When the script containing the global variable declaration
+    // is entered, the global variable must be declared, so that if it
+    // doesn't exist (not even in a prototype of the global object) it
+    // gets created with an initial undefined value. This is handled
+    // by the declarations part of the function representing the
+    // top-level global code; see Runtime::DeclareGlobalVariable. If
+    // it already exists (in the object or in a prototype), it is
+    // *not* touched until the variable declaration statement is
+    // executed.
+    //
+    // Executing the variable declaration statement will always
+    // guarantee to give the global object a "local" variable; a
+    // variable defined in the global object and not in any
+    // prototype. This way, global variable declarations can shadow
+    // properties in the prototype chain, but only after the variable
+    // declaration statement has been executed. This is important in
+    // browsers where the global object (window) has lots of
+    // properties defined in prototype objects.
+
+    if (!is_pre_parsing_ && top_scope_->is_global_scope()) {
+      // Compute the arguments for the runtime call.
+      ZoneList<Expression*>* arguments = new ZoneList<Expression*>(2);
+      // Be careful not to assign a value to the global variable if
+      // we're in a with. The initialization value should not
+      // necessarily be stored in the global object in that case,
+      // which is why we need to generate a separate assignment node.
+      arguments->Add(NEW(Literal(name)));  // we have at least 1 parameter
+      if (is_const || (value != NULL && !inside_with())) {
+        arguments->Add(value);
+        value = NULL;  // zap the value to avoid the unnecessary assignment
+      }
+      // Construct the call to Runtime::DeclareGlobal{Variable,Const}Locally
+      // and add it to the initialization statement block. Note that
+      // this function does different things depending on if we have
+      // 1 or 2 parameters.
+      CallRuntime* initialize;
+      if (is_const) {
+        initialize =
+          NEW(CallRuntime(
+            Factory::InitializeConstGlobal_symbol(),
+            Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
+            arguments));
+      } else {
+        initialize =
+          NEW(CallRuntime(
+            Factory::InitializeVarGlobal_symbol(),
+            Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
+            arguments));
+      }
+      block->AddStatement(NEW(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
+    // 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...
+    if (value != NULL) {
+      Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR);
+      Assignment* assignment = NEW(Assignment(op, last_var, value, position));
+      if (block) block->AddStatement(NEW(ExpressionStatement(assignment)));
+    }
+  } while (peek() == Token::COMMA);
+
+  if (!is_const && nvars == 1) {
+    // We have a single, non-const variable.
+    if (is_pre_parsing_) {
+      // If we're preparsing then we need to set the var to something
+      // in order for for-in loops to parse correctly.
+      *var = ValidLeftHandSideSentinel::instance();
+    } else {
+      ASSERT(last_var != NULL);
+      *var = last_var;
+    }
+  }
+
+  return block;
+}
+
+
+static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) {
+  ASSERT(!label.is_null());
+  if (labels != NULL)
+    for (int i = labels->length(); i-- > 0; )
+      if (labels->at(i).is_identical_to(label))
+        return true;
+
+  return false;
+}
+
+
+Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
+                                                      bool* ok) {
+  // ExpressionStatement | LabelledStatement ::
+  //   Expression ';'
+  //   Identifier ':' Statement
+
+  Expression* expr = ParseExpression(true, CHECK_OK);
+  if (peek() == Token::COLON && expr &&
+      expr->AsVariableProxy() != NULL &&
+      !expr->AsVariableProxy()->is_this()) {
+    VariableProxy* var = expr->AsVariableProxy();
+    Handle<String> label = var->name();
+    // TODO(1240780): We don't check for redeclaration of labels
+    // during preparsing since keeping track of the set of active
+    // labels requires nontrivial changes to the way scopes are
+    // structured.  However, these are probably changes we want to
+    // make later anyway so we should go back and fix this then.
+    if (!is_pre_parsing_) {
+      if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
+        SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
+        const char* elms[2] = { "Label", *c_string };
+        Vector<const char*> args(elms, 2);
+        ReportMessage("redeclaration", args);
+        *ok = false;
+        return NULL;
+      }
+      if (labels == NULL) labels = new ZoneStringList(4);
+      labels->Add(label);
+      // Remove the "ghost" variable that turned out to be a label
+      // from the top scope. This way, we don't try to resolve it
+      // during the scope processing.
+      top_scope_->RemoveUnresolved(var);
+    }
+    Expect(Token::COLON, CHECK_OK);
+    return ParseStatement(labels, ok);
+  }
+
+  // Parsed expression statement.
+  ExpectSemicolon(CHECK_OK);
+  return NEW(ExpressionStatement(expr));
+}
+
+
+IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
+  // IfStatement ::
+  //   'if' '(' Expression ')' Statement ('else' Statement)?
+
+  Expect(Token::IF, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* condition = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+  Statement* then_statement = ParseStatement(labels, CHECK_OK);
+  Statement* else_statement = NULL;
+  if (peek() == Token::ELSE) {
+    Next();
+    else_statement = ParseStatement(labels, CHECK_OK);
+  } else if (!is_pre_parsing_) {
+    else_statement = factory()->EmptyStatement();
+  }
+  return NEW(IfStatement(condition, then_statement, else_statement));
+}
+
+
+Statement* Parser::ParseContinueStatement(bool* ok) {
+  // ContinueStatement ::
+  //   'continue' Identifier? ';'
+
+  Expect(Token::CONTINUE, CHECK_OK);
+  Handle<String> label(static_cast<String**>(NULL));
+  Token::Value tok = peek();
+  if (!scanner_.has_line_terminator_before_next() &&
+      tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
+    label = ParseIdentifier(CHECK_OK);
+  }
+  IterationStatement* target = NULL;
+  if (!is_pre_parsing_) {
+    target = LookupContinueTarget(label, CHECK_OK);
+    if (target == NULL) {
+      // Illegal continue statement.  To be consistent with KJS we delay
+      // reporting of the syntax error until runtime.
+      Handle<String> error_type = Factory::illegal_continue_symbol();
+      if (!label.is_null()) error_type = Factory::unknown_label_symbol();
+      Expression* throw_error = NewThrowSyntaxError(error_type, label);
+      return NEW(ExpressionStatement(throw_error));
+    }
+  }
+  ExpectSemicolon(CHECK_OK);
+  return NEW(ContinueStatement(target));
+}
+
+
+Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
+  // BreakStatement ::
+  //   'break' Identifier? ';'
+
+  Expect(Token::BREAK, CHECK_OK);
+  Handle<String> label;
+  Token::Value tok = peek();
+  if (!scanner_.has_line_terminator_before_next() &&
+      tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
+    label = ParseIdentifier(CHECK_OK);
+  }
+  // Parse labelled break statements that target themselves into
+  // empty statements, e.g. 'l1: l2: l3: break l2;'
+  if (!label.is_null() && ContainsLabel(labels, label)) {
+    return factory()->EmptyStatement();
+  }
+  BreakableStatement* target = NULL;
+  if (!is_pre_parsing_) {
+    target = LookupBreakTarget(label, CHECK_OK);
+    if (target == NULL) {
+      // Illegal break statement.  To be consistent with KJS we delay
+      // reporting of the syntax error until runtime.
+      Handle<String> error_type = Factory::illegal_break_symbol();
+      if (!label.is_null()) error_type = Factory::unknown_label_symbol();
+      Expression* throw_error = NewThrowSyntaxError(error_type, label);
+      return NEW(ExpressionStatement(throw_error));
+    }
+  }
+  ExpectSemicolon(CHECK_OK);
+  return NEW(BreakStatement(target));
+}
+
+
+Statement* Parser::ParseReturnStatement(bool* ok) {
+  // ReturnStatement ::
+  //   'return' Expression? ';'
+
+  // Consume the return token. It is necessary to do the before
+  // reporting any errors on it, because of the way errors are
+  // reported (underlining).
+  Expect(Token::RETURN, CHECK_OK);
+
+  // An ECMAScript program is considered syntactically incorrect if it
+  // contains a return statement that is not within the body of a
+  // function. See ECMA-262, section 12.9, page 67.
+  //
+  // To be consistent with KJS we report the syntax error at runtime.
+  if (!is_pre_parsing_ && !top_scope_->is_function_scope()) {
+    Handle<String> type = Factory::illegal_return_symbol();
+    Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
+    return NEW(ExpressionStatement(throw_error));
+  }
+
+  Token::Value tok = peek();
+  if (scanner_.has_line_terminator_before_next() ||
+      tok == Token::SEMICOLON ||
+      tok == Token::RBRACE ||
+      tok == Token::EOS) {
+    ExpectSemicolon(CHECK_OK);
+    return NEW(ReturnStatement(GetLiteralUndefined()));
+  }
+
+  Expression* expr = ParseExpression(true, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+  return NEW(ReturnStatement(expr));
+}
+
+
+Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
+  // Parse the statement and collect escaping labels.
+  ZoneList<Label*>* label_list = NEW(ZoneList<Label*>(0));
+  LabelCollector collector(label_list);
+  Statement* stat;
+  { Target target(this, &collector);
+    with_nesting_level_++;
+    top_scope_->RecordWithStatement();
+    stat = ParseStatement(labels, CHECK_OK);
+    with_nesting_level_--;
+  }
+  // Create resulting block with two statements.
+  // 1: Evaluate the with expression.
+  // 2: The try-finally block evaluating the body.
+  Block* result = NEW(Block(NULL, 2, false));
+
+  if (result) {
+    result->AddStatement(NEW(WithEnterStatement(obj)));
+
+    // Create body block.
+    Block* body = NEW(Block(NULL, 1, false));
+    body->AddStatement(stat);
+
+    // Create exit block.
+    Block* exit = NEW(Block(NULL, 1, false));
+    exit->AddStatement(NEW(WithExitStatement()));
+
+    // Return a try-finally statement.
+    TryFinally* wrapper = NEW(TryFinally(body, exit));
+    wrapper->set_escaping_labels(collector.labels());
+    result->AddStatement(wrapper);
+    return result;
+  } else {
+    return NULL;
+  }
+}
+
+
+Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
+  // WithStatement ::
+  //   'with' '(' Expression ')' Statement
+
+  // We do not allow the use of 'with' statements in the internal JS
+  // code. If 'with' statements were allowed, the simplified setup of
+  // the runtime context chain would allow access to properties in the
+  // global object from within a 'with' statement.
+  ASSERT(!Bootstrapper::IsActive());
+
+  Expect(Token::WITH, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* expr = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  return WithHelper(expr, labels, CHECK_OK);
+}
+
+
+CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
+  // CaseClause ::
+  //   'case' Expression ':' Statement*
+  //   'default' ':' Statement*
+
+  Expression* label = NULL;  // NULL expression indicates default case
+  if (peek() == Token::CASE) {
+    Expect(Token::CASE, CHECK_OK);
+    label = ParseExpression(true, CHECK_OK);
+  } else {
+    Expect(Token::DEFAULT, CHECK_OK);
+    if (*default_seen_ptr) {
+      ReportMessage("multiple_defaults_in_switch",
+                    Vector<const char*>::empty());
+      *ok = false;
+      return NULL;
+    }
+    *default_seen_ptr = true;
+  }
+  Expect(Token::COLON, CHECK_OK);
+
+  ZoneListWrapper<Statement> statements = factory()->NewList<Statement>(5);
+  while (peek() != Token::CASE &&
+         peek() != Token::DEFAULT &&
+         peek() != Token::RBRACE) {
+    Statement* stat = ParseStatement(NULL, CHECK_OK);
+    statements.Add(stat);
+  }
+
+  return NEW(CaseClause(label, statements.elements()));
+}
+
+
+SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
+                                              bool* ok) {
+  // SwitchStatement ::
+  //   'switch' '(' Expression ')' '{' CaseClause* '}'
+
+  SwitchStatement* statement = NEW(SwitchStatement(labels));
+  Target target(this, statement);
+
+  Expect(Token::SWITCH, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* tag = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  bool default_seen = false;
+  ZoneListWrapper<CaseClause> cases = factory()->NewList<CaseClause>(4);
+  Expect(Token::LBRACE, CHECK_OK);
+  while (peek() != Token::RBRACE) {
+    CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
+    cases.Add(clause);
+  }
+  Expect(Token::RBRACE, CHECK_OK);
+
+  if (statement) statement->Initialize(tag, cases.elements());
+  return statement;
+}
+
+
+Statement* Parser::ParseThrowStatement(bool* ok) {
+  // ThrowStatement ::
+  //   'throw' Expression ';'
+
+  Expect(Token::THROW, CHECK_OK);
+  int pos = scanner().location().beg_pos;
+  if (scanner_.has_line_terminator_before_next()) {
+    ReportMessage("newline_after_throw", Vector<const char*>::empty());
+    *ok = false;
+    return NULL;
+  }
+  Expression* exception = ParseExpression(true, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+
+  return NEW(ExpressionStatement(new Throw(exception, pos)));
+}
+
+
+Expression* Parser::MakeCatchContext(Handle<String> id, VariableProxy* value) {
+  ZoneListWrapper<ObjectLiteral::Property> properties =
+      factory()->NewList<ObjectLiteral::Property>(1);
+  Literal* key = NEW(Literal(id));
+  ObjectLiteral::Property* property = NEW(ObjectLiteral::Property(key, value));
+  properties.Add(property);
+
+  // This must be called always, even during pre-parsing!
+  // (Computation of literal index must happen before pre-parse bailout.)
+  int literal_index = temp_scope_->NextMaterializedLiteralIndex();
+  if (is_pre_parsing_) {
+    return NULL;
+  }
+
+  // Construct the expression for calling Runtime::CreateObjectLiteral
+  // with the literal array as argument.
+  Handle<FixedArray> constant_properties = Factory::empty_fixed_array();
+  ZoneList<Expression*>* arguments = new ZoneList<Expression*>(1);
+  arguments->Add(new Literal(constant_properties));
+
+  return new ObjectLiteral(constant_properties,
+                           properties.elements(),
+                           literal_index);
+}
+
+
+TryStatement* Parser::ParseTryStatement(bool* ok) {
+  // TryStatement ::
+  //   'try' Block Catch
+  //   'try' Block Finally
+  //   'try' Block Catch Finally
+  //
+  // Catch ::
+  //   'catch' '(' Identifier ')' Block
+  //
+  // Finally ::
+  //   'finally' Block
+
+  Expect(Token::TRY, CHECK_OK);
+
+  ZoneList<Label*>* label_list = NEW(ZoneList<Label*>(0));
+  LabelCollector collector(label_list);
+  Block* try_block;
+
+  { Target target(this, &collector);
+    try_block = ParseBlock(NULL, CHECK_OK);
+  }
+
+  Block* catch_block = NULL;
+  VariableProxy* catch_var = NULL;
+  Block* finally_block = NULL;
+
+  Token::Value tok = peek();
+  if (tok != Token::CATCH && tok != Token::FINALLY) {
+    ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
+    *ok = false;
+    return NULL;
+  }
+
+  // If we can break out from the catch block and there is a finally block,
+  // then we will need to collect labels from the catch block. Since we don't
+  // know yet if there will be a finally block, we always collect the labels.
+  ZoneList<Label*>* catch_label_list = NEW(ZoneList<Label*>(0));
+  LabelCollector catch_collector(catch_label_list);
+  bool has_catch = false;
+  if (tok == Token::CATCH) {
+    has_catch = true;
+    Consume(Token::CATCH);
+
+    Expect(Token::LPAREN, CHECK_OK);
+    Handle<String> name = ParseIdentifier(CHECK_OK);
+    Expect(Token::RPAREN, CHECK_OK);
+
+    if (peek() == Token::LBRACE) {
+      // Allocate a temporary for holding the finally state while
+      // executing the finally block.
+      catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
+      Expression* obj = MakeCatchContext(name, catch_var);
+      { Target target(this, &catch_collector);
+        catch_block = WithHelper(obj, NULL, CHECK_OK);
+      }
+    } else {
+      Expect(Token::LBRACE, CHECK_OK);
+    }
+
+    tok = peek();
+  }
+
+  if (tok == Token::FINALLY || !has_catch) {
+    Consume(Token::FINALLY);
+    // Declare a variable for holding the finally state while
+    // executing the finally block.
+    finally_block = ParseBlock(NULL, CHECK_OK);
+  }
+
+  // Simplify the AST nodes by converting:
+  //   'try { } catch { } finally { }'
+  // to:
+  //   'try { try { } catch { } } finally { }'
+
+  if (!is_pre_parsing_ && catch_block != NULL && finally_block != NULL) {
+    TryCatch* statement = NEW(TryCatch(try_block, catch_var, catch_block));
+    statement->set_escaping_labels(collector.labels());
+    try_block = NEW(Block(NULL, 1, false));
+    try_block->AddStatement(statement);
+    catch_block = NULL;
+  }
+
+  TryStatement* result = NULL;
+  if (!is_pre_parsing_) {
+    if (catch_block != NULL) {
+      ASSERT(finally_block == NULL);
+      result = NEW(TryCatch(try_block, catch_var, catch_block));
+      result->set_escaping_labels(collector.labels());
+    } else {
+      ASSERT(finally_block != NULL);
+      result = NEW(TryFinally(try_block, finally_block));
+      // Add the labels of the try block and the catch block.
+      for (int i = 0; i < collector.labels()->length(); i++) {
+        catch_collector.labels()->Add(collector.labels()->at(i));
+      }
+      result->set_escaping_labels(catch_collector.labels());
+    }
+  }
+
+  return result;
+}
+
+
+LoopStatement* Parser::ParseDoStatement(ZoneStringList* labels, bool* ok) {
+  // DoStatement ::
+  //   'do' Statement 'while' '(' Expression ')' ';'
+
+  LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::DO_LOOP));
+  Target target(this, loop);
+
+  Expect(Token::DO, CHECK_OK);
+  Statement* body = ParseStatement(NULL, CHECK_OK);
+  Expect(Token::WHILE, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* cond = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  // Allow do-statements to be terminated with and without
+  // semi-colons. This allows code such as 'do;while(0)return' to
+  // parse, which would not be the case if we had used the
+  // ExpectSemicolon() functionality here.
+  if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
+
+  if (loop) loop->Initialize(NULL, cond, NULL, body);
+  return loop;
+}
+
+
+LoopStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
+  // WhileStatement ::
+  //   'while' '(' Expression ')' Statement
+
+  LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::WHILE_LOOP));
+  Target target(this, loop);
+
+  Expect(Token::WHILE, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* cond = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+  Statement* body = ParseStatement(NULL, CHECK_OK);
+
+  if (loop) loop->Initialize(NULL, cond, NULL, body);
+  return loop;
+}
+
+
+Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
+  // ForStatement ::
+  //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
+
+  Statement* init = NULL;
+
+  Expect(Token::FOR, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  if (peek() != Token::SEMICOLON) {
+    if (peek() == Token::VAR || peek() == Token::CONST) {
+      Expression* each = NULL;
+      Block* variable_statement =
+          ParseVariableDeclarations(false, &each, CHECK_OK);
+      if (peek() == Token::IN && each != NULL) {
+        ForInStatement* loop = NEW(ForInStatement(labels));
+        Target target(this, loop);
+
+        Expect(Token::IN, CHECK_OK);
+        Expression* enumerable = ParseExpression(true, CHECK_OK);
+        Expect(Token::RPAREN, CHECK_OK);
+
+        Statement* body = ParseStatement(NULL, CHECK_OK);
+        if (is_pre_parsing_) {
+          return NULL;
+        } else {
+          loop->Initialize(each, enumerable, body);
+          Block* result = NEW(Block(NULL, 2, false));
+          result->AddStatement(variable_statement);
+          result->AddStatement(loop);
+          // Parsed for-in loop w/ variable/const declaration.
+          return result;
+        }
+
+      } else {
+        init = variable_statement;
+      }
+
+    } else {
+      Expression* expression = ParseExpression(false, CHECK_OK);
+      if (peek() == Token::IN) {
+        // Report syntax error if the expression is an invalid
+        // left-hand side expression.
+        if (expression == NULL || !expression->IsValidLeftHandSide()) {
+          if (expression != NULL && expression->AsCall() != NULL) {
+            // According to ECMA-262 host function calls are permitted to
+            // return references.  This cannot happen in our system so we
+            // will always get an error.  We could report this as a syntax
+            // error here but for compatibility with KJS and SpiderMonkey we
+            // choose to report the error at runtime.
+            Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
+            expression = NewThrowReferenceError(type);
+          } else {
+            // Invalid left hand side expressions that are not function
+            // calls are reported as syntax errors at compile time.
+            ReportMessage("invalid_lhs_in_for_in",
+                          Vector<const char*>::empty());
+            *ok = false;
+            return NULL;
+          }
+        }
+        ForInStatement* loop = NEW(ForInStatement(labels));
+        Target target(this, loop);
+
+        Expect(Token::IN, CHECK_OK);
+        Expression* enumerable = ParseExpression(true, CHECK_OK);
+        Expect(Token::RPAREN, CHECK_OK);
+
+        Statement* body = ParseStatement(NULL, CHECK_OK);
+        if (loop) loop->Initialize(expression, enumerable, body);
+
+        // Parsed for-in loop.
+        return loop;
+
+      } else {
+        init = NEW(ExpressionStatement(expression));
+      }
+    }
+  }
+
+  // Standard 'for' loop
+  LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::FOR_LOOP));
+  Target target(this, loop);
+
+  // Parsed initializer at this point.
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  Expression* cond = NULL;
+  if (peek() != Token::SEMICOLON) {
+    cond = ParseExpression(true, CHECK_OK);
+  }
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  Statement* next = NULL;
+  if (peek() != Token::RPAREN) {
+    Expression* exp = ParseExpression(true, CHECK_OK);
+    next = NEW(ExpressionStatement(exp));
+  }
+  Expect(Token::RPAREN, CHECK_OK);
+
+  Statement* body = ParseStatement(NULL, CHECK_OK);
+
+  if (loop) loop->Initialize(init, cond, next, body);
+  return loop;
+}
+
+
+// Precedence = 1
+Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
+  // Expression ::
+  //   AssignmentExpression
+  //   Expression ',' AssignmentExpression
+
+  Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
+  while (peek() == Token::COMMA) {
+    Expect(Token::COMMA, CHECK_OK);
+    Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
+    result = NEW(BinaryOperation(Token::COMMA, result, right));
+  }
+  return result;
+}
+
+
+// Precedence = 2
+Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
+  // AssignmentExpression ::
+  //   ConditionalExpression
+  //   LeftHandSideExpression AssignmentOperator AssignmentExpression
+
+  Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
+
+  if (!Token::IsAssignmentOp(peek())) {
+    // Parsed conditional expression only (no assignment).
+    return expression;
+  }
+
+  if (expression == NULL || !expression->IsValidLeftHandSide()) {
+    if (expression != NULL && expression->AsCall() != NULL) {
+      // According to ECMA-262 host function calls are permitted to
+      // return references.  This cannot happen in our system so we
+      // will always get an error.  We could report this as a syntax
+      // error here but for compatibility with KJS and SpiderMonkey we
+      // choose to report the error at runtime.
+      Handle<String> type = Factory::invalid_lhs_in_assignment_symbol();
+      expression = NewThrowReferenceError(type);
+    } else {
+      // Invalid left hand side expressions that are not function
+      // calls are reported as syntax errors at compile time.
+      //
+      // NOTE: KJS sometimes delay the error reporting to runtime. If
+      // we want to be completely compatible we should do the same.
+      // For example: "(x++) = 42" gives a reference error at runtime
+      // with KJS whereas we report a syntax error at compile time.
+      ReportMessage("invalid_lhs_in_assignment", Vector<const char*>::empty());
+      *ok = false;
+      return NULL;
+    }
+  }
+
+
+  Token::Value op = Next();  // Get assignment operator.
+  int pos = scanner().location().beg_pos;
+  Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
+
+  // TODO(1231235): We try to estimate the set of properties set by
+  // constructors. We define a new property whenever there is an
+  // assignment to a property of 'this'. We should probably only add
+  // properties if we haven't seen them before. Otherwise we'll
+  // probably overestimate the number of properties.
+  Property* property = expression ? expression->AsProperty() : NULL;
+  if (op == Token::ASSIGN &&
+      property != NULL &&
+      property->obj()->AsVariableProxy() != NULL &&
+      property->obj()->AsVariableProxy()->is_this()) {
+    temp_scope_->AddProperty();
+  }
+
+  return NEW(Assignment(op, expression, right, pos));
+}
+
+
+// Precedence = 3
+Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
+  // ConditionalExpression ::
+  //   LogicalOrExpression
+  //   LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
+
+  // We start using the binary expression parser for prec >= 4 only!
+  Expression* expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
+  if (peek() != Token::CONDITIONAL) return expression;
+  Consume(Token::CONDITIONAL);
+  // In parsing the first assignment expression in conditional
+  // expressions we always accept the 'in' keyword; see ECMA-262,
+  // section 11.12, page 58.
+  Expression* left = ParseAssignmentExpression(true, CHECK_OK);
+  Expect(Token::COLON, CHECK_OK);
+  Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
+  return NEW(Conditional(expression, left, right));
+}
+
+
+static int Precedence(Token::Value tok, bool accept_IN) {
+  if (tok == Token::IN && !accept_IN)
+    return 0;  // 0 precedence will terminate binary expression parsing
+
+  return Token::Precedence(tok);
+}
+
+
+// Precedence >= 4
+Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
+  ASSERT(prec >= 4);
+  Expression* x = ParseUnaryExpression(CHECK_OK);
+  for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
+    // prec1 >= 4
+    while (Precedence(peek(), accept_IN) == prec1) {
+      Token::Value op = Next();
+      Expression* y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
+
+      // Compute some expressions involving only number literals.
+      if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber() &&
+          y && y->AsLiteral() && y->AsLiteral()->handle()->IsNumber()) {
+        double x_val = x->AsLiteral()->handle()->Number();
+        double y_val = y->AsLiteral()->handle()->Number();
+
+        switch (op) {
+          case Token::ADD:
+            x = NewNumberLiteral(x_val + y_val);
+            continue;
+          case Token::SUB:
+            x = NewNumberLiteral(x_val - y_val);
+            continue;
+          case Token::MUL:
+            x = NewNumberLiteral(x_val * y_val);
+            continue;
+          case Token::DIV:
+            x = NewNumberLiteral(x_val / y_val);
+            continue;
+          case Token::BIT_OR:
+            x = NewNumberLiteral(DoubleToInt32(x_val) | DoubleToInt32(y_val));
+            continue;
+          case Token::BIT_AND:
+            x = NewNumberLiteral(DoubleToInt32(x_val) & DoubleToInt32(y_val));
+            continue;
+          case Token::BIT_XOR:
+            x = NewNumberLiteral(DoubleToInt32(x_val) ^ DoubleToInt32(y_val));
+            continue;
+          case Token::SHL: {
+            int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
+            x = NewNumberLiteral(value);
+            continue;
+          }
+          case Token::SHR: {
+            uint32_t shift = DoubleToInt32(y_val) & 0x1f;
+            uint32_t value = DoubleToUint32(x_val) >> shift;
+            x = NewNumberLiteral(value);
+            continue;
+          }
+          case Token::SAR: {
+            uint32_t shift = DoubleToInt32(y_val) & 0x1f;
+            int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
+            x = NewNumberLiteral(value);
+            continue;
+          }
+          default:
+            break;
+        }
+      }
+
+      // For now we distinguish between comparisons and other binary
+      // operations.  (We could combine the two and get rid of this
+      // code an AST node eventually.)
+      if (Token::IsCompareOp(op)) {
+        // We have a comparison.
+        Token::Value cmp = op;
+        switch (op) {
+          case Token::NE: cmp = Token::EQ; break;
+          case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
+          default: break;
+        }
+        x = NEW(CompareOperation(cmp, x, y));
+        if (cmp != op) {
+          // The comparison was negated - add a NOT.
+          x = NEW(UnaryOperation(Token::NOT, x));
+        }
+
+      } else {
+        // We have a "normal" binary operation.
+        x = NEW(BinaryOperation(op, x, y));
+      }
+    }
+  }
+  return x;
+}
+
+
+Expression* Parser::ParseUnaryExpression(bool* ok) {
+  // UnaryExpression ::
+  //   PostfixExpression
+  //   'delete' UnaryExpression
+  //   'void' UnaryExpression
+  //   'typeof' UnaryExpression
+  //   '++' UnaryExpression
+  //   '--' UnaryExpression
+  //   '+' UnaryExpression
+  //   '-' UnaryExpression
+  //   '~' UnaryExpression
+  //   '!' UnaryExpression
+
+  Token::Value op = peek();
+  if (Token::IsUnaryOp(op)) {
+    op = Next();
+    Expression* x = ParseUnaryExpression(CHECK_OK);
+
+    // Compute some expressions involving only number literals.
+    if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber()) {
+      double x_val = x->AsLiteral()->handle()->Number();
+      switch (op) {
+        case Token::ADD:
+          return x;
+        case Token::SUB:
+          return NewNumberLiteral(-x_val);
+        case Token::BIT_NOT:
+          return NewNumberLiteral(~DoubleToInt32(x_val));
+        default: break;
+      }
+    }
+
+    return NEW(UnaryOperation(op, x));
+
+  } else if (Token::IsCountOp(op)) {
+    op = Next();
+    Expression* x = ParseUnaryExpression(CHECK_OK);
+    if (x == NULL || !x->IsValidLeftHandSide()) {
+      if (x != NULL && x->AsCall() != NULL) {
+        // According to ECMA-262 host function calls are permitted to
+        // return references.  This cannot happen in our system so we
+        // will always get an error.  We could report this as a syntax
+        // error here but for compatibility with KJS and SpiderMonkey we
+        // choose to report the error at runtime.
+        Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol();
+        x = NewThrowReferenceError(type);
+      } else {
+        // Invalid left hand side expressions that are not function
+        // calls are reported as syntax errors at compile time.
+        ReportMessage("invalid_lhs_in_prefix_op", Vector<const char*>::empty());
+        *ok = false;
+        return NULL;
+      }
+    }
+    return NEW(CountOperation(true /* prefix */, op, x));
+
+  } else {
+    return ParsePostfixExpression(ok);
+  }
+}
+
+
+Expression* Parser::ParsePostfixExpression(bool* ok) {
+  // PostfixExpression ::
+  //   LeftHandSideExpression ('++' | '--')?
+
+  Expression* result = ParseLeftHandSideExpression(CHECK_OK);
+  if (!scanner_.has_line_terminator_before_next() && Token::IsCountOp(peek())) {
+    if (result == NULL || !result->IsValidLeftHandSide()) {
+      if (result != NULL && result->AsCall() != NULL) {
+        // According to ECMA-262 host function calls are permitted to
+        // return references.  This cannot happen in our system so we
+        // will always get an error.  We could report this as a syntax
+        // error here but for compatibility with KJS and SpiderMonkey we
+        // choose to report the error at runtime.
+        Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol();
+        result = NewThrowReferenceError(type);
+      } else {
+        // Invalid left hand side expressions that are not function
+        // calls are reported as syntax errors at compile time.
+        ReportMessage("invalid_lhs_in_postfix_op",
+                      Vector<const char*>::empty());
+        *ok = false;
+        return NULL;
+      }
+    }
+    Token::Value next = Next();
+    result = NEW(CountOperation(false /* postfix */, next, result));
+  }
+  return result;
+}
+
+
+Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
+  // LeftHandSideExpression ::
+  //   (NewExpression | MemberExpression) ...
+
+  Expression* result;
+  if (peek() == Token::NEW) {
+    result = ParseNewExpression(CHECK_OK);
+  } else {
+    result = ParseMemberExpression(CHECK_OK);
+  }
+
+  while (true) {
+    switch (peek()) {
+      case Token::LBRACK: {
+        Consume(Token::LBRACK);
+        int pos = scanner().location().beg_pos;
+        Expression* index = ParseExpression(true, CHECK_OK);
+        result = factory()->NewProperty(result, index, pos);
+        Expect(Token::RBRACK, CHECK_OK);
+        break;
+      }
+
+      case Token::LPAREN: {
+        int pos = scanner().location().beg_pos;
+        ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
+
+        // Keep track of eval() calls since they disable all local variable
+        // optimizations. We can ignore locally declared variables with
+        // name 'eval' since they override the global 'eval' function. We
+        // only need to look at unresolved variables (VariableProxies).
+
+        if (!is_pre_parsing_) {
+          // We assume that only a function called 'eval' can be used
+          // to invoke the global eval() implementation. This permits
+          // for massive optimizations.
+          VariableProxy* callee = result->AsVariableProxy();
+          if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
+            // We do not allow direct calls to 'eval' in our internal
+            // JS files. Use builtin functions instead.
+            ASSERT(!Bootstrapper::IsActive());
+            top_scope_->RecordEvalCall();
+          } else {
+            // This is rather convoluted code to check if we're calling
+            // a function named 'eval' through a property access. If so,
+            // we mark it as a possible eval call (we don't know if the
+            // receiver will resolve to the global object or not), but
+            // we do not treat the call as an eval() call - we let the
+            // call get through to the JavaScript eval code defined in
+            // v8natives.js.
+            Property* property = result->AsProperty();
+            if (property != NULL) {
+              Literal* key = property->key()->AsLiteral();
+              if (key != NULL &&
+                  key->handle().is_identical_to(Factory::eval_symbol())) {
+                // We do not allow direct calls to 'eval' in our
+                // internal JS files. Use builtin functions instead.
+                ASSERT(!Bootstrapper::IsActive());
+                top_scope_->RecordEvalCall();
+              }
+            }
+          }
+        }
+
+        // Optimize the eval() case w/o arguments so we
+        // don't need to handle it every time at runtime.
+        //
+        // Note: For now we don't do static eval analysis
+        // as it appears that we need to be able to call
+        // eval() via alias names. We leave the code as
+        // is, in case we want to enable this again in the
+        // future.
+        const bool is_eval = false;
+        if (is_eval && args->length() == 0) {
+          result = NEW(Literal(Factory::undefined_value()));
+        } else {
+          result = factory()->NewCall(result, args, is_eval, pos);
+        }
+        break;
+      }
+
+      case Token::PERIOD: {
+        Consume(Token::PERIOD);
+        int pos = scanner().location().beg_pos;
+        Handle<String> name = ParseIdentifier(CHECK_OK);
+        result = factory()->NewProperty(result, NEW(Literal(name)), pos);
+        break;
+      }
+
+      default:
+        return result;
+    }
+  }
+}
+
+
+Expression* Parser::ParseNewExpression(bool* ok) {
+  // NewExpression ::
+  //   ('new')+ MemberExpression
+
+  // The grammar for new expressions is pretty warped. The keyword
+  // 'new' can either be a part of the new expression (where it isn't
+  // followed by an argument list) or a part of the member expression,
+  // where it must be followed by an argument list. To accommodate
+  // this, we parse the 'new' keywords greedily and keep track of how
+  // many we have parsed. This information is then passed on to the
+  // member expression parser, which is only allowed to match argument
+  // lists as long as it has 'new' prefixes left
+  List<int> new_positions(4);
+  while (peek() == Token::NEW) {
+    Consume(Token::NEW);
+    new_positions.Add(scanner().location().beg_pos);
+  }
+  ASSERT(new_positions.length() > 0);
+
+  Expression* result =
+      ParseMemberWithNewPrefixesExpression(&new_positions, CHECK_OK);
+  while (!new_positions.is_empty()) {
+    int last = new_positions.RemoveLast();
+    result = NEW(CallNew(result, new ZoneList<Expression*>(0), last));
+  }
+  return result;
+}
+
+
+Expression* Parser::ParseMemberExpression(bool* ok) {
+  static List<int> new_positions(0);
+  return ParseMemberWithNewPrefixesExpression(&new_positions, ok);
+}
+
+
+Expression* Parser::ParseMemberWithNewPrefixesExpression(
+    List<int>* new_positions,
+    bool* ok) {
+  // MemberExpression ::
+  //   (PrimaryExpression | FunctionLiteral)
+  //     ('[' Expression ']' | '.' Identifier | Arguments)*
+
+  // Parse the initial primary or function expression.
+  Expression* result = NULL;
+  if (peek() == Token::FUNCTION) {
+    Expect(Token::FUNCTION, CHECK_OK);
+    int function_token_position = scanner().location().beg_pos;
+    Handle<String> name;
+    if (peek() == Token::IDENTIFIER) name = ParseIdentifier(CHECK_OK);
+    result = ParseFunctionLiteral(name, function_token_position,
+                                  NESTED, CHECK_OK);
+  } else {
+    result = ParsePrimaryExpression(CHECK_OK);
+  }
+
+  while (true) {
+    switch (peek()) {
+      case Token::LBRACK: {
+        Consume(Token::LBRACK);
+        int pos = scanner().location().beg_pos;
+        Expression* index = ParseExpression(true, CHECK_OK);
+        result = factory()->NewProperty(result, index, pos);
+        Expect(Token::RBRACK, CHECK_OK);
+        break;
+      }
+      case Token::PERIOD: {
+        Consume(Token::PERIOD);
+        int pos = scanner().location().beg_pos;
+        Handle<String> name = ParseIdentifier(CHECK_OK);
+        result = factory()->NewProperty(result, NEW(Literal(name)), pos);
+        break;
+      }
+      case Token::LPAREN: {
+        if (new_positions->is_empty()) return result;
+        // Consume one of the new prefixes (already parsed).
+        ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
+        int last = new_positions->RemoveLast();
+        result = NEW(CallNew(result, args, last));
+        break;
+      }
+      default:
+        return result;
+    }
+  }
+}
+
+
+DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
+  // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
+  // contexts this is used as a statement which invokes the debugger as i a
+  // break point is present.
+  // DebuggerStatement ::
+  //   'debugger' ';'
+
+  Expect(Token::DEBUGGER, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+  return NEW(DebuggerStatement());
+}
+
+
+void Parser::ReportUnexpectedToken(Token::Value token) {
+  // We don't report stack overflows here, to avoid increasing the
+  // stack depth even further.  Instead we report it after parsing is
+  // over, in ParseProgram.
+  if (token == Token::ILLEGAL && scanner().stack_overflow())
+    return;
+  // Four of the tokens are treated specially
+  switch (token) {
+  case Token::EOS:
+    return ReportMessage("unexpected_eos", Vector<const char*>::empty());
+  case Token::NUMBER:
+    return ReportMessage("unexpected_token_number",
+                         Vector<const char*>::empty());
+  case Token::STRING:
+    return ReportMessage("unexpected_token_string",
+                         Vector<const char*>::empty());
+  case Token::IDENTIFIER:
+    return ReportMessage("unexpected_token_identifier",
+                         Vector<const char*>::empty());
+  default:
+    const char* name = Token::String(token);
+    ASSERT(name != NULL);
+    ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
+  }
+}
+
+
+Expression* Parser::ParsePrimaryExpression(bool* ok) {
+  // PrimaryExpression ::
+  //   'this'
+  //   'null'
+  //   'true'
+  //   'false'
+  //   Identifier
+  //   Number
+  //   String
+  //   ArrayLiteral
+  //   ObjectLiteral
+  //   RegExpLiteral
+  //   '(' Expression ')'
+
+  Expression* result = NULL;
+  switch (peek()) {
+    case Token::THIS: {
+      Consume(Token::THIS);
+      if (is_pre_parsing_) {
+        result = VariableProxySentinel::this_proxy();
+      } else {
+        VariableProxy* recv = top_scope_->receiver();
+        recv->var_uses()->RecordRead(1);
+        result = recv;
+      }
+      break;
+    }
+
+    case Token::NULL_LITERAL:
+      Consume(Token::NULL_LITERAL);
+      result = NEW(Literal(Factory::null_value()));
+      break;
+
+    case Token::TRUE_LITERAL:
+      Consume(Token::TRUE_LITERAL);
+      result = NEW(Literal(Factory::true_value()));
+      break;
+
+    case Token::FALSE_LITERAL:
+      Consume(Token::FALSE_LITERAL);
+      result = NEW(Literal(Factory::false_value()));
+      break;
+
+    case Token::IDENTIFIER: {
+      Handle<String> name = ParseIdentifier(CHECK_OK);
+      if (is_pre_parsing_) {
+        result = VariableProxySentinel::identifier_proxy();
+      } else {
+        result = top_scope_->NewUnresolved(name, inside_with());
+      }
+      break;
+    }
+
+    case Token::NUMBER: {
+      Consume(Token::NUMBER);
+      double value =
+        StringToDouble(scanner_.literal_string(), ALLOW_HEX | ALLOW_OCTALS);
+      result = NewNumberLiteral(value);
+      break;
+    }
+
+    case Token::STRING: {
+      Consume(Token::STRING);
+      Handle<String> symbol =
+          factory()->LookupSymbol(scanner_.literal_string(),
+                                  scanner_.literal_length());
+      result = NEW(Literal(symbol));
+      break;
+    }
+
+    case Token::ASSIGN_DIV:
+      result = ParseRegExpLiteral(true, CHECK_OK);
+      break;
+
+    case Token::DIV:
+      result = ParseRegExpLiteral(false, CHECK_OK);
+      break;
+
+    case Token::LBRACK:
+      result = ParseArrayLiteral(CHECK_OK);
+      break;
+
+    case Token::LBRACE:
+      result = ParseObjectLiteral(CHECK_OK);
+      break;
+
+    case Token::LPAREN:
+      Consume(Token::LPAREN);
+      result = ParseExpression(true, CHECK_OK);
+      Expect(Token::RPAREN, CHECK_OK);
+      break;
+
+    case Token::MOD:
+      if (allow_natives_syntax_ || extension_ != NULL) {
+        result = ParseV8Intrinsic(CHECK_OK);
+        break;
+      }
+      // If we're not allowing special syntax we fall-through to the
+      // default case.
+
+    default: {
+      Token::Value tok = peek();
+      // Token::Peek returns the value of the next token but
+      // location() gives info about the current token.
+      // Therefore, we need to read ahead to the next token
+      Next();
+      ReportUnexpectedToken(tok);
+      *ok = false;
+      return NULL;
+    }
+  }
+
+  return result;
+}
+
+
+Expression* Parser::ParseArrayLiteral(bool* ok) {
+  // ArrayLiteral ::
+  //   '[' Expression? (',' Expression?)* ']'
+
+  ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4);
+  Expect(Token::LBRACK, CHECK_OK);
+  while (peek() != Token::RBRACK) {
+    Expression* elem;
+    if (peek() == Token::COMMA) {
+      elem = GetLiteralTheHole();
+    } else {
+      elem = ParseAssignmentExpression(true, CHECK_OK);
+    }
+    values.Add(elem);
+    if (peek() != Token::RBRACK) {
+      Expect(Token::COMMA, CHECK_OK);
+    }
+  }
+  Expect(Token::RBRACK, CHECK_OK);
+
+  // Update the scope information before the pre-parsing bailout.
+  temp_scope_->set_contains_array_literal();
+
+  if (is_pre_parsing_) return NULL;
+
+  // Allocate a fixed array with all the literals.
+  Handle<FixedArray> literals =
+      Factory::NewFixedArray(values.length(), TENURED);
+
+  // Fill in the literals.
+  for (int i = 0; i < values.length(); i++) {
+    Literal* literal = values.at(i)->AsLiteral();
+    if (literal == NULL) {
+      literals->set_the_hole(i);
+    } else {
+      literals->set(i, *literal->handle());
+    }
+  }
+
+  return NEW(ArrayLiteral(literals, values.elements()));
+}
+
+
+bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
+  return property != NULL &&
+         property->kind() != ObjectLiteral::Property::PROTOTYPE;
+}
+
+
+Literal* Parser::GetBoilerplateValue(ObjectLiteral::Property* property) {
+  if (property->kind() == ObjectLiteral::Property::CONSTANT)
+    return property->value()->AsLiteral();
+  return GetLiteralUndefined();
+}
+
+
+Expression* Parser::ParseObjectLiteral(bool* ok) {
+  // ObjectLiteral ::
+  //   '{' (
+  //       ((Identifier | String | Number) ':' AssignmentExpression)
+  //     | (('get' | 'set') FunctionLiteral)
+  //    )*[','] '}'
+
+  ZoneListWrapper<ObjectLiteral::Property> properties =
+      factory()->NewList<ObjectLiteral::Property>(4);
+  int number_of_boilerplate_properties = 0;
+
+  Expect(Token::LBRACE, CHECK_OK);
+  while (peek() != Token::RBRACE) {
+    Literal* key = NULL;
+    switch (peek()) {
+      case Token::IDENTIFIER: {
+        // Store identifier keys as literal symbols to avoid
+        // resolving them when compiling code for the object
+        // literal.
+        bool is_getter = false;
+        bool is_setter = false;
+        Handle<String> id =
+            ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+        if (is_getter || is_setter) {
+          // Special handling of getter and setter syntax.
+          if (peek() == Token::IDENTIFIER) {
+            Handle<String> name = ParseIdentifier(CHECK_OK);
+            FunctionLiteral* value =
+                ParseFunctionLiteral(name, RelocInfo::kNoPosition,
+                                     DECLARATION, CHECK_OK);
+            ObjectLiteral::Property* property =
+                NEW(ObjectLiteral::Property(is_getter, value));
+            if (IsBoilerplateProperty(property))
+              number_of_boilerplate_properties++;
+            properties.Add(property);
+            if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
+            continue;  // restart the while
+          }
+        }
+        key = NEW(Literal(id));
+        break;
+      }
+
+      case Token::STRING: {
+        Consume(Token::STRING);
+        Handle<String> string =
+            factory()->LookupSymbol(scanner_.literal_string(),
+                                    scanner_.literal_length());
+        uint32_t index;
+        if (!string.is_null() && string->AsArrayIndex(&index)) {
+          key = NewNumberLiteral(index);
+        } else {
+          key = NEW(Literal(string));
+        }
+        break;
+      }
+
+      case Token::NUMBER: {
+        Consume(Token::NUMBER);
+        double value =
+          StringToDouble(scanner_.literal_string(), ALLOW_HEX | ALLOW_OCTALS);
+        key = NewNumberLiteral(value);
+        break;
+      }
+
+      default:
+        Expect(Token::RBRACE, CHECK_OK);
+        break;
+    }
+
+    Expect(Token::COLON, CHECK_OK);
+    Expression* value = ParseAssignmentExpression(true, CHECK_OK);
+
+    ObjectLiteral::Property* property =
+        NEW(ObjectLiteral::Property(key, value));
+
+    // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
+    if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
+    properties.Add(property);
+
+    // TODO(1240767): Consider allowing trailing comma.
+    if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
+  }
+  Expect(Token::RBRACE, CHECK_OK);
+  // Computation of literal_index must happen before pre parse bailout.
+  int literal_index = temp_scope_->NextMaterializedLiteralIndex();
+  if (is_pre_parsing_) return NULL;
+
+  Handle<FixedArray> constant_properties =
+      Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED);
+  int position = 0;
+  for (int i = 0; i < properties.length(); i++) {
+    ObjectLiteral::Property* property = properties.at(i);
+    if (!IsBoilerplateProperty(property)) continue;
+
+    // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
+    // value for COMPUTED properties, the real value is filled in at
+    // runtime. The enumeration order is maintained.
+    Handle<Object> key = property->key()->handle();
+    Literal* literal = GetBoilerplateValue(property);
+
+    // Add name, value pair to the fixed array.
+    constant_properties->set(position++, *key);
+    constant_properties->set(position++, *literal->handle());
+  }
+
+  // Construct the expression for calling Runtime::CreateObjectLiteral
+  // with the literal array as argument.
+  ZoneList<Expression*>* arguments = new ZoneList<Expression*>(1);
+  arguments->Add(new Literal(constant_properties));
+  return new ObjectLiteral(constant_properties,
+                           properties.elements(),
+                           literal_index);
+}
+
+
+Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
+  if (!scanner_.ScanRegExpPattern(seen_equal)) {
+    Next();
+    ReportMessage("unterminated_regexp", Vector<const char*>::empty());
+    *ok = false;
+    return NULL;
+  }
+
+  int literal_index = temp_scope_->NextMaterializedLiteralIndex();
+
+  if (is_pre_parsing_) {
+    // If we're preparsing we just do all the parsing stuff without
+    // building anything.
+    scanner_.ScanRegExpFlags();
+    Next();
+    return NULL;
+  }
+
+  Handle<String> js_pattern =
+      Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED);
+  scanner_.ScanRegExpFlags();
+  Handle<String> js_flags =
+      Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED);
+  Next();
+
+  return new RegExpLiteral(js_pattern, js_flags, literal_index);
+}
+
+
+ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
+  // Arguments ::
+  //   '(' (AssignmentExpression)*[','] ')'
+
+  ZoneListWrapper<Expression> result = factory()->NewList<Expression>(4);
+  Expect(Token::LPAREN, CHECK_OK);
+  bool done = (peek() == Token::RPAREN);
+  while (!done) {
+    Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
+    result.Add(argument);
+    done = (peek() == Token::RPAREN);
+    if (!done) Expect(Token::COMMA, CHECK_OK);
+  }
+  Expect(Token::RPAREN, CHECK_OK);
+  return result.elements();
+}
+
+
+FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
+                                              int function_token_position,
+                                              FunctionLiteralType type,
+                                              bool* ok) {
+  // Function ::
+  //   '(' FormalParameterList? ')' '{' FunctionBody '}'
+
+  bool is_named = !var_name.is_null();
+
+  // The name associated with this function. If it's a function expression,
+  // this is the actual function name, otherwise this is the name of the
+  // variable declared and initialized with the function (expression). In
+  // that case, we don't have a function name (it's empty).
+  Handle<String> name = is_named ? var_name : factory()->EmptySymbol();
+  // The function name, if any.
+  Handle<String> function_name = factory()->EmptySymbol();
+  if (is_named && (type == EXPRESSION || type == NESTED)) {
+    function_name = name;
+  }
+
+  int num_parameters = 0;
+  // Parse function body.
+  { Scope::Type type = Scope::FUNCTION_SCOPE;
+    Scope* scope = factory()->NewScope(top_scope_, type, inside_with());
+    LexicalScope lexical_scope(this, scope);
+    TemporaryScope temp_scope(this);
+    top_scope_->SetScopeName(name);
+
+    //  FormalParameterList ::
+    //    '(' (Identifier)*[','] ')'
+    Expect(Token::LPAREN, CHECK_OK);
+    int start_pos = scanner_.location().beg_pos;
+    bool done = (peek() == Token::RPAREN);
+    while (!done) {
+      Handle<String> param_name = ParseIdentifier(CHECK_OK);
+      if (!is_pre_parsing_) {
+        top_scope_->AddParameter(top_scope_->Declare(param_name,
+                                                     Variable::VAR));
+        num_parameters++;
+      }
+      done = (peek() == Token::RPAREN);
+      if (!done) Expect(Token::COMMA, CHECK_OK);
+    }
+    Expect(Token::RPAREN, CHECK_OK);
+
+    Expect(Token::LBRACE, CHECK_OK);
+    ZoneListWrapper<Statement> body = factory()->NewList<Statement>(8);
+
+    // If we have a named function expression, we add a local variable
+    // declaration to the body of the function with the name of the
+    // function and let it refer to the function itself (closure).
+    // NOTE: We create a proxy and resolve it here so that in the
+    // future we can change the AST to only refer to VariableProxies
+    // instead of Variables and Proxies as is the case now.
+    if (!function_name.is_null() && function_name->length() > 0) {
+      Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
+      VariableProxy* fproxy =
+          top_scope_->NewUnresolved(function_name, inside_with());
+      fproxy->BindTo(fvar);
+      body.Add(new ExpressionStatement(
+                   new Assignment(Token::INIT_VAR, fproxy,
+                                  NEW(ThisFunction()),
+                                  RelocInfo::kNoPosition)));
+    }
+
+    // Determine if the function will be lazily compiled. The mode can
+    // only be PARSE_LAZILY if the --lazy flag is true.
+    bool is_lazily_compiled =
+        mode() == PARSE_LAZILY && top_scope_->HasTrivialOuterContext();
+
+    int materialized_literal_count;
+    int expected_property_count;
+    bool contains_array_literal;
+    if (is_lazily_compiled && pre_data() != NULL) {
+      FunctionEntry entry = pre_data()->GetFunctionEnd(start_pos);
+      int end_pos = entry.end_pos();
+      Counters::total_preparse_skipped.Increment(end_pos - start_pos);
+      scanner_.SeekForward(end_pos);
+      materialized_literal_count = entry.literal_count();
+      expected_property_count = entry.property_count();
+      contains_array_literal = entry.contains_array_literal();
+    } else {
+      ParseSourceElements(&body, Token::RBRACE, CHECK_OK);
+      materialized_literal_count = temp_scope.materialized_literal_count();
+      expected_property_count = temp_scope.expected_property_count();
+      contains_array_literal = temp_scope.contains_array_literal();
+    }
+
+    Expect(Token::RBRACE, CHECK_OK);
+    int end_pos = scanner_.location().end_pos;
+
+    FunctionEntry entry = log()->LogFunction(start_pos);
+    if (entry.is_valid()) {
+      entry.set_end_pos(end_pos);
+      entry.set_literal_count(materialized_literal_count);
+      entry.set_property_count(expected_property_count);
+      entry.set_contains_array_literal(contains_array_literal);
+    }
+
+    FunctionLiteral* function_literal =
+        NEW(FunctionLiteral(name, top_scope_,
+                            body.elements(), materialized_literal_count,
+                            contains_array_literal, expected_property_count,
+                            num_parameters, start_pos, end_pos,
+                            function_name->length() > 0));
+    if (!is_pre_parsing_) {
+      function_literal->set_function_token_position(function_token_position);
+    }
+    return function_literal;
+  }
+}
+
+
+Expression* Parser::ParseV8Intrinsic(bool* ok) {
+  // CallRuntime ::
+  //   '%' Identifier Arguments
+
+  Expect(Token::MOD, CHECK_OK);
+  Handle<String> name = ParseIdentifier(CHECK_OK);
+  Runtime::Function* function =
+      Runtime::FunctionForName(scanner_.literal_string());
+  ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
+  if (function == NULL && extension_ != NULL) {
+    // The extension structures are only accessible while parsing the
+    // very first time not when reparsing because of lazy compilation.
+    top_scope_->ForceEagerCompilation();
+  }
+
+  // Check for built-in macros.
+  if (!is_pre_parsing_) {
+    if (function == Runtime::FunctionForId(Runtime::kIS_VAR)) {
+      // %IS_VAR(x)
+      //   evaluates to x if x is a variable,
+      //   leads to a parse error otherwise
+      if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) {
+        return args->at(0);
+      }
+      *ok = false;
+    // Check here for other macros.
+    // } else if (function == Runtime::FunctionForId(Runtime::kIS_VAR)) {
+    //   ...
+    }
+
+    if (!*ok) {
+      // We found a macro but it failed.
+      ReportMessage("unable_to_parse", Vector<const char*>::empty());
+      return NULL;
+    }
+  }
+
+  // Otherwise we have a runtime call.
+  return NEW(CallRuntime(name, function, args));
+}
+
+
+void Parser::Consume(Token::Value token) {
+  Token::Value next = Next();
+  USE(next);
+  USE(token);
+  ASSERT(next == token);
+}
+
+
+void Parser::Expect(Token::Value token, bool* ok) {
+  Token::Value next = Next();
+  if (next == token) return;
+  ReportUnexpectedToken(next);
+  *ok = false;
+}
+
+
+void Parser::ExpectSemicolon(bool* ok) {
+  // Check for automatic semicolon insertion according to
+  // the rules given in ECMA-262, section 7.9, page 21.
+  Token::Value tok = peek();
+  if (tok == Token::SEMICOLON) {
+    Next();
+    return;
+  }
+  if (scanner_.has_line_terminator_before_next() ||
+      tok == Token::RBRACE ||
+      tok == Token::EOS) {
+    return;
+  }
+  Expect(Token::SEMICOLON, ok);
+}
+
+
+Literal* Parser::GetLiteralUndefined() {
+  return NEW(Literal(Factory::undefined_value()));
+}
+
+
+Literal* Parser::GetLiteralTheHole() {
+  return NEW(Literal(Factory::the_hole_value()));
+}
+
+
+Literal* Parser::GetLiteralNumber(double value) {
+  return NewNumberLiteral(value);
+}
+
+
+Handle<String> Parser::ParseIdentifier(bool* ok) {
+  Expect(Token::IDENTIFIER, ok);
+  if (!*ok) return Handle<String>();
+  return factory()->LookupSymbol(scanner_.literal_string(),
+                                 scanner_.literal_length());
+}
+
+// This function reads an identifier and determines whether or not it
+// is 'get' or 'set'.  The reason for not using ParseIdentifier and
+// checking on the output is that this involves heap allocation which
+// we can't do during preparsing.
+Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get,
+                                                 bool* is_set,
+                                                 bool* ok) {
+  Expect(Token::IDENTIFIER, ok);
+  if (!*ok) return Handle<String>();
+  if (scanner_.literal_length() == 3) {
+    const char* token = scanner_.literal_string();
+    *is_get = strcmp(token, "get") == 0;
+    *is_set = !*is_get && strcmp(token, "set") == 0;
+  }
+  return factory()->LookupSymbol(scanner_.literal_string(),
+                                 scanner_.literal_length());
+}
+
+
+// ----------------------------------------------------------------------------
+// Parser support
+
+
+bool Parser::TargetStackContainsLabel(Handle<String> label) {
+  for (int i = target_stack_->length(); i-- > 0;) {
+    BreakableStatement* stat = target_stack_->at(i)->AsBreakableStatement();
+    if (stat != NULL && ContainsLabel(stat->labels(), label))
+      return true;
+  }
+  return false;
+}
+
+
+BreakableStatement* Parser::LookupBreakTarget(Handle<String> label, bool* ok) {
+  bool anonymous = label.is_null();
+  for (int i = target_stack_->length(); i-- > 0;) {
+    BreakableStatement* stat = target_stack_->at(i)->AsBreakableStatement();
+    if (stat == NULL) continue;
+
+    if ((anonymous && stat->is_target_for_anonymous()) ||
+        (!anonymous && ContainsLabel(stat->labels(), label))) {
+      RegisterLabelUse(stat->break_target(), i);
+      return stat;
+    }
+  }
+  return NULL;
+}
+
+
+IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
+                                                 bool* ok) {
+  bool anonymous = label.is_null();
+  for (int i = target_stack_->length(); i-- > 0;) {
+    IterationStatement* stat = target_stack_->at(i)->AsIterationStatement();
+    if (stat == NULL) continue;
+
+    ASSERT(stat->is_target_for_anonymous());
+    if (anonymous || ContainsLabel(stat->labels(), label)) {
+      RegisterLabelUse(stat->continue_target(), i);
+      return stat;
+    }
+  }
+  return NULL;
+}
+
+
+void Parser::RegisterLabelUse(Label* label, int index) {
+  // Register that a label found at the given index in the target
+  // stack has been used from the top of the target stack. Add the
+  // label to any LabelCollectors passed on the stack.
+  for (int i = target_stack_->length(); i-- > index;) {
+    LabelCollector* collector = target_stack_->at(i)->AsLabelCollector();
+    if (collector != NULL) collector->AddLabel(label);
+  }
+}
+
+
+Literal* Parser::NewNumberLiteral(double number) {
+  return NEW(Literal(Factory::NewNumber(number, TENURED)));
+}
+
+
+Expression* Parser::NewThrowReferenceError(Handle<String> type) {
+  return NewThrowError(Factory::MakeReferenceError_symbol(),
+                       type, HandleVector<Object>(NULL, 0));
+}
+
+
+Expression* Parser::NewThrowSyntaxError(Handle<String> type,
+                                        Handle<Object> first) {
+  int argc = first.is_null() ? 0 : 1;
+  Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
+  return NewThrowError(Factory::MakeSyntaxError_symbol(), type, arguments);
+}
+
+
+Expression* Parser::NewThrowTypeError(Handle<String> type,
+                                      Handle<Object> first,
+                                      Handle<Object> second) {
+  ASSERT(!first.is_null() && !second.is_null());
+  Handle<Object> elements[] = { first, second };
+  Vector< Handle<Object> > arguments =
+      HandleVector<Object>(elements, ARRAY_SIZE(elements));
+  return NewThrowError(Factory::MakeTypeError_symbol(), type, arguments);
+}
+
+
+Expression* Parser::NewThrowError(Handle<String> constructor,
+                                  Handle<String> type,
+                                  Vector< Handle<Object> > arguments) {
+  if (is_pre_parsing_) return NULL;
+
+  int argc = arguments.length();
+  Handle<JSArray> array = Factory::NewJSArray(argc, TENURED);
+  ASSERT(array->IsJSArray() && array->HasFastElements());
+  for (int i = 0; i < argc; i++) {
+    Handle<Object> element = arguments[i];
+    if (!element.is_null()) {
+      array->SetFastElement(i, *element);
+    }
+  }
+  ZoneList<Expression*>* args = new ZoneList<Expression*>(2);
+  args->Add(new Literal(type));
+  args->Add(new Literal(array));
+  return new Throw(new CallRuntime(constructor, NULL, args),
+                   scanner().location().beg_pos);
+}
+
+
+// ----------------------------------------------------------------------------
+// Regular expressions
+
+
+RegExpParser::RegExpParser(unibrow::CharacterStream* in,
+                           Handle<String>* error,
+                           bool multiline_mode)
+  : current_(kEndMarker),
+    next_(kEndMarker),
+    has_more_(true),
+    has_next_(true),
+    multiline_mode_(multiline_mode),
+    captures_seen_(0),
+    in_(in),
+    error_(error),
+    pushback_count_(0) {
+  Advance(2);
+}
+
+
+void RegExpParser::Advance() {
+  current_ = next_;
+  has_more_ = has_next_;
+  if (pushback_count_ > 0) {
+    pushback_count_--;
+    next_ = pushback_buffer_[pushback_count_];
+    has_next_ = true;
+  } else if (in()->has_more()) {
+    next_ = in()->GetNext();
+  } else {
+    next_ = kEndMarker;
+    has_next_ = false;
+  }
+}
+
+
+void RegExpParser::Advance(int dist) {
+  for (int i = 0; i < dist; i++)
+    Advance();
+}
+
+
+void RegExpParser::PushBack(uc32 character) {
+  if (has_next_) {
+    ASSERT(pushback_count_ < kMaxPushback);
+    pushback_buffer_[pushback_count_] = next_;
+    pushback_count_++;
+  }
+  if (has_more_) {
+    next_ = current_;
+    has_next_ = true;
+  }
+  current_ = character;
+  has_more_ = true;
+}
+
+
+bool RegExpParser::CanPushBack() {
+  return (pushback_count_ < kMaxPushback);
+}
+
+
+RegExpTree* RegExpParser::ReportError(Vector<const char> message, bool* ok) {
+  *ok = false;
+  *error_ = Factory::NewStringFromAscii(message, NOT_TENURED);
+  return NULL;
+}
+
+
+// Pattern ::
+//   Disjunction
+RegExpTree* RegExpParser::ParsePattern(bool* ok) {
+  return ParseDisjunction(ok);
+}
+
+
+// Disjunction ::
+//   Alternative
+//   Alternative | Disjunction
+RegExpTree* RegExpParser::ParseDisjunction(bool* ok) {
+  RegExpTree* first = ParseAlternative(CHECK_OK);
+  if (current() == '|') {
+    ZoneList<RegExpTree*>* nodes = new ZoneList<RegExpTree*>(2);
+    nodes->Add(first);
+    while (current() == '|') {
+      Advance();
+      RegExpTree* next = ParseAlternative(CHECK_OK);
+      nodes->Add(next);
+    }
+    return new RegExpDisjunction(nodes);
+  } else {
+    return first;
+  }
+}
+
+
+static bool IsAlternativeTerminator(uc32 c) {
+  return c == '|' || c == ')' || c == RegExpParser::kEndMarker;
+}
+
+
+// Alternative ::
+//   [empty]
+//   Alternative Term
+RegExpTree* RegExpParser::ParseAlternative(bool* ok) {
+  if (!IsAlternativeTerminator(current())) {
+    RegExpTree* first = ParseTerm(CHECK_OK);
+    if (!IsAlternativeTerminator(current())) {
+      ZoneList<RegExpTree*>* nodes = new ZoneList<RegExpTree*>(2);
+      nodes->Add(first);
+      while (!IsAlternativeTerminator(current())) {
+        RegExpTree* next = ParseTerm(CHECK_OK);
+        nodes->Add(next);
+      }
+      return new RegExpAlternative(nodes);
+    } else {
+      return first;
+    }
+  } else {
+    return RegExpEmpty::GetInstance();
+  }
+}
+
+
+class SourceCharacter {
+ public:
+  static bool Is(uc32 c) {
+    switch (c) {
+      // case ']': case '}':
+      // In spidermonkey and jsc these are treated as source characters
+      // so we do too.
+      case '^': case '$': case '\\': case '.': case '*': case '+':
+      case '?': case '(': case ')': case '[': case '{': case '|':
+      case RegExpParser::kEndMarker:
+        return false;
+      default:
+        return true;
+    }
+  }
+};
+
+
+static unibrow::Predicate<SourceCharacter> source_character;
+
+
+static inline bool IsSourceCharacter(uc32 c) {
+  return source_character.get(c);
+}
+
+
+static bool IsSpecialEscape(uc32 c) {
+  switch (c) {
+    case 'b': case 'B': case 'd': case 'D': case 's': case 'S':
+    case 'w': case 'W':
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+bool RegExpParser::ParseBackreferenceIndex(int* index_out) {
+  ASSERT_EQ('\\', current());
+  ASSERT('1' <= next() && next() <= '9');
+  ASSERT_EQ(0, pushback_count_);
+  // Try to parse a decimal literal that is less than then number
+  // of previously encountered left capturing parentheses.
+  // This is a not according the the ECMAScript specification. According to
+  // that, one must accept values up to the total number of left capturing
+  // parentheses in the entire input, even if they are meaningless.
+  if (captures_seen_ == 0)
+    return false;
+  int value = next() - '0';
+  if (value > captures_seen_)
+    return false;
+  static const int kMaxChars = kMaxPushback - 2;
+  EmbeddedVector<uc32, kMaxChars> chars_seen;
+  chars_seen[0] = next();
+  int char_count = 1;
+  Advance(2);
+  while (true) {
+    uc32 c = current();
+    if (IsDecimalDigit(c)) {
+      int next_value = 10 * value + (c - '0');
+      // To avoid reading past the end of the stack-allocated pushback
+      // buffers we only read kMaxChars before giving up.
+      if (next_value > captures_seen_ || char_count > kMaxChars) {
+        // If we give up we have to push the characters we read back
+        // onto the pushback buffer in the reverse order.
+        for (int i = 0; i < char_count; i++) {
+          PushBack(chars_seen[char_count - i - 1]);
+        }
+        PushBack('\\');
+        return false;
+      }
+      value = next_value;
+      chars_seen[char_count++] = current();
+      Advance();
+    } else {
+      *index_out = value;
+      return true;
+    }
+  }
+}
+
+
+// Term ::
+//   Assertion
+//   Atom
+//   Atom Quantifier
+RegExpTree* RegExpParser::ParseTerm(bool* ok) {
+  RegExpTree* atom = NULL;
+  switch (current()) {
+    // Assertion ::
+    //   ^
+    //   $
+    //   \ b
+    //   \ B
+    case '^':
+      Advance();
+      return new RegExpAssertion(
+          multiline_mode_ ? RegExpAssertion::START_OF_LINE
+                          : RegExpAssertion::START_OF_INPUT);
+    case '$':
+      Advance();
+      return new RegExpAssertion(
+          multiline_mode_ ? RegExpAssertion::END_OF_LINE
+                          : RegExpAssertion::END_OF_INPUT);
+    case '.':
+      Advance();
+      atom = new RegExpCharacterClass(CharacterRange::CharacterClass('.'));
+      break;
+    case '(':
+      atom = ParseGroup(CHECK_OK);
+      break;
+    case '[':
+      atom = ParseCharacterClass(CHECK_OK);
+      break;
+    // Atom ::
+    //   \ AtomEscape
+    case '\\':
+      if (has_next()) {
+        switch (next()) {
+          case 'b':
+            Advance(2);
+            return new RegExpAssertion(RegExpAssertion::BOUNDARY);
+          case 'B':
+            Advance(2);
+            return new RegExpAssertion(RegExpAssertion::NON_BOUNDARY);
+          // AtomEscape ::
+          //   CharacterClassEscape
+          //
+          // CharacterClassEscape :: one of
+          //   d D s S w W
+          case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
+            uc32 c = next();
+            Advance(2);
+            atom = new RegExpCharacterClass(CharacterRange::CharacterClass(c));
+            goto has_read_atom;
+          }
+          case '1': case '2': case '3': case '4': case '5': case '6':
+          case '7': case '8': case '9': {
+            int index = 0;
+            if (ParseBackreferenceIndex(&index)) {
+              atom = new RegExpBackreference(index);
+              goto has_read_atom;
+            } else {
+              // If this is not a backreference we go to the atom parser
+              // which will read it as an octal escape or identity escape.
+              goto parse_atom;
+            }
+          }
+          default:
+            goto parse_atom;
+        }
+      }
+      // All other escapes fall through to the default case since
+      // they correspond to single characters that can be
+      // represented within atoms.
+    default: {
+     parse_atom:
+      atom = ParseAtom(CHECK_OK);
+      break;
+    }
+  }
+ has_read_atom:
+  int min;
+  int max;
+  switch (current()) {
+    // QuantifierPrefix ::
+    //   *
+    //   +
+    //   ?
+    //   {
+    case '*':
+      min = 0;
+      max = RegExpQuantifier::kInfinity;
+      Advance();
+      break;
+    case '+':
+      min = 1;
+      max = RegExpQuantifier::kInfinity;
+      Advance();
+      break;
+    case '?':
+      min = 0;
+      max = 1;
+      Advance();
+      break;
+    case '{':
+      ParseIntervalQuantifier(&min, &max, CHECK_OK);
+      break;
+    default:
+      return atom;
+  }
+  bool is_greedy = true;
+  if (current() == '?') {
+    is_greedy = false;
+    Advance();
+  }
+  return new RegExpQuantifier(min, max, is_greedy, atom);
+}
+
+
+// QuantifierPrefix ::
+//   { DecimalDigits }
+//   { DecimalDigits , }
+//   { DecimalDigits , DecimalDigits }
+void* RegExpParser::ParseIntervalQuantifier(int* min_out,
+                                            int* max_out,
+                                            bool* ok) {
+  ASSERT_EQ(current(), '{');
+  static const char* kInvalidQuantifier = "Invalid quantifier";
+  Advance();
+  int min = 0;
+  if (!IsDecimalDigit(current())) {
+    // JSC allows {} and {,} as quantifiers (and { and } and all
+    // sorts of crazy stuff) but my puny human brain has been unable
+    // to figure out what they mean exactly, if anything.  For now
+    // we follow the spec and report a syntax error.
+    ReportError(CStrVector(kInvalidQuantifier), CHECK_OK);
+  }
+  while (IsDecimalDigit(current())) {
+    min = 10 * min + (current() - '0');
+    Advance();
+  }
+  int max = 0;
+  if (current() == '}') {
+    max = min;
+    Advance();
+  } else if (current() == ',') {
+    Advance();
+    if (current() == '}') {
+      max = RegExpQuantifier::kInfinity;
+      Advance();
+    } else {
+      while (IsDecimalDigit(current())) {
+        max = 10 * max + (current() - '0');
+        Advance();
+      }
+      if (current() != '}') {
+        ReportError(CStrVector(kInvalidQuantifier), CHECK_OK);
+      }
+      Advance();
+    }
+  } else {
+    ReportError(CStrVector(kInvalidQuantifier), CHECK_OK);
+  }
+  *min_out = min;
+  *max_out = max;
+  return NULL;
+}
+
+
+RegExpTree* RegExpParser::ParseAtom(bool* ok) {
+  ASSERT(current() == '\\' || IsSourceCharacter(current()));
+  ZoneList<uc16>* buf = new ZoneList<uc16>(4);
+  while (true) {
+    if (IsSourceCharacter(current())) {
+      buf->Add(current());
+      Advance();
+    } else if (current() == '\\') {
+      if (!has_next()) {
+        ReportError(CStrVector("\\ at end of pattern"), CHECK_OK);
+      } else if (IsSpecialEscape(next())) {
+        // If the next thing we see is a special escape we stop
+        // reading this atom.
+        break;
+      } else {
+        uc32 escape = ParseCharacterEscape(CHECK_OK);
+        buf->Add(escape);
+      }
+    } else {
+      break;
+    }
+  }
+  return new RegExpAtom(buf->ToConstVector());
+}
+
+// Upper and lower case letters differ by one bit.
+STATIC_CHECK('a'^'A' == 0x20);
+
+uc32 RegExpParser::ParseControlEscape(bool* ok) {
+  ASSERT(current() == 'c');
+  Advance();
+  if (!has_more()) {
+    ReportError(CStrVector("\\c at end of pattern"), ok);
+    return '\0';
+  }
+  uc32 letter = current() & ~(0x20);  // Collapse upper and lower case letters.
+  if (letter < 'A' || 'Z' < letter) {
+    // Non-spec error-correction: "\c" followed by non-control letter is
+    // interpreted as an IdentityEscape.
+    return 'c';
+  }
+  Advance();
+  return letter & 0x1f;  // Remainder modulo 32, per specification.
+}
+
+
+uc32 RegExpParser::ParseOctalLiteral(bool* ok) {
+  ASSERT('0' <= current() && current() <= '7');
+  // For compatibility with some other browsers (not all), we parse
+  // up to three octal digits with a value below 256.
+  uc32 value = current() - '0';
+  Advance();
+  if ('0' <= current() && current() <= '7') {
+    value = value * 8 + current() - '0';
+    Advance();
+    if (value < 32 && '0' <= current() && current() <= '7') {
+      value = value * 8 + current() - '0';
+      Advance();
+    }
+  }
+  return value;
+}
+
+bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
+  static const int kMaxChars = kMaxPushback;
+  EmbeddedVector<uc32, kMaxChars> chars_seen;
+  ASSERT(length <= kMaxChars);
+  uc32 val = 0;
+  bool done = false;
+  for (int i = 0; !done; i++) {
+    uc32 c = current();
+    int d = HexValue(c);
+    if (d < 0) {
+      while (i > 0) {
+        i--;
+        PushBack(chars_seen[i]);
+      }
+      return false;
+    }
+    val = val * 16 + d;
+    Advance();
+    if (i < length - 1) {
+      chars_seen[i] = c;
+    } else {
+      done = true;
+    }
+  }
+  *value = val;
+  return true;
+}
+
+
+uc32 RegExpParser::ParseCharacterEscape(bool* ok) {
+  ASSERT(current() == '\\');
+  ASSERT(has_next() && !IsSpecialEscape(next()));
+  Advance();
+  ASSERT(current() != 'b' && current() != 'B');
+  switch (current()) {
+    // ControlEscape :: one of
+    //   f n r t v
+    case 'f':
+      Advance();
+      return '\f';
+    case 'n':
+      Advance();
+      return '\n';
+    case 'r':
+      Advance();
+      return '\r';
+    case 't':
+      Advance();
+      return '\t';
+    case 'v':
+      Advance();
+      return '\v';
+    case 'c':
+      // Spec mandates that next character is ASCII letter.
+      // If not, we error-correct by interpreting "\c" as "c".
+      return ParseControlEscape(ok);
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7':
+      // For compatibility, we interpret a decimal escape that isn't
+      // a back reference (and therefore either \0 or not valid according
+      // to the specification) as a 1..3 digit octal character code.
+      return ParseOctalLiteral(ok);
+    case 'x': {
+      Advance();
+      uc32 value;
+      if (ParseHexEscape(2, &value)) {
+        return value;
+      }
+      // If \x is not followed by a two-digit hexadecimal, treat it
+      // as an identity escape.
+      return 'x';
+    }
+    case 'u': {
+      Advance();
+      uc32 value;
+      if (ParseHexEscape(4, &value)) {
+        return value;
+      }
+      // If \u is not followed by a four-digit hexadecimal, treat it
+      // as an identity escape.
+      return 'u';
+    }
+    default: {
+      // Extended identity escape. We accept any character that hasn't
+      // been matched by a more specific case, not just the subset required
+      // by the ECMAScript specification.
+      uc32 result = current();
+      Advance();
+      return result;
+    }
+  }
+  return 0;
+}
+
+
+RegExpTree* RegExpParser::ParseGroup(bool* ok) {
+  ASSERT_EQ(current(), '(');
+  char type = '(';
+  Advance();
+  if (current() == '?') {
+    switch (next()) {
+      case ':': case '=': case '!':
+        type = next();
+        Advance(2);
+        break;
+      default:
+        ReportError(CStrVector("Invalid group"), CHECK_OK);
+        break;
+    }
+  }
+  RegExpTree* body = ParseDisjunction(CHECK_OK);
+  if (current() != ')') {
+    ReportError(CStrVector("Unterminated group"), CHECK_OK);
+  }
+  Advance();
+  if (type == '(') {
+    captures_seen_++;
+    return new RegExpCapture(body);
+  } else if (type == ':') {
+    return body;
+  } else {
+    ASSERT(type == '=' || type == '!');
+    bool is_positive = (type == '=');
+    return new RegExpLookahead(body, is_positive);
+  }
+}
+
+
+CharacterRange RegExpParser::ParseClassAtom(bool* ok) {
+  uc32 first = current();
+  if (first == '\\') {
+    switch (next()) {
+      case 'b':
+        Advance(2);
+        return CharacterRange::Singleton('\b');
+      case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
+        uc32 c = next();
+        Advance(2);
+        return CharacterRange::CharacterClass(c);
+      }
+      default:
+        uc32 c = ParseCharacterEscape(CHECK_OK);
+        return CharacterRange::Singleton(c);
+    }
+  } else {
+    Advance();
+    return CharacterRange::Singleton(first);
+  }
+}
+
+
+RegExpTree* RegExpParser::ParseCharacterClass(bool* ok) {
+  static const char* kUnterminated = "Unterminated character class";
+  static const char* kIllegal = "Illegal character class";
+  static const char* kRangeOutOfOrder = "Range out of order in character class";
+
+  ASSERT_EQ(current(), '[');
+  Advance();
+  bool is_negated = false;
+  if (current() == '^') {
+    is_negated = true;
+    Advance();
+  }
+  ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+  while (has_more() && current() != ']') {
+    if (current() == '-') {
+      Advance();
+      ranges->Add(CharacterRange::Singleton('-'));
+    } else {
+      CharacterRange first = ParseClassAtom(CHECK_OK);
+      if (!first.is_character_class() && current() == '-') {
+        Advance();
+        CharacterRange next = ParseClassAtom(CHECK_OK);
+        if (next.is_character_class()) {
+          return ReportError(CStrVector(kIllegal), CHECK_OK);
+        }
+        if (first.from() > next.to()) {
+          ReportError(CStrVector(kRangeOutOfOrder), CHECK_OK);
+        }
+        ranges->Add(CharacterRange::Range(first.from(), next.to()));
+      } else {
+        ranges->Add(first);
+      }
+    }
+  }
+  if (!has_more()) {
+    return ReportError(CStrVector(kUnterminated), CHECK_OK);
+  }
+  Advance();
+  if (ranges->length() == 0) {
+    return RegExpEmpty::GetInstance();
+  } else {
+    return new RegExpCharacterClass(ranges, is_negated);
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// The Parser interface.
+
+// MakeAST() is just a wrapper for the corresponding Parser calls
+// so we don't have to expose the entire Parser class in the .h file.
+
+static bool always_allow_natives_syntax = false;
+
+
+ParserMessage::~ParserMessage() {
+  for (int i = 0; i < args().length(); i++)
+    DeleteArray(args()[i]);
+  DeleteArray(args().start());
+}
+
+
+ScriptDataImpl::~ScriptDataImpl() {
+  store_.Dispose();
+}
+
+
+int ScriptDataImpl::Length() {
+  return store_.length();
+}
+
+
+unsigned* ScriptDataImpl::Data() {
+  return store_.start();
+}
+
+
+ScriptDataImpl* PreParse(unibrow::CharacterStream* stream,
+                         v8::Extension* extension) {
+  Handle<Script> no_script;
+  bool allow_natives_syntax =
+      always_allow_natives_syntax ||
+      FLAG_allow_natives_syntax ||
+      Bootstrapper::IsActive();
+  PreParser parser(no_script, allow_natives_syntax, extension);
+  if (!parser.PreParseProgram(stream)) return NULL;
+  // The list owns the backing store so we need to clone the vector.
+  // That way, the result will be exactly the right size rather than
+  // the expected 50% too large.
+  Vector<unsigned> store = parser.recorder()->store()->ToVector().Clone();
+  return new ScriptDataImpl(store);
+}
+
+
+RegExpTree* ParseRegExp(unibrow::CharacterStream* stream,
+                        Handle<String>* error) {
+  ASSERT(error->is_null());
+  RegExpParser parser(stream, error, false);  // Get multiline flag somehow
+  bool ok = true;
+  RegExpTree* result = parser.ParsePattern(&ok);
+  if (!ok) {
+    ASSERT(result == NULL);
+    ASSERT(!error->is_null());
+  } else {
+    ASSERT(result != NULL);
+    ASSERT(error->is_null());
+  }
+  return result;
+}
+
+
+FunctionLiteral* MakeAST(bool compile_in_global_context,
+                         Handle<Script> script,
+                         v8::Extension* extension,
+                         ScriptDataImpl* pre_data) {
+  bool allow_natives_syntax =
+      always_allow_natives_syntax ||
+      FLAG_allow_natives_syntax ||
+      Bootstrapper::IsActive();
+  AstBuildingParser parser(script, allow_natives_syntax, extension, pre_data);
+  if (pre_data != NULL && pre_data->has_error()) {
+    Scanner::Location loc = pre_data->MessageLocation();
+    const char* message = pre_data->BuildMessage();
+    Vector<const char*> args = pre_data->BuildArgs();
+    parser.ReportMessageAt(loc, message, args);
+    DeleteArray(message);
+    for (int i = 0; i < args.length(); i++)
+      DeleteArray(args[i]);
+    DeleteArray(args.start());
+    return NULL;
+  }
+  Handle<String> source = Handle<String>(String::cast(script->source()));
+  SafeStringInputBuffer input(source.location());
+  FunctionLiteral* result = parser.ParseProgram(source,
+      &input, compile_in_global_context);
+  return result;
+}
+
+
+FunctionLiteral* MakeLazyAST(Handle<Script> script,
+                             Handle<String> name,
+                             int start_position,
+                             int end_position,
+                             bool is_expression) {
+  bool allow_natives_syntax_before = always_allow_natives_syntax;
+  always_allow_natives_syntax = true;
+  AstBuildingParser parser(script, true, NULL, NULL);  // always allow
+  always_allow_natives_syntax = allow_natives_syntax_before;
+  // Parse the function by pulling the function source from the script source.
+  Handle<String> script_source(String::cast(script->source()));
+  FunctionLiteral* result =
+      parser.ParseLazy(SubString(script_source, start_position, end_position),
+                       name,
+                       start_position,
+                       is_expression);
+  return result;
+}
+
+
+#undef NEW
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/parser.h b/regexp2000/src/parser.h
new file mode 100644 (file)
index 0000000..e572ac2
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PARSER_H_
+#define V8_PARSER_H_
+
+#include "scanner.h"
+
+namespace v8 { namespace internal {
+
+
+class ParserMessage : public Malloced {
+ public:
+  ParserMessage(Scanner::Location loc, const char* message,
+                Vector<const char*> args)
+      : loc_(loc),
+        message_(message),
+        args_(args) { }
+  ~ParserMessage();
+  Scanner::Location location() { return loc_; }
+  const char* message() { return message_; }
+  Vector<const char*> args() { return args_; }
+ private:
+  Scanner::Location loc_;
+  const char* message_;
+  Vector<const char*> args_;
+};
+
+
+class FunctionEntry BASE_EMBEDDED {
+ public:
+  explicit FunctionEntry(Vector<unsigned> backing) : backing_(backing) { }
+  FunctionEntry() : backing_(Vector<unsigned>::empty()) { }
+
+  int start_pos() { return backing_[kStartPosOffset]; }
+  void set_start_pos(int value) { backing_[kStartPosOffset] = value; }
+
+  int end_pos() { return backing_[kEndPosOffset]; }
+  void set_end_pos(int value) { backing_[kEndPosOffset] = value; }
+
+  int literal_count() { return backing_[kLiteralCountOffset]; }
+  void set_literal_count(int value) { backing_[kLiteralCountOffset] = value; }
+
+  int property_count() { return backing_[kPropertyCountOffset]; }
+  void set_property_count(int value) { backing_[kPropertyCountOffset] = value; }
+
+  bool contains_array_literal() {
+    return backing_[kContainsArrayLiteralOffset] != 0;
+  }
+  void set_contains_array_literal(bool value) {
+    backing_[kContainsArrayLiteralOffset] = value ? 1 : 0;
+  }
+
+  bool is_valid() { return backing_.length() > 0; }
+
+  static const int kSize = 5;
+
+ private:
+  Vector<unsigned> backing_;
+  static const int kStartPosOffset = 0;
+  static const int kEndPosOffset = 1;
+  static const int kLiteralCountOffset = 2;
+  static const int kPropertyCountOffset = 3;
+  static const int kContainsArrayLiteralOffset = 4;
+};
+
+
+class ScriptDataImpl : public ScriptData {
+ public:
+  explicit ScriptDataImpl(Vector<unsigned> store)
+      : store_(store),
+        last_entry_(0) { }
+  virtual ~ScriptDataImpl();
+  virtual int Length();
+  virtual unsigned* Data();
+  FunctionEntry GetFunctionEnd(int start);
+  bool SanityCheck();
+
+  Scanner::Location MessageLocation();
+  const char* BuildMessage();
+  Vector<const char*> BuildArgs();
+
+  bool has_error() { return store_[kHasErrorOffset]; }
+  unsigned magic() { return store_[kMagicOffset]; }
+  unsigned version() { return store_[kVersionOffset]; }
+
+  static const unsigned kMagicNumber = 0xBadDead;
+  static const unsigned kCurrentVersion = 1;
+
+  static const unsigned kMagicOffset = 0;
+  static const unsigned kVersionOffset = 1;
+  static const unsigned kHasErrorOffset = 2;
+  static const unsigned kSizeOffset = 3;
+  static const unsigned kHeaderSize = 4;
+
+ private:
+  unsigned Read(int position);
+  unsigned* ReadAddress(int position);
+  int EntryCount();
+  FunctionEntry nth(int n);
+
+  Vector<unsigned> store_;
+
+  // The last entry returned.  This is used to make lookup faster:
+  // the next entry to return is typically the next entry so lookup
+  // will usually be much faster if we start from the last entry.
+  int last_entry_;
+};
+
+
+// The parser: Takes a script and and context information, and builds a
+// FunctionLiteral AST node. Returns NULL and deallocates any allocated
+// AST nodes if parsing failed.
+FunctionLiteral* MakeAST(bool compile_in_global_context,
+                         Handle<Script> script,
+                         v8::Extension* extension,
+                         ScriptDataImpl* pre_data);
+
+
+ScriptDataImpl* PreParse(unibrow::CharacterStream* stream,
+                         v8::Extension* extension);
+
+RegExpTree* ParseRegExp(unibrow::CharacterStream* stream,
+                        Handle<String>* error);
+
+// Support for doing lazy compilation. The script is the script containing full
+// source of the script where the function is declared. The start_position and
+// end_position specifies the part of the script source which has the source
+// for the function decleration in the form:
+//
+//    (<formal parameters>) { <function body> }
+//
+// without any function keyword or name.
+//
+FunctionLiteral* MakeLazyAST(Handle<Script> script,
+                             Handle<String> name,
+                             int start_position,
+                             int end_position,
+                             bool is_expression);
+
+} }  // namespace v8::internal
+
+#endif  // V8_PARSER_H_
diff --git a/regexp2000/src/platform-linux.cc b/regexp2000/src/platform-linux.cc
new file mode 100644 (file)
index 0000000..46ca7dc
--- /dev/null
@@ -0,0 +1,697 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Platform specific code for Linux goes here
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdlib.h>
+
+// Ubuntu Dapper requires memory pages to be marked as
+// executable. Otherwise, OS raises an exception when executing code
+// in that page.
+#include <sys/types.h>  // mmap & munmap
+#include <sys/mman.h>   // mmap & munmap
+#include <sys/stat.h>   // open
+#include <sys/fcntl.h>  // open
+#include <unistd.h>     // getpagesize
+#include <execinfo.h>   // backtrace, backtrace_symbols
+#include <strings.h>    // index
+#include <errno.h>
+#include <stdarg.h>
+
+#undef MAP_TYPE
+
+#include "v8.h"
+
+#include "platform.h"
+
+
+namespace v8 { namespace internal {
+
+// 0 is never a valid thread id on Linux since tids and pids share a
+// name space and pid 0 is reserved (see man 2 kill).
+static const pthread_t kNoThread = (pthread_t) 0;
+
+
+double ceiling(double x) {
+  return ceil(x);
+}
+
+
+void OS::Setup() {
+  // Seed the random number generator.
+  // Convert the current time to a 64-bit integer first, before converting it
+  // to an unsigned. Going directly can cause an overflow and the seed to be
+  // set to all ones. The seed will be identical for different instances that
+  // call this setup code within the same millisecond.
+  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
+  srandom(static_cast<unsigned int>(seed));
+}
+
+
+int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
+  struct rusage usage;
+
+  if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
+  *secs = usage.ru_utime.tv_sec;
+  *usecs = usage.ru_utime.tv_usec;
+  return 0;
+}
+
+
+double OS::TimeCurrentMillis() {
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) < 0) return 0.0;
+  return (static_cast<double>(tv.tv_sec) * 1000) +
+         (static_cast<double>(tv.tv_usec) / 1000);
+}
+
+
+int64_t OS::Ticks() {
+  // Linux's gettimeofday has microsecond resolution.
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) < 0)
+    return 0;
+  return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
+}
+
+
+char* OS::LocalTimezone(double time) {
+  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
+  struct tm* t = localtime(&tv);
+  return const_cast<char*>(t->tm_zone);
+}
+
+
+double OS::DaylightSavingsOffset(double time) {
+  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
+  struct tm* t = localtime(&tv);
+  return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
+}
+
+
+double OS::LocalTimeOffset() {
+  time_t tv = time(NULL);
+  struct tm* t = localtime(&tv);
+  // tm_gmtoff includes any daylight savings offset, so subtract it.
+  return static_cast<double>(t->tm_gmtoff * msPerSecond -
+                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
+}
+
+
+FILE* OS::FOpen(const char* path, const char* mode) {
+  return fopen(path, mode);
+}
+
+
+void OS::Print(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  VPrint(format, args);
+  va_end(args);
+}
+
+
+void OS::VPrint(const char* format, va_list args) {
+  vprintf(format, args);
+}
+
+
+void OS::PrintError(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  VPrintError(format, args);
+  va_end(args);
+}
+
+
+void OS::VPrintError(const char* format, va_list args) {
+  vfprintf(stderr, format, args);
+}
+
+
+int OS::SNPrintF(Vector<char> str, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = VSNPrintF(str, format, args);
+  va_end(args);
+  return result;
+}
+
+
+int OS::VSNPrintF(Vector<char> str,
+                  const char* format,
+                  va_list args) {
+  int n = vsnprintf(str.start(), str.length(), format, args);
+  if (n < 0 || n >= str.length()) {
+    str[str.length() - 1] = '\0';
+    return -1;
+  } else {
+    return n;
+  }
+}
+
+
+void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
+  strncpy(dest.start(), src, n);
+}
+
+
+void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
+  wcscpy(dest.start(), src);
+}
+
+
+char *OS::StrDup(const char* str) {
+  return strdup(str);
+}
+
+
+double OS::nan_value() {
+  return NAN;
+}
+
+
+int OS::ActivationFrameAlignment() {
+  // No constraint on Linux.
+  return 0;
+}
+
+
+// We keep the lowest and highest addresses mapped as a quick way of
+// determining that pointers are outside the heap (used mostly in assertions
+// and verification).  The estimate is conservative, ie, not all addresses in
+// 'allocated' space are actually allocated to our heap.  The range is
+// [lowest, highest), inclusive on the low and and exclusive on the high end.
+static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
+static void* highest_ever_allocated = reinterpret_cast<void*>(0);
+
+
+static void UpdateAllocatedSpaceLimits(void* address, int size) {
+  lowest_ever_allocated = Min(lowest_ever_allocated, address);
+  highest_ever_allocated =
+      Max(highest_ever_allocated,
+          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
+}
+
+
+bool OS::IsOutsideAllocatedSpace(void* address) {
+  return address < lowest_ever_allocated || address >= highest_ever_allocated;
+}
+
+
+size_t OS::AllocateAlignment() {
+  return getpagesize();
+}
+
+
+void* OS::Allocate(const size_t requested,
+                   size_t* allocated,
+                   bool executable) {
+  const size_t msize = RoundUp(requested, getpagesize());
+  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (mbase == MAP_FAILED) {
+    LOG(StringEvent("OS::Allocate", "mmap failed"));
+    return NULL;
+  }
+  *allocated = msize;
+  UpdateAllocatedSpaceLimits(mbase, msize);
+  return mbase;
+}
+
+
+void OS::Free(void* buf, const size_t length) {
+  // TODO(1240712): munmap has a return value which is ignored here.
+  munmap(buf, length);
+}
+
+
+void OS::Sleep(int milliseconds) {
+  unsigned int ms = static_cast<unsigned int>(milliseconds);
+  usleep(1000 * ms);
+}
+
+
+void OS::Abort() {
+  // Redirect to std abort to signal abnormal program termination.
+  abort();
+}
+
+
+void OS::DebugBreak() {
+#if defined (__arm__) || defined(__thumb__)
+  asm("bkpt 0");
+#else
+  asm("int $3");
+#endif
+}
+
+
+class PosixMemoryMappedFile : public OS::MemoryMappedFile {
+ public:
+  PosixMemoryMappedFile(FILE* file, void* memory, int size)
+    : file_(file), memory_(memory), size_(size) { }
+  virtual ~PosixMemoryMappedFile();
+  virtual void* memory() { return memory_; }
+ private:
+  FILE* file_;
+  void* memory_;
+  int size_;
+};
+
+
+OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
+    void* initial) {
+  FILE* file = fopen(name, "w+");
+  if (file == NULL) return NULL;
+  int result = fwrite(initial, size, 1, file);
+  if (result < 1) {
+    fclose(file);
+    return NULL;
+  }
+  void* memory =
+      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
+  return new PosixMemoryMappedFile(file, memory, size);
+}
+
+
+PosixMemoryMappedFile::~PosixMemoryMappedFile() {
+  if (memory_) munmap(memory_, size_);
+  fclose(file_);
+}
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+static unsigned  StringToLongLong(char* buffer) {
+  return static_cast<unsigned>(strtoll(buffer, NULL, 16));  // NOLINT
+}
+
+#endif
+
+void OS::LogSharedLibraryAddresses() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  static const int MAP_LENGTH = 1024;
+  int fd = open("/proc/self/maps", O_RDONLY);
+  if (fd < 0) return;
+  while (true) {
+    char addr_buffer[11];
+    addr_buffer[0] = '0';
+    addr_buffer[1] = 'x';
+    addr_buffer[10] = 0;
+    int result = read(fd, addr_buffer + 2, 8);
+    if (result < 8) break;
+    unsigned start = StringToLongLong(addr_buffer);
+    result = read(fd, addr_buffer + 2, 1);
+    if (result < 1) break;
+    if (addr_buffer[2] != '-') break;
+    result = read(fd, addr_buffer + 2, 8);
+    if (result < 8) break;
+    unsigned end = StringToLongLong(addr_buffer);
+    char buffer[MAP_LENGTH];
+    int bytes_read = -1;
+    do {
+      bytes_read++;
+      if (bytes_read >= MAP_LENGTH - 1)
+        break;
+      result = read(fd, buffer + bytes_read, 1);
+      if (result < 1) break;
+    } while (buffer[bytes_read] != '\n');
+    buffer[bytes_read] = 0;
+    // Ignore mappings that are not executable.
+    if (buffer[3] != 'x') continue;
+    char* start_of_path = index(buffer, '/');
+    // There may be no filename in this line.  Skip to next.
+    if (start_of_path == NULL) continue;
+    buffer[bytes_read] = 0;
+    LOG(SharedLibraryEvent(start_of_path, start, end));
+  }
+  close(fd);
+#endif
+}
+
+
+int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+  void** addresses = NewArray<void*>(frames_size);
+
+  int frames_count = backtrace(addresses, frames_size);
+
+  char** symbols;
+  symbols = backtrace_symbols(addresses, frames_count);
+  if (symbols == NULL) {
+    DeleteArray(addresses);
+    return kStackWalkError;
+  }
+
+  for (int i = 0; i < frames_count; i++) {
+    frames[i].address = addresses[i];
+    // Format a text representation of the frame based on the information
+    // available.
+    SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
+             "%s",
+             symbols[i]);
+    // Make sure line termination is in place.
+    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
+  }
+
+  DeleteArray(addresses);
+  free(symbols);
+
+  return frames_count;
+}
+
+
+// Constants used for mmap.
+static const int kMmapFd = -1;
+static const int kMmapFdOffset = 0;
+
+
+VirtualMemory::VirtualMemory(size_t size) {
+  address_ = mmap(NULL, size, PROT_NONE,
+                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
+                  kMmapFd, kMmapFdOffset);
+  size_ = size;
+}
+
+
+VirtualMemory::~VirtualMemory() {
+  if (IsReserved()) {
+    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
+  }
+}
+
+
+bool VirtualMemory::IsReserved() {
+  return address_ != MAP_FAILED;
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
+  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+  if (MAP_FAILED == mmap(address, size, prot,
+                         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+                         kMmapFd, kMmapFdOffset)) {
+    return false;
+  }
+
+  UpdateAllocatedSpaceLimits(address, size);
+  return true;
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+  return mmap(address, size, PROT_NONE,
+              MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
+              kMmapFd, kMmapFdOffset) != MAP_FAILED;
+}
+
+
+class ThreadHandle::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(ThreadHandle::Kind kind) {
+    Initialize(kind);
+  }
+
+  void Initialize(ThreadHandle::Kind kind) {
+    switch (kind) {
+      case ThreadHandle::SELF: thread_ = pthread_self(); break;
+      case ThreadHandle::INVALID: thread_ = kNoThread; break;
+    }
+  }
+  pthread_t thread_;  // Thread handle for pthread.
+};
+
+
+ThreadHandle::ThreadHandle(Kind kind) {
+  data_ = new PlatformData(kind);
+}
+
+
+void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
+  data_->Initialize(kind);
+}
+
+
+ThreadHandle::~ThreadHandle() {
+  delete data_;
+}
+
+
+bool ThreadHandle::IsSelf() const {
+  return pthread_equal(data_->thread_, pthread_self());
+}
+
+
+bool ThreadHandle::IsValid() const {
+  return data_->thread_ != kNoThread;
+}
+
+
+Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+}
+
+
+Thread::~Thread() {
+}
+
+
+static void* ThreadEntry(void* arg) {
+  Thread* thread = reinterpret_cast<Thread*>(arg);
+  // This is also initialized by the first argument to pthread_create() but we
+  // don't know which thread will run first (the original thread or the new
+  // one) so we initialize it here too.
+  thread->thread_handle_data()->thread_ = pthread_self();
+  ASSERT(thread->IsValid());
+  thread->Run();
+  return NULL;
+}
+
+
+void Thread::Start() {
+  pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+  ASSERT(IsValid());
+}
+
+
+void Thread::Join() {
+  pthread_join(thread_handle_data()->thread_, NULL);
+}
+
+
+Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
+  pthread_key_t key;
+  int result = pthread_key_create(&key, NULL);
+  USE(result);
+  ASSERT(result == 0);
+  return static_cast<LocalStorageKey>(key);
+}
+
+
+void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  int result = pthread_key_delete(pthread_key);
+  USE(result);
+  ASSERT(result == 0);
+}
+
+
+void* Thread::GetThreadLocal(LocalStorageKey key) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  return pthread_getspecific(pthread_key);
+}
+
+
+void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  pthread_setspecific(pthread_key, value);
+}
+
+
+void Thread::YieldCPU() {
+  sched_yield();
+}
+
+
+class LinuxMutex : public Mutex {
+ public:
+
+  LinuxMutex() {
+    pthread_mutexattr_t attrs;
+    int result = pthread_mutexattr_init(&attrs);
+    ASSERT(result == 0);
+    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
+    ASSERT(result == 0);
+    result = pthread_mutex_init(&mutex_, &attrs);
+    ASSERT(result == 0);
+  }
+
+  virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
+
+  virtual int Lock() {
+    int result = pthread_mutex_lock(&mutex_);
+    return result;
+  }
+
+  virtual int Unlock() {
+    int result = pthread_mutex_unlock(&mutex_);
+    return result;
+  }
+
+ private:
+  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
+};
+
+
+Mutex* OS::CreateMutex() {
+  return new LinuxMutex();
+}
+
+
+class LinuxSemaphore : public Semaphore {
+ public:
+  explicit LinuxSemaphore(int count) {  sem_init(&sem_, 0, count); }
+  virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
+
+  virtual void Wait();
+  virtual void Signal() { sem_post(&sem_); }
+ private:
+  sem_t sem_;
+};
+
+void LinuxSemaphore::Wait() {
+  while (true) {
+    int result = sem_wait(&sem_);
+    if (result == 0) return;  // Successfully got semaphore.
+    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
+  }
+}
+
+Semaphore* OS::CreateSemaphore(int count) {
+  return new LinuxSemaphore(count);
+}
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+static Sampler* active_sampler_ = NULL;
+
+static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
+  USE(info);
+  if (signal != SIGPROF) return;
+  if (active_sampler_ == NULL) return;
+
+  TickSample sample;
+
+  // If profiling, we extract the current pc and sp.
+  if (active_sampler_->IsProfiling()) {
+    // Extracting the sample from the context is extremely machine dependent.
+    ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+    mcontext_t& mcontext = ucontext->uc_mcontext;
+#if defined (__arm__) || defined(__thumb__)
+    sample.pc = mcontext.gregs[R15];
+    sample.sp = mcontext.gregs[R13];
+#else
+    sample.pc = mcontext.gregs[REG_EIP];
+    sample.sp = mcontext.gregs[REG_ESP];
+#endif
+  }
+
+  // We always sample the VM state.
+  sample.state = Logger::state();
+
+  active_sampler_->Tick(&sample);
+}
+
+
+class Sampler::PlatformData : public Malloced {
+ public:
+  PlatformData() {
+    signal_handler_installed_ = false;
+  }
+
+  bool signal_handler_installed_;
+  struct sigaction old_signal_handler_;
+  struct itimerval old_timer_value_;
+};
+
+
+Sampler::Sampler(int interval, bool profiling)
+    : interval_(interval), profiling_(profiling), active_(false) {
+  data_ = new PlatformData();
+}
+
+
+Sampler::~Sampler() {
+  delete data_;
+}
+
+
+void Sampler::Start() {
+  // There can only be one active sampler at the time on POSIX
+  // platforms.
+  if (active_sampler_ != NULL) return;
+
+  // Request profiling signals.
+  struct sigaction sa;
+  sa.sa_sigaction = ProfilerSignalHandler;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO;
+  if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
+  data_->signal_handler_installed_ = true;
+
+  // Set the itimer to generate a tick for each interval.
+  itimerval itimer;
+  itimer.it_interval.tv_sec = interval_ / 1000;
+  itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
+  itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
+  itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
+  setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
+
+  // Set this sampler as the active sampler.
+  active_sampler_ = this;
+  active_ = true;
+}
+
+
+void Sampler::Stop() {
+  // Restore old signal handler
+  if (data_->signal_handler_installed_) {
+    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
+    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
+    data_->signal_handler_installed_ = false;
+  }
+
+  // This sampler is no longer the active sampler.
+  active_sampler_ = NULL;
+  active_ = false;
+}
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/platform-macos.cc b/regexp2000/src/platform-macos.cc
new file mode 100644 (file)
index 0000000..e57f79d
--- /dev/null
@@ -0,0 +1,652 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Platform specific code for MacOS goes here
+
+#include <ucontext.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <mach/mach_init.h>
+
+#include <AvailabilityMacros.h>
+
+#ifdef MAC_OS_X_VERSION_10_5
+# include <execinfo.h>  // backtrace, backtrace_symbols
+#endif
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <mach/semaphore.h>
+#include <mach/task.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#undef MAP_TYPE
+
+#include "v8.h"
+
+#include "platform.h"
+
+namespace v8 { namespace internal {
+
+// 0 is never a valid thread id on MacOSX since a ptread_t is
+// a pointer.
+static const pthread_t kNoThread = (pthread_t) 0;
+
+
+double ceiling(double x) {
+  // Correct Mac OS X Leopard 'ceil' behavior.
+  if (-1.0 < x && x < 0.0) {
+    return -0.0;
+  } else {
+    return ceil(x);
+  }
+}
+
+
+void OS::Setup() {
+  // Seed the random number generator.
+  // Convert the current time to a 64-bit integer first, before converting it
+  // to an unsigned. Going directly will cause an overflow and the seed to be
+  // set to all ones. The seed will be identical for different instances that
+  // call this setup code within the same millisecond.
+  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
+  srandom(static_cast<unsigned int>(seed));
+}
+
+
+int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
+  struct rusage usage;
+
+  if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
+  *secs = usage.ru_utime.tv_sec;
+  *usecs = usage.ru_utime.tv_usec;
+  return 0;
+}
+
+
+double OS::TimeCurrentMillis() {
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) < 0) return 0.0;
+  return (static_cast<double>(tv.tv_sec) * 1000) +
+         (static_cast<double>(tv.tv_usec) / 1000);
+}
+
+
+int64_t OS::Ticks() {
+  // Mac OS's gettimeofday has microsecond resolution.
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) < 0)
+    return 0;
+  return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
+}
+
+
+char* OS::LocalTimezone(double time) {
+  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
+  struct tm* t = localtime(&tv);
+  return const_cast<char*>(t->tm_zone);
+}
+
+
+double OS::DaylightSavingsOffset(double time) {
+  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
+  struct tm* t = localtime(&tv);
+  return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
+}
+
+
+double OS::LocalTimeOffset() {
+  time_t tv = time(NULL);
+  struct tm* t = localtime(&tv);
+  // tm_gmtoff includes any daylight savings offset, so subtract it.
+  return static_cast<double>(t->tm_gmtoff * msPerSecond -
+                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
+}
+
+
+FILE* OS::FOpen(const char* path, const char* mode) {
+  return fopen(path, mode);
+}
+
+
+void OS::Print(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  VPrint(format, args);
+  va_end(args);
+}
+
+
+void OS::VPrint(const char* format, va_list args) {
+  vprintf(format, args);
+}
+
+
+void OS::PrintError(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  VPrintError(format, args);
+  va_end(args);
+}
+
+
+void OS::VPrintError(const char* format, va_list args) {
+  vfprintf(stderr, format, args);
+}
+
+
+int OS::SNPrintF(Vector<char> str, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = VSNPrintF(str, format, args);
+  va_end(args);
+  return result;
+}
+
+
+int OS::VSNPrintF(Vector<char> str,
+                  const char* format,
+                  va_list args) {
+  int n = vsnprintf(str.start(), str.length(), format, args);
+  if (n < 0 || n >= str.length()) {
+    str[str.length() - 1] = '\0';
+    return -1;
+  } else {
+    return n;
+  }
+}
+
+
+void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
+  strncpy(dest.start(), src, n);
+}
+
+
+void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
+  wcscpy(dest.start(), src);
+}
+
+
+char *OS::StrDup(const char* str) {
+  return strdup(str);
+}
+
+
+// We keep the lowest and highest addresses mapped as a quick way of
+// determining that pointers are outside the heap (used mostly in assertions
+// and verification).  The estimate is conservative, ie, not all addresses in
+// 'allocated' space are actually allocated to our heap.  The range is
+// [lowest, highest), inclusive on the low and and exclusive on the high end.
+static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
+static void* highest_ever_allocated = reinterpret_cast<void*>(0);
+
+
+static void UpdateAllocatedSpaceLimits(void* address, int size) {
+  lowest_ever_allocated = Min(lowest_ever_allocated, address);
+  highest_ever_allocated =
+      Max(highest_ever_allocated,
+          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
+}
+
+
+bool OS::IsOutsideAllocatedSpace(void* address) {
+  return address < lowest_ever_allocated || address >= highest_ever_allocated;
+}
+
+
+size_t OS::AllocateAlignment() {
+  return getpagesize();
+}
+
+
+void* OS::Allocate(const size_t requested,
+                   size_t* allocated,
+                   bool executable) {
+  const size_t msize = RoundUp(requested, getpagesize());
+  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
+  if (mbase == MAP_FAILED) {
+    LOG(StringEvent("OS::Allocate", "mmap failed"));
+    return NULL;
+  }
+  *allocated = msize;
+  UpdateAllocatedSpaceLimits(mbase, msize);
+  return mbase;
+}
+
+
+void OS::Free(void* buf, const size_t length) {
+  // TODO(1240712): munmap has a return value which is ignored here.
+  munmap(buf, length);
+}
+
+
+void OS::Sleep(int miliseconds) {
+  usleep(1000 * miliseconds);
+}
+
+
+void OS::Abort() {
+  // Redirect to std abort to signal abnormal program termination
+  abort();
+}
+
+
+void OS::DebugBreak() {
+  asm("int $3");
+}
+
+
+class PosixMemoryMappedFile : public OS::MemoryMappedFile {
+ public:
+  PosixMemoryMappedFile(FILE* file, void* memory, int size)
+    : file_(file), memory_(memory), size_(size) { }
+  virtual ~PosixMemoryMappedFile();
+  virtual void* memory() { return memory_; }
+ private:
+  FILE* file_;
+  void* memory_;
+  int size_;
+};
+
+
+OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
+    void* initial) {
+  FILE* file = fopen(name, "w+");
+  if (file == NULL) return NULL;
+  fwrite(initial, size, 1, file);
+  void* memory =
+      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
+  return new PosixMemoryMappedFile(file, memory, size);
+}
+
+
+PosixMemoryMappedFile::~PosixMemoryMappedFile() {
+  if (memory_) munmap(memory_, size_);
+  fclose(file_);
+}
+
+
+void OS::LogSharedLibraryAddresses() {
+  // TODO(1233579): Implement.
+}
+
+
+double OS::nan_value() {
+  return NAN;
+}
+
+
+int OS::ActivationFrameAlignment() {
+  // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
+  // Function Call Guide".
+  return 16;
+}
+
+
+int OS::StackWalk(StackFrame* frames, int frames_size) {
+#ifndef MAC_OS_X_VERSION_10_5
+  return 0;
+#else
+  void** addresses = NewArray<void*>(frames_size);
+  int frames_count = backtrace(addresses, frames_size);
+
+  char** symbols;
+  symbols = backtrace_symbols(addresses, frames_count);
+  if (symbols == NULL) {
+    DeleteArray(addresses);
+    return kStackWalkError;
+  }
+
+  for (int i = 0; i < frames_count; i++) {
+    frames[i].address = addresses[i];
+    // Format a text representation of the frame based on the information
+    // available.
+    SNPrintF(MutableCStrVector(frames[i].text,
+                               kStackWalkMaxTextLen),
+             "%s",
+             symbols[i]);
+    // Make sure line termination is in place.
+    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
+  }
+
+  DeleteArray(addresses);
+  free(symbols);
+
+  return frames_count;
+#endif
+}
+
+
+// Constants used for mmap.
+static const int kMmapFd = -1;
+static const int kMmapFdOffset = 0;
+
+
+VirtualMemory::VirtualMemory(size_t size) {
+  address_ = mmap(NULL, size, PROT_NONE,
+                  MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+                  kMmapFd, kMmapFdOffset);
+  size_ = size;
+}
+
+
+VirtualMemory::~VirtualMemory() {
+  if (IsReserved()) {
+    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
+  }
+}
+
+
+bool VirtualMemory::IsReserved() {
+  return address_ != MAP_FAILED;
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
+  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+  if (MAP_FAILED == mmap(address, size, prot,
+                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+                         kMmapFd, kMmapFdOffset)) {
+    return false;
+  }
+
+  UpdateAllocatedSpaceLimits(address, size);
+  return true;
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+  return mmap(address, size, PROT_NONE,
+              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+              kMmapFd, kMmapFdOffset) != MAP_FAILED;
+}
+
+class ThreadHandle::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(ThreadHandle::Kind kind) {
+    Initialize(kind);
+  }
+
+  void Initialize(ThreadHandle::Kind kind) {
+    switch (kind) {
+      case ThreadHandle::SELF: thread_ = pthread_self(); break;
+      case ThreadHandle::INVALID: thread_ = kNoThread; break;
+    }
+  }
+  pthread_t thread_;  // Thread handle for pthread.
+};
+
+
+
+ThreadHandle::ThreadHandle(Kind kind) {
+  data_ = new PlatformData(kind);
+}
+
+
+void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
+  data_->Initialize(kind);
+}
+
+
+ThreadHandle::~ThreadHandle() {
+  delete data_;
+}
+
+
+bool ThreadHandle::IsSelf() const {
+  return pthread_equal(data_->thread_, pthread_self());
+}
+
+
+bool ThreadHandle::IsValid() const {
+  return data_->thread_ != kNoThread;
+}
+
+
+Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+}
+
+
+Thread::~Thread() {
+}
+
+
+static void* ThreadEntry(void* arg) {
+  Thread* thread = reinterpret_cast<Thread*>(arg);
+  // This is also initialized by the first argument to pthread_create() but we
+  // don't know which thread will run first (the original thread or the new
+  // one) so we initialize it here too.
+  thread->thread_handle_data()->thread_ = pthread_self();
+  ASSERT(thread->IsValid());
+  thread->Run();
+  return NULL;
+}
+
+
+void Thread::Start() {
+  pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+}
+
+
+void Thread::Join() {
+  pthread_join(thread_handle_data()->thread_, NULL);
+}
+
+
+Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
+  pthread_key_t key;
+  int result = pthread_key_create(&key, NULL);
+  USE(result);
+  ASSERT(result == 0);
+  return static_cast<LocalStorageKey>(key);
+}
+
+
+void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  int result = pthread_key_delete(pthread_key);
+  USE(result);
+  ASSERT(result == 0);
+}
+
+
+void* Thread::GetThreadLocal(LocalStorageKey key) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  return pthread_getspecific(pthread_key);
+}
+
+
+void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
+  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+  pthread_setspecific(pthread_key, value);
+}
+
+
+void Thread::YieldCPU() {
+  sched_yield();
+}
+
+
+class MacOSMutex : public Mutex {
+ public:
+
+  MacOSMutex() {
+    // For some reason the compiler doesn't allow you to write
+    // "this->mutex_ = PTHREAD_..." directly on mac.
+    pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&m, &attr);
+    mutex_ = m;
+  }
+
+  ~MacOSMutex() { pthread_mutex_destroy(&mutex_); }
+
+  int Lock() { return pthread_mutex_lock(&mutex_); }
+
+  int Unlock() { return pthread_mutex_unlock(&mutex_); }
+
+ private:
+  pthread_mutex_t mutex_;
+};
+
+
+Mutex* OS::CreateMutex() {
+  return new MacOSMutex();
+}
+
+
+class MacOSSemaphore : public Semaphore {
+ public:
+  explicit MacOSSemaphore(int count) {
+    semaphore_create(mach_task_self(), &semaphore_, SYNC_POLICY_FIFO, count);
+  }
+
+  ~MacOSSemaphore() {
+    semaphore_destroy(mach_task_self(), semaphore_);
+  }
+
+  // The MacOS mach semaphore documentation claims it does not have spurious
+  // wakeups, the way pthreads semaphores do.  So the code from the linux
+  // platform is not needed here.
+  void Wait() { semaphore_wait(semaphore_); }
+
+  void Signal() { semaphore_signal(semaphore_); }
+
+ private:
+  semaphore_t semaphore_;
+};
+
+
+Semaphore* OS::CreateSemaphore(int count) {
+  return new MacOSSemaphore(count);
+}
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+static Sampler* active_sampler_ = NULL;
+
+static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
+  USE(info);
+  if (signal != SIGPROF) return;
+  if (active_sampler_ == NULL) return;
+
+  TickSample sample;
+
+  // If profiling, we extract the current pc and sp.
+  if (active_sampler_->IsProfiling()) {
+    // Extracting the sample from the context is extremely machine dependent.
+    ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+    mcontext_t& mcontext = ucontext->uc_mcontext;
+#if __DARWIN_UNIX03
+    sample.pc = mcontext->__ss.__eip;
+    sample.sp = mcontext->__ss.__esp;
+#else  // !__DARWIN_UNIX03
+    sample.pc = mcontext->ss.eip;
+    sample.sp = mcontext->ss.esp;
+#endif  // __DARWIN_UNIX03
+  }
+
+  // We always sample the VM state.
+  sample.state = Logger::state();
+
+  active_sampler_->Tick(&sample);
+}
+
+
+class Sampler::PlatformData : public Malloced {
+ public:
+  PlatformData() {
+    signal_handler_installed_ = false;
+  }
+
+  bool signal_handler_installed_;
+  struct sigaction old_signal_handler_;
+  struct itimerval old_timer_value_;
+};
+
+
+Sampler::Sampler(int interval, bool profiling)
+    : interval_(interval), profiling_(profiling), active_(false) {
+  data_ = new PlatformData();
+}
+
+
+Sampler::~Sampler() {
+  delete data_;
+}
+
+
+void Sampler::Start() {
+  // There can only be one active sampler at the time on POSIX
+  // platforms.
+  if (active_sampler_ != NULL) return;
+
+  // Request profiling signals.
+  struct sigaction sa;
+  sa.sa_sigaction = ProfilerSignalHandler;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_SIGINFO;
+  if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
+  data_->signal_handler_installed_ = true;
+
+  // Set the itimer to generate a tick for each interval.
+  itimerval itimer;
+  itimer.it_interval.tv_sec = interval_ / 1000;
+  itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
+  itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
+  itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
+  setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
+
+  // Set this sampler as the active sampler.
+  active_sampler_ = this;
+  active_ = true;
+}
+
+
+void Sampler::Stop() {
+  // Restore old signal handler
+  if (data_->signal_handler_installed_) {
+    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
+    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
+    data_->signal_handler_installed_ = false;
+  }
+
+  // This sampler is no longer the active sampler.
+  active_sampler_ = NULL;
+  active_ = false;
+}
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/platform-nullos.cc b/regexp2000/src/platform-nullos.cc
new file mode 100644 (file)
index 0000000..98cb230
--- /dev/null
@@ -0,0 +1,421 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Platform specific code for NULLOS goes here
+
+// Minimal include to get access to abort, fprintf and friends for bootstrapping
+// messages.
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+
+
+namespace v8 { namespace internal {
+
+// Give V8 the opportunity to override the default ceil behaviour.
+double ceiling(double x) {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+// Initialize OS class early in the V8 startup.
+void OS::Setup() {
+  // Seed the random number generator.
+  UNIMPLEMENTED();
+}
+
+
+// Returns the accumulated user time for thread.
+int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
+  UNIMPLEMENTED();
+  *secs = 0;
+  *usecs = 0;
+  return 0;
+}
+
+
+// Returns current time as the number of milliseconds since
+// 00:00:00 UTC, January 1, 1970.
+double OS::TimeCurrentMillis() {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+// Returns ticks in microsecond resolution.
+int64_t OS::Ticks() {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+// Returns a string identifying the current timezone taking into
+// account daylight saving.
+char* OS::LocalTimezone(double time) {
+  UNIMPLEMENTED();
+  return "<none>";
+}
+
+
+// Returns the daylight savings offset in milliseconds for the given time.
+double OS::DaylightSavingsOffset(double time) {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+// Returns the local time offset in milliseconds east of UTC without
+// taking daylight savings time into account.
+double OS::LocalTimeOffset() {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+// Print (debug) message to console.
+void OS::Print(const char* format, ...) {
+  UNIMPLEMENTED();
+}
+
+
+// Print (debug) message to console.
+void OS::VPrint(const char* format, va_list args) {
+  // Minimalistic implementation for bootstrapping.
+  vfprintf(stdout, format, args);
+}
+
+
+// Print error message to console.
+void OS::PrintError(const char* format, ...) {
+  // Minimalistic implementation for bootstrapping.
+  va_list args;
+  va_start(args, format);
+  VPrintError(format, args);
+  va_end(args);
+}
+
+
+// Print error message to console.
+void OS::VPrintError(const char* format, va_list args) {
+  // Minimalistic implementation for bootstrapping.
+  vfprintf(stderr, format, args);
+}
+
+
+int OS::SNPrintF(char* str, size_t size, const char* format, ...) {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+int OS::VSNPrintF(char* str, size_t size, const char* format, va_list args) {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+double OS::nan_value() {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+bool OS::IsOutsideAllocatedSpace(void* address) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+size_t OS::AllocateAlignment() {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+void* OS::Allocate(const size_t requested,
+                   size_t* allocated,
+                   bool executable) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+void OS::Free(void* buf, const size_t length) {
+  // TODO(1240712): potential system call return value which is ignored here.
+  UNIMPLEMENTED();
+}
+
+
+void OS::Sleep(int milliseconds) {
+  UNIMPLEMENTED();
+}
+
+
+void OS::Abort() {
+  // Minimalistic implementation for bootstrapping.
+  abort();
+}
+
+
+void OS::DebugBreak() {
+  UNIMPLEMENTED();
+}
+
+
+OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
+    void* initial) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+void OS::LogSharedLibraryAddresses() {
+  UNIMPLEMENTED();
+}
+
+
+int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+VirtualMemory::VirtualMemory(size_t size, void* address_hint) {
+  UNIMPLEMENTED();
+}
+
+
+VirtualMemory::~VirtualMemory() {
+  UNIMPLEMENTED();
+}
+
+
+bool VirtualMemory::IsReserved() {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+class ThreadHandle::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(ThreadHandle::Kind kind) {
+    UNIMPLEMENTED();
+  }
+
+  void* pd_data_;
+};
+
+
+ThreadHandle::ThreadHandle(Kind kind) {
+  UNIMPLEMENTED();
+  // Shared setup follows.
+  data_ = new PlatformData(kind);
+}
+
+
+void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
+  UNIMPLEMENTED();
+}
+
+
+ThreadHandle::~ThreadHandle() {
+  UNIMPLEMENTED();
+  // Shared tear down follows.
+  delete data_;
+}
+
+
+bool ThreadHandle::IsSelf() const {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+bool ThreadHandle::IsValid() const {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+  UNIMPLEMENTED();
+}
+
+
+Thread::~Thread() {
+  UNIMPLEMENTED();
+}
+
+
+void Thread::Start() {
+  UNIMPLEMENTED();
+}
+
+
+void Thread::Join() {
+  UNIMPLEMENTED();
+}
+
+
+Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
+  UNIMPLEMENTED();
+  return static_cast<LocalStorageKey>(0);
+}
+
+
+void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
+  UNIMPLEMENTED();
+}
+
+
+void* Thread::GetThreadLocal(LocalStorageKey key) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
+  UNIMPLEMENTED();
+}
+
+
+void Thread::YieldCPU() {
+  UNIMPLEMENTED();
+}
+
+
+class NullMutex : public Mutex {
+ public:
+  NullMutex() : data_(NULL) {
+    UNIMPLEMENTED();
+  }
+
+  virtual ~NullMutex() {
+    UNIMPLEMENTED();
+  }
+
+  virtual int Lock() {
+    UNIMPLEMENTED();
+    return 0;
+  }
+
+  virtual int Unlock() {
+    UNIMPLEMENTED();
+    return 0;
+  }
+
+ private:
+  void* data_;
+};
+
+
+Mutex* OS::CreateMutex() {
+  UNIMPLEMENTED();
+  return new NullMutex();
+}
+
+
+class NullSemaphore : public Semaphore {
+ public:
+  explicit NullSemaphore(int count) : data_(NULL) {
+    UNIMPLEMENTED();
+  }
+
+  virtual ~NullSemaphore() {
+    UNIMPLEMENTED();
+  }
+
+  virtual void Wait() {
+    UNIMPLEMENTED();
+  }
+
+  virtual void Signal() {
+    UNIMPLEMENTED();
+  }
+ private:
+  void* data_;
+};
+
+
+Semaphore* OS::CreateSemaphore(int count) {
+  UNIMPLEMENTED();
+  return new NullSemaphore(count);
+}
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+class ProfileSampler::PlatformData  : public Malloced {
+ public:
+  PlatformData() {
+    UNIMPLEMENTED();
+  }
+};
+
+
+ProfileSampler::ProfileSampler(int interval) {
+  UNIMPLEMENTED();
+  // Shared setup follows.
+  data_ = new PlatformData();
+  interval_ = interval;
+  active_ = false;
+}
+
+
+ProfileSampler::~ProfileSampler() {
+  UNIMPLEMENTED();
+  // Shared tear down follows.
+  delete data_;
+}
+
+
+void ProfileSampler::Start() {
+  UNIMPLEMENTED();
+}
+
+
+void ProfileSampler::Stop() {
+  UNIMPLEMENTED();
+}
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/platform-win32.cc b/regexp2000/src/platform-win32.cc
new file mode 100644 (file)
index 0000000..803df77
--- /dev/null
@@ -0,0 +1,1574 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Platform specific code for Win32.
+#ifndef WIN32_LEAN_AND_MEAN
+// WIN32_LEAN_AND_MEAN implies NOCRYPT and NOGDI.
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#ifndef NOKERNEL
+#define NOKERNEL
+#endif
+#ifndef NOUSER
+#define NOUSER
+#endif
+#ifndef NOSERVICE
+#define NOSERVICE
+#endif
+#ifndef NOSOUND
+#define NOSOUND
+#endif
+#ifndef NOMCX
+#define NOMCX
+#endif
+
+#include <windows.h>
+
+#include <mmsystem.h>  // For timeGetTime().
+#include <dbghelp.h>  // For SymLoadModule64 and al.
+#include <tlhelp32.h>  // For Module32First and al.
+
+// These aditional WIN32 includes have to be right here as the #undef's below
+// makes it impossible to have them elsewhere.
+#include <winsock2.h>
+#include <process.h>  // for _beginthreadex()
+#include <stdlib.h>
+
+#pragma comment(lib, "winmm.lib")  // force linkage with winmm.
+
+#undef VOID
+#undef DELETE
+#undef IN
+#undef THIS
+#undef CONST
+#undef NAN
+#undef GetObject
+#undef CreateMutex
+#undef CreateSemaphore
+
+#include "v8.h"
+
+#include "platform.h"
+
+// Extra POSIX/ANSI routines for Win32. Please refer to The Open Group Base
+// Specification for specification of the correct semantics for these
+// functions.
+// (http://www.opengroup.org/onlinepubs/000095399/)
+
+// Test for finite value - usually defined in math.h
+namespace v8 {
+namespace internal {
+
+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;
+}
+
+
+// Generate a pseudo-random number in the range 0-2^31-1. Usually
+// defined in stdlib.h
+int random() {
+  return rand();
+}
+
+
+// Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually
+// defined in strings.h.
+int strncasecmp(const char* s1, const char* s2, int n) {
+  return _strnicmp(s1, s2, n);
+}
+
+namespace v8 { namespace internal {
+
+double ceiling(double x) {
+  return ceil(x);
+}
+
+// ----------------------------------------------------------------------------
+// The Time class represents time on win32. A timestamp is represented as
+// a 64-bit integer in 100 nano-seconds since January 1, 1601 (UTC). JavaScript
+// timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
+// January 1, 1970.
+
+class Time {
+ public:
+  // Constructors.
+  Time();
+  explicit Time(double jstime);
+  Time(int year, int mon, int day, int hour, int min, int sec);
+
+  // Convert timestamp to JavaScript representation.
+  double ToJSTime();
+
+  // Set timestamp to current time.
+  void SetToCurrentTime();
+
+  // Returns the local timezone offset in milliseconds east of UTC. This is
+  // the number of milliseconds you must add to UTC to get local time, i.e.
+  // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
+  // routine also takes into account whether daylight saving is effect
+  // at the time.
+  int64_t LocalOffset();
+
+  // Returns the daylight savings time offset for the time in milliseconds.
+  int64_t DaylightSavingsOffset();
+
+  // Returns a string identifying the current timezone for the
+  // timestamp taking into account daylight saving.
+  char* LocalTimezone();
+
+ private:
+  // Constants for time conversion.
+  static const int64_t kTimeEpoc = 116444736000000000;
+  static const int64_t kTimeScaler = 10000;
+  static const int64_t kMsPerMinute = 60000;
+
+  // Constants for timezone information.
+  static const int kTzNameSize = 128;
+  static const bool kShortTzNames = false;
+
+  // Timezone information. We need to have static buffers for the
+  // timezone names because we return pointers to these in
+  // LocalTimezone().
+  static bool tz_initialized_;
+  static TIME_ZONE_INFORMATION tzinfo_;
+  static char std_tz_name_[kTzNameSize];
+  static char dst_tz_name_[kTzNameSize];
+
+  // Initialize the timezone information (if not already done).
+  static void TzSet();
+
+  // Guess the name of the timezone from the bias.
+  static const char* GuessTimezoneNameFromBias(int bias);
+
+  // Return whether or not daylight savings time is in effect at this time.
+  bool InDST();
+
+  // Return the difference (in milliseconds) between this timestamp and
+  // another timestamp.
+  int64_t Diff(Time* other);
+
+  // Accessor for FILETIME representation.
+  FILETIME& ft() { return time_.ft_; }
+
+  // Accessor for integer representation.
+  int64_t& t() { return time_.t_; }
+
+  // Although win32 uses 64-bit integers for representing timestamps,
+  // these are packed into a FILETIME structure. The FILETIME structure
+  // is just a struct representing a 64-bit integer. The TimeStamp union
+  // allows access to both a FILETIME and an integer representation of
+  // the timestamp.
+  union TimeStamp {
+    FILETIME ft_;
+    int64_t t_;
+  };
+
+  TimeStamp time_;
+};
+
+// Static variables.
+bool Time::tz_initialized_ = false;
+TIME_ZONE_INFORMATION Time::tzinfo_;
+char Time::std_tz_name_[kTzNameSize];
+char Time::dst_tz_name_[kTzNameSize];
+
+
+// Initialize timestamp to start of epoc.
+Time::Time() {
+  t() = 0;
+}
+
+
+// Initialize timestamp from a JavaScript timestamp.
+Time::Time(double jstime) {
+  t() = static_cast<uint64_t>(jstime) * kTimeScaler + kTimeEpoc;
+}
+
+
+// Initialize timestamp from date/time components.
+Time::Time(int year, int mon, int day, int hour, int min, int sec) {
+  SYSTEMTIME st;
+  st.wYear = year;
+  st.wMonth = mon;
+  st.wDay = day;
+  st.wHour = hour;
+  st.wMinute = min;
+  st.wSecond = sec;
+  st.wMilliseconds = 0;
+  SystemTimeToFileTime(&st, &ft());
+}
+
+
+// Convert timestamp to JavaScript timestamp.
+double Time::ToJSTime() {
+  return static_cast<double>((t() - kTimeEpoc) / kTimeScaler);
+}
+
+
+// Guess the name of the timezone from the bias.
+// The guess is very biased towards the northern hemisphere.
+const char* Time::GuessTimezoneNameFromBias(int bias) {
+  static const int kHour = 60;
+  switch (-bias) {
+    case -9*kHour: return "Alaska";
+    case -8*kHour: return "Pacific";
+    case -7*kHour: return "Mountain";
+    case -6*kHour: return "Central";
+    case -5*kHour: return "Eastern";
+    case -4*kHour: return "Atlantic";
+    case  0*kHour: return "GMT";
+    case +1*kHour: return "Central Europe";
+    case +2*kHour: return "Eastern Europe";
+    case +3*kHour: return "Russia";
+    case +5*kHour + 30: return "India";
+    case +8*kHour: return "China";
+    case +9*kHour: return "Japan";
+    case +12*kHour: return "New Zealand";
+    default: return "Local";
+  }
+}
+
+
+// Initialize timezone information. The timezone information is obtained from
+// windows. If we cannot get the timezone information we fall back to CET.
+// Please notice that this code is not thread-safe.
+void Time::TzSet() {
+  // Just return if timezone information has already been initialized.
+  if (tz_initialized_) return;
+
+  // Obtain timezone information from operating system.
+  memset(&tzinfo_, 0, sizeof(tzinfo_));
+  if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
+    // If we cannot get timezone information we fall back to CET.
+    tzinfo_.Bias = -60;
+    tzinfo_.StandardDate.wMonth = 10;
+    tzinfo_.StandardDate.wDay = 5;
+    tzinfo_.StandardDate.wHour = 3;
+    tzinfo_.StandardBias = 0;
+    tzinfo_.DaylightDate.wMonth = 3;
+    tzinfo_.DaylightDate.wDay = 5;
+    tzinfo_.DaylightDate.wHour = 2;
+    tzinfo_.DaylightBias = -60;
+  }
+
+  // Make standard and DST timezone names.
+  OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize),
+               "%S",
+               tzinfo_.StandardName);
+  std_tz_name_[kTzNameSize - 1] = '\0';
+  OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize),
+               "%S",
+               tzinfo_.DaylightName);
+  dst_tz_name_[kTzNameSize - 1] = '\0';
+
+  // If OS returned empty string or resource id (like "@tzres.dll,-211")
+  // simply guess the name from the UTC bias of the timezone.
+  // To properly resolve the resource identifier requires a library load,
+  // which is not possible in a sandbox.
+  if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
+    OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1),
+                 "%s Standard Time",
+                 GuessTimezoneNameFromBias(tzinfo_.Bias));
+  }
+  if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
+    OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1),
+                 "%s Daylight Time",
+                 GuessTimezoneNameFromBias(tzinfo_.Bias));
+  }
+
+  // Timezone information initialized.
+  tz_initialized_ = true;
+}
+
+
+// Return the difference in milliseconds between this and another timestamp.
+int64_t Time::Diff(Time* other) {
+  return (t() - other->t()) / kTimeScaler;
+}
+
+
+// Set timestamp to current time.
+void Time::SetToCurrentTime() {
+  // The default GetSystemTimeAsFileTime has a ~15.5ms resolution.
+  // Because we're fast, we like fast timers which have at least a
+  // 1ms resolution.
+  //
+  // timeGetTime() provides 1ms granularity when combined with
+  // timeBeginPeriod().  If the host application for v8 wants fast
+  // timers, it can use timeBeginPeriod to increase the resolution.
+  //
+  // Using timeGetTime() has a drawback because it is a 32bit value
+  // and hence rolls-over every ~49days.
+  //
+  // To use the clock, we use GetSystemTimeAsFileTime as our base;
+  // and then use timeGetTime to extrapolate current time from the
+  // start time.  To deal with rollovers, we resync the clock
+  // any time when more than kMaxClockElapsedTime has passed or
+  // whenever timeGetTime creates a rollover.
+
+  static bool initialized = false;
+  static TimeStamp init_time;
+  static DWORD init_ticks;
+  static const int kHundredNanosecondsPerSecond = 10000;
+  static const int kMaxClockElapsedTime =
+      60*60*24*kHundredNanosecondsPerSecond;  // 1 day
+
+  // If we are uninitialized, we need to resync the clock.
+  bool needs_resync = !initialized;
+
+  // Get the current time.
+  TimeStamp time_now;
+  GetSystemTimeAsFileTime(&time_now.ft_);
+  DWORD ticks_now = timeGetTime();
+
+  // Check if we need to resync due to clock rollover.
+  needs_resync |= ticks_now < init_ticks;
+
+  // Check if we need to resync due to elapsed time.
+  needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime;
+
+  // Resync the clock if necessary.
+  if (needs_resync) {
+    GetSystemTimeAsFileTime(&init_time.ft_);
+    init_ticks = ticks_now = timeGetTime();
+    initialized = true;
+  }
+
+  // Finally, compute the actual time.  Why is this so hard.
+  DWORD elapsed = ticks_now - init_ticks;
+  this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000);
+}
+
+
+// Return the local timezone offset in milliseconds east of UTC. This
+// takes into account whether daylight saving is in effect at the time.
+int64_t Time::LocalOffset() {
+  // Initialize timezone information, if needed.
+  TzSet();
+
+  // Convert timestamp to date/time components. These are now in UTC
+  // format. NB: Please do not replace the following three calls with one
+  // call to FileTimeToLocalFileTime(), because it does not handle
+  // daylight saving correctly.
+  SYSTEMTIME utc;
+  FileTimeToSystemTime(&ft(), &utc);
+
+  // Convert to local time, using timezone information.
+  SYSTEMTIME local;
+  SystemTimeToTzSpecificLocalTime(&tzinfo_, &utc, &local);
+
+  // Convert local time back to a timestamp. This timestamp now
+  // has a bias similar to the local timezone bias in effect
+  // at the time of the original timestamp.
+  Time localtime;
+  SystemTimeToFileTime(&local, &localtime.ft());
+
+  // The difference between the new local timestamp and the original
+  // timestamp and is the local timezone offset.
+  return localtime.Diff(this);
+}
+
+
+// Return whether or not daylight savings time is in effect at this time.
+bool Time::InDST() {
+  // Initialize timezone information, if needed.
+  TzSet();
+
+  // Determine if DST is in effect at the specified time.
+  bool in_dst = false;
+  if (tzinfo_.StandardDate.wMonth != 0 || tzinfo_.DaylightDate.wMonth != 0) {
+    // Get the local timezone offset for the timestamp in milliseconds.
+    int64_t offset = LocalOffset();
+
+    // Compute the offset for DST. The bias parameters in the timezone info
+    // are specified in minutes. These must be converted to milliseconds.
+    int64_t dstofs = -(tzinfo_.Bias + tzinfo_.DaylightBias) * kMsPerMinute;
+
+    // If the local time offset equals the timezone bias plus the daylight
+    // bias then DST is in effect.
+    in_dst = offset == dstofs;
+  }
+
+  return in_dst;
+}
+
+
+// Return the dalight savings time offset for this time.
+int64_t Time::DaylightSavingsOffset() {
+  return InDST() ? 60 * kMsPerMinute : 0;
+}
+
+
+// Returns a string identifying the current timezone for the
+// timestamp taking into account daylight saving.
+char* Time::LocalTimezone() {
+  // Return the standard or DST time zone name based on whether daylight
+  // saving is in effect at the given time.
+  return InDST() ? dst_tz_name_ : std_tz_name_;
+}
+
+
+void OS::Setup() {
+  // Seed the random number generator.
+  // Convert the current time to a 64-bit integer first, before converting it
+  // to an unsigned. Going directly can cause an overflow and the seed to be
+  // set to all ones. The seed will be identical for different instances that
+  // call this setup code within the same millisecond.
+  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
+  srand(static_cast<unsigned int>(seed));
+}
+
+
+// Returns the accumulated user time for thread.
+int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
+  FILETIME dummy;
+  uint64_t usertime;
+
+  // Get the amount of time that the thread has executed in user mode.
+  if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy,
+                      reinterpret_cast<FILETIME*>(&usertime))) return -1;
+
+  // Adjust the resolution to micro-seconds.
+  usertime /= 10;
+
+  // Convert to seconds and microseconds
+  *secs = static_cast<uint32_t>(usertime / 1000000);
+  *usecs = static_cast<uint32_t>(usertime % 1000000);
+  return 0;
+}
+
+
+// Returns current time as the number of milliseconds since
+// 00:00:00 UTC, January 1, 1970.
+double OS::TimeCurrentMillis() {
+  Time t;
+  t.SetToCurrentTime();
+  return t.ToJSTime();
+}
+
+// Returns the tickcounter based on timeGetTime.
+int64_t OS::Ticks() {
+  return timeGetTime() * 1000;  // Convert to microseconds.
+}
+
+
+// Returns a string identifying the current timezone taking into
+// account daylight saving.
+char* OS::LocalTimezone(double time) {
+  return Time(time).LocalTimezone();
+}
+
+
+// Returns the local time offset in milliseconds east of UTC without
+// taking daylight savings time into account.
+double OS::LocalTimeOffset() {
+  // Use current time, rounded to the millisecond.
+  Time t(TimeCurrentMillis());
+  // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
+  return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset());
+}
+
+
+// Returns the daylight savings offset in milliseconds for the given
+// time.
+double OS::DaylightSavingsOffset(double time) {
+  int64_t offset = Time(time).DaylightSavingsOffset();
+  return static_cast<double>(offset);
+}
+
+
+// ----------------------------------------------------------------------------
+// Win32 console output.
+//
+// If a Win32 application is linked as a console application it has a normal
+// standard output and standard error. In this case normal printf works fine
+// for output. However, if the application is linked as a GUI application,
+// the process doesn't have a console, and therefore (debugging) output is lost.
+// This is the case if we are embedded in a windows program (like a browser).
+// In order to be able to get debug output in this case the the debugging
+// facility using OutputDebugString. This output goes to the active debugger
+// for the process (if any). Else the output can be monitored using DBMON.EXE.
+
+enum OutputMode {
+  UNKNOWN,  // Output method has not yet been determined.
+  CONSOLE,  // Output is written to stdout.
+  ODS       // Output is written to debug facility.
+};
+
+static OutputMode output_mode = UNKNOWN;  // Current output mode.
+
+
+// Determine if the process has a console for output.
+static bool HasConsole() {
+  // Only check the first time. Eventual race conditions are not a problem,
+  // because all threads will eventually determine the same mode.
+  if (output_mode == UNKNOWN) {
+    // We cannot just check that the standard output is attached to a console
+    // because this would fail if output is redirected to a file. Therefore we
+    // say that a process does not have an output console if either the
+    // standard output handle is invalid or its file type is unknown.
+    if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE &&
+        GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) != FILE_TYPE_UNKNOWN)
+      output_mode = CONSOLE;
+    else
+      output_mode = ODS;
+  }
+  return output_mode == CONSOLE;
+}
+
+
+static void VPrintHelper(FILE* stream, const char* format, va_list args) {
+  if (HasConsole()) {
+    vfprintf(stream, format, args);
+  } else {
+    // It is important to use safe print here in order to avoid
+    // overflowing the buffer. We might truncate the output, but this
+    // does not crash.
+    EmbeddedVector<char, 4096> buffer;
+    OS::VSNPrintF(buffer, format, args);
+    OutputDebugStringA(buffer.start());
+  }
+}
+
+
+FILE* OS::FOpen(const char* path, const char* mode) {
+  FILE* result;
+  if (fopen_s(&result, path, mode) == 0) {
+    return result;
+  } else {
+    return NULL;
+  }
+}
+
+
+// Print (debug) message to console.
+void OS::Print(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  VPrint(format, args);
+  va_end(args);
+}
+
+
+void OS::VPrint(const char* format, va_list args) {
+  VPrintHelper(stdout, format, args);
+}
+
+
+// Print error message to console.
+void OS::PrintError(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  VPrintError(format, args);
+  va_end(args);
+}
+
+
+void OS::VPrintError(const char* format, va_list args) {
+  VPrintHelper(stderr, format, args);
+}
+
+
+int OS::SNPrintF(Vector<char> str, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = VSNPrintF(str, format, args);
+  va_end(args);
+  return result;
+}
+
+
+int OS::VSNPrintF(Vector<char> str, const char* format, va_list args) {
+  int n = _vsnprintf_s(str.start(), str.length(), _TRUNCATE, format, args);
+  // Make sure to zero-terminate the string if the output was
+  // truncated or if there was an error.
+  if (n < 0 || n >= str.length()) {
+    str[str.length() - 1] = '\0';
+    return -1;
+  } else {
+    return n;
+  }
+}
+
+
+void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
+  int result = strncpy_s(dest.start(), dest.length(), src, n);
+  USE(result);
+  ASSERT(result == 0);
+}
+
+
+void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
+  int result = wcscpy_s(dest.start(), dest.length(), src);
+  USE(result);
+  ASSERT(result == 0);
+}
+
+
+char *OS::StrDup(const char* str) {
+  return _strdup(str);
+}
+
+
+// We keep the lowest and highest addresses mapped as a quick way of
+// determining that pointers are outside the heap (used mostly in assertions
+// and verification).  The estimate is conservative, ie, not all addresses in
+// 'allocated' space are actually allocated to our heap.  The range is
+// [lowest, highest), inclusive on the low and and exclusive on the high end.
+static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
+static void* highest_ever_allocated = reinterpret_cast<void*>(0);
+
+
+static void UpdateAllocatedSpaceLimits(void* address, int size) {
+  lowest_ever_allocated = Min(lowest_ever_allocated, address);
+  highest_ever_allocated =
+      Max(highest_ever_allocated,
+          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
+}
+
+
+bool OS::IsOutsideAllocatedSpace(void* pointer) {
+  if (pointer < lowest_ever_allocated || pointer >= highest_ever_allocated)
+    return true;
+  // Ask the Windows API
+  if (IsBadWritePtr(pointer, 1))
+    return true;
+  return false;
+}
+
+
+// Get the system's page size used by VirtualAlloc() or the next power
+// of two. The reason for always returning a power of two is that the
+// rounding up in OS::Allocate expects that.
+static size_t GetPageSize() {
+  static size_t page_size = 0;
+  if (page_size == 0) {
+    SYSTEM_INFO info;
+    GetSystemInfo(&info);
+    page_size = RoundUpToPowerOf2(info.dwPageSize);
+  }
+  return page_size;
+}
+
+
+// The allocation alignment is the guaranteed alignment for
+// VirtualAlloc'ed blocks of memory.
+size_t OS::AllocateAlignment() {
+  static size_t allocate_alignment = 0;
+  if (allocate_alignment == 0) {
+    SYSTEM_INFO info;
+    GetSystemInfo(&info);
+    allocate_alignment = info.dwAllocationGranularity;
+  }
+  return allocate_alignment;
+}
+
+
+void* OS::Allocate(const size_t requested,
+                   size_t* allocated,
+                   bool executable) {
+  // VirtualAlloc rounds allocated size to page size automatically.
+  size_t msize = RoundUp(requested, GetPageSize());
+
+  // Windows XP SP2 allows Data Excution Prevention (DEP).
+  int prot = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
+  LPVOID mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);
+  if (mbase == NULL) {
+    LOG(StringEvent("OS::Allocate", "VirtualAlloc failed"));
+    return NULL;
+  }
+
+  ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));
+
+  *allocated = msize;
+  UpdateAllocatedSpaceLimits(mbase, msize);
+  return mbase;
+}
+
+
+void OS::Free(void* buf, const size_t length) {
+  // TODO(1240712): VirtualFree has a return value which is ignored here.
+  VirtualFree(buf, 0, MEM_RELEASE);
+  USE(length);
+}
+
+
+void OS::Sleep(int milliseconds) {
+  ::Sleep(milliseconds);
+}
+
+
+void OS::Abort() {
+  // Redirect to windows specific abort to ensure
+  // collaboration with sandboxing.
+  __debugbreak();
+}
+
+
+void OS::DebugBreak() {
+  __debugbreak();
+}
+
+
+class Win32MemoryMappedFile : public OS::MemoryMappedFile {
+ public:
+  Win32MemoryMappedFile(HANDLE file, HANDLE file_mapping, void* memory)
+    : file_(file), file_mapping_(file_mapping), memory_(memory) { }
+  virtual ~Win32MemoryMappedFile();
+  virtual void* memory() { return memory_; }
+ private:
+  HANDLE file_;
+  HANDLE file_mapping_;
+  void* memory_;
+};
+
+
+OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
+    void* initial) {
+  // Open a physical file
+  HANDLE file = CreateFileA(name, GENERIC_READ | GENERIC_WRITE,
+      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
+  if (file == NULL) return NULL;
+  // Create a file mapping for the physical file
+  HANDLE file_mapping = CreateFileMapping(file, NULL,
+      PAGE_READWRITE, 0, static_cast<DWORD>(size), NULL);
+  if (file_mapping == NULL) return NULL;
+  // Map a view of the file into memory
+  void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
+  if (memory) memmove(memory, initial, size);
+  return new Win32MemoryMappedFile(file, file_mapping, memory);
+}
+
+
+Win32MemoryMappedFile::~Win32MemoryMappedFile() {
+  if (memory_ != NULL)
+    UnmapViewOfFile(memory_);
+  CloseHandle(file_mapping_);
+  CloseHandle(file_);
+}
+
+
+// The following code loads functions defined in DbhHelp.h and TlHelp32.h
+// dynamically. This is to avoid beeing depending on dbghelp.dll and
+// tlhelp32.dll when running (the functions in tlhelp32.dll have been moved to
+// kernel32.dll at some point so loading functions defines in TlHelp32.h
+// dynamically might not be necessary any more - for some versions of Windows?).
+
+// Function pointers to functions dynamically loaded from dbghelp.dll.
+#define DBGHELP_FUNCTION_LIST(V)  \
+  V(SymInitialize)                \
+  V(SymGetOptions)                \
+  V(SymSetOptions)                \
+  V(SymGetSearchPath)             \
+  V(SymLoadModule64)              \
+  V(StackWalk64)                  \
+  V(SymGetSymFromAddr64)          \
+  V(SymGetLineFromAddr64)         \
+  V(SymFunctionTableAccess64)     \
+  V(SymGetModuleBase64)
+
+// Function pointers to functions dynamically loaded from dbghelp.dll.
+#define TLHELP32_FUNCTION_LIST(V)  \
+  V(CreateToolhelp32Snapshot)      \
+  V(Module32FirstW)                \
+  V(Module32NextW)
+
+// Define the decoration to use for the type and variable name used for
+// dynamically loaded DLL function..
+#define DLL_FUNC_TYPE(name) _##name##_
+#define DLL_FUNC_VAR(name) _##name
+
+// Define the type for each dynamically loaded DLL function. The function
+// definitions are copied from DbgHelp.h and TlHelp32.h. The IN and VOID macros
+// from the Windows include files are redefined here to have the function
+// definitions to be as close to the ones in the original .h files as possible.
+#ifndef IN
+#define IN
+#endif
+#ifndef VOID
+#define VOID void
+#endif
+
+// DbgHelp.h functions.
+typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess,
+                                                       IN PSTR UserSearchPath,
+                                                       IN BOOL fInvadeProcess);
+typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID);
+typedef DWORD (__stdcall *DLL_FUNC_TYPE(SymSetOptions))(IN DWORD SymOptions);
+typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSearchPath))(
+    IN HANDLE hProcess,
+    OUT PSTR SearchPath,
+    IN DWORD SearchPathLength);
+typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymLoadModule64))(
+    IN HANDLE hProcess,
+    IN HANDLE hFile,
+    IN PSTR ImageName,
+    IN PSTR ModuleName,
+    IN DWORD64 BaseOfDll,
+    IN DWORD SizeOfDll);
+typedef BOOL (__stdcall *DLL_FUNC_TYPE(StackWalk64))(
+    DWORD MachineType,
+    HANDLE hProcess,
+    HANDLE hThread,
+    LPSTACKFRAME64 StackFrame,
+    PVOID ContextRecord,
+    PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+    PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+    PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+    PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
+typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetSymFromAddr64))(
+    IN HANDLE hProcess,
+    IN DWORD64 qwAddr,
+    OUT PDWORD64 pdwDisplacement,
+    OUT PIMAGEHLP_SYMBOL64 Symbol);
+typedef BOOL (__stdcall *DLL_FUNC_TYPE(SymGetLineFromAddr64))(
+    IN HANDLE hProcess,
+    IN DWORD64 qwAddr,
+    OUT PDWORD pdwDisplacement,
+    OUT PIMAGEHLP_LINE64 Line64);
+// DbgHelp.h typedefs. Implementation found in dbghelp.dll.
+typedef PVOID (__stdcall *DLL_FUNC_TYPE(SymFunctionTableAccess64))(
+    HANDLE hProcess,
+    DWORD64 AddrBase);  // DbgHelp.h typedef PFUNCTION_TABLE_ACCESS_ROUTINE64
+typedef DWORD64 (__stdcall *DLL_FUNC_TYPE(SymGetModuleBase64))(
+    HANDLE hProcess,
+    DWORD64 AddrBase);  // DbgHelp.h typedef PGET_MODULE_BASE_ROUTINE64
+
+// TlHelp32.h functions.
+typedef HANDLE (__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))(
+    DWORD dwFlags,
+    DWORD th32ProcessID);
+typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32FirstW))(HANDLE hSnapshot,
+                                                        LPMODULEENTRY32W lpme);
+typedef BOOL (__stdcall *DLL_FUNC_TYPE(Module32NextW))(HANDLE hSnapshot,
+                                                       LPMODULEENTRY32W lpme);
+
+#undef IN
+#undef VOID
+
+// Declare a variable for each dynamically loaded DLL function.
+#define DEF_DLL_FUNCTION(name) DLL_FUNC_TYPE(name) DLL_FUNC_VAR(name) = NULL;
+DBGHELP_FUNCTION_LIST(DEF_DLL_FUNCTION)
+TLHELP32_FUNCTION_LIST(DEF_DLL_FUNCTION)
+#undef DEF_DLL_FUNCTION
+
+// Load the functions. This function has a lot of "ugly" macros in order to
+// keep down code duplication.
+
+static bool LoadDbgHelpAndTlHelp32() {
+  static bool dbghelp_loaded = false;
+
+  if (dbghelp_loaded) return true;
+
+  HMODULE module;
+
+  // Load functions from the dbghelp.dll module.
+  module = LoadLibrary(TEXT("dbghelp.dll"));
+  if (module == NULL) {
+    return false;
+  }
+
+#define LOAD_DLL_FUNC(name)                                                 \
+  DLL_FUNC_VAR(name) =                                                      \
+      reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
+
+DBGHELP_FUNCTION_LIST(LOAD_DLL_FUNC)
+
+#undef LOAD_DLL_FUNC
+
+  // Load functions from the kernel32.dll module (the TlHelp32.h function used
+  // to be in tlhelp32.dll but are now moved to kernel32.dll).
+  module = LoadLibrary(TEXT("kernel32.dll"));
+  if (module == NULL) {
+    return false;
+  }
+
+#define LOAD_DLL_FUNC(name)                                                 \
+  DLL_FUNC_VAR(name) =                                                      \
+      reinterpret_cast<DLL_FUNC_TYPE(name)>(GetProcAddress(module, #name));
+
+TLHELP32_FUNCTION_LIST(LOAD_DLL_FUNC)
+
+#undef LOAD_DLL_FUNC
+
+  // Check that all functions where loaded.
+  bool result =
+#define DLL_FUNC_LOADED(name) (DLL_FUNC_VAR(name) != NULL) &&
+
+DBGHELP_FUNCTION_LIST(DLL_FUNC_LOADED)
+TLHELP32_FUNCTION_LIST(DLL_FUNC_LOADED)
+
+#undef DLL_FUNC_LOADED
+  true;
+
+  dbghelp_loaded = result;
+  return result;
+  // NOTE: The modules are never unloaded and will stay arround until the
+  // application is closed.
+}
+
+
+// Load the symbols for generating stack traces.
+static bool LoadSymbols(HANDLE process_handle) {
+  static bool symbols_loaded = false;
+
+  if (symbols_loaded) return true;
+
+  BOOL ok;
+
+  // Initialize the symbol engine.
+  ok = _SymInitialize(process_handle,  // hProcess
+                      NULL,            // UserSearchPath
+                      FALSE);          // fInvadeProcess
+  if (!ok) return false;
+
+  DWORD options = _SymGetOptions();
+  options |= SYMOPT_LOAD_LINES;
+  options |= SYMOPT_FAIL_CRITICAL_ERRORS;
+  options = _SymSetOptions(options);
+
+  char buf[OS::kStackWalkMaxNameLen] = {0};
+  ok = _SymGetSearchPath(process_handle, buf, OS::kStackWalkMaxNameLen);
+  if (!ok) {
+    int err = GetLastError();
+    PrintF("%d\n", err);
+    return false;
+  }
+
+  HANDLE snapshot = _CreateToolhelp32Snapshot(
+      TH32CS_SNAPMODULE,       // dwFlags
+      GetCurrentProcessId());  // th32ProcessId
+  if (snapshot == INVALID_HANDLE_VALUE) return false;
+  MODULEENTRY32W module_entry;
+  module_entry.dwSize = sizeof(module_entry);  // Set the size of the structure.
+  BOOL cont = _Module32FirstW(snapshot, &module_entry);
+  while (cont) {
+    DWORD64 base;
+    // NOTE the SymLoadModule64 function has the peculiarity of accepting a
+    // both unicode and ASCII strings even though the parameter is PSTR.
+    base = _SymLoadModule64(
+        process_handle,                                       // hProcess
+        0,                                                    // hFile
+        reinterpret_cast<PSTR>(module_entry.szExePath),       // ImageName
+        reinterpret_cast<PSTR>(module_entry.szModule),        // ModuleName
+        reinterpret_cast<DWORD64>(module_entry.modBaseAddr),  // BaseOfDll
+        module_entry.modBaseSize);                            // SizeOfDll
+    if (base == 0) {
+      int err = GetLastError();
+      if (err != ERROR_MOD_NOT_FOUND &&
+          err != ERROR_INVALID_HANDLE) return false;
+    }
+    LOG(SharedLibraryEvent(
+            module_entry.szExePath,
+            reinterpret_cast<unsigned int>(module_entry.modBaseAddr),
+            reinterpret_cast<unsigned int>(module_entry.modBaseAddr +
+                                           module_entry.modBaseSize)));
+    cont = _Module32NextW(snapshot, &module_entry);
+  }
+  CloseHandle(snapshot);
+
+  symbols_loaded = true;
+  return true;
+}
+
+
+void OS::LogSharedLibraryAddresses() {
+  // SharedLibraryEvents are logged when loading symbol information.
+  // Only the shared libraries loaded at the time of the call to
+  // LogSharedLibraryAddresses are logged.  DLLs loaded after
+  // initialization are not accounted for.
+  if (!LoadDbgHelpAndTlHelp32()) return;
+  HANDLE process_handle = GetCurrentProcess();
+  LoadSymbols(process_handle);
+}
+
+
+// Walk the stack using the facilities in dbghelp.dll and tlhelp32.dll
+
+// Switch off warning 4748 (/GS can not protect parameters and local variables
+// from local buffer overrun because optimizations are disabled in function) as
+// it is triggered by the use of inline assembler.
+#pragma warning(push)
+#pragma warning(disable : 4748)
+int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+  BOOL ok;
+
+  // Load the required functions from DLL's.
+  if (!LoadDbgHelpAndTlHelp32()) return kStackWalkError;
+
+  // Get the process and thread handles.
+  HANDLE process_handle = GetCurrentProcess();
+  HANDLE thread_handle = GetCurrentThread();
+
+  // Read the symbols.
+  if (!LoadSymbols(process_handle)) return kStackWalkError;
+
+  // Capture current context.
+  CONTEXT context;
+  memset(&context, 0, sizeof(context));
+  context.ContextFlags = CONTEXT_CONTROL;
+  context.ContextFlags = CONTEXT_CONTROL;
+  __asm    call x
+  __asm x: pop eax
+  __asm    mov context.Eip, eax
+  __asm    mov context.Ebp, ebp
+  __asm    mov context.Esp, esp
+  // NOTE: At some point, we could use RtlCaptureContext(&context) to
+  // capture the context instead of inline assembler. However it is
+  // only available on XP, Vista, Server 2003 and Server 2008 which
+  // might not be sufficient.
+
+  // Initialize the stack walking
+  STACKFRAME64 stack_frame;
+  memset(&stack_frame, 0, sizeof(stack_frame));
+  stack_frame.AddrPC.Offset = context.Eip;
+  stack_frame.AddrPC.Mode = AddrModeFlat;
+  stack_frame.AddrFrame.Offset = context.Ebp;
+  stack_frame.AddrFrame.Mode = AddrModeFlat;
+  stack_frame.AddrStack.Offset = context.Esp;
+  stack_frame.AddrStack.Mode = AddrModeFlat;
+  int frames_count = 0;
+
+  // Collect stack frames.
+  while (frames_count < frames_size) {
+    ok = _StackWalk64(
+        IMAGE_FILE_MACHINE_I386,    // MachineType
+        process_handle,             // hProcess
+        thread_handle,              // hThread
+        &stack_frame,               // StackFrame
+        &context,                   // ContextRecord
+        NULL,                       // ReadMemoryRoutine
+        _SymFunctionTableAccess64,  // FunctionTableAccessRoutine
+        _SymGetModuleBase64,        // GetModuleBaseRoutine
+        NULL);                      // TranslateAddress
+    if (!ok) break;
+
+    // Store the address.
+    ASSERT((stack_frame.AddrPC.Offset >> 32) == 0);  // 32-bit address.
+    frames[frames_count].address =
+        reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
+
+    // Try to locate a symbol for this frame.
+    DWORD64 symbol_displacement;
+    IMAGEHLP_SYMBOL64* symbol = NULL;
+    symbol = NewArray<IMAGEHLP_SYMBOL64>(kStackWalkMaxNameLen);
+    if (!symbol) return kStackWalkError;  // Out of memory.
+    memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + kStackWalkMaxNameLen);
+    symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+    symbol->MaxNameLength = kStackWalkMaxNameLen;
+    ok = _SymGetSymFromAddr64(process_handle,             // hProcess
+                              stack_frame.AddrPC.Offset,  // Address
+                              &symbol_displacement,       // Displacement
+                              symbol);                    // Symbol
+    if (ok) {
+      // Try to locate more source information for the symbol.
+      IMAGEHLP_LINE64 Line;
+      memset(&Line, 0, sizeof(Line));
+      Line.SizeOfStruct = sizeof(Line);
+      DWORD line_displacement;
+      ok = _SymGetLineFromAddr64(
+          process_handle,             // hProcess
+          stack_frame.AddrPC.Offset,  // dwAddr
+          &line_displacement,         // pdwDisplacement
+          &Line);                     // Line
+      // Format a text representation of the frame based on the information
+      // available.
+      if (ok) {
+        SNPrintF(MutableCStrVector(frames[frames_count].text,
+                                   kStackWalkMaxTextLen),
+                 "%s %s:%d:%d",
+                 symbol->Name, Line.FileName, Line.LineNumber,
+                 line_displacement);
+      } else {
+        SNPrintF(MutableCStrVector(frames[frames_count].text,
+                                   kStackWalkMaxTextLen),
+                 "%s",
+                 symbol->Name);
+      }
+      // Make sure line termination is in place.
+      frames[frames_count].text[kStackWalkMaxTextLen - 1] = '\0';
+    } else {
+      // No text representation of this frame
+      frames[frames_count].text[0] = '\0';
+
+      // Continue if we are just missing a module (for non C/C++ frames a
+      // module will never be found).
+      int err = GetLastError();
+      if (err != ERROR_MOD_NOT_FOUND) {
+        DeleteArray(symbol);
+        break;
+      }
+    }
+    DeleteArray(symbol);
+
+    frames_count++;
+  }
+
+  // Return the number of frames filled in.
+  return frames_count;
+}
+
+// Restore warnings to previous settings.
+#pragma warning(pop)
+
+
+double OS::nan_value() {
+  static const __int64 nanval = 0xfff8000000000000;
+  return *reinterpret_cast<const double*>(&nanval);
+}
+
+
+int OS::ActivationFrameAlignment() {
+  // No constraint on Windows.
+  return 0;
+}
+
+
+bool VirtualMemory::IsReserved() {
+  return address_ != NULL;
+}
+
+
+VirtualMemory::VirtualMemory(size_t size) {
+  address_ = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
+  size_ = size;
+}
+
+
+VirtualMemory::~VirtualMemory() {
+  if (IsReserved()) {
+    if (0 == VirtualFree(address(), 0, MEM_RELEASE)) address_ = NULL;
+  }
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
+  int prot = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
+  if (NULL == VirtualAlloc(address, size, MEM_COMMIT, prot)) {
+    return false;
+  }
+
+  UpdateAllocatedSpaceLimits(address, size);
+  return true;
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+  ASSERT(IsReserved());
+  return VirtualFree(address, size, MEM_DECOMMIT) != NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+// Win32 thread support.
+
+// Definition of invalid thread handle and id.
+static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
+static const DWORD kNoThreadId = 0;
+
+
+class ThreadHandle::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(ThreadHandle::Kind kind) {
+    Initialize(kind);
+  }
+
+  void Initialize(ThreadHandle::Kind kind) {
+    switch (kind) {
+      case ThreadHandle::SELF: tid_ = GetCurrentThreadId(); break;
+      case ThreadHandle::INVALID: tid_ = kNoThreadId; break;
+    }
+  }
+  DWORD tid_;  // Win32 thread identifier.
+};
+
+
+// Entry point for threads. The supplied argument is a pointer to the thread
+// object. The entry function dispatches to the run method in the thread
+// object. It is important that this function has __stdcall calling
+// convention.
+static unsigned int __stdcall ThreadEntry(void* arg) {
+  Thread* thread = reinterpret_cast<Thread*>(arg);
+  // This is also initialized by the last parameter to _beginthreadex() but we
+  // don't know which thread will run first (the original thread or the new
+  // one) so we initialize it here too.
+  thread->thread_handle_data()->tid_ = GetCurrentThreadId();
+  thread->Run();
+  return 0;
+}
+
+
+// Initialize thread handle to invalid handle.
+ThreadHandle::ThreadHandle(ThreadHandle::Kind kind) {
+  data_ = new PlatformData(kind);
+}
+
+
+ThreadHandle::~ThreadHandle() {
+  delete data_;
+}
+
+
+// The thread is running if it has the same id as the current thread.
+bool ThreadHandle::IsSelf() const {
+  return GetCurrentThreadId() == data_->tid_;
+}
+
+
+// Test for invalid thread handle.
+bool ThreadHandle::IsValid() const {
+  return data_->tid_ != kNoThreadId;
+}
+
+
+void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
+  data_->Initialize(kind);
+}
+
+
+class Thread::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(HANDLE thread) : thread_(thread) {}
+  HANDLE thread_;
+};
+
+
+// Initialize a Win32 thread object. The thread has an invalid thread
+// handle until it is started.
+
+Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+  data_ = new PlatformData(kNoThread);
+}
+
+
+// Close our own handle for the thread.
+Thread::~Thread() {
+  if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
+  delete data_;
+}
+
+
+// Create a new thread. It is important to use _beginthreadex() instead of
+// the Win32 function CreateThread(), because the CreateThread() does not
+// initialize thread specific structures in the C runtime library.
+void Thread::Start() {
+  data_->thread_ = reinterpret_cast<HANDLE>(
+      _beginthreadex(NULL,
+                     0,
+                     ThreadEntry,
+                     this,
+                     0,
+                     reinterpret_cast<unsigned int*>(
+                         &thread_handle_data()->tid_)));
+  ASSERT(IsValid());
+}
+
+
+// Wait for thread to terminate.
+void Thread::Join() {
+  WaitForSingleObject(data_->thread_, INFINITE);
+}
+
+
+Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
+  DWORD result = TlsAlloc();
+  ASSERT(result != TLS_OUT_OF_INDEXES);
+  return static_cast<LocalStorageKey>(result);
+}
+
+
+void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
+  BOOL result = TlsFree(static_cast<DWORD>(key));
+  USE(result);
+  ASSERT(result);
+}
+
+
+void* Thread::GetThreadLocal(LocalStorageKey key) {
+  return TlsGetValue(static_cast<DWORD>(key));
+}
+
+
+void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
+  BOOL result = TlsSetValue(static_cast<DWORD>(key), value);
+  USE(result);
+  ASSERT(result);
+}
+
+
+
+void Thread::YieldCPU() {
+  Sleep(0);
+}
+
+
+// ----------------------------------------------------------------------------
+// Win32 mutex support.
+//
+// On Win32 mutexes are implemented using CRITICAL_SECTION objects. These are
+// faster than Win32 Mutex objects because they are implemented using user mode
+// atomic instructions. Therefore we only do ring transitions if there is lock
+// contention.
+
+class Win32Mutex : public Mutex {
+ public:
+
+  Win32Mutex() { InitializeCriticalSection(&cs_); }
+
+  ~Win32Mutex() { DeleteCriticalSection(&cs_); }
+
+  int Lock() {
+    EnterCriticalSection(&cs_);
+    return 0;
+  }
+
+  int Unlock() {
+    LeaveCriticalSection(&cs_);
+    return 0;
+  }
+
+ private:
+  CRITICAL_SECTION cs_;  // Critical section used for mutex
+};
+
+
+Mutex* OS::CreateMutex() {
+  return new Win32Mutex();
+}
+
+
+// ----------------------------------------------------------------------------
+// Win32 semaphore support.
+//
+// On Win32 semaphores are implemented using Win32 Semaphore objects. The
+// semaphores are anonymous. Also, the semaphores are initialized to have
+// no upper limit on count.
+
+
+class Win32Semaphore : public Semaphore {
+ public:
+  explicit Win32Semaphore(int count) {
+    sem = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
+  }
+
+  ~Win32Semaphore() {
+    CloseHandle(sem);
+  }
+
+  void Wait() {
+    WaitForSingleObject(sem, INFINITE);
+  }
+
+  void Signal() {
+    LONG dummy;
+    ReleaseSemaphore(sem, 1, &dummy);
+  }
+
+ private:
+  HANDLE sem;
+};
+
+
+Semaphore* OS::CreateSemaphore(int count) {
+  return new Win32Semaphore(count);
+}
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+// ----------------------------------------------------------------------------
+// Win32 profiler support.
+//
+// On win32 we use a sampler thread with high priority to sample the program
+// counter for the profiled thread.
+
+class Sampler::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(Sampler* sampler) {
+    sampler_ = sampler;
+    sampler_thread_ = INVALID_HANDLE_VALUE;
+    profiled_thread_ = INVALID_HANDLE_VALUE;
+  }
+
+  Sampler* sampler_;
+  HANDLE sampler_thread_;
+  HANDLE profiled_thread_;
+
+  // Sampler thread handler.
+  void Runner() {
+    // Context used for sampling the register state of the profiled thread.
+    CONTEXT context;
+    memset(&context, 0, sizeof(context));
+    // Loop until the sampler is disengaged.
+    while (sampler_->IsActive()) {
+      TickSample sample;
+
+      // If profiling, we record the pc and sp of the profiled thread.
+      if (sampler_->IsProfiling()) {
+        // Pause the profiled thread and get its context.
+        SuspendThread(profiled_thread_);
+        context.ContextFlags = CONTEXT_FULL;
+        GetThreadContext(profiled_thread_, &context);
+        ResumeThread(profiled_thread_);
+        // Invoke tick handler with program counter and stack pointer.
+        sample.pc = context.Eip;
+        sample.sp = context.Esp;
+      }
+
+      // We always sample the VM state.
+      sample.state = Logger::state();
+      sampler_->Tick(&sample);
+
+      // Wait until next sampling.
+      Sleep(sampler_->interval_);
+    }
+  }
+};
+
+
+// Entry point for sampler thread.
+static unsigned int __stdcall SamplerEntry(void* arg) {
+  Sampler::PlatformData* data =
+      reinterpret_cast<Sampler::PlatformData*>(arg);
+  data->Runner();
+  return 0;
+}
+
+
+// Initialize a profile sampler.
+Sampler::Sampler(int interval, bool profiling)
+    : interval_(interval), profiling_(profiling), active_(false) {
+  data_ = new PlatformData(this);
+}
+
+
+Sampler::~Sampler() {
+  delete data_;
+}
+
+
+// Start profiling.
+void Sampler::Start() {
+  // If we are profiling, we need to be able to access the calling
+  // thread.
+  if (IsProfiling()) {
+    // Get a handle to the calling thread. This is the thread that we are
+    // going to profile. We need to duplicate the handle because we are
+    // going to use it in the sampler thread. using GetThreadHandle() will
+    // not work in this case.
+    BOOL ok = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+                              GetCurrentProcess(), &data_->profiled_thread_,
+                              THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME |
+                              THREAD_QUERY_INFORMATION, FALSE, 0);
+    if (!ok) return;
+  }
+
+  // Start sampler thread.
+  unsigned int tid;
+  active_ = true;
+  data_->sampler_thread_ = reinterpret_cast<HANDLE>(
+      _beginthreadex(NULL, 0, SamplerEntry, data_, 0, &tid));
+  // Set thread to high priority to increase sampling accuracy.
+  SetThreadPriority(data_->sampler_thread_, THREAD_PRIORITY_TIME_CRITICAL);
+}
+
+
+// Stop profiling.
+void Sampler::Stop() {
+  // Seting active to false triggers termination of the sampler
+  // thread.
+  active_ = false;
+
+  // Wait for sampler thread to terminate.
+  WaitForSingleObject(data_->sampler_thread_, INFINITE);
+
+  // Release the thread handles
+  CloseHandle(data_->sampler_thread_);
+  CloseHandle(data_->profiled_thread_);
+}
+
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/platform.h b/regexp2000/src/platform.h
new file mode 100644 (file)
index 0000000..7238d70
--- /dev/null
@@ -0,0 +1,449 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This module contains the platform-specific code. This make the rest of the
+// code less dependent on operating system, compilers and runtime libraries.
+// This module does specifically not deal with differences between different
+// processor architecture.
+// The platform classes have the same definition for all platforms. The
+// implementation for a particular platform is put in platform_<os>.cc.
+// The build system then uses the implementation for the target platform.
+//
+// This design has been choosen because it is simple and fast. Alternatively,
+// the platform dependent classes could have been implemented using abstract
+// superclasses with virtual methods and having specializations for each
+// platform. This design was rejected because it was more complicated and
+// slower. It would require factory methods for selecting the right
+// implementation and the overhead of virtual methods for performance
+// sensitive like mutex locking/unlocking.
+
+#ifndef V8_PLATFORM_H_
+#define V8_PLATFORM_H_
+
+#ifdef WIN32
+
+enum {
+  FP_NAN,
+  FP_INFINITE,
+  FP_ZERO,
+  FP_SUBNORMAL,
+  FP_NORMAL
+};
+
+#define 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);
+
+int random();
+
+int strncasecmp(const char* s1, const char* s2, int n);
+
+#else
+
+// 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 defined(__GNUC__)
+#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
+#endif
+
+#if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100
+#include <limits>
+#undef INFINITY
+#define INFINITY std::numeric_limits<double>::infinity()
+#endif
+
+#endif  // WIN32
+
+namespace v8 { namespace internal {
+
+double ceiling(double x);
+
+// ----------------------------------------------------------------------------
+// OS
+//
+// This class has static methods for the different platform specific
+// functions. Add methods here to cope with differences between the
+// supported platforms.
+
+class OS {
+ public:
+  // Initializes the platform OS support. Called once at VM startup.
+  static void Setup();
+
+  // Returns the accumulated user time for thread. This routine
+  // can be used for profiling. The implementation should
+  // strive for high-precision timer resolution, preferable
+  // micro-second resolution.
+  static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
+
+  // Get a tick counter normalized to one tick per microsecond.
+  // Used for calculating time intervals.
+  static int64_t Ticks();
+
+  // Returns current time as the number of milliseconds since
+  // 00:00:00 UTC, January 1, 1970.
+  static double TimeCurrentMillis();
+
+  // Returns a string identifying the current time zone. The
+  // timestamp is used for determining if DST is in effect.
+  static char* LocalTimezone(double time);
+
+  // Returns the local time offset in milliseconds east of UTC without
+  // taking daylight savings time into account.
+  static double LocalTimeOffset();
+
+  // Returns the daylight savings offset for the given time.
+  static double DaylightSavingsOffset(double time);
+
+  static FILE* FOpen(const char* path, const char* mode);
+
+  // Print output to console. This is mostly used for debugging output.
+  // On platforms that has standard terminal output, the output
+  // should go to stdout.
+  static void Print(const char* format, ...);
+  static void VPrint(const char* format, va_list args);
+
+  // Print error output to console. This is mostly used for error message
+  // output. On platforms that has standard terminal output, the output
+  // should go to stderr.
+  static void PrintError(const char* format, ...);
+  static void VPrintError(const char* format, va_list args);
+
+  // Allocate/Free memory used by JS heap. Pages are readable/writeable, but
+  // they are not guaranteed to be executable unless 'executable' is true.
+  // Returns the address of allocated memory, or NULL if failed.
+  static void* Allocate(const size_t requested,
+                        size_t* allocated,
+                        bool executable);
+  static void Free(void* buf, const size_t length);
+  // Get the Alignment guaranteed by Allocate().
+  static size_t AllocateAlignment();
+
+  // Returns an indication of whether a pointer is in a space that
+  // has been allocated by Allocate().  This method may conservatively
+  // always return false, but giving more accurate information may
+  // improve the robustness of the stack dump code in the presence of
+  // heap corruption.
+  static bool IsOutsideAllocatedSpace(void* pointer);
+
+  // Sleep for a number of miliseconds.
+  static void Sleep(const int miliseconds);
+
+  // Abort the current process.
+  static void Abort();
+
+  // Debug break.
+  static void DebugBreak();
+
+  // Walk the stack.
+  static const int kStackWalkError = -1;
+  static const int kStackWalkMaxNameLen = 256;
+  static const int kStackWalkMaxTextLen = 256;
+  struct StackFrame {
+    void* address;
+    char text[kStackWalkMaxTextLen];
+  };
+
+  static int StackWalk(StackFrame* frames, int frames_size);
+
+  // Factory method for creating platform dependent Mutex.
+  // Please use delete to reclaim the storage for the returned Mutex.
+  static Mutex* CreateMutex();
+
+  // Factory method for creating platform dependent Semaphore.
+  // Please use delete to reclaim the storage for the returned Semaphore.
+  static Semaphore* CreateSemaphore(int count);
+
+  class MemoryMappedFile {
+   public:
+    static MemoryMappedFile* create(const char* name, int size, void* initial);
+    virtual ~MemoryMappedFile() { }
+    virtual void* memory() = 0;
+  };
+
+  // Safe formatting print. Ensures that str is always null-terminated.
+  // Returns the number of chars written, or -1 if output was truncated.
+  static int SNPrintF(Vector<char> str, const char* format, ...);
+  static int VSNPrintF(Vector<char> str,
+                       const char* format,
+                       va_list args);
+
+  static void StrNCpy(Vector<char> dest, const char* src, size_t n);
+  static void WcsCpy(Vector<wchar_t> dest, const wchar_t* src);
+  static char* StrDup(const char* str);
+
+  // Support for profiler.  Can do nothing, in which case ticks
+  // occuring in shared libraries will not be properly accounted
+  // for.
+  static void LogSharedLibraryAddresses();
+
+  // Returns the double constant NAN
+  static double nan_value();
+
+  // Returns the activation frame alignment constraint or zero if
+  // the platform doesn't care. Guaranteed to be a power of two.
+  static int ActivationFrameAlignment();
+
+ private:
+  static const int msPerSecond = 1000;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
+};
+
+
+class VirtualMemory {
+ public:
+  // Reserves virtual memory with size.
+  explicit VirtualMemory(size_t size);
+  ~VirtualMemory();
+
+  // Returns whether the memory has been reserved.
+  bool IsReserved();
+
+  // Returns the start address of the reserved memory.
+  void* address() {
+    ASSERT(IsReserved());
+    return address_;
+  };
+
+  // Returns the size of the reserved memory.
+  size_t size() { return size_; }
+
+  // Commits real memory. Returns whether the operation succeeded.
+  bool Commit(void* address, size_t size, bool executable);
+
+  // Uncommit real memory.  Returns whether the operation succeeded.
+  bool Uncommit(void* address, size_t size);
+
+ private:
+  void* address_;  // Start address of the virtual memory.
+  size_t size_;  // Size of the virtual memory.
+};
+
+
+// ----------------------------------------------------------------------------
+// ThreadHandle
+//
+// A ThreadHandle represents a thread identifier for a thread. The ThreadHandle
+// does not own the underlying os handle. Thread handles can be used for
+// refering to threads and testing equality.
+
+class ThreadHandle {
+ public:
+  enum Kind { SELF, INVALID };
+  explicit ThreadHandle(Kind kind);
+
+  // Destructor.
+  ~ThreadHandle();
+
+  // Test for thread running.
+  bool IsSelf() const;
+
+  // Test for valid thread handle.
+  bool IsValid() const;
+
+  // Get platform-specific data.
+  class PlatformData;
+  PlatformData* thread_handle_data() { return data_; }
+
+  // Initialize the handle to kind
+  void Initialize(Kind kind);
+
+ private:
+  PlatformData* data_;  // Captures platform dependent data.
+};
+
+
+// ----------------------------------------------------------------------------
+// Thread
+//
+// Thread objects are used for creating and running threads. When the start()
+// method is called the new thread starts running the run() method in the new
+// thread. The Thread object should not be deallocated before the thread has
+// terminated.
+
+class Thread: public ThreadHandle {
+ public:
+  // Opaque data type for thread-local storage keys.
+  enum LocalStorageKey {};
+
+  // Create new thread.
+  Thread();
+  virtual ~Thread();
+
+  // Start new thread by calling the Run() method in the new thread.
+  void Start();
+
+  // Wait until thread terminates.
+  void Join();
+
+  // Abstract method for run handler.
+  virtual void Run() = 0;
+
+  // Thread-local storage.
+  static LocalStorageKey CreateThreadLocalKey();
+  static void DeleteThreadLocalKey(LocalStorageKey key);
+  static void* GetThreadLocal(LocalStorageKey key);
+  static void SetThreadLocal(LocalStorageKey key, void* value);
+
+  // A hint to the scheduler to let another thread run.
+  static void YieldCPU();
+
+ private:
+  class PlatformData;
+  PlatformData* data_;
+  DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+
+// ----------------------------------------------------------------------------
+// Mutex
+//
+// Mutexes are used for serializing access to non-reentrant sections of code.
+// The implementations of mutex should allow for nested/recursive locking.
+
+class Mutex {
+ public:
+  virtual ~Mutex() {}
+
+  // Locks the given mutex. If the mutex is currently unlocked, it becomes
+  // locked and owned by the calling thread, and immediately. If the mutex
+  // is already locked by another thread, suspends the calling thread until
+  // the mutex is unlocked.
+  virtual int Lock() = 0;
+
+  // Unlocks the given mutex. The mutex is assumed to be locked and owned by
+  // the calling thread on entrance.
+  virtual int Unlock() = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+// ScopedLock
+//
+// Stack-allocated ScopedLocks provide block-scoped locking and unlocking
+// of a mutex.
+class ScopedLock {
+ public:
+  explicit ScopedLock(Mutex* mutex): mutex_(mutex) {
+    mutex_->Lock();
+  }
+  ~ScopedLock() {
+    mutex_->Unlock();
+  }
+
+ private:
+  Mutex* mutex_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedLock);
+};
+
+
+// ----------------------------------------------------------------------------
+// Semaphore
+//
+// A semaphore object is a synchronization object that maintains a count. The
+// count is decremented each time a thread completes a wait for the semaphore
+// object and incremented each time a thread signals the semaphore. When the
+// count reaches zero,  threads waiting for the semaphore blocks until the
+// count becomes non-zero.
+
+class Semaphore {
+ public:
+  virtual ~Semaphore() {}
+
+  // Suspends the calling thread until the counter is non zero
+  // and then decrements the semaphore counter.
+  virtual void Wait() = 0;
+
+  // Increments the semaphore counter.
+  virtual void Signal() = 0;
+};
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+// ----------------------------------------------------------------------------
+// Sampler
+//
+// A sampler periodically samples the state of the VM and optionally
+// (if used for profiling) the program counter and stack pointer for
+// the thread that created it.
+
+// TickSample captures the information collected for each sample.
+class TickSample {
+ public:
+  TickSample() : pc(0), sp(0), state(OTHER) {}
+  unsigned int pc;  // Instruction pointer.
+  unsigned int sp;  // Stack pointer.
+  StateTag state;   // The state of the VM.
+};
+
+class Sampler {
+ public:
+  // Initialize sampler.
+  explicit Sampler(int interval, bool profiling);
+  virtual ~Sampler();
+
+  // This method is called for each sampling period with the current
+  // program counter.
+  virtual void Tick(TickSample* sample) = 0;
+
+  // Start and stop sampler.
+  void Start();
+  void Stop();
+
+  // Is the sampler used for profiling.
+  inline bool IsProfiling() { return profiling_; }
+
+  class PlatformData;
+ protected:
+  inline bool IsActive() { return active_; }
+
+ private:
+  int interval_;
+  bool profiling_;
+  bool active_;
+  PlatformData* data_;  // Platform specific data.
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
+};
+
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+} }  // namespace v8::internal
+
+#endif  // V8_PLATFORM_H_
diff --git a/regexp2000/src/prettyprinter.cc b/regexp2000/src/prettyprinter.cc
new file mode 100644 (file)
index 0000000..fef270e
--- /dev/null
@@ -0,0 +1,1052 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdarg.h>
+
+#include "v8.h"
+
+#include "prettyprinter.h"
+#include "scopes.h"
+#include "platform.h"
+
+namespace v8 { namespace internal {
+
+#ifdef DEBUG
+
+PrettyPrinter::PrettyPrinter() {
+  output_ = NULL;
+  size_ = 0;
+  pos_ = 0;
+}
+
+
+PrettyPrinter::~PrettyPrinter() {
+  DeleteArray(output_);
+}
+
+
+void PrettyPrinter::VisitBlock(Block* node) {
+  if (!node->is_initializer_block()) Print("{ ");
+  PrintStatements(node->statements());
+  if (node->statements()->length() > 0) Print(" ");
+  if (!node->is_initializer_block()) Print("}");
+}
+
+
+void PrettyPrinter::VisitDeclaration(Declaration* node) {
+  Print("var ");
+  PrintLiteral(node->proxy()->name(), false);
+  if (node->fun() != NULL) {
+    Print(" = ");
+    PrintFunctionLiteral(node->fun());
+  }
+  Print(";");
+}
+
+
+void PrettyPrinter::VisitExpressionStatement(ExpressionStatement* node) {
+  Visit(node->expression());
+  Print(";");
+}
+
+
+void PrettyPrinter::VisitEmptyStatement(EmptyStatement* node) {
+  Print(";");
+}
+
+
+void PrettyPrinter::VisitIfStatement(IfStatement* node) {
+  Print("if (");
+  Visit(node->condition());
+  Print(") ");
+  Visit(node->then_statement());
+  if (node->HasElseStatement()) {
+    Print(" else ");
+    Visit(node->else_statement());
+  }
+}
+
+
+void PrettyPrinter::VisitContinueStatement(ContinueStatement* node) {
+  Print("continue");
+  ZoneStringList* labels = node->target()->labels();
+  if (labels != NULL) {
+    Print(" ");
+    ASSERT(labels->length() > 0);  // guaranteed to have at least one entry
+    PrintLiteral(labels->at(0), false);  // any label from the list is fine
+  }
+  Print(";");
+}
+
+
+void PrettyPrinter::VisitBreakStatement(BreakStatement* node) {
+  Print("break");
+  ZoneStringList* labels = node->target()->labels();
+  if (labels != NULL) {
+    Print(" ");
+    ASSERT(labels->length() > 0);  // guaranteed to have at least one entry
+    PrintLiteral(labels->at(0), false);  // any label from the list is fine
+  }
+  Print(";");
+}
+
+
+void PrettyPrinter::VisitReturnStatement(ReturnStatement* node) {
+  Print("return ");
+  Visit(node->expression());
+  Print(";");
+}
+
+
+void PrettyPrinter::VisitWithEnterStatement(WithEnterStatement* node) {
+  Print("<enter with> (");
+  Visit(node->expression());
+  Print(") ");
+}
+
+
+void PrettyPrinter::VisitWithExitStatement(WithExitStatement* node) {
+  Print("<exit with>");
+}
+
+
+void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) {
+  PrintLabels(node->labels());
+  Print("switch (");
+  Visit(node->tag());
+  Print(") { ");
+  ZoneList<CaseClause*>* cases = node->cases();
+  for (int i = 0; i < cases->length(); i++)
+    PrintCaseClause(cases->at(i));
+  Print("}");
+}
+
+
+void PrettyPrinter::VisitLoopStatement(LoopStatement* node) {
+  PrintLabels(node->labels());
+  switch (node->type()) {
+    case LoopStatement::DO_LOOP:
+      ASSERT(node->init() == NULL);
+      ASSERT(node->next() == NULL);
+      Print("do ");
+      Visit(node->body());
+      Print(" while (");
+      Visit(node->cond());
+      Print(");");
+      break;
+
+    case LoopStatement::FOR_LOOP:
+      Print("for (");
+      if (node->init() != NULL) {
+        Visit(node->init());
+        Print(" ");
+      } else {
+        Print("; ");
+      }
+      if (node->cond() != NULL)
+        Visit(node->cond());
+      Print("; ");
+      if (node->next() != NULL)
+        Visit(node->next());  // prints extra ';', unfortunately
+      // to fix: should use Expression for next
+      Print(") ");
+      Visit(node->body());
+      break;
+
+    case LoopStatement::WHILE_LOOP:
+      ASSERT(node->init() == NULL);
+      ASSERT(node->next() == NULL);
+      Print("while (");
+      Visit(node->cond());
+      Print(") ");
+      Visit(node->body());
+      break;
+  }
+}
+
+
+void PrettyPrinter::VisitForInStatement(ForInStatement* node) {
+  PrintLabels(node->labels());
+  Print("for (");
+  Visit(node->each());
+  Print(" in ");
+  Visit(node->enumerable());
+  Print(") ");
+  Visit(node->body());
+}
+
+
+void PrettyPrinter::VisitTryCatch(TryCatch* node) {
+  Print("try ");
+  Visit(node->try_block());
+  Print(" catch (");
+  Visit(node->catch_var());
+  Print(") ");
+  Visit(node->catch_block());
+}
+
+
+void PrettyPrinter::VisitTryFinally(TryFinally* node) {
+  Print("try ");
+  Visit(node->try_block());
+  Print(" finally ");
+  Visit(node->finally_block());
+}
+
+
+void PrettyPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
+  Print("debugger ");
+}
+
+
+void PrettyPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
+  Print("(");
+  PrintFunctionLiteral(node);
+  Print(")");
+}
+
+
+void PrettyPrinter::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* node) {
+  Print("(");
+  PrintLiteral(node->boilerplate(), true);
+  Print(")");
+}
+
+
+void PrettyPrinter::VisitConditional(Conditional* node) {
+  Visit(node->condition());
+  Print(" ? ");
+  Visit(node->then_expression());
+  Print(" : ");
+  Visit(node->else_expression());
+}
+
+
+void PrettyPrinter::VisitLiteral(Literal* node) {
+  PrintLiteral(node->handle(), true);
+}
+
+
+void PrettyPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
+  Print(" RegExp(");
+  PrintLiteral(node->pattern(), false);
+  Print(",");
+  PrintLiteral(node->flags(), false);
+  Print(") ");
+}
+
+
+void PrettyPrinter::VisitObjectLiteral(ObjectLiteral* node) {
+  Print("{ ");
+  for (int i = 0; i < node->properties()->length(); i++) {
+    if (i != 0) Print(",");
+    ObjectLiteral::Property* property = node->properties()->at(i);
+    Print(" ");
+    Visit(property->key());
+    Print(": ");
+    Visit(property->value());
+  }
+  Print(" }");
+}
+
+
+void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
+  Print("[ ");
+  for (int i = 0; i < node->values()->length(); i++) {
+    if (i != 0) Print(",");
+    Visit(node->values()->at(i));
+  }
+  Print(" ]");
+}
+
+
+void PrettyPrinter::VisitSlot(Slot* node) {
+  switch (node->type()) {
+    case Slot::PARAMETER:
+      Print("parameter[%d]", node->index());
+      break;
+    case Slot::LOCAL:
+      Print("frame[%d]", node->index());
+      break;
+    case Slot::CONTEXT:
+      Print(".context[%d]", node->index());
+      break;
+    case Slot::LOOKUP:
+      Print(".context[");
+      PrintLiteral(node->var()->name(), false);
+      Print("]");
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void PrettyPrinter::VisitVariableProxy(VariableProxy* node) {
+  PrintLiteral(node->name(), false);
+}
+
+
+void PrettyPrinter::VisitAssignment(Assignment* node) {
+  Visit(node->target());
+  Print(" %s ", Token::String(node->op()));
+  Visit(node->value());
+}
+
+
+void PrettyPrinter::VisitThrow(Throw* node) {
+  Print("throw ");
+  Visit(node->exception());
+}
+
+
+void PrettyPrinter::VisitProperty(Property* node) {
+  Expression* key = node->key();
+  Literal* literal = key->AsLiteral();
+  if (literal != NULL && literal->handle()->IsSymbol()) {
+    Print("(");
+    Visit(node->obj());
+    Print(").");
+    PrintLiteral(literal->handle(), false);
+  } else {
+    Visit(node->obj());
+    Print("[");
+    Visit(key);
+    Print("]");
+  }
+}
+
+
+void PrettyPrinter::VisitCall(Call* node) {
+  Visit(node->expression());
+  PrintArguments(node->arguments());
+}
+
+
+void PrettyPrinter::VisitCallNew(CallNew* node) {
+  Print("new (");
+  Visit(node->expression());
+  Print(")");
+  PrintArguments(node->arguments());
+}
+
+
+void PrettyPrinter::VisitCallRuntime(CallRuntime* node) {
+  Print("%%");
+  PrintLiteral(node->name(), false);
+  PrintArguments(node->arguments());
+}
+
+
+void PrettyPrinter::VisitUnaryOperation(UnaryOperation* node) {
+  Print("(%s", Token::String(node->op()));
+  Visit(node->expression());
+  Print(")");
+}
+
+
+void PrettyPrinter::VisitCountOperation(CountOperation* node) {
+  Print("(");
+  if (node->is_prefix()) Print("%s", Token::String(node->op()));
+  Visit(node->expression());
+  if (node->is_postfix()) Print("%s", Token::String(node->op()));
+  Print(")");
+}
+
+
+void PrettyPrinter::VisitBinaryOperation(BinaryOperation* node) {
+  Print("(");
+  Visit(node->left());
+  Print("%s", Token::String(node->op()));
+  Visit(node->right());
+  Print(")");
+}
+
+
+void PrettyPrinter::VisitCompareOperation(CompareOperation* node) {
+  Print("(");
+  Visit(node->left());
+  Print("%s", Token::String(node->op()));
+  Visit(node->right());
+  Print(")");
+}
+
+
+void PrettyPrinter::VisitThisFunction(ThisFunction* node) {
+  Print("<this-function>");
+}
+
+
+const char* PrettyPrinter::Print(Node* node) {
+  Init();
+  Visit(node);
+  return output_;
+}
+
+
+const char* PrettyPrinter::PrintExpression(FunctionLiteral* program) {
+  Init();
+  ExpressionStatement* statement =
+    program->body()->at(0)->AsExpressionStatement();
+  Visit(statement->expression());
+  return output_;
+}
+
+
+const char* PrettyPrinter::PrintProgram(FunctionLiteral* program) {
+  Init();
+  PrintStatements(program->body());
+  Print("\n");
+  return output_;
+}
+
+
+void PrettyPrinter::PrintOut(Node* node) {
+  PrettyPrinter printer;
+  PrintF("%s", printer.Print(node));
+}
+
+
+void PrettyPrinter::Init() {
+  if (size_ == 0) {
+    ASSERT(output_ == NULL);
+    const int initial_size = 256;
+    output_ = NewArray<char>(initial_size);
+    size_ = initial_size;
+  }
+  output_[0] = '\0';
+  pos_ = 0;
+}
+
+
+void PrettyPrinter::Print(const char* format, ...) {
+  for (;;) {
+    va_list arguments;
+    va_start(arguments, format);
+    int n = OS::VSNPrintF(Vector<char>(output_, size_) + pos_,
+                          format,
+                          arguments);
+    va_end(arguments);
+
+    if (n >= 0) {
+      // there was enough space - we are done
+      pos_ += n;
+      return;
+    } else {
+      // there was not enough space - allocate more and try again
+      const int slack = 32;
+      int new_size = size_ + (size_ >> 1) + slack;
+      char* new_output = NewArray<char>(new_size);
+      memcpy(new_output, output_, pos_);
+      DeleteArray(output_);
+      output_ = new_output;
+      size_ = new_size;
+    }
+  }
+}
+
+
+void PrettyPrinter::PrintStatements(ZoneList<Statement*>* statements) {
+  for (int i = 0; i < statements->length(); i++) {
+    if (i != 0) Print(" ");
+    Visit(statements->at(i));
+  }
+}
+
+
+void PrettyPrinter::PrintLabels(ZoneStringList* labels) {
+  if (labels != NULL) {
+    for (int i = 0; i < labels->length(); i++) {
+      PrintLiteral(labels->at(i), false);
+      Print(": ");
+    }
+  }
+}
+
+
+void PrettyPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
+  Print("(");
+  for (int i = 0; i < arguments->length(); i++) {
+    if (i != 0) Print(", ");
+    Visit(arguments->at(i));
+  }
+  Print(")");
+}
+
+
+void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) {
+  Object* object = *value;
+  if (object->IsString()) {
+    String* string = String::cast(object);
+    if (quote) Print("\"");
+    for (int i = 0; i < string->length(); i++) {
+      Print("%c", string->Get(i));
+    }
+    if (quote) Print("\"");
+  } else if (object == Heap::null_value()) {
+    Print("null");
+  } else if (object == Heap::true_value()) {
+    Print("true");
+  } else if (object == Heap::false_value()) {
+    Print("false");
+  } else if (object == Heap::undefined_value()) {
+    Print("undefined");
+  } else if (object->IsNumber()) {
+    Print("%g", object->Number());
+  } else if (object->IsJSObject()) {
+    // regular expression
+    if (object->IsJSFunction()) {
+      Print("JS-Function");
+    } else if (object->IsJSArray()) {
+      Print("JS-array[%u]", JSArray::cast(object)->length());
+    } else if (object->IsJSObject()) {
+      Print("JS-Object");
+    } else {
+      Print("?UNKNOWN?");
+    }
+  } else if (object->IsFixedArray()) {
+    Print("FixedArray");
+  } else {
+    Print("<unknown literal %p>", object);
+  }
+}
+
+
+void PrettyPrinter::PrintParameters(Scope* scope) {
+  Print("(");
+  for (int i = 0; i < scope->num_parameters(); i++) {
+    if (i  > 0) Print(", ");
+    PrintLiteral(scope->parameter(i)->name(), false);
+  }
+  Print(")");
+}
+
+
+void PrettyPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
+  for (int i = 0; i < declarations->length(); i++) {
+    if (i > 0) Print(" ");
+    Visit(declarations->at(i));
+  }
+}
+
+
+void PrettyPrinter::PrintFunctionLiteral(FunctionLiteral* function) {
+  Print("function ");
+  PrintLiteral(function->name(), false);
+  PrintParameters(function->scope());
+  Print(" { ");
+  PrintDeclarations(function->scope()->declarations());
+  PrintStatements(function->body());
+  Print(" }");
+}
+
+
+void PrettyPrinter::PrintCaseClause(CaseClause* clause) {
+  if (clause->is_default()) {
+    Print("default");
+  } else {
+    Print("case ");
+    Visit(clause->label());
+  }
+  Print(": ");
+  PrintStatements(clause->statements());
+  if (clause->statements()->length() > 0)
+    Print(" ");
+}
+
+
+//-----------------------------------------------------------------------------
+
+class IndentedScope BASE_EMBEDDED {
+ public:
+  IndentedScope() {
+    ast_printer_->inc_indent();
+  }
+
+  explicit IndentedScope(const char* txt) {
+    ast_printer_->PrintIndented(txt);
+    ast_printer_->Print("\n");
+    ast_printer_->inc_indent();
+  }
+
+  virtual ~IndentedScope() {
+    ast_printer_->dec_indent();
+  }
+
+  static void SetAstPrinter(AstPrinter* a) { ast_printer_ = a; }
+
+ private:
+  static AstPrinter* ast_printer_;
+};
+
+
+AstPrinter* IndentedScope::ast_printer_ = NULL;
+
+
+//-----------------------------------------------------------------------------
+
+int AstPrinter::indent_ = 0;
+
+
+AstPrinter::AstPrinter() {
+  ASSERT(indent_ == 0);
+  IndentedScope::SetAstPrinter(this);
+}
+
+
+AstPrinter::~AstPrinter() {
+  ASSERT(indent_ == 0);
+  IndentedScope::SetAstPrinter(NULL);
+}
+
+
+void AstPrinter::PrintIndented(const char* txt) {
+  for (int i = 0; i < indent_; i++) {
+    Print(".   ");
+  }
+  Print(txt);
+}
+
+
+void AstPrinter::PrintLiteralIndented(const char* info,
+                                      Handle<Object> value,
+                                      bool quote) {
+  PrintIndented(info);
+  Print(" ");
+  PrintLiteral(value, quote);
+  Print("\n");
+}
+
+
+void AstPrinter::PrintLiteralWithModeIndented(const char* info,
+                                              Variable* var,
+                                              Handle<Object> value) {
+  if (var == NULL) {
+    PrintLiteralIndented(info, value, true);
+  } else {
+    EmbeddedVector<char, 256> buf;
+    OS::SNPrintF(buf, "%s (mode = %s)", info,
+                 Variable::Mode2String(var->mode()));
+    PrintLiteralIndented(buf.start(), value, true);
+  }
+}
+
+
+void AstPrinter::PrintLabelsIndented(const char* info, ZoneStringList* labels) {
+  if (labels != NULL && labels->length() > 0) {
+    if (info == NULL) {
+      PrintIndented("LABELS ");
+    } else {
+      PrintIndented(info);
+      Print(" ");
+    }
+    PrintLabels(labels);
+    Print("\n");
+  } else if (info != NULL) {
+    PrintIndented(info);
+  }
+}
+
+
+void AstPrinter::PrintIndentedVisit(const char* s, Node* node) {
+  IndentedScope indent(s);
+  Visit(node);
+}
+
+
+const char* AstPrinter::PrintProgram(FunctionLiteral* program) {
+  Init();
+  { IndentedScope indent("FUNC");
+    PrintLiteralIndented("NAME", program->name(), true);
+    PrintParameters(program->scope());
+    PrintDeclarations(program->scope()->declarations());
+    PrintStatements(program->body());
+  }
+  return Output();
+}
+
+
+void AstPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
+  if (declarations->length() > 0) {
+    IndentedScope indent("DECLS");
+    for (int i = 0; i < declarations->length(); i++) {
+      Visit(declarations->at(i));
+    }
+  }
+}
+
+
+void AstPrinter::PrintParameters(Scope* scope) {
+  if (scope->num_parameters() > 0) {
+    IndentedScope indent("PARAMS");
+    for (int i = 0; i < scope->num_parameters(); i++) {
+      PrintLiteralWithModeIndented("VAR ", scope->parameter(i),
+                                   scope->parameter(i)->name());
+    }
+  }
+}
+
+
+void AstPrinter::PrintStatements(ZoneList<Statement*>* statements) {
+  for (int i = 0; i < statements->length(); i++) {
+    Visit(statements->at(i));
+  }
+}
+
+
+void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
+  for (int i = 0; i < arguments->length(); i++) {
+    Visit(arguments->at(i));
+  }
+}
+
+
+void AstPrinter::PrintCaseClause(CaseClause* clause) {
+  if (clause->is_default()) {
+    IndentedScope indent("DEFAULT");
+    PrintStatements(clause->statements());
+  } else {
+    IndentedScope indent("CASE");
+    Visit(clause->label());
+    PrintStatements(clause->statements());
+  }
+}
+
+
+void AstPrinter::VisitBlock(Block* node) {
+  const char* block_txt = node->is_initializer_block() ? "BLOCK INIT" : "BLOCK";
+  IndentedScope indent(block_txt);
+  PrintStatements(node->statements());
+}
+
+
+void AstPrinter::VisitDeclaration(Declaration* node) {
+  if (node->fun() == NULL) {
+    // var or const declarations
+    PrintLiteralWithModeIndented(
+      Variable::Mode2String(node->mode()),
+      node->proxy()->AsVariable(), node->proxy()->name());
+  } else {
+    // function declarations
+    PrintIndented("FUNCTION ");
+    PrintLiteral(node->proxy()->name(), true);
+    Print(" = function ");
+    PrintLiteral(node->fun()->name(), false);
+    Print("\n");
+  }
+}
+
+
+void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) {
+  Visit(node->expression());
+}
+
+
+void AstPrinter::VisitEmptyStatement(EmptyStatement* node) {
+  PrintIndented("EMPTY\n");
+}
+
+
+void AstPrinter::VisitIfStatement(IfStatement* node) {
+  PrintIndentedVisit("IF", node->condition());
+  PrintIndentedVisit("THEN", node->then_statement());
+  if (node->HasElseStatement()) {
+    PrintIndentedVisit("ELSE", node->else_statement());
+  }
+}
+
+
+void AstPrinter::VisitContinueStatement(ContinueStatement* node) {
+  PrintLabelsIndented("CONTINUE", node->target()->labels());
+}
+
+
+void AstPrinter::VisitBreakStatement(BreakStatement* node) {
+  PrintLabelsIndented("BREAK", node->target()->labels());
+}
+
+
+void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
+  PrintIndentedVisit("RETURN", node->expression());
+}
+
+
+void AstPrinter::VisitWithEnterStatement(WithEnterStatement* node) {
+  PrintIndentedVisit("WITH ENTER", node->expression());
+}
+
+
+void AstPrinter::VisitWithExitStatement(WithExitStatement* node) {
+  PrintIndented("WITH EXIT\n");
+}
+
+
+void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
+  IndentedScope indent("SWITCH");
+  PrintLabelsIndented(NULL, node->labels());
+  PrintIndentedVisit("TAG", node->tag());
+  for (int i = 0; i < node->cases()->length(); i++) {
+    PrintCaseClause(node->cases()->at(i));
+  }
+}
+
+
+void AstPrinter::VisitLoopStatement(LoopStatement* node) {
+  IndentedScope indent(node->OperatorString());
+  PrintLabelsIndented(NULL, node->labels());
+  if (node->init()) PrintIndentedVisit("INIT", node->init());
+  if (node->cond()) PrintIndentedVisit("COND", node->cond());
+  if (node->body()) PrintIndentedVisit("BODY", node->body());
+  if (node->next()) PrintIndentedVisit("NEXT", node->next());
+}
+
+
+void AstPrinter::VisitForInStatement(ForInStatement* node) {
+  IndentedScope indent("FOR IN");
+  PrintIndentedVisit("FOR", node->each());
+  PrintIndentedVisit("IN", node->enumerable());
+  PrintIndentedVisit("BODY", node->body());
+}
+
+
+void AstPrinter::VisitTryCatch(TryCatch* node) {
+  IndentedScope indent("TRY CATCH");
+  PrintIndentedVisit("TRY", node->try_block());
+  PrintIndentedVisit("CATCHVAR", node->catch_var());
+  PrintIndentedVisit("CATCH", node->catch_block());
+}
+
+
+void AstPrinter::VisitTryFinally(TryFinally* node) {
+  IndentedScope indent("TRY FINALLY");
+  PrintIndentedVisit("TRY", node->try_block());
+  PrintIndentedVisit("FINALLY", node->finally_block());
+}
+
+
+void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
+  IndentedScope indent("DEBUGGER");
+}
+
+
+void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
+  IndentedScope indent("FUNC LITERAL");
+  PrintLiteralIndented("NAME", node->name(), false);
+  PrintParameters(node->scope());
+  // We don't want to see the function literal in this case: it
+  // will be printed via PrintProgram when the code for it is
+  // generated.
+  // PrintStatements(node->body());
+}
+
+
+void AstPrinter::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* node) {
+  IndentedScope indent("FUNC LITERAL");
+  PrintLiteralIndented("BOILERPLATE", node->boilerplate(), true);
+}
+
+
+void AstPrinter::VisitConditional(Conditional* node) {
+  IndentedScope indent("CONDITIONAL");
+  PrintIndentedVisit("?", node->condition());
+  PrintIndentedVisit("THEN", node->then_expression());
+  PrintIndentedVisit("ELSE", node->else_expression());
+}
+
+
+void AstPrinter::VisitLiteral(Literal* node) {
+  PrintLiteralIndented("LITERAL", node->handle(), true);
+}
+
+
+void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
+  IndentedScope indent("REGEXP LITERAL");
+  PrintLiteral(node->pattern(), false);
+  Print(",");
+  PrintLiteral(node->flags(), false);
+}
+
+
+void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
+  IndentedScope indent("OBJ LITERAL");
+  for (int i = 0; i < node->properties()->length(); i++) {
+    const char* prop_kind = NULL;
+    switch (node->properties()->at(i)->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+        prop_kind = "PROPERTY - CONSTANT";
+        break;
+      case ObjectLiteral::Property::COMPUTED:
+        prop_kind = "PROPERTY - COMPUTED";
+        break;
+      case ObjectLiteral::Property::PROTOTYPE:
+        prop_kind = "PROPERTY - PROTOTYPE";
+        break;
+      case ObjectLiteral::Property::GETTER:
+        prop_kind = "PROPERTY - GETTER";
+        break;
+      case ObjectLiteral::Property::SETTER:
+        prop_kind = "PROPERTY - SETTER";
+        break;
+      default:
+        UNREACHABLE();
+        break;
+    }
+    IndentedScope prop(prop_kind);
+    PrintIndentedVisit("KEY", node->properties()->at(i)->key());
+    PrintIndentedVisit("VALUE", node->properties()->at(i)->value());
+  }
+}
+
+
+void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
+  IndentedScope indent("ARRAY LITERAL");
+  if (node->values()->length() > 0) {
+    IndentedScope indent("VALUES");
+    for (int i = 0; i < node->values()->length(); i++) {
+      Visit(node->values()->at(i));
+    }
+  }
+}
+
+
+void AstPrinter::VisitSlot(Slot* node) {
+  PrintIndented("SLOT ");
+  switch (node->type()) {
+    case Slot::PARAMETER:
+      Print("parameter[%d]", node->index());
+      break;
+    case Slot::LOCAL:
+      Print("frame[%d]", node->index());
+      break;
+    case Slot::CONTEXT:
+      Print(".context[%d]", node->index());
+      break;
+    case Slot::LOOKUP:
+      Print(".context[");
+      PrintLiteral(node->var()->name(), false);
+      Print("]");
+      break;
+    default:
+      UNREACHABLE();
+  }
+  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;
+    Visit(var->rewrite());
+  }
+}
+
+
+void AstPrinter::VisitAssignment(Assignment* node) {
+  IndentedScope indent(Token::Name(node->op()));
+  Visit(node->target());
+  Visit(node->value());
+}
+
+
+void AstPrinter::VisitThrow(Throw* node) {
+  PrintIndentedVisit("THROW", node->exception());
+}
+
+
+void AstPrinter::VisitProperty(Property* node) {
+  IndentedScope indent("PROPERTY");
+  Visit(node->obj());
+  Literal* literal = node->key()->AsLiteral();
+  if (literal != NULL && literal->handle()->IsSymbol()) {
+    PrintLiteralIndented("LITERAL", literal->handle(), false);
+  } else {
+    PrintIndentedVisit("KEY", node->key());
+  }
+}
+
+
+void AstPrinter::VisitCall(Call* node) {
+  IndentedScope indent("CALL");
+  Visit(node->expression());
+  PrintArguments(node->arguments());
+}
+
+
+void AstPrinter::VisitCallNew(CallNew* node) {
+  IndentedScope indent("CALL NEW");
+  Visit(node->expression());
+  PrintArguments(node->arguments());
+}
+
+
+void AstPrinter::VisitCallRuntime(CallRuntime* node) {
+  PrintLiteralIndented("CALL RUNTIME ", node->name(), false);
+  IndentedScope indent;
+  PrintArguments(node->arguments());
+}
+
+
+void AstPrinter::VisitUnaryOperation(UnaryOperation* node) {
+  PrintIndentedVisit(Token::Name(node->op()), node->expression());
+}
+
+
+void AstPrinter::VisitCountOperation(CountOperation* node) {
+  EmbeddedVector<char, 128> buf;
+  OS::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
+               Token::Name(node->op()));
+  PrintIndentedVisit(buf.start(), node->expression());
+}
+
+
+void AstPrinter::VisitBinaryOperation(BinaryOperation* node) {
+  IndentedScope indent(Token::Name(node->op()));
+  Visit(node->left());
+  Visit(node->right());
+}
+
+
+void AstPrinter::VisitCompareOperation(CompareOperation* node) {
+  IndentedScope indent(Token::Name(node->op()));
+  Visit(node->left());
+  Visit(node->right());
+}
+
+
+void AstPrinter::VisitThisFunction(ThisFunction* node) {
+  IndentedScope indent("THIS-FUNCTION");
+}
+
+
+
+#endif  // DEBUG
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/prettyprinter.h b/regexp2000/src/prettyprinter.h
new file mode 100644 (file)
index 0000000..e10b357
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PRETTYPRINTER_H_
+#define V8_PRETTYPRINTER_H_
+
+#include "ast.h"
+
+namespace v8 { namespace internal {
+
+#ifdef DEBUG
+
+class PrettyPrinter: public Visitor {
+ public:
+  PrettyPrinter();
+  virtual ~PrettyPrinter();
+
+  // The following routines print a node into a string.
+  // The result string is alive as long as the PrettyPrinter is alive.
+  const char* Print(Node* node);
+  const char* PrintExpression(FunctionLiteral* program);
+  const char* PrintProgram(FunctionLiteral* program);
+
+  // Print a node to stdout.
+  static void PrintOut(Node* node);
+
+  // Individual nodes
+#define DEF_VISIT(type)                         \
+  virtual void Visit##type(type* node);
+  NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+ private:
+  char* output_;  // output string buffer
+  int size_;  // output_ size
+  int pos_;  // current printing position
+
+ protected:
+  void Init();
+  void Print(const char* format, ...);
+  const char* Output() const { return output_; }
+
+  virtual void PrintStatements(ZoneList<Statement*>* statements);
+  void PrintLabels(ZoneStringList* labels);
+  virtual void PrintArguments(ZoneList<Expression*>* arguments);
+  void PrintLiteral(Handle<Object> value, bool quote);
+  void PrintParameters(Scope* scope);
+  void PrintDeclarations(ZoneList<Declaration*>* declarations);
+  void PrintFunctionLiteral(FunctionLiteral* function);
+  void PrintCaseClause(CaseClause* clause);
+};
+
+
+// Prints the AST structure
+class AstPrinter: public PrettyPrinter {
+ public:
+  AstPrinter();
+  virtual ~AstPrinter();
+
+  const char* PrintProgram(FunctionLiteral* program);
+
+  // Individual nodes
+#define DEF_VISIT(type)                         \
+  virtual void Visit##type(type* node);
+  NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+ private:
+  friend class IndentedScope;
+  void PrintIndented(const char* txt);
+  void PrintIndentedVisit(const char* s, Node* node);
+
+  void PrintStatements(ZoneList<Statement*>* statements);
+  void PrintDeclarations(ZoneList<Declaration*>* declarations);
+  void PrintParameters(Scope* scope);
+  void PrintArguments(ZoneList<Expression*>* arguments);
+  void PrintCaseClause(CaseClause* clause);
+  void PrintLiteralIndented(const char* info, Handle<Object> value, bool quote);
+  void PrintLiteralWithModeIndented(const char* info,
+                                    Variable* var,
+                                    Handle<Object> value);
+  void PrintLabelsIndented(const char* info, ZoneStringList* labels);
+
+  void inc_indent() { indent_++; }
+  void dec_indent() { indent_--; }
+
+  static int indent_;
+};
+
+#endif  // DEBUG
+
+} }  // namespace v8::internal
+
+#endif  // V8_PRETTYPRINTER_H_
diff --git a/regexp2000/src/property.cc b/regexp2000/src/property.cc
new file mode 100644 (file)
index 0000000..6c21530
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+namespace v8 { namespace internal {
+
+
+void DescriptorWriter::Write(Descriptor* desc) {
+  ASSERT(desc->key_->IsSymbol());
+  descriptors_->Set(pos_, desc);
+  advance();
+}
+
+
+void DescriptorWriter::WriteFrom(DescriptorReader* reader) {
+  Descriptor desc;
+  reader->Get(&desc);
+  Write(&desc);
+}
+
+
+#ifdef DEBUG
+void LookupResult::Print() {
+  if (!IsValid()) {
+    PrintF("Not Found\n");
+    return;
+  }
+
+  PrintF("LookupResult:\n");
+  PrintF(" -cacheable = %s\n", IsCacheable() ? "true" : "false");
+  PrintF(" -attributes = %x\n", GetAttributes());
+  switch (type()) {
+    case NORMAL:
+      PrintF(" -type = normal\n");
+      PrintF(" -entry = %d", GetDictionaryEntry());
+      break;
+    case MAP_TRANSITION:
+      PrintF(" -type = map transition\n");
+      PrintF(" -map:\n");
+      GetTransitionMap()->Print();
+      PrintF("\n");
+      break;
+    case CONSTANT_FUNCTION:
+      PrintF(" -type = constant function\n");
+      PrintF(" -function:\n");
+      GetConstantFunction()->Print();
+      PrintF("\n");
+      break;
+    case FIELD:
+      PrintF(" -type = field\n");
+      PrintF(" -index = %d", GetFieldIndex());
+      PrintF("\n");
+      break;
+    case CALLBACKS:
+      PrintF(" -type = call backs\n");
+      PrintF(" -callback object:\n");
+      GetCallbackObject()->Print();
+      break;
+    case INTERCEPTOR:
+      PrintF(" -type = lookup interceptor\n");
+      break;
+    case CONSTANT_TRANSITION:
+      PrintF(" -type = constant property transition\n");
+      break;
+    case NULL_DESCRIPTOR:
+      PrintF(" =type = null descriptor\n");
+      break;
+  }
+}
+
+
+void Descriptor::Print() {
+  PrintF("Descriptor ");
+  GetKey()->ShortPrint();
+  PrintF(" @ ");
+  GetValue()->ShortPrint();
+  PrintF(" %d\n", GetDetails().index());
+}
+
+
+#endif
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/property.h b/regexp2000/src/property.h
new file mode 100644 (file)
index 0000000..1c9b0d2
--- /dev/null
@@ -0,0 +1,389 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PROPERTY_H_
+#define V8_PROPERTY_H_
+
+namespace v8 { namespace internal {
+
+
+// Abstraction for elements in instance-descriptor arrays.
+//
+// Each descriptor has a key, property attributes, property type,
+// property index (in the actual instance-descriptor array) and
+// optionally a piece of data.
+//
+
+class Descriptor BASE_EMBEDDED {
+ public:
+  static int IndexFromValue(Object* value) {
+    return Smi::cast(value)->value();
+  }
+
+  Object* KeyToSymbol() {
+    if (!key_->IsSymbol()) {
+      Object* result = Heap::LookupSymbol(key_);
+      if (result->IsFailure()) return result;
+      key_ = String::cast(result);
+    }
+    return key_;
+  }
+
+  String* GetKey() { return key_; }
+  Object* GetValue() { return value_; }
+  PropertyDetails GetDetails() { return details_; }
+
+#ifdef DEBUG
+  void Print();
+#endif
+
+  void SetEnumerationIndex(int index) {
+    ASSERT(PropertyDetails::IsValidIndex(index));
+    details_ = PropertyDetails(details_.attributes(), details_.type(), index);
+  }
+
+ private:
+  String* key_;
+  Object* value_;
+  PropertyDetails details_;
+
+ protected:
+  Descriptor() : details_(Smi::FromInt(0)) {}
+
+  void Init(String* key, Object* value, PropertyDetails details) {
+    key_ = key;
+    value_ = value;
+    details_ = details;
+  }
+
+  Descriptor(String* key, Object* value, PropertyDetails details)
+      : key_(key),
+        value_(value),
+        details_(details) { }
+
+  Descriptor(String* key,
+             Object* value,
+             PropertyAttributes attributes,
+             PropertyType type,
+             int index = 0)
+      : key_(key),
+        value_(value),
+        details_(attributes, type, index) { }
+
+  friend class DescriptorWriter;
+  friend class DescriptorReader;
+  friend class DescriptorArray;
+};
+
+
+class MapTransitionDescriptor: public Descriptor {
+ public:
+  MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
+      : Descriptor(key, map, attributes, MAP_TRANSITION) { }
+};
+
+// Marks a field name in a map so that adding the field is guaranteed
+// to create a FIELD descriptor in the new map.  Used after adding
+// a constant function the first time, creating a CONSTANT_FUNCTION
+// descriptor in the new map.  This avoids creating multiple maps with
+// the same CONSTANT_FUNCTION field.
+class ConstTransitionDescriptor: public Descriptor {
+ public:
+  explicit ConstTransitionDescriptor(String* key)
+      : Descriptor(key, Smi::FromInt(0), NONE, CONSTANT_TRANSITION) { }
+};
+
+
+class FieldDescriptor: public Descriptor {
+ public:
+  FieldDescriptor(String* key,
+                  int field_index,
+                  PropertyAttributes attributes,
+                  int index = 0)
+      : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {}
+};
+
+
+class ConstantFunctionDescriptor: public Descriptor {
+ public:
+  ConstantFunctionDescriptor(String* key,
+                             JSFunction* function,
+                             PropertyAttributes attributes,
+                             int index = 0)
+      : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
+};
+
+
+class CallbacksDescriptor:  public Descriptor {
+ public:
+  CallbacksDescriptor(String* key,
+                      Object* proxy,
+                      PropertyAttributes attributes,
+                      int index = 0)
+      : Descriptor(key, proxy, attributes, CALLBACKS, index) {}
+};
+
+
+class LookupResult BASE_EMBEDDED {
+ public:
+  // Where did we find the result;
+  enum {
+    NOT_FOUND,
+    DESCRIPTOR_TYPE,
+    DICTIONARY_TYPE,
+    INTERCEPTOR_TYPE,
+    CONSTANT_TYPE
+  } lookup_type_;
+
+  LookupResult()
+      : lookup_type_(NOT_FOUND),
+        cacheable_(true),
+        details_(NONE, NORMAL) {}
+
+  void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
+    lookup_type_ = DESCRIPTOR_TYPE;
+    holder_ = holder;
+    details_ = details;
+    number_ = number;
+  }
+
+  void ConstantResult(JSObject* holder) {
+    lookup_type_ = CONSTANT_TYPE;
+    holder_ = holder;
+    details_ =
+        PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM |
+                                                        DONT_DELETE),
+                        CALLBACKS);
+    number_ = -1;
+  }
+
+  void DictionaryResult(JSObject* holder, int entry) {
+    lookup_type_ = DICTIONARY_TYPE;
+    holder_ = holder;
+    details_ = holder->property_dictionary()->DetailsAt(entry);
+    number_ = entry;
+  }
+
+  void InterceptorResult(JSObject* holder) {
+    lookup_type_ = INTERCEPTOR_TYPE;
+    holder_ = holder;
+    details_ = PropertyDetails(NONE, INTERCEPTOR);
+  }
+
+  void NotFound() {
+    lookup_type_ = NOT_FOUND;
+  }
+
+  JSObject* holder() {
+    ASSERT(IsValid());
+    return holder_;
+  }
+
+  PropertyType type() {
+    ASSERT(IsValid());
+    return details_.type();
+  }
+
+  bool IsTransitionType() {
+    PropertyType t = type();
+    if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true;
+    return false;
+  }
+
+  PropertyAttributes GetAttributes() {
+    ASSERT(IsValid());
+    return details_.attributes();
+  }
+
+  PropertyDetails GetPropertyDetails() {
+    return details_;
+  }
+
+  bool IsReadOnly() { return details_.IsReadOnly(); }
+  bool IsDontDelete() { return details_.IsDontDelete(); }
+  bool IsDontEnum() { return details_.IsDontEnum(); }
+
+  bool IsValid() { return  lookup_type_ != NOT_FOUND; }
+  bool IsNotFound() { return lookup_type_ == NOT_FOUND; }
+
+  // Tells whether the result is a property.
+  // Excluding transitions and the null descriptor.
+  bool IsProperty() {
+    return IsValid() && type() < FIRST_PHANTOM_PROPERTY_TYPE;
+  }
+
+  bool IsCacheable() { return cacheable_; }
+  void DisallowCaching() { cacheable_ = false; }
+
+  // Tells whether the value needs to be loaded.
+  bool IsLoaded() {
+    if (lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE) {
+      Object* value = GetValue();
+      if (value->IsJSFunction()) {
+        return JSFunction::cast(value)->IsLoaded();
+      }
+    }
+    return true;
+  }
+
+  Map* GetTransitionMap() {
+    ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
+    ASSERT(type() == MAP_TRANSITION);
+    return Map::cast(GetValue());
+  }
+
+  int GetFieldIndex() {
+    ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
+    ASSERT(type() == FIELD);
+    return Descriptor::IndexFromValue(GetValue());
+  }
+
+  int GetDictionaryEntry() {
+    ASSERT(lookup_type_ == DICTIONARY_TYPE);
+    return number_;
+  }
+
+  JSFunction* GetConstantFunction() {
+    ASSERT(type() == CONSTANT_FUNCTION);
+    return JSFunction::cast(GetValue());
+  }
+
+  Object* GetCallbackObject() {
+    if (lookup_type_ == CONSTANT_TYPE) {
+      // For now we only have the __proto__ as constant type.
+      return Heap::prototype_accessors();
+    }
+    return GetValue();
+  }
+
+#ifdef DEBUG
+  void Print();
+#endif
+
+  Object* GetValue() {
+    if (lookup_type_ == DESCRIPTOR_TYPE) {
+      DescriptorArray* descriptors = holder()->map()->instance_descriptors();
+      return descriptors->GetValue(number_);
+    }
+    // In the dictionary case, the data is held in the value field.
+    ASSERT(lookup_type_ == DICTIONARY_TYPE);
+    return holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
+  }
+
+ private:
+  JSObject* holder_;
+  int number_;
+  bool cacheable_;
+  PropertyDetails details_;
+};
+
+
+// The DescriptorStream is an abstraction for iterating over a map's
+// instance descriptors.
+class DescriptorStream BASE_EMBEDDED {
+ public:
+  explicit DescriptorStream(DescriptorArray* descriptors, int pos) {
+    descriptors_ = descriptors;
+    pos_ = pos;
+    limit_ = descriptors_->number_of_descriptors();
+  }
+
+  // Tells whether we have reached the end of the steam.
+  bool eos() { return pos_ >= limit_; }
+
+  int next_position() { return pos_ + 1; }
+  void advance() { pos_ = next_position(); }
+
+ protected:
+  DescriptorArray* descriptors_;
+  int pos_;   // Current position.
+  int limit_;  // Limit for posistion.
+};
+
+
+class DescriptorReader: public DescriptorStream {
+ public:
+  explicit DescriptorReader(DescriptorArray* descriptors, int pos = 0)
+      : DescriptorStream(descriptors, pos) {}
+
+  String* GetKey() { return descriptors_->GetKey(pos_); }
+  Object* GetValue() { return descriptors_->GetValue(pos_); }
+  PropertyDetails GetDetails() {
+    return PropertyDetails(descriptors_->GetDetails(pos_));
+  }
+
+  int GetFieldIndex() { return Descriptor::IndexFromValue(GetValue()); }
+
+  bool IsDontEnum() { return GetDetails().IsDontEnum(); }
+
+  PropertyType type() { return GetDetails().type(); }
+
+  // Tells whether the type is a transition.
+  bool IsTransition() {
+    PropertyType t = type();
+    ASSERT(t != INTERCEPTOR);
+    return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
+  }
+
+  bool IsNullDescriptor() {
+    return type() == NULL_DESCRIPTOR;
+  }
+
+  JSFunction* GetConstantFunction() { return JSFunction::cast(GetValue()); }
+
+  AccessorDescriptor* GetCallbacks() {
+    ASSERT(type() == CALLBACKS);
+    Proxy* p = Proxy::cast(GetCallbacksObject());
+    return reinterpret_cast<AccessorDescriptor*>(p->proxy());
+  }
+
+  Object* GetCallbacksObject() {
+    ASSERT(type() == CALLBACKS);
+    return GetValue();
+  }
+
+  bool Equals(String* name) { return name->Equals(GetKey()); }
+
+  void Get(Descriptor* desc) {
+    descriptors_->Get(pos_, desc);
+  }
+};
+
+class DescriptorWriter: public DescriptorStream {
+ public:
+  explicit DescriptorWriter(DescriptorArray* descriptors)
+      : DescriptorStream(descriptors, 0) {}
+
+  // Append a descriptor to this stream.
+  void Write(Descriptor* desc);
+  // Read a descriptor from the reader and append it to this stream.
+  void WriteFrom(DescriptorReader* reader);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_PROPERTY_H_
diff --git a/regexp2000/src/regexp-delay.js b/regexp2000/src/regexp-delay.js
new file mode 100644 (file)
index 0000000..e15240a
--- /dev/null
@@ -0,0 +1,373 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Expect $Object = global.Object;
+// Expect $Array = global.Array;
+
+const $RegExp = global.RegExp;
+
+// A recursive descent parser for Patterns according to the grammar of
+// ECMA-262 15.10.1, with deviations noted below.
+function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
+  // RegExp : Called as constructor; see ECMA-262, section 15.10.4.
+  if (IS_REGEXP(pattern)) {
+    if (!IS_UNDEFINED(flags)) {
+      throw MakeTypeError('regexp_flags', []);
+    }
+    flags = (pattern.global ? 'g' : '')
+        + (pattern.ignoreCase ? 'i' : '')
+        + (pattern.multiline ? 'm' : '');
+    pattern = pattern.source;
+  }
+
+  pattern = IS_UNDEFINED(pattern) ? '' : ToString(pattern);
+  flags = IS_UNDEFINED(flags) ? '' : ToString(flags);
+
+  var global = false;
+  var ignoreCase = false;
+  var multiline = false;
+
+  for (var i = 0; i < flags.length; i++) {
+    var c = flags.charAt(i);
+    switch (c) {
+      case 'g':
+        if (global) throw MakeSyntaxError('duplicate_regexp_flag', ['g']);
+        global = true;
+        break;
+      case 'i':
+        if (ignoreCase) throw MakeSyntaxError('duplicate_regexp_flag', ['i']);
+        ignoreCase = true;
+        break;
+      case 'm':
+        if (multiline) throw MakeSyntaxError('duplicate_regexp_flag', ['m']);
+        multiline = true;
+        break;
+      default:
+        // Ignore flags that have no meaning to be consistent with
+        // KJS.
+        break;
+    }
+  }
+
+  if (isConstructorCall) {
+    // ECMA-262, section 15.10.7.1.
+    %SetProperty(object, 'source', pattern,
+                 DONT_DELETE |  READ_ONLY | DONT_ENUM);
+
+    // ECMA-262, section 15.10.7.2.
+    %SetProperty(object, 'global', global, DONT_DELETE | READ_ONLY | DONT_ENUM);
+
+    // ECMA-262, section 15.10.7.3.
+    %SetProperty(object, 'ignoreCase', ignoreCase,
+                 DONT_DELETE | READ_ONLY | DONT_ENUM);
+
+    // ECMA-262, section 15.10.7.4.
+    %SetProperty(object, 'multiline', multiline,
+                 DONT_DELETE | READ_ONLY | DONT_ENUM);
+
+    // ECMA-262, section 15.10.7.5.
+    %SetProperty(object, 'lastIndex', 0, DONT_DELETE | DONT_ENUM);
+  } else { // RegExp is being recompiled via RegExp.prototype.compile.
+    %IgnoreAttributesAndSetProperty(object, 'source', pattern);
+    %IgnoreAttributesAndSetProperty(object, 'global', global);
+    %IgnoreAttributesAndSetProperty(object, 'ignoreCase', ignoreCase);
+    %IgnoreAttributesAndSetProperty(object, 'multiline', multiline);
+    %IgnoreAttributesAndSetProperty(object, 'lastIndex', 0);
+  }
+
+  // Call internal function to compile the pattern.
+  %RegExpCompile(object, pattern, flags);
+}
+
+
+function RegExpConstructor(pattern, flags) {
+  if (%IsConstructCall()) {
+    DoConstructRegExp(this, pattern, flags, true);
+  } else {
+    // RegExp : Called as function; see ECMA-262, section 15.10.3.1.
+    if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) {
+      return pattern;
+    }
+    return new $RegExp(pattern, flags);
+  }
+}
+
+
+// Deprecated RegExp.prototype.compile method.  We behave like the constructor
+// were called again.  In SpiderMonkey, this method returns the regexp object.
+// In KJS, it returns undefined.  For compatibility with KJS, we match their
+// behavior.
+function CompileRegExp(pattern, flags) {
+  // Both KJS and SpiderMonkey treat a missing pattern argument as the
+  // empty subject string, and an actual undefined value passed as the
+  // patter as the string 'undefined'.  Note that KJS is inconsistent
+  // here, treating undefined values differently in
+  // RegExp.prototype.compile and in the constructor, where they are
+  // the empty string.  For compatibility with KJS, we match their
+  // behavior.
+  if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
+    DoConstructRegExp(this, 'undefined', flags, false);
+  } else {
+    DoConstructRegExp(this, pattern, flags, false);
+  }
+}
+
+
+// DoRegExpExec and DoRegExpExecGlobal are wrappers around the runtime
+// %RegExp and %RegExpGlobal functions that ensure that the static
+// properties of the RegExp constructor are set.
+function DoRegExpExec(regexp, string, index) {
+  var matchIndices = %RegExpExec(regexp, string, index);
+  if (!IS_NULL(matchIndices)) {
+    regExpCaptures = matchIndices;
+    regExpSubject = regExpInput = string;
+  }
+  return matchIndices;
+}
+
+
+function DoRegExpExecGlobal(regexp, string) {
+  // Here, matchIndices is an array of arrays of substring indices.
+  var matchIndices = %RegExpExecGlobal(regexp, string);
+  if (matchIndices.length != 0) {
+    regExpCaptures = matchIndices[matchIndices.length - 1];
+    regExpSubject = regExpInput = string;
+  }
+  return matchIndices;
+}
+
+
+function RegExpExec(string) {
+  if (%_ArgumentsLength() == 0) {
+    string = regExpInput;
+  }
+  var s = ToString(string);
+  var length = s.length;
+  var lastIndex = this.lastIndex;
+  var i = this.global ? TO_INTEGER(lastIndex) : 0;
+
+  if (i < 0 || i > s.length) {
+    this.lastIndex = 0;
+    return null;
+  }
+
+  // matchIndices is an array of integers with length of captures*2,
+  // each pair of integers specified the start and the end of index
+  // in the string.
+  var matchIndices = DoRegExpExec(this, s, i);
+
+  if (matchIndices == null) {
+    if (this.global) this.lastIndex = 0;
+    return matchIndices; // no match
+  }
+
+  var numResults = matchIndices.length >> 1;
+  var result = new $Array(numResults);
+  for (var i = 0; i < numResults; i++) {
+    var matchStart = matchIndices[2*i];
+    var matchEnd = matchIndices[2*i + 1];
+    if (matchStart != -1 && matchEnd != -1) {
+      result[i] = s.slice(matchStart, matchEnd);
+    } else {
+      // Make sure the element is present. Avoid reading the undefined
+      // property from the global object since this may change.
+      result[i] = void 0;
+    }
+  }
+
+  if (this.global)
+    this.lastIndex = matchIndices[1];
+  result.index = matchIndices[0];
+  result.input = s;
+  return result;
+}
+
+
+function RegExpTest(string) {
+  var result = (%_ArgumentsLength() == 0) ? this.exec() : this.exec(string);
+  return result != null;
+}
+
+
+function RegExpToString() {
+  // If this.source is an empty string, output /(?:)/.
+  // http://bugzilla.mozilla.org/show_bug.cgi?id=225550
+  // ecma_2/RegExp/properties-001.js.
+  var src = this.source ? this.source : '(?:)';
+  var result = '/' + src + '/';
+  if (this.global)
+    result += 'g';
+  if (this.ignoreCase)
+    result += 'i';
+  if (this.multiline)
+    result += 'm';
+  return result;
+}
+
+
+// Getters for the static properties lastMatch, lastParen, leftContext, and
+// rightContext of the RegExp constructor.  The properties are computed based
+// on the captures array of the last successful match and the subject string
+// of the last successful match.
+function RegExpGetLastMatch() {
+  return regExpSubject.slice(regExpCaptures[0], regExpCaptures[1]);
+}
+
+
+function RegExpGetLastParen() {
+  var length = regExpCaptures.length;
+  if (length <= 2) return ''; // There were no captures.
+  // We match the SpiderMonkey behavior: return the substring defined by the
+  // last pair (after the first pair) of elements of the capture array even if
+  // it is empty.
+  return regExpSubject.slice(regExpCaptures[length - 2],
+                             regExpCaptures[length - 1]);
+}
+
+
+function RegExpGetLeftContext() {
+  return regExpSubject.slice(0, regExpCaptures[0]);
+}
+
+
+function RegExpGetRightContext() {
+  return regExpSubject.slice(regExpCaptures[1], regExpSubject.length);
+}
+
+
+// The properties $1..$9 are the first nine capturing substrings of the last
+// successful match, or ''.  The function RegExpMakeCaptureGetter will be
+// called with an index greater than or equal to 1 but it actually works for
+// any non-negative index.
+function RegExpMakeCaptureGetter(n) {
+  return function() {
+    var index = n * 2;
+    if (index >= regExpCaptures.length) return '';
+    var matchStart = regExpCaptures[index];
+    var matchEnd = regExpCaptures[index + 1];
+    if (matchStart == -1 || matchEnd == -1) return '';
+    return regExpSubject.slice(matchStart, matchEnd);
+  };
+}
+
+
+// Properties of the builtins object for recording the result of the last
+// regexp match.  The property regExpCaptures is the matchIndices array of the
+// last successful regexp match (an array of start/end index pairs for the
+// match and all the captured substrings), the invariant is that there is at
+// least two elements.  The property regExpSubject is the subject string for
+// the last successful match.
+var regExpCaptures = [0, 0];
+var regExpSubject = '';
+var regExpInput = "";
+
+// -------------------------------------------------------------------
+
+function SetupRegExp() {
+  %FunctionSetInstanceClassName($RegExp, 'RegExp');
+  %FunctionSetPrototype($RegExp, new $Object());
+  %SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
+  %SetCode($RegExp, RegExpConstructor);
+
+  InstallFunctions($RegExp.prototype, DONT_ENUM, $Array(
+    "exec", RegExpExec,
+    "test", RegExpTest,
+    "toString", RegExpToString,
+    "compile", CompileRegExp
+  ));
+
+  // The spec says nothing about the length of exec and test, but
+  // SpiderMonkey and KJS have length equal to 0.
+  %FunctionSetLength($RegExp.prototype.exec, 0);
+  %FunctionSetLength($RegExp.prototype.test, 0);
+  // The length of compile is 1 in SpiderMonkey.
+  %FunctionSetLength($RegExp.prototype.compile, 1);
+
+  // The properties input, $input, and $_ are aliases for each other.  When this
+  // value is set in SpiderMonkey, the value it is set to is coerced to a
+  // string.  We mimic that behavior with a slight difference: in SpiderMonkey
+  // the value of the expression 'RegExp.input = null' (for instance) is the
+  // string "null" (ie, the value after coercion), while in V8 it is the value
+  // null (ie, the value before coercion).
+  // Getter and setter for the input.
+  function RegExpGetInput() { return regExpInput; }
+  function RegExpSetInput(string) { regExpInput = ToString(string); }
+
+  %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
+  %DefineAccessor($RegExp, 'input', SETTER, RegExpSetInput, DONT_DELETE);
+  %DefineAccessor($RegExp, '$_', GETTER, RegExpGetInput, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, '$_', SETTER, RegExpSetInput, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, '$input', GETTER, RegExpGetInput, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, '$input', SETTER, RegExpSetInput, DONT_ENUM | DONT_DELETE);
+
+  // The properties multiline and $* are aliases for each other.  When this
+  // value is set in SpiderMonkey, the value it is set to is coerced to a
+  // boolean.  We mimic that behavior with a slight difference: in SpiderMonkey
+  // the value of the expression 'RegExp.multiline = null' (for instance) is the
+  // boolean false (ie, the value after coercion), while in V8 it is the value
+  // null (ie, the value before coercion).
+
+  // Getter and setter for multiline.
+  var multiline = false;
+  function RegExpGetMultiline() { return multiline; };
+  function RegExpSetMultiline(flag) { multiline = flag ? true : false; };
+
+  %DefineAccessor($RegExp, 'multiline', GETTER, RegExpGetMultiline, DONT_DELETE);
+  %DefineAccessor($RegExp, 'multiline', SETTER, RegExpSetMultiline, DONT_DELETE);
+  %DefineAccessor($RegExp, '$*', GETTER, RegExpGetMultiline, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, '$*', SETTER, RegExpSetMultiline, DONT_ENUM | DONT_DELETE);
+
+
+  function NoOpSetter(ignored) {}
+
+
+  // Static properties set by a successful match.
+  %DefineAccessor($RegExp, 'lastMatch', GETTER, RegExpGetLastMatch, DONT_DELETE);
+  %DefineAccessor($RegExp, 'lastMatch', SETTER, NoOpSetter, DONT_DELETE);
+  %DefineAccessor($RegExp, '$&', GETTER, RegExpGetLastMatch, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, '$&', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, 'lastParen', GETTER, RegExpGetLastParen, DONT_DELETE);
+  %DefineAccessor($RegExp, 'lastParen', SETTER, NoOpSetter, DONT_DELETE);
+  %DefineAccessor($RegExp, '$+', GETTER, RegExpGetLastParen, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, '$+', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, 'leftContext', GETTER, RegExpGetLeftContext, DONT_DELETE);
+  %DefineAccessor($RegExp, 'leftContext', SETTER, NoOpSetter, DONT_DELETE);
+  %DefineAccessor($RegExp, '$`', GETTER, RegExpGetLeftContext, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, '$`', SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, 'rightContext', GETTER, RegExpGetRightContext, DONT_DELETE);
+  %DefineAccessor($RegExp, 'rightContext', SETTER, NoOpSetter, DONT_DELETE);
+  %DefineAccessor($RegExp, "$'", GETTER, RegExpGetRightContext, DONT_ENUM | DONT_DELETE);
+  %DefineAccessor($RegExp, "$'", SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
+
+  for (var i = 1; i < 10; ++i) {
+    %DefineAccessor($RegExp, '$' + i, GETTER, RegExpMakeCaptureGetter(i), DONT_DELETE);
+    %DefineAccessor($RegExp, '$' + i, SETTER, NoOpSetter, DONT_DELETE);
+  }
+}
+
+
+SetupRegExp();
diff --git a/regexp2000/src/rewriter.cc b/regexp2000/src/rewriter.cc
new file mode 100644 (file)
index 0000000..ebbc383
--- /dev/null
@@ -0,0 +1,329 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+#include "scopes.h"
+#include "rewriter.h"
+
+namespace v8 { namespace internal {
+
+
+class Processor: public Visitor {
+ public:
+  explicit Processor(VariableProxy* result)
+      : result_(result),
+        result_assigned_(false),
+        is_set_(false),
+        in_try_(false) {
+  }
+
+  void Process(ZoneList<Statement*>* statements);
+  bool result_assigned() const  { return result_assigned_; }
+
+ private:
+  VariableProxy* result_;
+
+  // We are not tracking result usage via the result_'s use
+  // counts (we leave the accurate computation to the
+  // usage analyzer). Instead we simple remember if
+  // there was ever an assignment to result_.
+  bool result_assigned_;
+
+  // To avoid storing to .result all the time, we eliminate some of
+  // the stores by keeping track of whether or not we're sure .result
+  // will be overwritten anyway. This is a bit more tricky than what I
+  // was hoping for
+  bool is_set_;
+  bool in_try_;
+
+  Expression* SetResult(Expression* value) {
+    result_assigned_ = true;
+    return new Assignment(Token::ASSIGN, result_, value,
+                          RelocInfo::kNoPosition);
+  }
+
+  // Node visitors.
+#define DEF_VISIT(type) \
+  virtual void Visit##type(type* node);
+  NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+};
+
+
+void Processor::Process(ZoneList<Statement*>* statements) {
+  for (int i = statements->length() - 1; i >= 0; --i) {
+    Visit(statements->at(i));
+  }
+}
+
+
+void Processor::VisitBlock(Block* node) {
+  // An initializer block is the rewritten form of a variable declaration
+  // with initialization expressions. The initializer block contains the
+  // list of assignments corresponding to the initialization expressions.
+  // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
+  // a variable declaration with initialization expression is 'undefined'
+  // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
+  // returns 'undefined'. To obtain the same behavior with v8, we need
+  // to prevent rewriting in that case.
+  if (!node->is_initializer_block()) Process(node->statements());
+}
+
+
+void Processor::VisitExpressionStatement(ExpressionStatement* node) {
+  // Rewrite : <x>; -> .result = <x>;
+  if (!is_set_) {
+    node->set_expression(SetResult(node->expression()));
+    if (!in_try_) is_set_ = true;
+  }
+}
+
+
+void Processor::VisitIfStatement(IfStatement* node) {
+  // Rewrite both then and else parts (reversed).
+  bool save = is_set_;
+  Visit(node->else_statement());
+  bool set_after_then = is_set_;
+  is_set_ = save;
+  Visit(node->then_statement());
+  is_set_ = is_set_ && set_after_then;
+}
+
+
+
+
+void Processor::VisitLoopStatement(LoopStatement* node) {
+  // Rewrite loop body statement.
+  bool set_after_loop = is_set_;
+  Visit(node->body());
+  is_set_ = is_set_ && set_after_loop;
+}
+
+
+void Processor::VisitForInStatement(ForInStatement* node) {
+  // Rewrite for-in body statement.
+  bool set_after_for = is_set_;
+  Visit(node->body());
+  is_set_ = is_set_ && set_after_for;
+}
+
+
+void Processor::VisitTryCatch(TryCatch* node) {
+  // Rewrite both try and catch blocks (reversed order).
+  bool set_after_catch = is_set_;
+  Visit(node->catch_block());
+  is_set_ = is_set_ && set_after_catch;
+  bool save = in_try_;
+  in_try_ = true;
+  Visit(node->try_block());
+  in_try_ = save;
+}
+
+
+void Processor::VisitTryFinally(TryFinally* node) {
+  // Rewrite both try and finally block (reversed order).
+  Visit(node->finally_block());
+  bool save = in_try_;
+  in_try_ = true;
+  Visit(node->try_block());
+  in_try_ = save;
+}
+
+
+void Processor::VisitSwitchStatement(SwitchStatement* node) {
+  // Rewrite statements in all case clauses in reversed order.
+  ZoneList<CaseClause*>* clauses = node->cases();
+  bool set_after_switch = is_set_;
+  for (int i = clauses->length() - 1; i >= 0; --i) {
+    CaseClause* clause = clauses->at(i);
+    Process(clause->statements());
+  }
+  is_set_ = is_set_ && set_after_switch;
+}
+
+
+void Processor::VisitContinueStatement(ContinueStatement* node) {
+  is_set_ = false;
+}
+
+
+void Processor::VisitBreakStatement(BreakStatement* node) {
+  is_set_ = false;
+}
+
+
+// Do nothing:
+void Processor::VisitDeclaration(Declaration* node) {}
+void Processor::VisitEmptyStatement(EmptyStatement* node) {}
+void Processor::VisitReturnStatement(ReturnStatement* node) {}
+void Processor::VisitWithEnterStatement(WithEnterStatement* node) {}
+void Processor::VisitWithExitStatement(WithExitStatement* node) {}
+void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
+
+
+// Expressions are never visited yet.
+void Processor::VisitFunctionLiteral(FunctionLiteral* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitConditional(Conditional* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitSlot(Slot* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitVariableProxy(VariableProxy* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitLiteral(Literal* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitRegExpLiteral(RegExpLiteral* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitArrayLiteral(ArrayLiteral* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitObjectLiteral(ObjectLiteral* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitAssignment(Assignment* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitThrow(Throw* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitProperty(Property* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitCall(Call* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitCallNew(CallNew* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitCallRuntime(CallRuntime* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitUnaryOperation(UnaryOperation* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitCountOperation(CountOperation* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitBinaryOperation(BinaryOperation* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitCompareOperation(CompareOperation* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitThisFunction(ThisFunction* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+bool Rewriter::Process(FunctionLiteral* function) {
+  Scope* scope = function->scope();
+  if (scope->is_function_scope()) return true;
+
+  ZoneList<Statement*>* body = function->body();
+  if (body->is_empty()) return true;
+
+  VariableProxy* result = scope->NewTemporary(Factory::result_symbol());
+  Processor processor(result);
+  processor.Process(body);
+  if (processor.HasStackOverflow()) return false;
+
+  if (processor.result_assigned()) body->Add(new ReturnStatement(result));
+  return true;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/rewriter.h b/regexp2000/src/rewriter.h
new file mode 100644 (file)
index 0000000..aa1cd2a
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_REWRITER_H_
+#define V8_REWRITER_H_
+
+namespace v8 { namespace internal {
+
+
+// Currently, the rewriter takes function literals (only top-level)
+// and rewrites them to return the value of the last expression in
+// them.
+//
+// The rewriter adds a (hidden) variable, called .result, to the
+// activation, and tries to figure out where it needs to store into
+// this variable. If the variable is ever used, we conclude by adding
+// a return statement that returns the variable to the body of the
+// given function.
+
+class Rewriter {
+ public:
+  static bool Process(FunctionLiteral* function);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_REWRITER_H_
diff --git a/regexp2000/src/runtime.cc b/regexp2000/src/runtime.cc
new file mode 100644 (file)
index 0000000..dcd2b01
--- /dev/null
@@ -0,0 +1,5532 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "accessors.h"
+#include "api.h"
+#include "arguments.h"
+#include "compiler.h"
+#include "cpu.h"
+#include "dateparser.h"
+#include "debug.h"
+#include "execution.h"
+#include "jsregexp.h"
+#include "platform.h"
+#include "runtime.h"
+#include "scopeinfo.h"
+#include "v8threads.h"
+#include "smart-pointer.h"
+
+namespace v8 { namespace internal {
+
+
+#define RUNTIME_ASSERT(value) do {                                   \
+  if (!(value)) return IllegalOperation();                           \
+} while (false)
+
+// Cast the given object to a value of the specified type and store
+// it in a variable with the given name.  If the object is not of the
+// expected type call IllegalOperation and return.
+#define CONVERT_CHECKED(Type, name, obj)                             \
+  RUNTIME_ASSERT(obj->Is##Type());                                   \
+  Type* name = Type::cast(obj);
+
+#define CONVERT_ARG_CHECKED(Type, name, index)                       \
+  RUNTIME_ASSERT(args[index]->Is##Type());                           \
+  Handle<Type> name = args.at<Type>(index);
+
+// Cast the given object to a boolean and store it in a variable with
+// the given name.  If the object is not a boolean call IllegalOperation
+// and return.
+#define CONVERT_BOOLEAN_CHECKED(name, obj)                            \
+  RUNTIME_ASSERT(obj->IsBoolean());                                   \
+  bool name = (obj)->IsTrue();
+
+// Cast the given object to a double and store it in a variable with
+// the given name.  If the object is not a number (as opposed to
+// the number not-a-number) call IllegalOperation and return.
+#define CONVERT_DOUBLE_CHECKED(name, obj)                            \
+  RUNTIME_ASSERT(obj->IsNumber());                                   \
+  double name = (obj)->Number();
+
+// Call the specified converter on the object *comand store the result in
+// a variable of the specified type with the given name.  If the
+// object is not a Number call IllegalOperation and return.
+#define CONVERT_NUMBER_CHECKED(type, name, Type, obj)                \
+  RUNTIME_ASSERT(obj->IsNumber());                                   \
+  type name = NumberTo##Type(obj);
+
+// Non-reentrant string buffer for efficient general use in this file.
+static StaticResource<StringInputBuffer> string_input_buffer;
+
+
+static Object* IllegalOperation() {
+  return Top::Throw(Heap::illegal_access_symbol());
+}
+
+
+static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
+  CONVERT_CHECKED(JSObject, boilerplate, args[0]);
+  return Heap::CopyJSObject(boilerplate);
+}
+
+
+static Handle<Map> ComputeObjectLiteralMap(
+    Handle<Context> context,
+    Handle<FixedArray> constant_properties,
+    bool* is_result_from_cache) {
+  if (FLAG_canonicalize_object_literal_maps) {
+    // First find prefix of consecutive symbol keys.
+    int number_of_properties = constant_properties->length()/2;
+    int number_of_symbol_keys = 0;
+    while ((number_of_symbol_keys < number_of_properties) &&
+           (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
+      number_of_symbol_keys++;
+    }
+    // Based on the number of prefix symbols key we decide whether
+    // to use the map cache in the global context.
+    const int kMaxKeys = 10;
+    if ((number_of_symbol_keys == number_of_properties) &&
+        (number_of_symbol_keys < kMaxKeys)) {
+      // Create the fixed array with the key.
+      Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
+      for (int i = 0; i < number_of_symbol_keys; i++) {
+        keys->set(i, constant_properties->get(i*2));
+      }
+      *is_result_from_cache = true;
+      return Factory::ObjectLiteralMapFromCache(context, keys);
+    }
+  }
+  *is_result_from_cache = false;
+  return Handle<Map>(context->object_function()->initial_map());
+}
+
+
+static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  // Copy the arguments.
+  Handle<FixedArray> literals = args.at<FixedArray>(0);
+  int literals_index = Smi::cast(args[1])->value();
+  Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
+
+  // Get the global context from the literals array.  This is the
+  // context in which the function was created and we use the object
+  // function from this context to create the object literal.  We do
+  // not use the object function from the current global context
+  // because this might be the object function from another context
+  // which we should not have access to.
+  Handle<Context> context =
+      Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
+
+  bool is_result_from_cache;
+  Handle<Map> map = ComputeObjectLiteralMap(context,
+                                            constant_properties,
+                                            &is_result_from_cache);
+
+  Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
+  {  // Add the constant propeties to the boilerplate.
+    int length = constant_properties->length();
+    OptimizedObjectForAddingMultipleProperties opt(boilerplate,
+                                                   !is_result_from_cache);
+    for (int index = 0; index < length; index +=2) {
+      Handle<Object> key(constant_properties->get(index+0));
+      Handle<Object> value(constant_properties->get(index+1));
+      uint32_t element_index = 0;
+      if (key->IsSymbol()) {
+        // If key is a symbol it is not an array element.
+        Handle<String> name(String::cast(*key));
+        ASSERT(!name->AsArrayIndex(&element_index));
+        SetProperty(boilerplate, name, value, NONE);
+      } else if (Array::IndexFromObject(*key, &element_index)) {
+        // Array index (uint32).
+        SetElement(boilerplate, element_index, value);
+      } else {
+        // Non-uint32 number.
+        ASSERT(key->IsNumber());
+        double num = key->Number();
+        char arr[100];
+        Vector<char> buffer(arr, ARRAY_SIZE(arr));
+        const char* str = DoubleToCString(num, buffer);
+        Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
+        SetProperty(boilerplate, name, value, NONE);
+      }
+    }
+  }
+
+  // Update the functions literal and return the boilerplate.
+  literals->set(literals_index, *boilerplate);
+
+  return *boilerplate;
+}
+
+
+static Object* Runtime_CreateArrayLiteral(Arguments args) {
+  // Takes a FixedArray of elements containing the literal elements of
+  // the array literal and produces JSArray with those elements.
+  // Additionally takes the literals array of the surrounding function
+  // which contains the context from which to get the Array function
+  // to use for creating the array literal.
+  ASSERT(args.length() == 2);
+  CONVERT_CHECKED(FixedArray, elements, args[0]);
+  CONVERT_CHECKED(FixedArray, literals, args[1]);
+  JSFunction* constructor =
+      JSFunction::GlobalContextFromLiterals(literals)->array_function();
+  // Create the JSArray.
+  Object* object = Heap::AllocateJSObject(constructor);
+  if (object->IsFailure()) return object;
+
+  // Copy the elements.
+  Object* content = elements->Copy();
+  if (content->IsFailure()) return content;
+
+  // Set the elements.
+  JSArray::cast(object)->SetContent(FixedArray::cast(content));
+  return object;
+}
+
+
+static Object* Runtime_ClassOf(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+  Object* obj = args[0];
+  if (!obj->IsJSObject()) return Heap::null_value();
+  return JSObject::cast(obj)->class_name();
+}
+
+
+static Object* Runtime_HasStringClass(Arguments args) {
+  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
+}
+
+
+static Object* Runtime_HasDateClass(Arguments args) {
+  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
+}
+
+
+static Object* Runtime_HasArrayClass(Arguments args) {
+  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
+}
+
+
+static Object* Runtime_HasFunctionClass(Arguments args) {
+  return Heap::ToBoolean(
+             args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
+}
+
+
+static Object* Runtime_HasNumberClass(Arguments args) {
+  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
+}
+
+
+static Object* Runtime_HasBooleanClass(Arguments args) {
+  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
+}
+
+
+static Object* Runtime_HasArgumentsClass(Arguments args) {
+  return Heap::ToBoolean(
+             args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
+}
+
+
+static Object* Runtime_HasRegExpClass(Arguments args) {
+  return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
+}
+
+
+static Object* Runtime_IsInPrototypeChain(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+  // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
+  Object* O = args[0];
+  Object* V = args[1];
+  while (true) {
+    Object* prototype = V->GetPrototype();
+    if (prototype->IsNull()) return Heap::false_value();
+    if (O == prototype) return Heap::true_value();
+    V = prototype;
+  }
+}
+
+
+static Object* Runtime_IsConstructCall(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 0);
+  JavaScriptFrameIterator it;
+  return Heap::ToBoolean(it.frame()->IsConstructor());
+}
+
+
+static Object* Runtime_RegExpCompile(Arguments args) {
+  HandleScope scope;  // create a new handle scope
+  ASSERT(args.length() == 3);
+  CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
+  Handle<JSRegExp> re(raw_re);
+  CONVERT_CHECKED(String, raw_pattern, args[1]);
+  Handle<String> pattern(raw_pattern);
+  CONVERT_CHECKED(String, raw_flags, args[2]);
+  Handle<String> flags(raw_flags);
+  return *RegExpImpl::Compile(re, pattern, flags);
+}
+
+
+static Object* Runtime_CreateApiFunction(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
+  Handle<FunctionTemplateInfo> data(raw_data);
+  return *Factory::CreateApiFunction(data);
+}
+
+
+static Object* Runtime_IsTemplate(Arguments args) {
+  ASSERT(args.length() == 1);
+  Object* arg = args[0];
+  bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
+  return Heap::ToBoolean(result);
+}
+
+
+static Object* Runtime_GetTemplateField(Arguments args) {
+  ASSERT(args.length() == 2);
+  CONVERT_CHECKED(HeapObject, templ, args[0]);
+  RUNTIME_ASSERT(templ->IsStruct());
+  CONVERT_CHECKED(Smi, field, args[1]);
+  return HeapObject::GetHeapObjectField(templ, field->value());
+}
+
+
+static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
+  HandleScope scope;
+  Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
+  Handle<Object> args[2] = { type_handle, name };
+  Handle<Object> error =
+      Factory::NewTypeError("redeclaration", HandleVector(args, 2));
+  return Top::Throw(*error);
+}
+
+
+static Object* Runtime_DeclareGlobals(Arguments args) {
+  HandleScope scope;
+  Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
+
+  CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
+  Handle<Context> context = args.at<Context>(1);
+  bool is_eval = Smi::cast(args[2])->value() == 1;
+
+  // 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;
+
+  // Only optimize the object if we intend to add more than 5 properties.
+  OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
+
+  // Traverse the name/value pairs and set the properties.
+  int length = pairs->length();
+  for (int i = 0; i < length; i += 2) {
+    HandleScope scope;
+    Handle<String> name(String::cast(pairs->get(i)));
+    Handle<Object> value(pairs->get(i + 1));
+
+    // We have to declare a global const property. To capture we only
+    // assign to it when evaluating the assignment for "const x =
+    // <expr>" the initial value is the hole.
+    bool is_const_property = value->IsTheHole();
+
+    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.
+      LookupResult lookup;
+      global->Lookup(*name, &lookup);
+      if (lookup.IsProperty()) {
+        // Determine if the property is local by comparing the holder
+        // against the global object. The information will be used to
+        // avoid throwing re-declaration errors when declaring
+        // variables or constants that exist in the prototype chain.
+        bool is_local = (*global == lookup.holder());
+        // Get the property attributes and determine if the property is
+        // read-only.
+        PropertyAttributes attributes = global->GetPropertyAttribute(*name);
+        bool is_read_only = (attributes & READ_ONLY) != 0;
+        if (lookup.type() == INTERCEPTOR) {
+          // If the interceptor says the property is there, we
+          // just return undefined without overwriting the property.
+          // Otherwise, we continue to setting the property.
+          if (attributes != ABSENT) {
+            // Check if the existing property conflicts with regards to const.
+            if (is_local && (is_read_only || is_const_property)) {
+              const char* type = (is_read_only) ? "const" : "var";
+              return ThrowRedeclarationError(type, name);
+            };
+            // The property already exists without conflicting: Go to
+            // the next declaration.
+            continue;
+          }
+          // Fall-through and introduce the absent property by using
+          // SetProperty.
+        } else {
+          if (is_local && (is_read_only || is_const_property)) {
+            const char* type = (is_read_only) ? "const" : "var";
+            return ThrowRedeclarationError(type, name);
+          }
+          // The property already exists without conflicting: Go to
+          // the next declaration.
+          continue;
+        }
+      }
+    } else {
+      // Copy the function and update its context. Use it as value.
+      Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
+      Handle<JSFunction> function =
+          Factory::NewFunctionFromBoilerplate(boilerplate, context);
+      value = function;
+    }
+
+    LookupResult lookup;
+    global->LocalLookup(*name, &lookup);
+
+    PropertyAttributes attributes = is_const_property
+        ? static_cast<PropertyAttributes>(base | READ_ONLY)
+        : base;
+
+    if (lookup.IsProperty()) {
+      // 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.
+
+      // Check for conflicting re-declarations. We cannot have
+      // conflicting types in case of intercepted properties because
+      // they are absent.
+      if (lookup.type() != INTERCEPTOR &&
+          (lookup.IsReadOnly() || is_const_property)) {
+        const char* type = (lookup.IsReadOnly()) ? "const" : "var";
+        return ThrowRedeclarationError(type, name);
+      }
+      SetProperty(global, name, value, attributes);
+    } else {
+      // If a property with this name does not already exist on the
+      // global object add the property locally.  We take special
+      // precautions to always add it as a local property even in case
+      // of callbacks in the prototype chain (this rules out using
+      // SetProperty).  Also, we must use the handle-based version to
+      // avoid GC issues.
+      IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
+    }
+  }
+
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_DeclareContextSlot(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 4);
+
+  CONVERT_ARG_CHECKED(Context, context, 0);
+  Handle<String> name(String::cast(args[1]));
+  PropertyAttributes mode =
+      static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
+  ASSERT(mode == READ_ONLY || mode == NONE);
+  Handle<Object> initial_value(args[3]);
+
+  // Declarations are always done in the function context.
+  context = Handle<Context>(context->fcontext());
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes);
+
+  if (attributes != ABSENT) {
+    // The name was declared before; check for conflicting
+    // re-declarations: This is similar to the code in parser.cc in
+    // the AstBuildingParser::Declare function.
+    if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
+      // Functions are not read-only.
+      ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
+      const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
+      return ThrowRedeclarationError(type, name);
+    }
+
+    // Initialize it if necessary.
+    if (*initial_value != NULL) {
+      if (index >= 0) {
+        // The variable or constant context slot should always be in
+        // the function context; not in any outer context nor in the
+        // arguments object.
+        ASSERT(holder.is_identical_to(context));
+        if (((attributes & READ_ONLY) == 0) ||
+            context->get(index)->IsTheHole()) {
+          context->set(index, *initial_value);
+        }
+      } else {
+        // Slow case: The property is not in the FixedArray part of the context.
+        Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
+        SetProperty(context_ext, name, initial_value, mode);
+      }
+    }
+
+  } else {
+    // The property is not in the function context. It needs to be
+    // "declared" in the function context's extension context, or in the
+    // global context.
+    Handle<JSObject> context_ext;
+    if (context->has_extension()) {
+      // The function context's extension context exists - use it.
+      context_ext = Handle<JSObject>(context->extension());
+    } else {
+      // The function context's extension context does not exists - allocate
+      // it.
+      context_ext = Factory::NewJSObject(Top::context_extension_function());
+      // And store it in the extension slot.
+      context->set_extension(*context_ext);
+    }
+    ASSERT(*context_ext != NULL);
+
+    // Declare the property by setting it to the initial value if provided,
+    // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
+    // constant declarations).
+    ASSERT(!context_ext->HasLocalProperty(*name));
+    Handle<Object> value(Heap::undefined_value());
+    if (*initial_value != NULL) value = initial_value;
+    SetProperty(context_ext, name, value, mode);
+    ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
+  }
+
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_InitializeVarGlobal(Arguments args) {
+  NoHandleAllocation nha;
+
+  // Determine if we need to assign to the variable if it already
+  // exists (based on the number of arguments).
+  RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
+  bool assign = args.length() == 2;
+
+  CONVERT_ARG_CHECKED(String, name, 0);
+  GlobalObject* global = Top::context()->global();
+
+  // According to ECMA-262, section 12.2, page 62, the property must
+  // not be deletable.
+  PropertyAttributes attributes = DONT_DELETE;
+
+  // Lookup the property locally in the global object. If it isn't
+  // there, we add the property and take special precautions to always
+  // add it as a local property even in case of callbacks in the
+  // prototype chain (this rules out using SetProperty).
+  // We have IgnoreAttributesAndSetLocalProperty for this.
+  LookupResult lookup;
+  global->LocalLookup(*name, &lookup);
+  if (!lookup.IsProperty()) {
+    Object* value = (assign) ? args[1] : Heap::undefined_value();
+    return global->IgnoreAttributesAndSetLocalProperty(*name,
+                                                       value,
+                                                       attributes);
+  }
+
+  // Determine if this is a redeclaration of something read-only.
+  if (lookup.IsReadOnly()) {
+    return ThrowRedeclarationError("const", name);
+  }
+
+  // Determine if this is a redeclaration of an intercepted read-only
+  // property and figure out if the property exists at all.
+  bool found = true;
+  PropertyType type = lookup.type();
+  if (type == INTERCEPTOR) {
+    PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
+    if (intercepted == ABSENT) {
+      // The interceptor claims the property isn't there. We need to
+      // make sure to introduce it.
+      found = false;
+    } else if ((intercepted & READ_ONLY) != 0) {
+      // The property is present, but read-only. Since we're trying to
+      // overwrite it with a variable declaration we must throw a
+      // re-declaration error.
+      return ThrowRedeclarationError("const", name);
+    }
+    // Restore global object from context (in case of GC).
+    global = Top::context()->global();
+  }
+
+  if (found && !assign) {
+    // The global property is there and we're not assigning any value
+    // to it. Just return.
+    return Heap::undefined_value();
+  }
+
+  // Assign the value (or undefined) to the property.
+  Object* value = (assign) ? args[1] : Heap::undefined_value();
+  return global->SetProperty(&lookup, *name, value, attributes);
+}
+
+
+static Object* Runtime_InitializeConstGlobal(Arguments args) {
+  // All constants are declared with an initial value. The name
+  // of the constant is the first argument and the initial value
+  // is the second.
+  RUNTIME_ASSERT(args.length() == 2);
+  CONVERT_ARG_CHECKED(String, name, 0);
+  Handle<Object> value = args.at<Object>(1);
+
+  // Get the current global object from top.
+  GlobalObject* global = Top::context()->global();
+
+  // According to ECMA-262, section 12.2, page 62, the property must
+  // not be deletable. Since it's a const, it must be READ_ONLY too.
+  PropertyAttributes attributes =
+      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
+
+  // Lookup the property locally in the global object. If it isn't
+  // there, we add the property and take special precautions to always
+  // add it as a local property even in case of callbacks in the
+  // prototype chain (this rules out using SetProperty).
+  // We use IgnoreAttributesAndSetLocalProperty instead
+  LookupResult lookup;
+  global->LocalLookup(*name, &lookup);
+  if (!lookup.IsProperty()) {
+    return global->IgnoreAttributesAndSetLocalProperty(*name,
+                                                       *value,
+                                                       attributes);
+  }
+
+  // Determine if this is a redeclaration of something not
+  // read-only. In case the result is hidden behind an interceptor we
+  // need to ask it for the property attributes.
+  if (!lookup.IsReadOnly()) {
+    if (lookup.type() != INTERCEPTOR) {
+      return ThrowRedeclarationError("var", name);
+    }
+
+    PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
+
+    // Throw re-declaration error if the intercepted property is present
+    // but not read-only.
+    if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
+      return ThrowRedeclarationError("var", name);
+    }
+
+    // Restore global object from context (in case of GC) and continue
+    // with setting the value because the property is either absent or
+    // read-only. We also have to do redo the lookup.
+    global = Top::context()->global();
+
+    // BUG 1213579: Handle the case where we have to set a read-only
+    // property through an interceptor and only do it if it's
+    // uninitialized, e.g. the hole. Nirk...
+    global->SetProperty(*name, *value, attributes);
+    return *value;
+  }
+
+  // Set the value, but only we're assigning the initial value to a
+  // constant. For now, we determine this by checking if the
+  // current value is the hole.
+  PropertyType type = lookup.type();
+  if (type == FIELD) {
+    FixedArray* properties = global->properties();
+    int index = lookup.GetFieldIndex();
+    if (properties->get(index)->IsTheHole()) {
+      properties->set(index, *value);
+    }
+  } else if (type == NORMAL) {
+    Dictionary* dictionary = global->property_dictionary();
+    int entry = lookup.GetDictionaryEntry();
+    if (dictionary->ValueAt(entry)->IsTheHole()) {
+      dictionary->ValueAtPut(entry, *value);
+    }
+  } else {
+    // Ignore re-initialization of constants that have already been
+    // assigned a function value.
+    ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
+  }
+
+  // Use the set value as the result of the operation.
+  return *value;
+}
+
+
+static Object* Runtime_InitializeConstContextSlot(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+
+  Handle<Object> value(args[0]);
+  ASSERT(!value->IsTheHole());
+  CONVERT_ARG_CHECKED(Context, context, 1);
+  Handle<String> name(String::cast(args[2]));
+
+  // Initializations are always done in the function context.
+  context = Handle<Context>(context->fcontext());
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes);
+
+  // The property should always be present. It is always declared
+  // before being initialized through DeclareContextSlot.
+  ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
+
+  // If the slot is in the context, we set it but only if it hasn't
+  // been set before.
+  if (index >= 0) {
+    // The constant context slot should always be in the function
+    // context; not in any outer context nor in the arguments object.
+    ASSERT(holder.is_identical_to(context));
+    if (context->get(index)->IsTheHole()) {
+      context->set(index, *value);
+    }
+    return *value;
+  }
+
+  // Otherwise, the slot must be in a JS object extension.
+  Handle<JSObject> context_ext(JSObject::cast(*holder));
+
+  // We must initialize the value only if it wasn't initialized
+  // before, e.g. for const declarations in a loop. The property has
+  // the hole value if it wasn't initialized yet. NOTE: We cannot use
+  // GetProperty() to get the current value as it 'unholes' the value.
+  LookupResult lookup;
+  context_ext->LocalLookupRealNamedProperty(*name, &lookup);
+  ASSERT(lookup.IsProperty());  // the property was declared
+  ASSERT(lookup.IsReadOnly());  // and it was declared as read-only
+
+  PropertyType type = lookup.type();
+  if (type == FIELD) {
+    FixedArray* properties = context_ext->properties();
+    int index = lookup.GetFieldIndex();
+    if (properties->get(index)->IsTheHole()) {
+      properties->set(index, *value);
+    }
+  } else if (type == NORMAL) {
+    Dictionary* dictionary = context_ext->property_dictionary();
+    int entry = lookup.GetDictionaryEntry();
+    if (dictionary->ValueAt(entry)->IsTheHole()) {
+      dictionary->ValueAtPut(entry, *value);
+    }
+  } else {
+    // We should not reach here. Any real, named property should be
+    // either a field or a dictionary slot.
+    UNREACHABLE();
+  }
+  return *value;
+}
+
+
+static Object* Runtime_RegExpExec(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
+  Handle<JSRegExp> regexp(raw_regexp);
+  CONVERT_CHECKED(String, raw_subject, args[1]);
+  Handle<String> subject(raw_subject);
+  Handle<Object> index(args[2]);
+  ASSERT(index->IsNumber());
+  return *RegExpImpl::Exec(regexp, subject, index);
+}
+
+
+static Object* Runtime_RegExpExecGlobal(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+  CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
+  Handle<JSRegExp> regexp(raw_regexp);
+  CONVERT_CHECKED(String, raw_subject, args[1]);
+  Handle<String> subject(raw_subject);
+  return *RegExpImpl::ExecGlobal(regexp, subject);
+}
+
+
+static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 4);
+  CONVERT_ARG_CHECKED(FixedArray, literals, 0);
+  int index = Smi::cast(args[1])->value();
+  Handle<String> pattern = args.at<String>(2);
+  Handle<String> flags = args.at<String>(3);
+
+  // Get the RegExp function from the context in the literals array.
+  // This is the RegExp function from the context in which the
+  // function was created.  We do not use the RegExp function from the
+  // current global context because this might be the RegExp function
+  // from another context which we should not have access to.
+  Handle<JSFunction> constructor =
+      Handle<JSFunction>(
+          JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
+  // Compute the regular expression literal.
+  bool has_pending_exception;
+  Handle<Object> regexp =
+      RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
+                                      &has_pending_exception);
+  if (has_pending_exception) {
+    ASSERT(Top::has_pending_exception());
+    return Failure::Exception();
+  }
+  literals->set(index, *regexp);
+  return *regexp;
+}
+
+
+static Object* Runtime_FunctionGetName(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSFunction, f, args[0]);
+  return f->shared()->name();
+}
+
+
+static Object* Runtime_FunctionSetName(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSFunction, f, args[0]);
+  CONVERT_CHECKED(String, name, args[1]);
+  f->shared()->set_name(name);
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_FunctionGetScript(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSFunction, fun, args[0]);
+  Handle<Object> script = Handle<Object>(fun->shared()->script());
+  if (!script->IsScript()) return Heap::undefined_value();
+
+  return *GetScriptWrapper(Handle<Script>::cast(script));
+}
+
+
+static Object* Runtime_FunctionGetSourceCode(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSFunction, f, args[0]);
+  return f->shared()->GetSourceCode();
+}
+
+
+static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSFunction, fun, args[0]);
+  int pos = fun->shared()->start_position();
+  return Smi::FromInt(pos);
+}
+
+
+static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSFunction, fun, args[0]);
+  CONVERT_CHECKED(String, name, args[1]);
+  fun->SetInstanceClassName(name);
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_FunctionSetLength(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSFunction, fun, args[0]);
+  CONVERT_CHECKED(Smi, length, args[1]);
+  fun->shared()->set_length(length->value());
+  return length;
+}
+
+
+static Object* Runtime_FunctionSetPrototype(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSFunction, fun, args[0]);
+  Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
+  if (obj->IsFailure()) return obj;
+  return args[0];  // return TOS
+}
+
+
+static Object* Runtime_SetCode(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSFunction, raw_target, args[0]);
+  Handle<JSFunction> target(raw_target);
+  Handle<Object> code = args.at<Object>(1);
+
+  Handle<Context> context(target->context());
+
+  if (!code->IsNull()) {
+    RUNTIME_ASSERT(code->IsJSFunction());
+    Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
+    SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
+    if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
+      return Failure::Exception();
+    }
+    // Set the code, formal parameter count, and the length of the target
+    // function.
+    target->set_code(fun->code());
+    target->shared()->set_length(fun->shared()->length());
+    target->shared()->set_formal_parameter_count(
+        fun->shared()->formal_parameter_count());
+    // Set the source code of the target function to undefined.
+    // SetCode is only used for built-in constructors like String,
+    // Array, and Object, and some web code
+    // doesn't like seeing source code for constructors.
+    target->shared()->set_script(Heap::undefined_value());
+    context = Handle<Context>(fun->context());
+
+    // Make sure we get a fresh copy of the literal vector to avoid
+    // cross context contamination.
+    int number_of_literals = fun->NumberOfLiterals();
+    Handle<FixedArray> literals =
+        Factory::NewFixedArray(number_of_literals, TENURED);
+    if (number_of_literals > 0) {
+      // Insert the object, regexp and array functions in the literals
+      // array prefix.  These are the functions that will be used when
+      // creating object, regexp and array literals.
+      literals->set(JSFunction::kLiteralGlobalContextIndex,
+                    context->global_context());
+    }
+    target->set_literals(*literals, SKIP_WRITE_BARRIER);
+  }
+
+  target->set_context(*context);
+  return *target;
+}
+
+
+static Object* CharCodeAt(String* subject, Object* index) {
+  uint32_t i = 0;
+  if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
+  // Flatten the string.  If someone wants to get a char at an index
+  // in a cons string, it is likely that more indices will be
+  // accessed.
+  subject->TryFlatten();
+  if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
+  return Smi::FromInt(subject->Get(i));
+}
+
+
+static Object* Runtime_StringCharCodeAt(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(String, subject, args[0]);
+  Object* index = args[1];
+  return CharCodeAt(subject, index);
+}
+
+
+static Object* Runtime_CharFromCode(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+  uint32_t code;
+  if (Array::IndexFromObject(args[0], &code)) {
+    if (code <= 0xffff) {
+      return Heap::LookupSingleCharacterStringFromCode(code);
+    }
+  }
+  return Heap::empty_string();
+}
+
+
+// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
+// limit, we can fix the size of tables.
+static const int kBMMaxShift = 0xff;
+// Reduce alphabet to this size.
+static const int kBMAlphabetSize = 0x100;
+// For patterns below this length, the skip length of Boyer-Moore is too short
+// to compensate for the algorithmic overhead compared to simple brute force.
+static const int kBMMinPatternLength = 5;
+
+// Holds the two buffers used by Boyer-Moore string search's Good Suffix
+// shift. Only allows the last kBMMaxShift characters of the needle
+// to be indexed.
+class BMGoodSuffixBuffers {
+ public:
+  BMGoodSuffixBuffers() {}
+  inline void init(int needle_length) {
+    ASSERT(needle_length > 1);
+    int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
+    int len = needle_length - start;
+    biased_suffixes_ = suffixes_ - start;
+    biased_good_suffix_shift_ = good_suffix_shift_ - start;
+    for (int i = 0; i <= len; i++) {
+      good_suffix_shift_[i] = len;
+    }
+  }
+  inline int& suffix(int index) {
+    ASSERT(biased_suffixes_ + index >= suffixes_);
+    return biased_suffixes_[index];
+  }
+  inline int& shift(int index) {
+    ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
+    return biased_good_suffix_shift_[index];
+  }
+ private:
+  int suffixes_[kBMMaxShift + 1];
+  int good_suffix_shift_[kBMMaxShift + 1];
+  int* biased_suffixes_;
+  int* biased_good_suffix_shift_;
+  DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
+};
+
+// buffers reused by BoyerMoore
+static int bad_char_occurence[kBMAlphabetSize];
+static BMGoodSuffixBuffers bmgs_buffers;
+
+// Compute the bad-char table for Boyer-Moore in the static buffer.
+template <typename pchar>
+static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
+                                          int start) {
+  // Run forwards to populate bad_char_table, so that *last* instance
+  // of character equivalence class is the one registered.
+  // Notice: Doesn't include the last character.
+  int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
+                                        : kBMAlphabetSize;
+  if (start == 0) {  // All patterns less than kBMMaxShift in length.
+    memset(bad_char_occurence, -1, table_size * sizeof(*bad_char_occurence));
+  } else {
+    for (int i = 0; i < table_size; i++) {
+      bad_char_occurence[i] = start - 1;
+    }
+  }
+  for (int i = start; i < pattern.length() - 1; i++) {
+    pchar c = pattern[i];
+    int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
+    bad_char_occurence[bucket] = i;
+  }
+}
+
+template <typename pchar>
+static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
+                                              int start) {
+  int m = pattern.length();
+  int len = m - start;
+  // Compute Good Suffix tables.
+  bmgs_buffers.init(m);
+
+  bmgs_buffers.shift(m-1) = 1;
+  bmgs_buffers.suffix(m) = m + 1;
+  pchar last_char = pattern[m - 1];
+  int suffix = m + 1;
+  for (int i = m; i > start;) {
+    for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
+      if (bmgs_buffers.shift(suffix) == len) {
+        bmgs_buffers.shift(suffix) = suffix - i;
+      }
+      suffix = bmgs_buffers.suffix(suffix);
+    }
+    i--;
+    suffix--;
+    bmgs_buffers.suffix(i) = suffix;
+    if (suffix == m) {
+      // No suffix to extend, so we check against last_char only.
+      while (i > start && pattern[i - 1] != last_char) {
+        if (bmgs_buffers.shift(m) == len) {
+          bmgs_buffers.shift(m) = m - i;
+        }
+        i--;
+        bmgs_buffers.suffix(i) = m;
+      }
+      if (i > start) {
+        i--;
+        suffix--;
+        bmgs_buffers.suffix(i) = suffix;
+      }
+    }
+  }
+  if (suffix < m) {
+    for (int i = start; i <= m; i++) {
+      if (bmgs_buffers.shift(i) == len) {
+        bmgs_buffers.shift(i) = suffix - start;
+      }
+      if (i == suffix) {
+        suffix = bmgs_buffers.suffix(suffix);
+      }
+    }
+  }
+}
+
+template <typename schar, typename pchar>
+static inline int CharOccurence(int char_code) {
+  if (sizeof(schar) == 1) {
+    return bad_char_occurence[char_code];
+  }
+  if (sizeof(pchar) == 1) {
+    if (char_code > String::kMaxAsciiCharCode) {
+      return -1;
+    }
+    return bad_char_occurence[char_code];
+  }
+  return bad_char_occurence[char_code % kBMAlphabetSize];
+}
+
+// Restricted simplified Boyer-Moore string matching. Restricts tables to a
+// suffix of long pattern strings and handles only equivalence classes
+// of the full alphabet. This allows us to ensure that tables take only
+// a fixed amount of space.
+template <typename schar, typename pchar>
+static int BoyerMooreSimplified(Vector<const schar> subject,
+                                Vector<const pchar> pattern,
+                                int start_index,
+                                bool* complete) {
+  int n = subject.length();
+  int m = pattern.length();
+  // Only preprocess at most kBMMaxShift last characters of pattern.
+  int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
+
+  BoyerMoorePopulateBadCharTable(pattern, start);
+
+  int badness = -m;  // How bad we are doing without a good-suffix table.
+  int idx;  // No matches found prior to this index.
+  pchar last_char = pattern[m - 1];
+  // Perform search
+  for (idx = start_index; idx <= n - m;) {
+    int j = m - 1;
+    int c;
+    while (last_char != (c = subject[idx + j])) {
+      int bc_occ = CharOccurence<schar, pchar>(c);
+      int shift = j - bc_occ;
+      idx += shift;
+      badness += 1 - shift;  // at most zero, so badness cannot increase.
+      if (idx > n - m) {
+        *complete = true;
+        return -1;
+      }
+    }
+    j--;
+    while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
+    if (j < 0) {
+      *complete = true;
+      return idx;
+    } else {
+      int bc_occ = CharOccurence<schar, pchar>(c);
+      int shift = bc_occ < j ? j - bc_occ : 1;
+      idx += shift;
+      // Badness increases by the number of characters we have
+      // checked, and decreases by the number of characters we
+      // can skip by shifting. It's a measure of how we are doing
+      // compared to reading each character exactly once.
+      badness += (m - j) - shift;
+      if (badness > 0) {
+        *complete = false;
+        return idx;
+      }
+    }
+  }
+  *complete = true;
+  return -1;
+}
+
+
+template <typename schar, typename pchar>
+static int BoyerMooreIndexOf(Vector<const schar> subject,
+                             Vector<const pchar> pattern,
+                             int idx) {
+  int n = subject.length();
+  int m = pattern.length();
+  // Only preprocess at most kBMMaxShift last characters of pattern.
+  int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
+
+  // Build the Good Suffix table and continue searching.
+  BoyerMoorePopulateGoodSuffixTable(pattern, start);
+  pchar last_char = pattern[m - 1];
+  // Continue search from i.
+  do {
+    int j = m - 1;
+    schar c;
+    while (last_char != (c = subject[idx + j])) {
+      int shift = j - CharOccurence<schar, pchar>(c);
+      idx += shift;
+      if (idx > n - m) {
+        return -1;
+      }
+    }
+    while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
+    if (j < 0) {
+      return idx;
+    } else if (j < start) {
+      // we have matched more than our tables allow us to be smart about.
+      idx += 1;
+    } else {
+      int gs_shift = bmgs_buffers.shift(j + 1);       // Good suffix shift.
+      int bc_occ = CharOccurence<schar, pchar>(c);
+      int shift = j - bc_occ;                         // Bad-char shift.
+      shift = (gs_shift > shift) ? gs_shift : shift;
+      idx += shift;
+    }
+  } while (idx <= n - m);
+
+  return -1;
+}
+
+
+template <typename schar>
+static int SingleCharIndexOf(Vector<const schar> string,
+                             uc16 pattern_char,
+                             int start_index) {
+  if (sizeof(schar) == 1 && pattern_char > String::kMaxAsciiCharCode) {
+    return -1;
+  }
+  for (int i = start_index, n = string.length(); i < n; i++) {
+    if (pattern_char == string[i]) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+// Trivial string search for shorter strings.
+// On return, if "complete" is set to true, the return value is the
+// final result of searching for the patter in the subject.
+// If "complete" is set to false, the return value is the index where
+// further checking should start, i.e., it's guaranteed that the pattern
+// does not occur at a position prior to the returned index.
+template <typename pchar, typename schar>
+static int SimpleIndexOf(Vector<const schar> subject,
+                         Vector<const pchar> pattern,
+                         int idx,
+                         bool* complete) {
+  // Badness is a count of how much work we have done.  When we have
+  // done enough work we decide it's probably worth switching to a better
+  // algorithm.
+  int badness = -10 - (pattern.length() << 2);
+  // We know our pattern is at least 2 characters, we cache the first so
+  // the common case of the first character not matching is faster.
+  pchar pattern_first_char = pattern[0];
+
+  for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
+    badness++;
+    if (badness > 0) {
+      *complete = false;
+      return (i);
+    }
+    if (subject[i] != pattern_first_char) continue;
+    int j = 1;
+    do {
+      if (pattern[j] != subject[i+j]) {
+        break;
+      }
+      j++;
+    } while (j < pattern.length());
+    if (j == pattern.length()) {
+      *complete = true;
+      return i;
+    }
+    badness += j;
+  }
+  *complete = true;
+  return -1;
+}
+
+// Simple indexOf that never bails out. For short patterns only.
+template <typename pchar, typename schar>
+static int SimpleIndexOf(Vector<const schar> subject,
+                         Vector<const pchar> pattern,
+                         int idx) {
+  pchar pattern_first_char = pattern[0];
+  for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
+    if (subject[i] != pattern_first_char) continue;
+    int j = 1;
+    do {
+      if (pattern[j] != subject[i+j]) {
+        break;
+      }
+      j++;
+    } while (j < pattern.length());
+    if (j == pattern.length()) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+
+// Dispatch to different algorithms.
+template <typename schar, typename pchar>
+static int StringMatchStrategy(Vector<const schar> sub,
+                               Vector<const pchar> pat,
+                               int start_index) {
+  ASSERT(pat.length() > 1);
+
+  // We have an ASCII haystack and a non-ASCII needle. Check if there
+  // really is a non-ASCII character in the needle and bail out if there
+  // is.
+  if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
+    for (int i = 0; i < pat.length(); i++) {
+      uc16 c = pat[i];
+      if (c > String::kMaxAsciiCharCode) {
+        return -1;
+      }
+    }
+  }
+  if (pat.length() < kBMMinPatternLength) {
+    // We don't believe fancy searching can ever be more efficient.
+    // The max shift of Boyer-Moore on a pattern of this length does
+    // not compensate for the overhead.
+    return SimpleIndexOf(sub, pat, start_index);
+  }
+  // Try algorithms in order of increasing setup cost and expected performance.
+  bool complete;
+  int idx = SimpleIndexOf(sub, pat, start_index, &complete);
+  if (complete) return idx;
+  idx = BoyerMooreSimplified(sub, pat, idx, &complete);
+  if (complete) return idx;
+  return BoyerMooreIndexOf(sub, pat, idx);
+}
+
+// Perform string match of pattern on subject, starting at start index.
+// Caller must ensure that 0 <= start_index <= sub->length(),
+// and should check that pat->length() + start_index <= sub->length()
+int Runtime::StringMatch(Handle<String> sub,
+                         Handle<String> pat,
+                         int start_index) {
+  ASSERT(0 <= start_index);
+  ASSERT(start_index <= sub->length());
+
+  int pattern_length = pat->length();
+  if (pattern_length == 0) return start_index;
+
+  int subject_length = sub->length();
+  if (start_index + pattern_length > subject_length) return -1;
+
+  FlattenString(sub);
+  // Searching for one specific character is common.  For one
+  // character patterns linear search is necessary, so any smart
+  // algorithm is unnecessary overhead.
+  if (pattern_length == 1) {
+    AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
+    if (sub->is_ascii_representation()) {
+      return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index);
+    }
+    return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
+  }
+
+  FlattenString(pat);
+
+  AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
+  // dispatch on type of strings
+  if (pat->is_ascii_representation()) {
+    Vector<const char> pat_vector = pat->ToAsciiVector();
+    if (sub->is_ascii_representation()) {
+      return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
+    }
+    return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
+  }
+  Vector<const uc16> pat_vector = pat->ToUC16Vector();
+  if (sub->is_ascii_representation()) {
+    return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
+  }
+  return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
+}
+
+
+static Object* Runtime_StringIndexOf(Arguments args) {
+  HandleScope scope;  // create a new handle scope
+  ASSERT(args.length() == 3);
+
+  CONVERT_ARG_CHECKED(String, sub, 0);
+  CONVERT_ARG_CHECKED(String, pat, 1);
+
+  Object* index = args[2];
+  uint32_t start_index;
+  if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
+
+  int position = Runtime::StringMatch(sub, pat, start_index);
+  return Smi::FromInt(position);
+}
+
+
+static Object* Runtime_StringLastIndexOf(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 3);
+
+  CONVERT_CHECKED(String, sub, args[0]);
+  CONVERT_CHECKED(String, pat, args[1]);
+  Object* index = args[2];
+
+  sub->TryFlatten();
+  pat->TryFlatten();
+
+  uint32_t start_index;
+  if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
+
+  uint32_t pattern_length = pat->length();
+  uint32_t sub_length = sub->length();
+
+  if (start_index + pattern_length > sub_length) {
+    start_index = sub_length - pattern_length;
+  }
+
+  for (int i = start_index; i >= 0; i--) {
+    bool found = true;
+    for (uint32_t j = 0; j < pattern_length; j++) {
+      if (sub->Get(i + j) != pat->Get(j)) {
+        found = false;
+        break;
+      }
+    }
+    if (found) return Smi::FromInt(i);
+  }
+
+  return Smi::FromInt(-1);
+}
+
+
+static Object* Runtime_StringLocaleCompare(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(String, str1, args[0]);
+  CONVERT_CHECKED(String, str2, args[1]);
+
+  if (str1 == str2) return Smi::FromInt(0);  // Equal.
+  int str1_length = str1->length();
+  int str2_length = str2->length();
+
+  // Decide trivial cases without flattening.
+  if (str1_length == 0) {
+    if (str2_length == 0) return Smi::FromInt(0);  // Equal.
+    return Smi::FromInt(-str2_length);
+  } else {
+    if (str2_length == 0) return Smi::FromInt(str1_length);
+  }
+
+  int end = str1_length < str2_length ? str1_length : str2_length;
+
+  // No need to flatten if we are going to find the answer on the first
+  // character.  At this point we know there is at least one character
+  // in each string, due to the trivial case handling above.
+  int d = str1->Get(0) - str2->Get(0);
+  if (d != 0) return Smi::FromInt(d);
+
+  str1->TryFlatten();
+  str2->TryFlatten();
+
+  static StringInputBuffer buf1;
+  static StringInputBuffer buf2;
+
+  buf1.Reset(str1);
+  buf2.Reset(str2);
+
+  for (int i = 0; i < end; i++) {
+    uint16_t char1 = buf1.GetNext();
+    uint16_t char2 = buf2.GetNext();
+    if (char1 != char2) return Smi::FromInt(char1 - char2);
+  }
+
+  return Smi::FromInt(str1_length - str2_length);
+}
+
+
+static Object* Runtime_StringSlice(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 3);
+
+  CONVERT_CHECKED(String, value, args[0]);
+  CONVERT_DOUBLE_CHECKED(from_number, args[1]);
+  CONVERT_DOUBLE_CHECKED(to_number, args[2]);
+
+  int start = FastD2I(from_number);
+  int end = FastD2I(to_number);
+
+  RUNTIME_ASSERT(end >= start);
+  RUNTIME_ASSERT(start >= 0);
+  RUNTIME_ASSERT(end <= value->length());
+  return value->Slice(start, end);
+}
+
+
+static Object* Runtime_NumberToRadixString(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(value, args[0]);
+  if (isnan(value)) {
+    return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+  }
+  if (isinf(value)) {
+    if (value < 0) {
+      return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+    }
+    return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+  }
+  CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
+  int radix = FastD2I(radix_number);
+  RUNTIME_ASSERT(2 <= radix && radix <= 36);
+  char* str = DoubleToRadixCString(value, radix);
+  Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
+  DeleteArray(str);
+  return result;
+}
+
+
+static Object* Runtime_NumberToFixed(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(value, args[0]);
+  if (isnan(value)) {
+    return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+  }
+  if (isinf(value)) {
+    if (value < 0) {
+      return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+    }
+    return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+  }
+  CONVERT_DOUBLE_CHECKED(f_number, args[1]);
+  int f = FastD2I(f_number);
+  RUNTIME_ASSERT(f >= 0);
+  char* str = DoubleToFixedCString(value, f);
+  Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
+  DeleteArray(str);
+  return res;
+}
+
+
+static Object* Runtime_NumberToExponential(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(value, args[0]);
+  if (isnan(value)) {
+    return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+  }
+  if (isinf(value)) {
+    if (value < 0) {
+      return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+    }
+    return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+  }
+  CONVERT_DOUBLE_CHECKED(f_number, args[1]);
+  int f = FastD2I(f_number);
+  RUNTIME_ASSERT(f >= -1 && f <= 20);
+  char* str = DoubleToExponentialCString(value, f);
+  Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
+  DeleteArray(str);
+  return res;
+}
+
+
+static Object* Runtime_NumberToPrecision(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(value, args[0]);
+  if (isnan(value)) {
+    return Heap::AllocateStringFromAscii(CStrVector("NaN"));
+  }
+  if (isinf(value)) {
+    if (value < 0) {
+      return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
+    }
+    return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
+  }
+  CONVERT_DOUBLE_CHECKED(f_number, args[1]);
+  int f = FastD2I(f_number);
+  RUNTIME_ASSERT(f >= 1 && f <= 21);
+  char* str = DoubleToPrecisionCString(value, f);
+  Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
+  DeleteArray(str);
+  return res;
+}
+
+
+// Returns a single character string where first character equals
+// string->Get(index).
+static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
+  if (index < static_cast<uint32_t>(string->length())) {
+    string->TryFlatten();
+    return LookupSingleCharacterStringFromCode(string->Get(index));
+  }
+  return Execution::CharAt(string, index);
+}
+
+
+Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
+  // Handle [] indexing on Strings
+  if (object->IsString()) {
+    Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
+    if (!result->IsUndefined()) return *result;
+  }
+
+  // Handle [] indexing on String objects
+  if (object->IsStringObjectWithCharacterAt(index)) {
+    Handle<JSValue> js_value = Handle<JSValue>::cast(object);
+    Handle<Object> result =
+        GetCharAt(Handle<String>(String::cast(js_value->value())), index);
+    if (!result->IsUndefined()) return *result;
+  }
+
+  if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
+    Handle<Object> prototype = GetPrototype(object);
+    return prototype->GetElement(index);
+  }
+
+  return object->GetElement(index);
+}
+
+
+Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
+  HandleScope scope;
+
+  if (object->IsUndefined() || object->IsNull()) {
+    Handle<Object> args[2] = { key, object };
+    Handle<Object> error =
+        Factory::NewTypeError("non_object_property_load",
+                              HandleVector(args, 2));
+    return Top::Throw(*error);
+  }
+
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (Array::IndexFromObject(*key, &index)) {
+    return GetElementOrCharAt(object, index);
+  }
+
+  // Convert the key to a string - possibly by calling back into JavaScript.
+  Handle<String> name;
+  if (key->IsString()) {
+    name = Handle<String>::cast(key);
+  } else {
+    bool has_pending_exception = false;
+    Handle<Object> converted =
+        Execution::ToString(key, &has_pending_exception);
+    if (has_pending_exception) return Failure::Exception();
+    name = Handle<String>::cast(converted);
+  }
+
+  // Check if the name is trivially convertable to an index and get
+  // the element if so.
+  if (name->AsArrayIndex(&index)) {
+    return GetElementOrCharAt(object, index);
+  } else {
+    PropertyAttributes attr;
+    return object->GetProperty(*name, &attr);
+  }
+}
+
+
+static Object* Runtime_GetProperty(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  Handle<Object> object = args.at<Object>(0);
+  Handle<Object> key = args.at<Object>(1);
+
+  return Runtime::GetObjectProperty(object, key);
+}
+
+
+
+// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
+static Object* Runtime_KeyedGetProperty(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  // Fast cases for getting named properties of the receiver JSObject
+  // itself. The global proxy objects has to be excluded since
+  // LocalLookup on the global proxy object can return a valid result
+  // eventhough the global proxy object never has properties.  This is
+  // the case because the global proxy object forwards everything to
+  // its hidden prototype including local lookups.
+  if (args[0]->IsJSObject() &&
+      !args[0]->IsJSGlobalProxy() &&
+      args[1]->IsString()) {
+    JSObject* receiver = JSObject::cast(args[0]);
+    String* key = String::cast(args[1]);
+    if (receiver->HasFastProperties()) {
+      // Attempt to use lookup cache.
+      Object* obj = Heap::GetKeyedLookupCache();
+      if (obj->IsFailure()) return obj;
+      LookupCache* cache = LookupCache::cast(obj);
+      Map* receiver_map = receiver->map();
+      int offset = cache->Lookup(receiver_map, key);
+      if (offset != LookupCache::kNotFound) {
+        Object* value = receiver->FastPropertyAt(offset);
+        return value->IsTheHole() ? Heap::undefined_value() : value;
+      }
+      // Lookup cache miss.  Perform lookup and update the cache if
+      // appropriate.
+      LookupResult result;
+      receiver->LocalLookup(key, &result);
+      if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
+        int offset = result.GetFieldIndex();
+        Object* obj = cache->Put(receiver_map, key, offset);
+        if (obj->IsFailure()) return obj;
+        Heap::SetKeyedLookupCache(LookupCache::cast(obj));
+        Object* value = receiver->FastPropertyAt(offset);
+        return value->IsTheHole() ? Heap::undefined_value() : value;
+      }
+    } else {
+      // Attempt dictionary lookup.
+      Dictionary* dictionary = receiver->property_dictionary();
+      int entry = dictionary->FindStringEntry(key);
+      if ((entry != DescriptorArray::kNotFound) &&
+          (dictionary->DetailsAt(entry).type() == NORMAL)) {
+        return dictionary->ValueAt(entry);
+      }
+    }
+  }
+
+  // Fall back to GetObjectProperty.
+  return Runtime::GetObjectProperty(args.at<Object>(0),
+                                    args.at<Object>(1));
+}
+
+
+Object* Runtime::SetObjectProperty(Handle<Object> object,
+                                   Handle<Object> key,
+                                   Handle<Object> value,
+                                   PropertyAttributes attr) {
+  HandleScope scope;
+
+  if (object->IsUndefined() || object->IsNull()) {
+    Handle<Object> args[2] = { key, object };
+    Handle<Object> error =
+        Factory::NewTypeError("non_object_property_store",
+                              HandleVector(args, 2));
+    return Top::Throw(*error);
+  }
+
+  // If the object isn't a JavaScript object, we ignore the store.
+  if (!object->IsJSObject()) return *value;
+
+  Handle<JSObject> js_object = Handle<JSObject>::cast(object);
+
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (Array::IndexFromObject(*key, &index)) {
+    ASSERT(attr == NONE);
+
+    // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
+    // of a string using [] notation.  We need to support this too in
+    // JavaScript.
+    // In the case of a String object we just need to redirect the assignment to
+    // the underlying string if the index is in range.  Since the underlying
+    // string does nothing with the assignment then we can ignore such
+    // assignments.
+    if (js_object->IsStringObjectWithCharacterAt(index)) {
+      return *value;
+    }
+
+    Handle<Object> result = SetElement(js_object, index, value);
+    if (result.is_null()) return Failure::Exception();
+    return *value;
+  }
+
+  if (key->IsString()) {
+    Handle<Object> result;
+    if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
+      ASSERT(attr == NONE);
+      result = SetElement(js_object, index, value);
+    } else {
+      Handle<String> key_string = Handle<String>::cast(key);
+      key_string->TryFlatten();
+      result = SetProperty(js_object, key_string, value, attr);
+    }
+    if (result.is_null()) return Failure::Exception();
+    return *value;
+  }
+
+  // Call-back into JavaScript to convert the key to a string.
+  bool has_pending_exception = false;
+  Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
+  if (has_pending_exception) return Failure::Exception();
+  Handle<String> name = Handle<String>::cast(converted);
+
+  if (name->AsArrayIndex(&index)) {
+    ASSERT(attr == NONE);
+    return js_object->SetElement(index, *value);
+  } else {
+    return js_object->SetProperty(*name, *value, attr);
+  }
+}
+
+
+static Object* Runtime_SetProperty(Arguments args) {
+  NoHandleAllocation ha;
+  RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
+
+  Handle<Object> object = args.at<Object>(0);
+  Handle<Object> key = args.at<Object>(1);
+  Handle<Object> value = args.at<Object>(2);
+
+  // Compute attributes.
+  PropertyAttributes attributes = NONE;
+  if (args.length() == 4) {
+    CONVERT_CHECKED(Smi, value_obj, args[3]);
+    int unchecked_value = value_obj->value();
+    // Only attribute bits should be set.
+    RUNTIME_ASSERT(
+        (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+    attributes = static_cast<PropertyAttributes>(unchecked_value);
+  }
+  return Runtime::SetObjectProperty(object, key, value, attributes);
+}
+
+
+// Set a local property, even if it is READ_ONLY.  If the property does not
+// exist, it will be added with attributes NONE.
+static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
+  NoHandleAllocation ha;
+  RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
+  CONVERT_CHECKED(JSObject, object, args[0]);
+  CONVERT_CHECKED(String, name, args[1]);
+  // Compute attributes.
+  PropertyAttributes attributes = NONE;
+  if (args.length() == 4) {
+    CONVERT_CHECKED(Smi, value_obj, args[3]);
+    int unchecked_value = value_obj->value();
+    // Only attribute bits should be set.
+    RUNTIME_ASSERT(
+        (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+    attributes = static_cast<PropertyAttributes>(unchecked_value);
+  }
+
+  return object->
+      IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
+}
+
+
+static Object* Runtime_DeleteProperty(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSObject, object, args[0]);
+  CONVERT_CHECKED(String, key, args[1]);
+  return object->DeleteProperty(key);
+}
+
+
+static Object* Runtime_HasLocalProperty(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+  CONVERT_CHECKED(String, key, args[1]);
+
+  // Only JS objects can have properties.
+  if (args[0]->IsJSObject()) {
+    JSObject* object = JSObject::cast(args[0]);
+    if (object->HasLocalProperty(key)) return Heap::true_value();
+  } else if (args[0]->IsString()) {
+    // Well, there is one exception:  Handle [] on strings.
+    uint32_t index;
+    if (key->AsArrayIndex(&index)) {
+      String* string = String::cast(args[0]);
+      if (index < static_cast<uint32_t>(string->length()))
+        return Heap::true_value();
+    }
+  }
+  return Heap::false_value();
+}
+
+
+static Object* Runtime_HasProperty(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 2);
+
+  // Only JS objects can have properties.
+  if (args[0]->IsJSObject()) {
+    JSObject* object = JSObject::cast(args[0]);
+    CONVERT_CHECKED(String, key, args[1]);
+    if (object->HasProperty(key)) return Heap::true_value();
+  }
+  return Heap::false_value();
+}
+
+
+static Object* Runtime_HasElement(Arguments args) {
+  NoHandleAllocation na;
+  ASSERT(args.length() == 2);
+
+  // Only JS objects can have elements.
+  if (args[0]->IsJSObject()) {
+    JSObject* object = JSObject::cast(args[0]);
+    CONVERT_CHECKED(Smi, index_obj, args[1]);
+    uint32_t index = index_obj->value();
+    if (object->HasElement(index)) return Heap::true_value();
+  }
+  return Heap::false_value();
+}
+
+
+static Object* Runtime_IsPropertyEnumerable(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(JSObject, object, args[0]);
+  CONVERT_CHECKED(String, key, args[1]);
+
+  uint32_t index;
+  if (key->AsArrayIndex(&index)) {
+    return Heap::ToBoolean(object->HasElement(index));
+  }
+
+  LookupResult result;
+  object->LocalLookup(key, &result);
+  if (!result.IsProperty()) return Heap::false_value();
+  return Heap::ToBoolean(!result.IsDontEnum());
+}
+
+
+static Object* Runtime_GetPropertyNames(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSObject, raw_object, args[0]);
+  Handle<JSObject> object(raw_object);
+  return *GetKeysFor(object);
+}
+
+
+// Returns either a FixedArray as Runtime_GetPropertyNames,
+// or, if the given object has an enum cache that contains
+// all enumerable properties of the object and its prototypes
+// have none, the map of the object. This is used to speed up
+// the check for deletions during a for-in.
+static Object* Runtime_GetPropertyNamesFast(Arguments args) {
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSObject, raw_object, args[0]);
+
+  if (raw_object->IsSimpleEnum()) return raw_object->map();
+
+  HandleScope scope;
+  Handle<JSObject> object(raw_object);
+  Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
+
+  // Test again, since cache may have been built by preceding call.
+  if (object->IsSimpleEnum()) return object->map();
+
+  return *content;
+}
+
+
+static Object* Runtime_GetArgumentsProperty(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  // Compute the frame holding the arguments.
+  JavaScriptFrameIterator it;
+  it.AdvanceToArgumentsFrame();
+  JavaScriptFrame* frame = it.frame();
+
+  // Get the actual number of provided arguments.
+  const uint32_t n = frame->GetProvidedParametersCount();
+
+  // Try to convert the key to an index. If successful and within
+  // index return the the argument from the frame.
+  uint32_t index;
+  if (Array::IndexFromObject(args[0], &index) && index < n) {
+    return frame->GetParameter(index);
+  }
+
+  // Convert the key to a string.
+  HandleScope scope;
+  bool exception = false;
+  Handle<Object> converted =
+      Execution::ToString(args.at<Object>(0), &exception);
+  if (exception) return Failure::Exception();
+  Handle<String> key = Handle<String>::cast(converted);
+
+  // Try to convert the string key into an array index.
+  if (key->AsArrayIndex(&index)) {
+    if (index < n) {
+      return frame->GetParameter(index);
+    } else {
+      return Top::initial_object_prototype()->GetElement(index);
+    }
+  }
+
+  // Handle special arguments properties.
+  if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
+  if (key->Equals(Heap::callee_symbol())) return frame->function();
+
+  // Lookup in the initial Object.prototype object.
+  return Top::initial_object_prototype()->GetProperty(*key);
+}
+
+
+static Object* Runtime_ToBool(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  return args[0]->ToBoolean();
+}
+
+
+// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
+// Possible optimizations: put the type string into the oddballs.
+static Object* Runtime_Typeof(Arguments args) {
+  NoHandleAllocation ha;
+
+  Object* obj = args[0];
+  if (obj->IsNumber()) return Heap::number_symbol();
+  HeapObject* heap_obj = HeapObject::cast(obj);
+
+  // typeof an undetectable object is 'undefined'
+  if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
+
+  InstanceType instance_type = heap_obj->map()->instance_type();
+  if (instance_type < FIRST_NONSTRING_TYPE) {
+    return Heap::string_symbol();
+  }
+
+  switch (instance_type) {
+    case ODDBALL_TYPE:
+      if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
+        return Heap::boolean_symbol();
+      }
+      if (heap_obj->IsNull()) {
+        return Heap::object_symbol();
+      }
+      ASSERT(heap_obj->IsUndefined());
+      return Heap::undefined_symbol();
+    case JS_FUNCTION_TYPE:
+      return Heap::function_symbol();
+    default:
+      // For any kind of object not handled above, the spec rule for
+      // host objects gives that it is okay to return "object"
+      return Heap::object_symbol();
+  }
+}
+
+
+static Object* Runtime_StringToNumber(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(String, subject, args[0]);
+  subject->TryFlatten();
+  return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
+}
+
+
+static Object* Runtime_StringFromCharCodeArray(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSArray, codes, args[0]);
+  int length = Smi::cast(codes->length())->value();
+
+  // Check if the string can be ASCII.
+  int i;
+  for (i = 0; i < length; i++) {
+    Object* element = codes->GetElement(i);
+    CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
+    if ((chr & 0xffff) > String::kMaxAsciiCharCode)
+      break;
+  }
+
+  Object* object = NULL;
+  if (i == length) {  // The string is ASCII.
+    object = Heap::AllocateRawAsciiString(length);
+  } else {  // The string is not ASCII.
+    object = Heap::AllocateRawTwoByteString(length);
+  }
+
+  if (object->IsFailure()) return object;
+  String* result = String::cast(object);
+  for (int i = 0; i < length; i++) {
+    Object* element = codes->GetElement(i);
+    CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
+    result->Set(i, chr & 0xffff);
+  }
+  return result;
+}
+
+
+// kNotEscaped is generated by the following:
+//
+// #!/bin/perl
+// for (my $i = 0; $i < 256; $i++) {
+//   print "\n" if $i % 16 == 0;
+//   my $c = chr($i);
+//   my $escaped = 1;
+//   $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
+//   print $escaped ? "0, " : "1, ";
+// }
+
+
+static bool IsNotEscaped(uint16_t character) {
+  // Only for 8 bit characters, the rest are always escaped (in a different way)
+  ASSERT(character < 256);
+  static const char kNotEscaped[256] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  };
+  return kNotEscaped[character] != 0;
+}
+
+
+static Object* Runtime_URIEscape(Arguments args) {
+  const char hex_chars[] = "0123456789ABCDEF";
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(String, source, args[0]);
+
+  source->TryFlatten();
+
+  int escaped_length = 0;
+  int length = source->length();
+  {
+    Access<StringInputBuffer> buffer(&string_input_buffer);
+    buffer->Reset(source);
+    while (buffer->has_more()) {
+      uint16_t character = buffer->GetNext();
+      if (character >= 256) {
+        escaped_length += 6;
+      } else if (IsNotEscaped(character)) {
+        escaped_length++;
+      } else {
+        escaped_length += 3;
+      }
+      // We don't allow strings that are longer than Smi range.
+      if (!Smi::IsValid(escaped_length)) {
+        Top::context()->mark_out_of_memory();
+        return Failure::OutOfMemoryException();
+      }
+    }
+  }
+  // No length change implies no change.  Return original string if no change.
+  if (escaped_length == length) {
+    return source;
+  }
+  Object* o = Heap::AllocateRawAsciiString(escaped_length);
+  if (o->IsFailure()) return o;
+  String* destination = String::cast(o);
+  int dest_position = 0;
+
+  Access<StringInputBuffer> buffer(&string_input_buffer);
+  buffer->Rewind();
+  while (buffer->has_more()) {
+    uint16_t character = buffer->GetNext();
+    if (character >= 256) {
+      destination->Set(dest_position, '%');
+      destination->Set(dest_position+1, 'u');
+      destination->Set(dest_position+2, hex_chars[character >> 12]);
+      destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
+      destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
+      destination->Set(dest_position+5, hex_chars[character & 0xf]);
+      dest_position += 6;
+    } else if (IsNotEscaped(character)) {
+      destination->Set(dest_position, character);
+      dest_position++;
+    } else {
+      destination->Set(dest_position, '%');
+      destination->Set(dest_position+1, hex_chars[character >> 4]);
+      destination->Set(dest_position+2, hex_chars[character & 0xf]);
+      dest_position += 3;
+    }
+  }
+  return destination;
+}
+
+
+static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
+  static const signed char kHexValue['g'] = {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    0,  1,  2,   3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15 };
+
+  if (character1 > 'f') return -1;
+  int hi = kHexValue[character1];
+  if (hi == -1) return -1;
+  if (character2 > 'f') return -1;
+  int lo = kHexValue[character2];
+  if (lo == -1) return -1;
+  return (hi << 4) + lo;
+}
+
+
+static inline int Unescape(String* source, int i, int length, int* step) {
+  uint16_t character = source->Get(i);
+  int32_t hi, lo;
+  if (character == '%' &&
+      i <= length - 6 &&
+      source->Get(i + 1) == 'u' &&
+      (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
+      (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
+    *step = 6;
+    return (hi << 8) + lo;
+  } else if (character == '%' &&
+      i <= length - 3 &&
+      (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
+    *step = 3;
+    return lo;
+  } else {
+    *step = 1;
+    return character;
+  }
+}
+
+
+static Object* Runtime_URIUnescape(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(String, source, args[0]);
+
+  source->TryFlatten();
+
+  bool ascii = true;
+  int length = source->length();
+
+  int unescaped_length = 0;
+  for (int i = 0; i < length; unescaped_length++) {
+    int step;
+    if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
+      ascii = false;
+    i += step;
+  }
+
+  // No length change implies no change.  Return original string if no change.
+  if (unescaped_length == length)
+    return source;
+
+  Object* o = ascii ?
+              Heap::AllocateRawAsciiString(unescaped_length) :
+              Heap::AllocateRawTwoByteString(unescaped_length);
+  if (o->IsFailure()) return o;
+  String* destination = String::cast(o);
+
+  int dest_position = 0;
+  for (int i = 0; i < length; dest_position++) {
+    int step;
+    destination->Set(dest_position, Unescape(source, i, length, &step));
+    i += step;
+  }
+  return destination;
+}
+
+
+static Object* Runtime_StringParseInt(Arguments args) {
+  NoHandleAllocation ha;
+
+  CONVERT_CHECKED(String, s, args[0]);
+  CONVERT_DOUBLE_CHECKED(n, args[1]);
+  int radix = FastD2I(n);
+
+  s->TryFlatten();
+
+  int len = s->length();
+  int i;
+
+  // Skip leading white space.
+  for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
+  if (i == len) return Heap::nan_value();
+
+  // Compute the sign (default to +).
+  int sign = 1;
+  if (s->Get(i) == '-') {
+    sign = -1;
+    i++;
+  } else if (s->Get(i) == '+') {
+    i++;
+  }
+
+  // Compute the radix if 0.
+  if (radix == 0) {
+    radix = 10;
+    if (i < len && s->Get(i) == '0') {
+      radix = 8;
+      if (i + 1 < len) {
+        int c = s->Get(i + 1);
+        if (c == 'x' || c == 'X') {
+          radix = 16;
+          i += 2;
+        }
+      }
+    }
+  } else if (radix == 16) {
+    // Allow 0x or 0X prefix if radix is 16.
+    if (i + 1 < len && s->Get(i) == '0') {
+      int c = s->Get(i + 1);
+      if (c == 'x' || c == 'X') i += 2;
+    }
+  }
+
+  RUNTIME_ASSERT(2 <= radix && radix <= 36);
+  double value;
+  int end_index = StringToInt(s, i, radix, &value);
+  if (end_index != i) {
+    return Heap::NumberFromDouble(sign * value);
+  }
+  return Heap::nan_value();
+}
+
+
+static Object* Runtime_StringParseFloat(Arguments args) {
+  NoHandleAllocation ha;
+  CONVERT_CHECKED(String, str, args[0]);
+
+  // ECMA-262 section 15.1.2.3, empty string is NaN
+  double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
+
+  // Create a number object from the value.
+  return Heap::NumberFromDouble(value);
+}
+
+
+static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
+static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
+
+
+template <class Converter>
+static Object* ConvertCase(Arguments args,
+                           unibrow::Mapping<Converter, 128>* mapping) {
+  NoHandleAllocation ha;
+
+  CONVERT_CHECKED(String, s, args[0]);
+  int raw_string_length = s->length();
+  // Assume that the string is not empty; we need this assumption later
+  if (raw_string_length == 0) return s;
+  int length = raw_string_length;
+
+  s->TryFlatten();
+
+  // We try this twice, once with the assumption that the result is
+  // no longer than the input and, if that assumption breaks, again
+  // with the exact length.  This is implemented using a goto back
+  // to this label if we discover that the assumption doesn't hold.
+  // I apologize sincerely for this and will give a vaffel-is to
+  // the first person who can implement it in a nicer way.
+ try_convert:
+
+  // Allocate the resulting string.
+  //
+  // NOTE: This assumes that the upper/lower case of an ascii
+  // character is also ascii.  This is currently the case, but it
+  // might break in the future if we implement more context and locale
+  // dependent upper/lower conversions.
+  Object* o = s->IsAsciiRepresentation()
+      ? Heap::AllocateRawAsciiString(length)
+      : Heap::AllocateRawTwoByteString(length);
+  if (o->IsFailure()) return o;
+  String* result = String::cast(o);
+  bool has_changed_character = false;
+
+  // Convert all characters to upper case, assuming that they will fit
+  // in the buffer
+  Access<StringInputBuffer> buffer(&string_input_buffer);
+  buffer->Reset(s);
+  unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
+  int i = 0;
+  // We can assume that the string is not empty
+  uc32 current = buffer->GetNext();
+  while (i < length) {
+    bool has_next = buffer->has_more();
+    uc32 next = has_next ? buffer->GetNext() : 0;
+    int char_length = mapping->get(current, next, chars);
+    if (char_length == 0) {
+      // The case conversion of this character is the character itself.
+      result->Set(i, current);
+      i++;
+    } else if (char_length == 1) {
+      // Common case: converting the letter resulted in one character.
+      ASSERT(static_cast<uc32>(chars[0]) != current);
+      result->Set(i, chars[0]);
+      has_changed_character = true;
+      i++;
+    } else if (length == raw_string_length) {
+      // We've assumed that the result would be as long as the
+      // input but here is a character that converts to several
+      // characters.  No matter, we calculate the exact length
+      // of the result and try the whole thing again.
+      //
+      // Note that this leaves room for optimization.  We could just
+      // memcpy what we already have to the result string.  Also,
+      // the result string is the last object allocated we could
+      // "realloc" it and probably, in the vast majority of cases,
+      // extend the existing string to be able to hold the full
+      // result.
+      int next_length = 0;
+      if (has_next) {
+        next_length = mapping->get(next, 0, chars);
+        if (next_length == 0) next_length = 1;
+      }
+      int current_length = i + char_length + next_length;
+      while (buffer->has_more()) {
+        current = buffer->GetNext();
+        // NOTE: we use 0 as the next character here because, while
+        // the next character may affect what a character converts to,
+        // it does not in any case affect the length of what it convert
+        // to.
+        int char_length = mapping->get(current, 0, chars);
+        if (char_length == 0) char_length = 1;
+        current_length += char_length;
+      }
+      length = current_length;
+      goto try_convert;
+    } else {
+      for (int j = 0; j < char_length; j++) {
+        result->Set(i, chars[j]);
+        i++;
+      }
+      has_changed_character = true;
+    }
+    current = next;
+  }
+  if (has_changed_character) {
+    return result;
+  } else {
+    // If we didn't actually change anything in doing the conversion
+    // we simple return the result and let the converted string
+    // become garbage; there is no reason to keep two identical strings
+    // alive.
+    return s;
+  }
+}
+
+
+static Object* Runtime_StringToLowerCase(Arguments args) {
+  return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
+}
+
+
+static Object* Runtime_StringToUpperCase(Arguments args) {
+  return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
+}
+
+
+static Object* Runtime_ConsStringFst(Arguments args) {
+  NoHandleAllocation ha;
+
+  CONVERT_CHECKED(ConsString, str, args[0]);
+  return str->first();
+}
+
+
+static Object* Runtime_ConsStringSnd(Arguments args) {
+  NoHandleAllocation ha;
+
+  CONVERT_CHECKED(ConsString, str, args[0]);
+  return str->second();
+}
+
+
+static Object* Runtime_NumberToString(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  Object* number = args[0];
+  RUNTIME_ASSERT(number->IsNumber());
+
+  Object* cached = Heap::GetNumberStringCache(number);
+  if (cached != Heap::undefined_value()) {
+    return cached;
+  }
+
+  char arr[100];
+  Vector<char> buffer(arr, ARRAY_SIZE(arr));
+  const char* str;
+  if (number->IsSmi()) {
+    int num = Smi::cast(number)->value();
+    str = IntToCString(num, buffer);
+  } else {
+    double num = HeapNumber::cast(number)->value();
+    str = DoubleToCString(num, buffer);
+  }
+  Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
+
+  if (!result->IsFailure()) {
+    Heap::SetNumberStringCache(number, String::cast(result));
+  }
+  return result;
+}
+
+
+static Object* Runtime_NumberToInteger(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  Object* obj = args[0];
+  if (obj->IsSmi()) return obj;
+  CONVERT_DOUBLE_CHECKED(number, obj);
+  return Heap::NumberFromDouble(DoubleToInteger(number));
+}
+
+
+static Object* Runtime_NumberToJSUint32(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  Object* obj = args[0];
+  if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
+  CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
+  return Heap::NumberFromUint32(number);
+}
+
+
+static Object* Runtime_NumberToJSInt32(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  Object* obj = args[0];
+  if (obj->IsSmi()) return obj;
+  CONVERT_DOUBLE_CHECKED(number, obj);
+  return Heap::NumberFromInt32(DoubleToInt32(number));
+}
+
+
+static Object* Runtime_NumberAdd(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  return Heap::AllocateHeapNumber(x + y);
+}
+
+
+static Object* Runtime_NumberSub(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  return Heap::AllocateHeapNumber(x - y);
+}
+
+
+static Object* Runtime_NumberMul(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  return Heap::AllocateHeapNumber(x * y);
+}
+
+
+static Object* Runtime_NumberUnaryMinus(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(-x);
+}
+
+
+static Object* Runtime_NumberDiv(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  return Heap::NewNumberFromDouble(x / y);
+}
+
+
+static Object* Runtime_NumberMod(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+
+#ifdef WIN32
+  // Workaround MS fmod bugs. ECMA-262 says:
+  // dividend is finite and divisor is an infinity => result equals dividend
+  // dividend is a zero and divisor is nonzero finite => result equals dividend
+  if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
+      !(x == 0 && (y != 0 && isfinite(y))))
+#endif
+  x = fmod(x, y);
+  // NewNumberFromDouble may return a Smi instead of a Number object
+  return Heap::NewNumberFromDouble(x);
+}
+
+
+static Object* Runtime_StringAdd(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(String, str1, args[0]);
+  CONVERT_CHECKED(String, str2, args[1]);
+  int len1 = str1->length();
+  int len2 = str2->length();
+  if (len1 == 0) return str2;
+  if (len2 == 0) return str1;
+  int length_sum = len1 + len2;
+  // Make sure that an out of memory exception is thrown if the length
+  // of the new cons string is too large to fit in a Smi.
+  if (length_sum > Smi::kMaxValue || length_sum < 0) {
+    Top::context()->mark_out_of_memory();
+    return Failure::OutOfMemoryException();
+  }
+  return Heap::AllocateConsString(str1, str2);
+}
+
+
+template<typename sinkchar>
+static inline void StringBuilderConcatHelper(String* special,
+                                             sinkchar* sink,
+                                             FixedArray* fixed_array,
+                                             int array_length) {
+  int position = 0;
+  for (int i = 0; i < array_length; i++) {
+    Object* element = fixed_array->get(i);
+    if (element->IsSmi()) {
+      int len = Smi::cast(element)->value();
+      int pos = len >> 11;
+      len &= 0x7ff;
+      String::WriteToFlat(special, sink + position, pos, pos + len);
+      position += len;
+    } else {
+      String* string = String::cast(element);
+      int element_length = string->length();
+      String::WriteToFlat(string, sink + position, 0, element_length);
+      position += element_length;
+    }
+  }
+}
+
+
+static Object* Runtime_StringBuilderConcat(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+  CONVERT_CHECKED(JSArray, array, args[0]);
+  CONVERT_CHECKED(String, special, args[1]);
+  int special_length = special->length();
+  Object* smi_array_length = array->length();
+  if (!smi_array_length->IsSmi()) {
+    Top::context()->mark_out_of_memory();
+    return Failure::OutOfMemoryException();
+  }
+  int array_length = Smi::cast(smi_array_length)->value();
+  if (!array->HasFastElements()) {
+    return Top::Throw(Heap::illegal_argument_symbol());
+  }
+  FixedArray* fixed_array = FixedArray::cast(array->elements());
+  if (fixed_array->length() < array_length) {
+    array_length = fixed_array->length();
+  }
+
+  if (array_length == 0) {
+    return Heap::empty_string();
+  } else if (array_length == 1) {
+    Object* first = fixed_array->get(0);
+    if (first->IsString()) return first;
+  }
+
+  bool ascii = special->IsAsciiRepresentation();
+  int position = 0;
+  for (int i = 0; i < array_length; i++) {
+    Object* elt = fixed_array->get(i);
+    if (elt->IsSmi()) {
+      int len = Smi::cast(elt)->value();
+      int pos = len >> 11;
+      len &= 0x7ff;
+      if (pos + len > special_length) {
+        return Top::Throw(Heap::illegal_argument_symbol());
+      }
+      position += len;
+    } else if (elt->IsString()) {
+      String* element = String::cast(elt);
+      int element_length = element->length();
+      if (!Smi::IsValid(element_length + position)) {
+        Top::context()->mark_out_of_memory();
+        return Failure::OutOfMemoryException();
+      }
+      position += element_length;
+      if (ascii && !element->IsAsciiRepresentation()) {
+        ascii = false;
+      }
+    } else {
+      return Top::Throw(Heap::illegal_argument_symbol());
+    }
+  }
+
+  int length = position;
+  Object* object;
+
+  if (ascii) {
+    object = Heap::AllocateRawAsciiString(length);
+    if (object->IsFailure()) return object;
+    SeqAsciiString* answer = SeqAsciiString::cast(object);
+    StringBuilderConcatHelper(special,
+                              answer->GetChars(),
+                              fixed_array,
+                              array_length);
+    return answer;
+  } else {
+    object = Heap::AllocateRawTwoByteString(length);
+    if (object->IsFailure()) return object;
+    SeqTwoByteString* answer = SeqTwoByteString::cast(object);
+    StringBuilderConcatHelper(special,
+                              answer->GetChars(),
+                              fixed_array,
+                              array_length);
+    return answer;
+  }
+}
+
+
+static Object* Runtime_NumberOr(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return Heap::NumberFromInt32(x | y);
+}
+
+
+static Object* Runtime_NumberAnd(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return Heap::NumberFromInt32(x & y);
+}
+
+
+static Object* Runtime_NumberXor(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return Heap::NumberFromInt32(x ^ y);
+}
+
+
+static Object* Runtime_NumberNot(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  return Heap::NumberFromInt32(~x);
+}
+
+
+static Object* Runtime_NumberShl(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return Heap::NumberFromInt32(x << (y & 0x1f));
+}
+
+
+static Object* Runtime_NumberShr(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return Heap::NumberFromUint32(x >> (y & 0x1f));
+}
+
+
+static Object* Runtime_NumberSar(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
+}
+
+
+static Object* Runtime_NumberEquals(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
+  if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
+  if (x == y) return Smi::FromInt(EQUAL);
+  Object* result;
+  if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
+    result = Smi::FromInt(EQUAL);
+  } else {
+    result = Smi::FromInt(NOT_EQUAL);
+  }
+  return result;
+}
+
+
+static Object* Runtime_StringEquals(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(String, x, args[0]);
+  CONVERT_CHECKED(String, y, args[1]);
+
+  bool not_equal = !x->Equals(y);
+  // This is slightly convoluted because the value that signifies
+  // equality is 0 and inequality is 1 so we have to negate the result
+  // from String::Equals.
+  ASSERT(not_equal == 0 || not_equal == 1);
+  STATIC_CHECK(EQUAL == 0);
+  STATIC_CHECK(NOT_EQUAL == 1);
+  return Smi::FromInt(not_equal);
+}
+
+
+static Object* Runtime_NumberCompare(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 3);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  if (isnan(x) || isnan(y)) return args[2];
+  if (x == y) return Smi::FromInt(EQUAL);
+  if (isless(x, y)) return Smi::FromInt(LESS);
+  return Smi::FromInt(GREATER);
+}
+
+
+// Compare two Smis as if they were converted to strings and then
+// compared lexicographically.
+static Object* Runtime_SmiLexicographicCompare(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  // Arrays for the individual characters of the two Smis.  Smis are
+  // 31 bit integers and 10 decimal digits are therefore enough.
+  static int x_elms[10];
+  static int y_elms[10];
+
+  // Extract the integer values from the Smis.
+  CONVERT_CHECKED(Smi, x, args[0]);
+  CONVERT_CHECKED(Smi, y, args[1]);
+  int x_value = x->value();
+  int y_value = y->value();
+
+  // If the integers are equal so are the string representations.
+  if (x_value == y_value) return Smi::FromInt(EQUAL);
+
+  // If one of the integers are zero the normal integer order is the
+  // same as the lexicographic order of the string representations.
+  if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
+
+  // If only one of the intergers is negative the negative number is
+  // smallest because the char code of '-' is less than the char code
+  // of any digit.  Otherwise, we make both values positive.
+  if (x_value < 0 || y_value < 0) {
+    if (y_value >= 0) return Smi::FromInt(LESS);
+    if (x_value >= 0) return Smi::FromInt(GREATER);
+    x_value = -x_value;
+    y_value = -y_value;
+  }
+
+  // Convert the integers to arrays of their decimal digits.
+  int x_index = 0;
+  int y_index = 0;
+  while (x_value > 0) {
+    x_elms[x_index++] = x_value % 10;
+    x_value /= 10;
+  }
+  while (y_value > 0) {
+    y_elms[y_index++] = y_value % 10;
+    y_value /= 10;
+  }
+
+  // Loop through the arrays of decimal digits finding the first place
+  // where they differ.
+  while (--x_index >= 0 && --y_index >= 0) {
+    int diff = x_elms[x_index] - y_elms[y_index];
+    if (diff != 0) return Smi::FromInt(diff);
+  }
+
+  // If one array is a suffix of the other array, the longest array is
+  // the representation of the largest of the Smis in the
+  // lexicographic ordering.
+  return Smi::FromInt(x_index - y_index);
+}
+
+
+static Object* Runtime_StringCompare(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_CHECKED(String, x, args[0]);
+  CONVERT_CHECKED(String, y, args[1]);
+
+  // A few fast case tests before we flatten.
+  if (x == y) return Smi::FromInt(EQUAL);
+  if (y->length() == 0) {
+    if (x->length() == 0) return Smi::FromInt(EQUAL);
+    return Smi::FromInt(GREATER);
+  } else if (x->length() == 0) {
+    return Smi::FromInt(LESS);
+  }
+
+  int d = x->Get(0) - y->Get(0);
+  if (d < 0) return Smi::FromInt(LESS);
+  else if (d > 0) return Smi::FromInt(GREATER);
+
+  x->TryFlatten();
+  y->TryFlatten();
+
+  static StringInputBuffer bufx;
+  static StringInputBuffer bufy;
+  bufx.Reset(x);
+  bufy.Reset(y);
+  while (bufx.has_more() && bufy.has_more()) {
+    int d = bufx.GetNext() - bufy.GetNext();
+    if (d < 0) return Smi::FromInt(LESS);
+    else if (d > 0) return Smi::FromInt(GREATER);
+  }
+
+  // x is (non-trivial) prefix of y:
+  if (bufy.has_more()) return Smi::FromInt(LESS);
+  // y is prefix of x:
+  return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
+}
+
+
+static Object* Runtime_Math_abs(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(fabs(x));
+}
+
+
+static Object* Runtime_Math_acos(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(acos(x));
+}
+
+
+static Object* Runtime_Math_asin(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(asin(x));
+}
+
+
+static Object* Runtime_Math_atan(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(atan(x));
+}
+
+
+static Object* Runtime_Math_atan2(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  double result;
+  if (isinf(x) && isinf(y)) {
+    // Make sure that the result in case of two infinite arguments
+    // is a multiple of Pi / 4. The sign of the result is determined
+    // by the first argument (x) and the sign of the second argument
+    // determines the multiplier: one or three.
+    static double kPiDividedBy4 = 0.78539816339744830962;
+    int multiplier = (x < 0) ? -1 : 1;
+    if (y < 0) multiplier *= 3;
+    result = multiplier * kPiDividedBy4;
+  } else {
+    result = atan2(x, y);
+  }
+  return Heap::AllocateHeapNumber(result);
+}
+
+
+static Object* Runtime_Math_ceil(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::NumberFromDouble(ceiling(x));
+}
+
+
+static Object* Runtime_Math_cos(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(cos(x));
+}
+
+
+static Object* Runtime_Math_exp(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(exp(x));
+}
+
+
+static Object* Runtime_Math_floor(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::NumberFromDouble(floor(x));
+}
+
+
+static Object* Runtime_Math_log(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(log(x));
+}
+
+
+static Object* Runtime_Math_pow(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 2);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  CONVERT_DOUBLE_CHECKED(y, args[1]);
+  if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
+    return Heap::nan_value();
+  } else if (y == 0) {
+    return Smi::FromInt(1);
+  } else {
+    return Heap::AllocateHeapNumber(pow(x, y));
+  }
+}
+
+// Returns a number value with positive sign, greater than or equal to
+// 0 but less than 1, chosen randomly.
+static Object* Runtime_Math_random(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 0);
+
+  // To get much better precision, we combine the results of two
+  // invocations of random(). The result is computed by normalizing a
+  // double in the range [0, RAND_MAX + 1) obtained by adding the
+  // high-order bits in the range [0, RAND_MAX] with the low-order
+  // bits in the range [0, 1).
+  double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
+  double hi = static_cast<double>(random());
+  double result = (hi + lo) / (RAND_MAX + 1.0);
+  ASSERT(result >= 0 && result < 1);
+  return Heap::AllocateHeapNumber(result);
+}
+
+
+static Object* Runtime_Math_round(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
+  return Heap::NumberFromDouble(floor(x + 0.5));
+}
+
+
+static Object* Runtime_Math_sin(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(sin(x));
+}
+
+
+static Object* Runtime_Math_sqrt(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(sqrt(x));
+}
+
+
+static Object* Runtime_Math_tan(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::AllocateHeapNumber(tan(x));
+}
+
+
+// The NewArguments function is only used when constructing the
+// arguments array when calling non-functions from JavaScript in
+// runtime.js:CALL_NON_FUNCTION.
+static Object* Runtime_NewArguments(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  // ECMA-262, 3rd., 10.1.8, p.39
+  CONVERT_CHECKED(JSFunction, callee, args[0]);
+
+  // Compute the frame holding the arguments.
+  JavaScriptFrameIterator it;
+  it.AdvanceToArgumentsFrame();
+  JavaScriptFrame* frame = it.frame();
+
+  const int length = frame->GetProvidedParametersCount();
+  Object* result = Heap::AllocateArgumentsObject(callee, length);
+  if (result->IsFailure()) return result;
+  if (length > 0) {
+    Object* obj =  Heap::AllocateFixedArray(length);
+    if (obj->IsFailure()) return obj;
+    FixedArray* array = FixedArray::cast(obj);
+    ASSERT(array->length() == length);
+    WriteBarrierMode mode = array->GetWriteBarrierMode();
+    for (int i = 0; i < length; i++) {
+      array->set(i, frame->GetParameter(i), mode);
+    }
+    JSObject::cast(result)->set_elements(array);
+  }
+  return result;
+}
+
+
+static Object* Runtime_NewArgumentsFast(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 3);
+
+  JSFunction* callee = JSFunction::cast(args[0]);
+  Object** parameters = reinterpret_cast<Object**>(args[1]);
+  const int length = Smi::cast(args[2])->value();
+
+  Object* result = Heap::AllocateArgumentsObject(callee, length);
+  if (result->IsFailure()) return result;
+  ASSERT(Heap::InNewSpace(result));
+
+  // Allocate the elements if needed.
+  if (length > 0) {
+    // Allocate the fixed array.
+    Object* obj = Heap::AllocateRawFixedArray(length);
+    if (obj->IsFailure()) return obj;
+    reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
+    FixedArray* array = FixedArray::cast(obj);
+    array->set_length(length);
+    WriteBarrierMode mode = array->GetWriteBarrierMode();
+    for (int i = 0; i < length; i++) {
+      array->set(i, *--parameters, mode);
+    }
+    JSObject::cast(result)->set_elements(FixedArray::cast(obj),
+                                         SKIP_WRITE_BARRIER);
+  }
+  return result;
+}
+
+
+static Object* Runtime_NewClosure(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+  CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
+  CONVERT_ARG_CHECKED(Context, context, 1);
+
+  Handle<JSFunction> result =
+      Factory::NewFunctionFromBoilerplate(boilerplate, context);
+  return *result;
+}
+
+
+static Object* Runtime_NewObject(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  Object* constructor = args[0];
+  if (constructor->IsJSFunction()) {
+    JSFunction* function = JSFunction::cast(constructor);
+
+    // Handle steping into constructors.
+    if (Debug::StepInActive()) {
+      StackFrameIterator it;
+      it.Advance();
+      ASSERT(it.frame()->is_construct());
+      it.Advance();
+      if (it.frame()->fp() == Debug::step_in_fp()) {
+        HandleScope scope;
+        Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
+      }
+    }
+
+    if (function->has_initial_map() &&
+        function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
+      // The 'Function' function ignores the receiver object when
+      // called using 'new' and creates a new JSFunction object that
+      // is returned.  The receiver object is only used for error
+      // reporting if an error occurs when constructing the new
+      // JSFunction.  AllocateJSObject should not be used to allocate
+      // JSFunctions since it does not properly initialize the shared
+      // part of the function.  Since the receiver is ignored anyway,
+      // we use the global object as the receiver instead of a new
+      // JSFunction object.  This way, errors are reported the same
+      // way whether or not 'Function' is called using 'new'.
+      return Top::context()->global();
+    }
+    return Heap::AllocateJSObject(function);
+  }
+
+  HandleScope scope;
+  Handle<Object> cons(constructor);
+  // The constructor is not a function; throw a type error.
+  Handle<Object> type_error =
+    Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
+  return Top::Throw(*type_error);
+}
+
+
+static Object* Runtime_LazyCompile(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  Handle<JSFunction> function = args.at<JSFunction>(0);
+#ifdef DEBUG
+  if (FLAG_trace_lazy) {
+    PrintF("[lazy: ");
+    function->shared()->name()->Print();
+    PrintF("]\n");
+  }
+#endif
+
+  // Compile the target function.
+  ASSERT(!function->is_compiled());
+  if (!CompileLazy(function, KEEP_EXCEPTION)) {
+    return Failure::Exception();
+  }
+
+  return function->code();
+}
+
+
+static Object* Runtime_GetCalledFunction(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 0);
+  StackFrameIterator it;
+  // Get past the JS-to-C exit frame.
+  ASSERT(it.frame()->is_exit());
+  it.Advance();
+  // Get past the CALL_NON_FUNCTION activation frame.
+  ASSERT(it.frame()->is_java_script());
+  it.Advance();
+  // Argument adaptor frames do not copy the function; we have to skip
+  // past them to get to the real calling frame.
+  if (it.frame()->is_arguments_adaptor()) it.Advance();
+  // Get the function from the top of the expression stack of the
+  // calling frame.
+  StandardFrame* frame = StandardFrame::cast(it.frame());
+  int index = frame->ComputeExpressionsCount() - 1;
+  Object* result = frame->GetExpression(index);
+  return result;
+}
+
+
+static Object* Runtime_GetFunctionDelegate(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  RUNTIME_ASSERT(!args[0]->IsJSFunction());
+  return *Execution::GetFunctionDelegate(args.at<Object>(0));
+}
+
+
+static Object* Runtime_NewContext(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSFunction, function, args[0]);
+  int length = ScopeInfo<>::NumberOfContextSlots(function->code());
+  Object* result = Heap::AllocateFunctionContext(length, function);
+  if (result->IsFailure()) return result;
+
+  Top::set_context(Context::cast(result));
+
+  return result;  // non-failure
+}
+
+
+static Object* Runtime_PushContext(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  // Convert the object to a proper JavaScript object.
+  Object* object = args[0];
+  if (!object->IsJSObject()) {
+    object = object->ToObject();
+    if (object->IsFailure()) {
+      if (!Failure::cast(object)->IsInternalError()) return object;
+      HandleScope scope;
+      Handle<Object> handle(args[0]);
+      Handle<Object> result =
+          Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
+      return Top::Throw(*result);
+    }
+  }
+
+  Object* result =
+      Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
+  if (result->IsFailure()) return result;
+
+  Top::set_context(Context::cast(result));
+
+  return result;
+}
+
+
+static Object* Runtime_LookupContext(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+
+  CONVERT_ARG_CHECKED(Context, context, 0);
+  CONVERT_ARG_CHECKED(String, name, 1);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = FOLLOW_CHAINS;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes);
+
+  if (index < 0 && !holder.is_null()) {
+    ASSERT(holder->IsJSObject());
+    return *holder;
+  }
+
+  // No intermediate context found. Use global object by default.
+  return Top::context()->global();
+}
+
+
+// A mechanism to return pairs of Object*'s. This is somewhat
+// compiler-dependent as it assumes that a 64-bit value (a long long)
+// is returned via two registers (edx:eax on ia32). Both the ia32 and
+// arm platform support this; it is mostly an issue of "coaxing" the
+// compiler to do the right thing.
+//
+// TODO(1236026): This is a non-portable hack that should be removed.
+typedef uint64_t ObjectPair;
+static inline ObjectPair MakePair(Object* x, Object* y) {
+  return reinterpret_cast<uint32_t>(x) |
+      (reinterpret_cast<ObjectPair>(y) << 32);
+}
+
+
+static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
+  ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
+  USE(attributes);
+  return x->IsTheHole() ? Heap::undefined_value() : x;
+}
+
+
+static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
+  ASSERT(!holder->IsGlobalObject());
+  Context* top = Top::context();
+  // Get the context extension function.
+  JSFunction* context_extension_function =
+      top->global_context()->context_extension_function();
+  // If the holder isn't a context extension object, we just return it
+  // as the receiver. This allows arguments objects to be used as
+  // receivers, but only if they are put in the context scope chain
+  // explicitly via a with-statement.
+  Object* constructor = holder->map()->constructor();
+  if (constructor != context_extension_function) return holder;
+  // Fall back to using the global object as the receiver if the
+  // property turns out to be a local variable allocated in a context
+  // extension object - introduced via eval.
+  return top->global()->global_receiver();
+}
+
+
+static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+
+  if (!args[0]->IsContext() || !args[1]->IsString()) {
+    return MakePair(IllegalOperation(), NULL);
+  }
+  Handle<Context> context = args.at<Context>(0);
+  Handle<String> name = args.at<String>(1);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = FOLLOW_CHAINS;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes);
+
+  // If the index is non-negative, the slot has been found in a local
+  // variable or a parameter. Read it from the context object or the
+  // arguments object.
+  if (index >= 0) {
+    // If the "property" we were looking for is a local variable or an
+    // argument in a context, the receiver is the global object; see
+    // ECMA-262, 3rd., 10.1.6 and 10.2.3.
+    JSObject* receiver = Top::context()->global()->global_receiver();
+    Object* value = (holder->IsContext())
+        ? Context::cast(*holder)->get(index)
+        : JSObject::cast(*holder)->GetElement(index);
+    return MakePair(Unhole(value, attributes), receiver);
+  }
+
+  // If the holder is found, we read the property from it.
+  if (!holder.is_null() && holder->IsJSObject()) {
+    JSObject* object = JSObject::cast(*holder);
+    ASSERT(object->HasProperty(*name));
+    JSObject* receiver = (object->IsGlobalObject())
+        ? GlobalObject::cast(object)->global_receiver()
+        : ComputeReceiverForNonGlobal(object);
+    // No need to unhole the value here. This is taken care of by the
+    // GetProperty function.
+    Object* value = object->GetProperty(*name);
+    return MakePair(value, receiver);
+  }
+
+  if (throw_error) {
+    // The property doesn't exist - throw exception.
+    Handle<Object> reference_error =
+        Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
+    return MakePair(Top::Throw(*reference_error), NULL);
+  } else {
+    // The property doesn't exist - return undefined
+    return MakePair(Heap::undefined_value(), Heap::undefined_value());
+  }
+}
+
+
+static ObjectPair Runtime_LoadContextSlot(Arguments args) {
+  return LoadContextSlotHelper(args, true);
+}
+
+
+static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
+  return LoadContextSlotHelper(args, false);
+}
+
+
+static Object* Runtime_StoreContextSlot(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+
+  Handle<Object> value(args[0]);
+  CONVERT_ARG_CHECKED(Context, context, 1);
+  CONVERT_ARG_CHECKED(String, name, 2);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = FOLLOW_CHAINS;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes);
+
+  if (index >= 0) {
+    if (holder->IsContext()) {
+      // Ignore if read_only variable.
+      if ((attributes & READ_ONLY) == 0) {
+        Handle<Context>::cast(holder)->set(index, *value);
+      }
+    } else {
+      ASSERT((attributes & READ_ONLY) == 0);
+      Object* result =
+          Handle<JSObject>::cast(holder)->SetElement(index, *value);
+      USE(result);
+      ASSERT(!result->IsFailure());
+    }
+    return *value;
+  }
+
+  // Slow case: The property is not in a FixedArray context.
+  // It is either in an JSObject extension context or it was not found.
+  Handle<JSObject> context_ext;
+
+  if (!holder.is_null()) {
+    // The property exists in the extension context.
+    context_ext = Handle<JSObject>::cast(holder);
+  } else {
+    // The property was not found. It needs to be stored in the global context.
+    ASSERT(attributes == ABSENT);
+    attributes = NONE;
+    context_ext = Handle<JSObject>(Top::context()->global());
+  }
+
+  // Set the property, but ignore if read_only variable.
+  if ((attributes & READ_ONLY) == 0) {
+    Handle<Object> set = SetProperty(context_ext, name, value, attributes);
+    if (set.is_null()) {
+      // Failure::Exception is converted to a null handle in the
+      // handle-based methods such as SetProperty.  We therefore need
+      // to convert null handles back to exceptions.
+      ASSERT(Top::has_pending_exception());
+      return Failure::Exception();
+    }
+  }
+  return *value;
+}
+
+
+static Object* Runtime_Throw(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  return Top::Throw(args[0]);
+}
+
+
+static Object* Runtime_ReThrow(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  return Top::ReThrow(args[0]);
+}
+
+
+static Object* Runtime_ThrowReferenceError(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  Handle<Object> name(args[0]);
+  Handle<Object> reference_error =
+    Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
+  return Top::Throw(*reference_error);
+}
+
+
+static Object* Runtime_StackOverflow(Arguments args) {
+  NoHandleAllocation na;
+  return Top::StackOverflow();
+}
+
+
+static Object* RuntimePreempt(Arguments args) {
+  // Clear the preempt request flag.
+  StackGuard::Continue(PREEMPT);
+
+  ContextSwitcher::PreemptionReceived();
+
+  {
+    v8::Unlocker unlocker;
+    Thread::YieldCPU();
+  }
+
+  return Heap::undefined_value();
+}
+
+
+static Object* DebugBreakHelper() {
+  // Just continue if breaks are disabled.
+  if (Debug::disable_break()) {
+    return Heap::undefined_value();
+  }
+
+  // Don't break in system functions. If the current function is
+  // either in the builtins object of some context or is in the debug
+  // context just return with the debug break stack guard active.
+  JavaScriptFrameIterator it;
+  JavaScriptFrame* frame = it.frame();
+  Object* fun = frame->function();
+  if (fun->IsJSFunction()) {
+    GlobalObject* global = JSFunction::cast(fun)->context()->global();
+    if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
+      return Heap::undefined_value();
+    }
+  }
+
+  // Clear the debug request flag.
+  StackGuard::Continue(DEBUGBREAK);
+
+  HandleScope scope;
+  // Enter the debugger. Just continue if we fail to enter the debugger.
+  EnterDebugger debugger;
+  if (debugger.FailedToEnter()) {
+    return Heap::undefined_value();
+  }
+
+  // Notify the debug event listeners.
+  Debugger::OnDebugBreak(Factory::undefined_value());
+
+  // Return to continue execution.
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_DebugBreak(Arguments args) {
+  ASSERT(args.length() == 0);
+  return DebugBreakHelper();
+}
+
+
+static Object* Runtime_StackGuard(Arguments args) {
+  ASSERT(args.length() == 1);
+
+  // First check if this is a real stack overflow.
+  if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
+
+  // If not real stack overflow the stack guard was used to interrupt
+  // execution for another purpose.
+  if (StackGuard::IsDebugBreak()) DebugBreakHelper();
+  if (StackGuard::IsPreempted()) RuntimePreempt(args);
+  if (StackGuard::IsInterrupted()) {
+    // interrupt
+    StackGuard::Continue(INTERRUPT);
+    return Top::StackOverflow();
+  }
+  return Heap::undefined_value();
+}
+
+
+// NOTE: These PrintXXX functions are defined for all builds (not just
+// DEBUG builds) because we may want to be able to trace function
+// calls in all modes.
+static void PrintString(String* str) {
+  // not uncommon to have empty strings
+  if (str->length() > 0) {
+    SmartPointer<char> s =
+        str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+    PrintF("%s", *s);
+  }
+}
+
+
+static void PrintObject(Object* obj) {
+  if (obj->IsSmi()) {
+    PrintF("%d", Smi::cast(obj)->value());
+  } else if (obj->IsString() || obj->IsSymbol()) {
+    PrintString(String::cast(obj));
+  } else if (obj->IsNumber()) {
+    PrintF("%g", obj->Number());
+  } else if (obj->IsFailure()) {
+    PrintF("<failure>");
+  } else if (obj->IsUndefined()) {
+    PrintF("<undefined>");
+  } else if (obj->IsNull()) {
+    PrintF("<null>");
+  } else if (obj->IsTrue()) {
+    PrintF("<true>");
+  } else if (obj->IsFalse()) {
+    PrintF("<false>");
+  } else {
+    PrintF("%p", obj);
+  }
+}
+
+
+static int StackSize() {
+  int n = 0;
+  for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
+  return n;
+}
+
+
+static void PrintTransition(Object* result) {
+  // indentation
+  { const int nmax = 80;
+    int n = StackSize();
+    if (n <= nmax)
+      PrintF("%4d:%*s", n, n, "");
+    else
+      PrintF("%4d:%*s", n, nmax, "...");
+  }
+
+  if (result == NULL) {
+    // constructor calls
+    JavaScriptFrameIterator it;
+    JavaScriptFrame* frame = it.frame();
+    if (frame->IsConstructor()) PrintF("new ");
+    // function name
+    Object* fun = frame->function();
+    if (fun->IsJSFunction()) {
+      PrintObject(JSFunction::cast(fun)->shared()->name());
+    } else {
+      PrintObject(fun);
+    }
+    // function arguments
+    // (we are intentionally only printing the actually
+    // supplied parameters, not all parameters required)
+    PrintF("(this=");
+    PrintObject(frame->receiver());
+    const int length = frame->GetProvidedParametersCount();
+    for (int i = 0; i < length; i++) {
+      PrintF(", ");
+      PrintObject(frame->GetParameter(i));
+    }
+    PrintF(") {\n");
+
+  } else {
+    // function result
+    PrintF("} -> ");
+    PrintObject(result);
+    PrintF("\n");
+  }
+}
+
+
+static Object* Runtime_TraceEnter(Arguments args) {
+  ASSERT(args.length() == 0);
+  NoHandleAllocation ha;
+  PrintTransition(NULL);
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_TraceExit(Arguments args) {
+  NoHandleAllocation ha;
+  PrintTransition(args[0]);
+  return args[0];  // return TOS
+}
+
+
+static Object* Runtime_DebugPrint(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+#ifdef DEBUG
+  if (args[0]->IsString()) {
+    // If we have a string, assume it's a code "marker"
+    // and print some interesting cpu debugging info.
+    JavaScriptFrameIterator it;
+    JavaScriptFrame* frame = it.frame();
+    PrintF("fp = %p, sp = %p, pp = %p: ",
+           frame->fp(), frame->sp(), frame->pp());
+  } else {
+    PrintF("DebugPrint: ");
+  }
+  args[0]->Print();
+#else
+  // ShortPrint is available in release mode. Print is not.
+  args[0]->ShortPrint();
+#endif
+  PrintF("\n");
+  Flush();
+
+  return args[0];  // return TOS
+}
+
+
+static Object* Runtime_DebugTrace(Arguments args) {
+  ASSERT(args.length() == 0);
+  NoHandleAllocation ha;
+  Top::PrintStack();
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_DateCurrentTime(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 0);
+
+  // According to ECMA-262, section 15.9.1, page 117, the precision of
+  // the number in a Date object representing a particular instant in
+  // time is milliseconds. Therefore, we floor the result of getting
+  // the OS time.
+  double millis = floor(OS::TimeCurrentMillis());
+  return Heap::NumberFromDouble(millis);
+}
+
+
+static Object* Runtime_DateParseString(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(String, string_object, args[0]);
+
+  Handle<String> str(string_object);
+  Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
+  if (DateParser::Parse(*str, *output)) {
+    return *Factory::NewJSArrayWithElements(output);
+  } else {
+    return *Factory::null_value();
+  }
+}
+
+
+static Object* Runtime_DateLocalTimezone(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  char* zone = OS::LocalTimezone(x);
+  return Heap::AllocateStringFromUtf8(CStrVector(zone));
+}
+
+
+static Object* Runtime_DateLocalTimeOffset(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 0);
+
+  return Heap::NumberFromDouble(OS::LocalTimeOffset());
+}
+
+
+static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(x, args[0]);
+  return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
+}
+
+
+static Object* Runtime_NumberIsFinite(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(value, args[0]);
+  Object* result;
+  if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
+    result = Heap::false_value();
+  } else {
+    result = Heap::true_value();
+  }
+  return result;
+}
+
+
+static Object* EvalContext() {
+  // The topmost JS frame belongs to the eval function which called
+  // the CompileString runtime function. We need to unwind one level
+  // to get to the caller of eval.
+  StackFrameLocator locator;
+  JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
+
+  // TODO(900055): Right now we check if the caller of eval() supports
+  // eval to determine if it's an aliased eval or not. This may not be
+  // entirely correct in the unlikely case where a function uses both
+  // aliased and direct eval calls.
+  HandleScope scope;
+  if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
+    // Aliased eval: Evaluate in the global context of the eval
+    // function to support aliased, cross environment evals.
+    return *Top::global_context();
+  }
+
+  // Fetch the caller context from the frame.
+  Handle<Context> caller(Context::cast(frame->context()));
+
+  // Check for eval() invocations that cross environments. Use the
+  // context from the stack if evaluating in current environment.
+  Handle<Context> target = Top::global_context();
+  if (caller->global_context() == *target) return *caller;
+
+  // Compute a function closure that captures the calling context. We
+  // need a function that has trivial scope info, since it is only
+  // used to hold the context chain together.
+  Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
+                                                    Factory::undefined_value());
+  closure->set_context(*caller);
+
+  // Create a new adaptor context that has the target environment as
+  // the extension object. This enables the evaluated code to see both
+  // the current context with locals and everything and to see global
+  // variables declared in the target global object. Furthermore, any
+  // properties introduced with 'var' will be added to the target
+  // global object because it is the extension object.
+  Handle<Context> adaptor =
+    Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
+  adaptor->set_extension(target->global());
+  return *adaptor;
+}
+
+
+static Object* Runtime_EvalReceiver(Arguments args) {
+  StackFrameLocator locator;
+  return locator.FindJavaScriptFrame(1)->receiver();
+}
+
+
+static Object* Runtime_GlobalReceiver(Arguments args) {
+  ASSERT(args.length() == 1);
+  Object* global = args[0];
+  if (!global->IsJSGlobalObject()) return Heap::null_value();
+  return JSGlobalObject::cast(global)->global_receiver();
+}
+
+
+static Object* Runtime_CompileString(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  CONVERT_ARG_CHECKED(String, source, 0);
+  CONVERT_ARG_CHECKED(Smi, line_offset, 1);
+  bool contextual = args[2]->IsTrue();
+  RUNTIME_ASSERT(contextual || args[2]->IsFalse());
+
+  // Compute the eval context.
+  Handle<Context> context;
+  if (contextual) {
+    // Get eval context. May not be available if we are calling eval
+    // through an alias, and the corresponding frame doesn't have a
+    // proper eval context set up.
+    Object* eval_context = EvalContext();
+    if (eval_context->IsFailure()) return eval_context;
+    context = Handle<Context>(Context::cast(eval_context));
+  } else {
+    context = Handle<Context>(Top::context()->global_context());
+  }
+
+
+  // Compile source string.
+  bool is_global = context->IsGlobalContext();
+  Handle<JSFunction> boilerplate =
+      Compiler::CompileEval(source, line_offset->value(), is_global);
+  if (boilerplate.is_null()) return Failure::Exception();
+  Handle<JSFunction> fun =
+      Factory::NewFunctionFromBoilerplate(boilerplate, context);
+  return *fun;
+}
+
+
+static Object* Runtime_CompileScript(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 4);
+
+  CONVERT_ARG_CHECKED(String, source, 0);
+  CONVERT_ARG_CHECKED(String, script, 1);
+  CONVERT_CHECKED(Smi, line_attrs, args[2]);
+  int line = line_attrs->value();
+  CONVERT_CHECKED(Smi, col_attrs, args[3]);
+  int col = col_attrs->value();
+  Handle<JSFunction> boilerplate =
+      Compiler::Compile(source, script, line, col, NULL, NULL);
+  if (boilerplate.is_null()) return Failure::Exception();
+  Handle<JSFunction> fun =
+      Factory::NewFunctionFromBoilerplate(boilerplate,
+                                          Handle<Context>(Top::context()));
+  return *fun;
+}
+
+
+static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
+  // This utility adjusts the property attributes for newly created Function
+  // object ("new Function(...)") by changing the map.
+  // All it does is changing the prototype property to enumerable
+  // as specified in ECMA262, 15.3.5.2.
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, func, 0);
+  ASSERT(func->map()->instance_type() ==
+         Top::function_instance_map()->instance_type());
+  ASSERT(func->map()->instance_size() ==
+         Top::function_instance_map()->instance_size());
+  func->set_map(*Top::function_instance_map());
+  return *func;
+}
+
+
+// Push an array unto an array of arrays if it is not already in the
+// array.  Returns true if the element was pushed on the stack and
+// false otherwise.
+static Object* Runtime_PushIfAbsent(Arguments args) {
+  ASSERT(args.length() == 2);
+  CONVERT_CHECKED(JSArray, array, args[0]);
+  CONVERT_CHECKED(JSArray, element, args[1]);
+  RUNTIME_ASSERT(array->HasFastElements());
+  int length = Smi::cast(array->length())->value();
+  FixedArray* elements = FixedArray::cast(array->elements());
+  for (int i = 0; i < length; i++) {
+    if (elements->get(i) == element) return Heap::false_value();
+  }
+  Object* obj = array->SetFastElement(length, element);
+  if (obj->IsFailure()) return obj;
+  return Heap::true_value();
+}
+
+
+// This will not allocate (flatten the string), but it may run
+// very slowly for very deeply nested ConsStrings.  For debugging use only.
+static Object* Runtime_GlobalPrint(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(String, string, args[0]);
+  StringInputBuffer buffer(string);
+  while (buffer.has_more()) {
+    uint16_t character = buffer.GetNext();
+    PrintF("%c", character);
+  }
+  return string;
+}
+
+
+static Object* Runtime_RemoveArrayHoles(Arguments args) {
+  ASSERT(args.length() == 1);
+  // Ignore the case if this is not a JSArray.
+  if (!args[0]->IsJSArray()) return args[0];
+  return JSArray::cast(args[0])->RemoveHoles();
+}
+
+
+// Move contents of argument 0 (an array) to argument 1 (an array)
+static Object* Runtime_MoveArrayContents(Arguments args) {
+  ASSERT(args.length() == 2);
+  CONVERT_CHECKED(JSArray, from, args[0]);
+  CONVERT_CHECKED(JSArray, to, args[1]);
+  to->SetContent(FixedArray::cast(from->elements()));
+  to->set_length(from->length());
+  from->SetContent(Heap::empty_fixed_array());
+  from->set_length(0);
+  return to;
+}
+
+
+// How many elements does this array have?
+static Object* Runtime_EstimateNumberOfElements(Arguments args) {
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(JSArray, array, args[0]);
+  HeapObject* elements = array->elements();
+  if (elements->IsDictionary()) {
+    return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
+  } else {
+    return array->length();
+  }
+}
+
+
+// Returns an array that tells you where in the [0, length) interval an array
+// might have elements.  Can either return keys or intervals.  Keys can have
+// gaps in (undefined).  Intervals can also span over some undefined keys.
+static Object* Runtime_GetArrayKeys(Arguments args) {
+  ASSERT(args.length() == 2);
+  HandleScope scope;
+  CONVERT_CHECKED(JSArray, raw_array, args[0]);
+  Handle<JSArray> array(raw_array);
+  CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
+  if (array->elements()->IsDictionary()) {
+    // Create an array and get all the keys into it, then remove all the
+    // keys that are not integers in the range 0 to length-1.
+    Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
+    int keys_length = keys->length();
+    for (int i = 0; i < keys_length; i++) {
+      Object* key = keys->get(i);
+      uint32_t index;
+      if (!Array::IndexFromObject(key, &index) || index >= length) {
+        // Zap invalid keys.
+        keys->set_undefined(i);
+      }
+    }
+    return *Factory::NewJSArrayWithElements(keys);
+  } else {
+    Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
+    // -1 means start of array.
+    single_interval->set(0,
+                         Smi::FromInt(-1),
+                         SKIP_WRITE_BARRIER);
+    Handle<Object> length_object =
+        Factory::NewNumber(static_cast<double>(length));
+    single_interval->set(1, *length_object);
+    return *Factory::NewJSArrayWithElements(single_interval);
+  }
+}
+
+
+// DefineAccessor takes an optional final argument which is the
+// property attributes (eg, DONT_ENUM, DONT_DELETE).  IMPORTANT: due
+// to the way accessors are implemented, it is set for both the getter
+// and setter on the first call to DefineAccessor and ignored on
+// subsequent calls.
+static Object* Runtime_DefineAccessor(Arguments args) {
+  RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
+  // Compute attributes.
+  PropertyAttributes attributes = NONE;
+  if (args.length() == 5) {
+    CONVERT_CHECKED(Smi, attrs, args[4]);
+    int value = attrs->value();
+    // Only attribute bits should be set.
+    ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+    attributes = static_cast<PropertyAttributes>(value);
+  }
+
+  CONVERT_CHECKED(JSObject, obj, args[0]);
+  CONVERT_CHECKED(String, name, args[1]);
+  CONVERT_CHECKED(Smi, flag, args[2]);
+  CONVERT_CHECKED(JSFunction, fun, args[3]);
+  return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
+}
+
+
+static Object* Runtime_LookupAccessor(Arguments args) {
+  ASSERT(args.length() == 3);
+  CONVERT_CHECKED(JSObject, obj, args[0]);
+  CONVERT_CHECKED(String, name, args[1]);
+  CONVERT_CHECKED(Smi, flag, args[2]);
+  return obj->LookupAccessor(name, flag->value() == 0);
+}
+
+
+// Helper functions for wrapping and unwrapping stack frame ids.
+static Smi* WrapFrameId(StackFrame::Id id) {
+  ASSERT(IsAligned(OffsetFrom(id), 4));
+  return Smi::FromInt(id >> 2);
+}
+
+
+static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
+  return static_cast<StackFrame::Id>(wrapped->value() << 2);
+}
+
+
+// Adds a JavaScript function as a debug event listener.
+// args[0]: debug event listener function
+// args[1]: object supplied during callback
+static Object* Runtime_AddDebugEventListener(Arguments args) {
+  ASSERT(args.length() == 2);
+  // Convert the parameters to API objects to call the API function for adding
+  // a JavaScript function as debug event listener.
+  CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
+  v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
+  v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
+  v8::Debug::AddDebugEventListener(fun, data);
+
+  return Heap::undefined_value();
+}
+
+
+// Removes a JavaScript function debug event listener.
+// args[0]: debug event listener function
+static Object* Runtime_RemoveDebugEventListener(Arguments args) {
+  ASSERT(args.length() == 1);
+  // Convert the parameter to an API object to call the API function for
+  // removing a JavaScript function debug event listener.
+  CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
+  v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
+  v8::Debug::RemoveDebugEventListener(fun);
+
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_Break(Arguments args) {
+  ASSERT(args.length() == 0);
+  StackGuard::DebugBreak();
+  return Heap::undefined_value();
+}
+
+
+static Object* DebugLookupResultValue(LookupResult* result) {
+  Object* value;
+  switch (result->type()) {
+    case NORMAL: {
+      Dictionary* dict =
+          JSObject::cast(result->holder())->property_dictionary();
+      value = dict->ValueAt(result->GetDictionaryEntry());
+      if (value->IsTheHole()) {
+        return Heap::undefined_value();
+      }
+      return value;
+    }
+    case FIELD:
+      value =
+          JSObject::cast(
+              result->holder())->FastPropertyAt(result->GetFieldIndex());
+      if (value->IsTheHole()) {
+        return Heap::undefined_value();
+      }
+      return value;
+    case CONSTANT_FUNCTION:
+      return result->GetConstantFunction();
+    case CALLBACKS:
+    case INTERCEPTOR:
+    case MAP_TRANSITION:
+    case CONSTANT_TRANSITION:
+    case NULL_DESCRIPTOR:
+      return Heap::undefined_value();
+    default:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
+  HandleScope scope;
+
+  ASSERT(args.length() == 2);
+
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  CONVERT_ARG_CHECKED(String, name, 1);
+
+  // Check if the name is trivially convertible to an index and get the element
+  // if so.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) {
+    Handle<FixedArray> details = Factory::NewFixedArray(2);
+    details->set(0, Runtime::GetElementOrCharAt(obj, index));
+    details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
+    return *Factory::NewJSArrayWithElements(details);
+  }
+
+  // Perform standard local lookup on the object.
+  LookupResult result;
+  obj->Lookup(*name, &result);
+  if (result.IsProperty()) {
+    Handle<Object> value(DebugLookupResultValue(&result));
+    Handle<FixedArray> details = Factory::NewFixedArray(2);
+    details->set(0, *value);
+    details->set(1, result.GetPropertyDetails().AsSmi());
+    return *Factory::NewJSArrayWithElements(details);
+  }
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_DebugGetProperty(Arguments args) {
+  HandleScope scope;
+
+  ASSERT(args.length() == 2);
+
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  CONVERT_ARG_CHECKED(String, name, 1);
+
+  LookupResult result;
+  obj->Lookup(*name, &result);
+  if (result.IsProperty()) {
+    return DebugLookupResultValue(&result);
+  }
+  return Heap::undefined_value();
+}
+
+
+// Return the names of the local named properties.
+// args[0]: object
+static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  if (!args[0]->IsJSObject()) {
+    return Heap::undefined_value();
+  }
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+  int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
+  Handle<FixedArray> names = Factory::NewFixedArray(n);
+  obj->GetLocalPropertyNames(*names);
+  return *Factory::NewJSArrayWithElements(names);
+}
+
+
+// Return the names of the local indexed properties.
+// args[0]: object
+static Object* Runtime_DebugLocalElementNames(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  if (!args[0]->IsJSObject()) {
+    return Heap::undefined_value();
+  }
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+  int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
+  Handle<FixedArray> names = Factory::NewFixedArray(n);
+  obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
+  return *Factory::NewJSArrayWithElements(names);
+}
+
+
+// Return the property type calculated from the property details.
+// args[0]: smi with property details.
+static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(Smi, details, args[0]);
+  PropertyType type = PropertyDetails(details).type();
+  return Smi::FromInt(static_cast<int>(type));
+}
+
+
+// Return the property attribute calculated from the property details.
+// args[0]: smi with property details.
+static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(Smi, details, args[0]);
+  PropertyAttributes attributes = PropertyDetails(details).attributes();
+  return Smi::FromInt(static_cast<int>(attributes));
+}
+
+
+// Return the property insertion index calculated from the property details.
+// args[0]: smi with property details.
+static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
+  ASSERT(args.length() == 1);
+  CONVERT_CHECKED(Smi, details, args[0]);
+  int index = PropertyDetails(details).index();
+  return Smi::FromInt(index);
+}
+
+
+// Return information on whether an object has a named or indexed interceptor.
+// args[0]: object
+static Object* Runtime_DebugInterceptorInfo(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  if (!args[0]->IsJSObject()) {
+    return Smi::FromInt(0);
+  }
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+
+  int result = 0;
+  if (obj->HasNamedInterceptor()) result |= 2;
+  if (obj->HasIndexedInterceptor()) result |= 1;
+
+  return Smi::FromInt(result);
+}
+
+
+// Return property names from named interceptor.
+// args[0]: object
+static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  RUNTIME_ASSERT(obj->HasNamedInterceptor());
+
+  v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
+  if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+  return Heap::undefined_value();
+}
+
+
+// Return element names from indexed interceptor.
+// args[0]: object
+static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  RUNTIME_ASSERT(obj->HasIndexedInterceptor());
+
+  v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
+  if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+  return Heap::undefined_value();
+}
+
+
+// Return property value from named interceptor.
+// args[0]: object
+// args[1]: property name
+static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  RUNTIME_ASSERT(obj->HasNamedInterceptor());
+  CONVERT_ARG_CHECKED(String, name, 1);
+
+  PropertyAttributes attributes;
+  return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
+}
+
+
+// Return element value from indexed interceptor.
+// args[0]: object
+// args[1]: index
+static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  RUNTIME_ASSERT(obj->HasIndexedInterceptor());
+  CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
+
+  return obj->GetElementWithInterceptor(*obj, index);
+}
+
+
+static Object* Runtime_CheckExecutionState(Arguments args) {
+  ASSERT(args.length() >= 1);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  // Check that the break id is valid and that there is a valid frame
+  // where execution is broken.
+  if (break_id != Top::break_id() ||
+      Top::break_frame_id() == StackFrame::NO_ID) {
+    return Top::Throw(Heap::illegal_execution_state_symbol());
+  }
+
+  return Heap::true_value();
+}
+
+
+static Object* Runtime_GetFrameCount(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  // Check arguments.
+  Object* result = Runtime_CheckExecutionState(args);
+  if (result->IsFailure()) return result;
+
+  // Count all frames which are relevant to debugging stack trace.
+  int n = 0;
+  StackFrame::Id id = Top::break_frame_id();
+  for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
+  return Smi::FromInt(n);
+}
+
+
+static const int kFrameDetailsFrameIdIndex = 0;
+static const int kFrameDetailsReceiverIndex = 1;
+static const int kFrameDetailsFunctionIndex = 2;
+static const int kFrameDetailsArgumentCountIndex = 3;
+static const int kFrameDetailsLocalCountIndex = 4;
+static const int kFrameDetailsSourcePositionIndex = 5;
+static const int kFrameDetailsConstructCallIndex = 6;
+static const int kFrameDetailsDebuggerFrameIndex = 7;
+static const int kFrameDetailsFirstDynamicIndex = 8;
+
+// Return an array with frame details
+// args[0]: number: break id
+// args[1]: number: frame index
+//
+// The array returned contains the following information:
+// 0: Frame id
+// 1: Receiver
+// 2: Function
+// 3: Argument count
+// 4: Local count
+// 5: Source position
+// 6: Constructor call
+// 7: Debugger frame
+// Arguments name, value
+// Locals name, value
+static Object* Runtime_GetFrameDetails(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+
+  // Check arguments.
+  Object* check = Runtime_CheckExecutionState(args);
+  if (check->IsFailure()) return check;
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+
+  // Find the relevant frame with the requested index.
+  StackFrame::Id id = Top::break_frame_id();
+  int count = 0;
+  JavaScriptFrameIterator it(id);
+  for (; !it.done(); it.Advance()) {
+    if (count == index) break;
+    count++;
+  }
+  if (it.done()) return Heap::undefined_value();
+
+  // Traverse the saved contexts chain to find the active context for the
+  // selected frame.
+  SaveContext* save = Top::save_context();
+  while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
+    save = save->prev();
+  }
+
+  // Get the frame id.
+  Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
+
+  // Find source position.
+  int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
+
+  // Check for constructor frame.
+  bool constructor = it.frame()->IsConstructor();
+
+  // Get code and read scope info from it for local variable information.
+  Handle<Code> code(it.frame()->FindCode());
+  ScopeInfo<> info(*code);
+
+  // Get the context.
+  Handle<Context> context(Context::cast(it.frame()->context()));
+
+  // Get the locals names and values into a temporary array.
+  //
+  // TODO(1240907): Hide compiler-introduced stack variables
+  // (e.g. .result)?  For users of the debugger, they will probably be
+  // confusing.
+  Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
+  for (int i = 0; i < info.NumberOfLocals(); i++) {
+    // Name of the local.
+    locals->set(i * 2, *info.LocalName(i));
+
+    // Fetch the value of the local - either from the stack or from a
+    // heap-allocated context.
+    if (i < info.number_of_stack_slots()) {
+      locals->set(i * 2 + 1, it.frame()->GetExpression(i));
+    } else {
+      Handle<String> name = info.LocalName(i);
+      // Traverse the context chain to the function context as all local
+      // variables stored in the context will be on the function context.
+      while (!context->is_function_context()) {
+        context = Handle<Context>(context->previous());
+      }
+      ASSERT(context->is_function_context());
+      locals->set(i * 2 + 1,
+                  context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
+                                                             NULL)));
+    }
+  }
+
+  // Now advance to the arguments adapter frame (if any). If contains all
+  // the provided parameters and
+
+  // Now advance to the arguments adapter frame (if any). It contains all
+  // the provided parameters whereas the function frame always have the number
+  // of arguments matching the functions parameters. The rest of the
+  // information (except for what is collected above) is the same.
+  it.AdvanceToArgumentsFrame();
+
+  // Find the number of arguments to fill. At least fill the number of
+  // parameters for the function and fill more if more parameters are provided.
+  int argument_count = info.number_of_parameters();
+  if (argument_count < it.frame()->GetProvidedParametersCount()) {
+    argument_count = it.frame()->GetProvidedParametersCount();
+  }
+
+  // Calculate the size of the result.
+  int details_size = kFrameDetailsFirstDynamicIndex +
+                     2 * (argument_count + info.NumberOfLocals());
+  Handle<FixedArray> details = Factory::NewFixedArray(details_size);
+
+  // Add the frame id.
+  details->set(kFrameDetailsFrameIdIndex, *frame_id);
+
+  // Add the function (same as in function frame).
+  details->set(kFrameDetailsFunctionIndex, it.frame()->function());
+
+  // Add the arguments count.
+  details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
+
+  // Add the locals count
+  details->set(kFrameDetailsLocalCountIndex,
+               Smi::FromInt(info.NumberOfLocals()));
+
+  // Add the source position.
+  if (position != RelocInfo::kNoPosition) {
+    details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
+  } else {
+    details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
+  }
+
+  // Add the constructor information.
+  details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
+
+  // Add information on whether this frame is invoked in the debugger context.
+  details->set(kFrameDetailsDebuggerFrameIndex,
+               Heap::ToBoolean(*save->context() == *Debug::debug_context()));
+
+  // Fill the dynamic part.
+  int details_index = kFrameDetailsFirstDynamicIndex;
+
+  // Add arguments name and value.
+  for (int i = 0; i < argument_count; i++) {
+    // Name of the argument.
+    if (i < info.number_of_parameters()) {
+      details->set(details_index++, *info.parameter_name(i));
+    } else {
+      details->set(details_index++, Heap::undefined_value());
+    }
+
+    // Parameter value.
+    if (i < it.frame()->GetProvidedParametersCount()) {
+      details->set(details_index++, it.frame()->GetParameter(i));
+    } else {
+      details->set(details_index++, Heap::undefined_value());
+    }
+  }
+
+  // Add locals name and value from the temporary copy from the function frame.
+  for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
+    details->set(details_index++, locals->get(i));
+  }
+
+  // Add the receiver (same as in function frame).
+  // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
+  // THE FRAME ITERATOR TO WRAP THE RECEIVER.
+  Handle<Object> receiver(it.frame()->receiver());
+  if (!receiver->IsJSObject()) {
+    // If the receiver is NOT a JSObject we have hit an optimization
+    // where a value object is not converted into a wrapped JS objects.
+    // To hide this optimization from the debugger, we wrap the receiver
+    // by creating correct wrapper object based on the calling frame's
+    // global context.
+    it.Advance();
+    Handle<Context> calling_frames_global_context(
+        Context::cast(Context::cast(it.frame()->context())->global_context()));
+    receiver = Factory::ToObject(receiver, calling_frames_global_context);
+  }
+  details->set(kFrameDetailsReceiverIndex, *receiver);
+
+  ASSERT_EQ(details_size, details_index);
+  return *Factory::NewJSArrayWithElements(details);
+}
+
+
+static Object* Runtime_GetCFrames(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  Object* result = Runtime_CheckExecutionState(args);
+  if (result->IsFailure()) return result;
+
+  static const int kMaxCFramesSize = 200;
+  OS::StackFrame frames[kMaxCFramesSize];
+  int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
+  if (frames_count == OS::kStackWalkError) {
+    return Heap::undefined_value();
+  }
+
+  Handle<String> address_str = Factory::LookupAsciiSymbol("address");
+  Handle<String> text_str = Factory::LookupAsciiSymbol("text");
+  Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
+  for (int i = 0; i < frames_count; i++) {
+    Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
+    frame_value->SetProperty(
+        *address_str,
+        *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
+        NONE);
+
+    // Get the stack walk text for this frame.
+    Handle<String> frame_text;
+    if (strlen(frames[i].text) > 0) {
+      Vector<const char> str(frames[i].text, strlen(frames[i].text));
+      frame_text = Factory::NewStringFromAscii(str);
+    }
+
+    if (!frame_text.is_null()) {
+      frame_value->SetProperty(*text_str, *frame_text, NONE);
+    }
+
+    frames_array->set(i, *frame_value);
+  }
+  return *Factory::NewJSArrayWithElements(frames_array);
+}
+
+
+static Object* Runtime_GetBreakLocations(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
+  Handle<SharedFunctionInfo> shared(raw_fun->shared());
+  // Find the number of break points
+  Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
+  if (break_locations->IsUndefined()) return Heap::undefined_value();
+  // Return array as JS array
+  return *Factory::NewJSArrayWithElements(
+      Handle<FixedArray>::cast(break_locations));
+}
+
+
+// Set a break point in a function
+// args[0]: function
+// args[1]: number: break source position (within the function source)
+// args[2]: number: break point object
+static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
+  Handle<SharedFunctionInfo> shared(raw_fun->shared());
+  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+  RUNTIME_ASSERT(source_position >= 0);
+  Handle<Object> break_point_object_arg = args.at<Object>(2);
+
+  // Set break point.
+  Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
+
+  return Heap::undefined_value();
+}
+
+
+static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
+                                              int position) {
+  // Iterate the heap looking for SharedFunctionInfo generated from the
+  // script. The inner most SharedFunctionInfo containing the source position
+  // for the requested break point is found.
+  // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
+  // which is found is not compiled it is compiled and the heap is iterated
+  // again as the compilation might create inner functions from the newly
+  // compiled function and the actual requested break point might be in one of
+  // these functions.
+  bool done = false;
+  // The current candidate for the source position:
+  int target_start_position = RelocInfo::kNoPosition;
+  Handle<SharedFunctionInfo> target;
+  // The current candidate for the last function in script:
+  Handle<SharedFunctionInfo> last;
+  while (!done) {
+    HeapIterator iterator;
+    while (iterator.has_next()) {
+      HeapObject* obj = iterator.next();
+      ASSERT(obj != NULL);
+      if (obj->IsSharedFunctionInfo()) {
+        Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
+        if (shared->script() == *script) {
+          // If the SharedFunctionInfo found has the requested script data and
+          // contains the source position it is a candidate.
+          int start_position = shared->function_token_position();
+          if (start_position == RelocInfo::kNoPosition) {
+            start_position = shared->start_position();
+          }
+          if (start_position <= position &&
+              position <= shared->end_position()) {
+            // If there is no candidate or this function is within the currrent
+            // candidate this is the new candidate.
+            if (target.is_null()) {
+              target_start_position = start_position;
+              target = shared;
+            } else {
+              if (target_start_position < start_position &&
+                  shared->end_position() < target->end_position()) {
+                target_start_position = start_position;
+                target = shared;
+              }
+            }
+          }
+
+          // Keep track of the last function in the script.
+          if (last.is_null() ||
+              shared->end_position() > last->start_position()) {
+            last = shared;
+          }
+        }
+      }
+    }
+
+    // Make sure some candidate is selected.
+    if (target.is_null()) {
+      if (!last.is_null()) {
+        // Position after the last function - use last.
+        target = last;
+      } else {
+        // Unable to find function - possibly script without any function.
+        return Heap::undefined_value();
+      }
+    }
+
+    // If the candidate found is compiled we are done. NOTE: when lazy
+    // compilation of inner functions is introduced some additional checking
+    // needs to be done here to compile inner functions.
+    done = target->is_compiled();
+    if (!done) {
+      // If the candidate is not compiled compile it to reveal any inner
+      // functions which might contain the requested source position.
+      CompileLazyShared(target, KEEP_EXCEPTION);
+    }
+  }
+
+  return *target;
+}
+
+
+// Change the state of a break point in a script. NOTE: Regarding performance
+// see the NOTE for GetScriptFromScriptData.
+// args[0]: script to set break point in
+// args[1]: number: break source position (within the script source)
+// args[2]: number: break point object
+static Object* Runtime_SetScriptBreakPoint(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
+  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+  RUNTIME_ASSERT(source_position >= 0);
+  Handle<Object> break_point_object_arg = args.at<Object>(2);
+
+  // Get the script from the script wrapper.
+  RUNTIME_ASSERT(wrapper->value()->IsScript());
+  Handle<Script> script(Script::cast(wrapper->value()));
+
+  Object* result = FindSharedFunctionInfoInScript(script, source_position);
+  if (!result->IsUndefined()) {
+    Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
+    // Find position within function. The script position might be before the
+    // source position of the first function.
+    int position;
+    if (shared->start_position() > source_position) {
+      position = 0;
+    } else {
+      position = source_position - shared->start_position();
+    }
+    Debug::SetBreakPoint(shared, position, break_point_object_arg);
+  }
+  return  Heap::undefined_value();
+}
+
+
+// Clear a break point
+// args[0]: number: break point object
+static Object* Runtime_ClearBreakPoint(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  Handle<Object> break_point_object_arg = args.at<Object>(0);
+
+  // Clear break point.
+  Debug::ClearBreakPoint(break_point_object_arg);
+
+  return Heap::undefined_value();
+}
+
+
+// Change the state of break on exceptions
+// args[0]: boolean indicating uncaught exceptions
+// args[1]: boolean indicating on/off
+static Object* Runtime_ChangeBreakOnException(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+  ASSERT(args[0]->IsNumber());
+  ASSERT(args[1]->IsBoolean());
+
+  // Update break point state
+  ExceptionBreakType type =
+      static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
+  bool enable = args[1]->ToBoolean()->IsTrue();
+  Debug::ChangeBreakOnException(type, enable);
+  return Heap::undefined_value();
+}
+
+
+// Prepare for stepping
+// args[0]: break id for checking execution state
+// args[1]: step action from the enumeration StepAction
+// args[2]: number of times to perform the step
+static Object* Runtime_PrepareStep(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 3);
+  // Check arguments.
+  Object* check = Runtime_CheckExecutionState(args);
+  if (check->IsFailure()) return check;
+  if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
+    return Top::Throw(Heap::illegal_argument_symbol());
+  }
+
+  // Get the step action and check validity.
+  StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
+  if (step_action != StepIn &&
+      step_action != StepNext &&
+      step_action != StepOut &&
+      step_action != StepInMin &&
+      step_action != StepMin) {
+    return Top::Throw(Heap::illegal_argument_symbol());
+  }
+
+  // Get the number of steps.
+  int step_count = NumberToInt32(args[2]);
+  if (step_count < 1) {
+    return Top::Throw(Heap::illegal_argument_symbol());
+  }
+
+  // Prepare step.
+  Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
+  return Heap::undefined_value();
+}
+
+
+// Clear all stepping set by PrepareStep.
+static Object* Runtime_ClearStepping(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 0);
+  Debug::ClearStepping();
+  return Heap::undefined_value();
+}
+
+
+// Creates a copy of the with context chain. The copy of the context chain is
+// is linked to the function context supplied.
+static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
+                                            Handle<Context> function_context) {
+  // At the bottom of the chain. Return the function context to link to.
+  if (context_chain->is_function_context()) {
+    return function_context;
+  }
+
+  // Recursively copy the with contexts.
+  Handle<Context> previous(context_chain->previous());
+  Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
+  return Factory::NewWithContext(
+      CopyWithContextChain(function_context, previous), extension);
+}
+
+
+// Helper function to find or create the arguments object for
+// Runtime_DebugEvaluate.
+static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
+                                         Handle<JSFunction> function,
+                                         Handle<Code> code,
+                                         const ScopeInfo<>* sinfo,
+                                         Handle<Context> function_context) {
+  // Try to find the value of 'arguments' to pass as parameter. If it is not
+  // found (that is the debugged function does not reference 'arguments' and
+  // does not support eval) then create an 'arguments' object.
+  int index;
+  if (sinfo->number_of_stack_slots() > 0) {
+    index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
+    if (index != -1) {
+      return Handle<Object>(frame->GetExpression(index));
+    }
+  }
+
+  if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
+    index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
+                                          NULL);
+    if (index != -1) {
+      return Handle<Object>(function_context->get(index));
+    }
+  }
+
+  const int length = frame->GetProvidedParametersCount();
+  Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
+  Handle<FixedArray> array = Factory::NewFixedArray(length);
+  WriteBarrierMode mode = array->GetWriteBarrierMode();
+  for (int i = 0; i < length; i++) {
+    array->set(i, frame->GetParameter(i), mode);
+  }
+  arguments->set_elements(*array);
+  return arguments;
+}
+
+
+// Evaluate a piece of JavaScript in the context of a stack frame for
+// debugging. This is acomplished by creating a new context which in its
+// extension part has all the parameters and locals of the function on the
+// stack frame. A function which calls eval with the code to evaluate is then
+// compiled in this context and called in this context. As this context
+// replaces the context of the function on the stack frame a new (empty)
+// function is created as well to be used as the closure for the context.
+// This function and the context acts as replacements for the function on the
+// stack frame presenting the same view of the values of parameters and
+// local variables as if the piece of JavaScript was evaluated at the point
+// where the function on the stack frame is currently stopped.
+static Object* Runtime_DebugEvaluate(Arguments args) {
+  HandleScope scope;
+
+  // Check the execution state and decode arguments frame and source to be
+  // evaluated.
+  ASSERT(args.length() == 4);
+  Object* check_result = Runtime_CheckExecutionState(args);
+  if (check_result->IsFailure()) return check_result;
+  CONVERT_CHECKED(Smi, wrapped_id, args[1]);
+  CONVERT_ARG_CHECKED(String, source, 2);
+  CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
+
+  // Handle the processing of break.
+  DisableBreak disable_break_save(disable_break);
+
+  // Get the frame where the debugging is performed.
+  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  JavaScriptFrameIterator it(id);
+  JavaScriptFrame* frame = it.frame();
+  Handle<JSFunction> function(JSFunction::cast(frame->function()));
+  Handle<Code> code(function->code());
+  ScopeInfo<> sinfo(*code);
+
+  // Traverse the saved contexts chain to find the active context for the
+  // selected frame.
+  SaveContext* save = Top::save_context();
+  while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
+    save = save->prev();
+  }
+  ASSERT(save != NULL);
+  SaveContext savex;
+  Top::set_context(*(save->context()));
+
+  // Create the (empty) function replacing the function on the stack frame for
+  // the purpose of evaluating in the context created below. It is important
+  // that this function does not describe any parameters and local variables
+  // in the context. If it does then this will cause problems with the lookup
+  // in Context::Lookup, where context slots for parameters and local variables
+  // are looked at before the extension object.
+  Handle<JSFunction> go_between =
+      Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
+  go_between->set_context(function->context());
+#ifdef DEBUG
+  ScopeInfo<> go_between_sinfo(go_between->shared()->code());
+  ASSERT(go_between_sinfo.number_of_parameters() == 0);
+  ASSERT(go_between_sinfo.number_of_context_slots() == 0);
+#endif
+
+  // Allocate and initialize a context extension object with all the
+  // arguments, stack locals heap locals and extension properties of the
+  // debugged function.
+  Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
+  // First fill all parameters to the context extension.
+  for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
+    SetProperty(context_ext,
+                sinfo.parameter_name(i),
+                Handle<Object>(frame->GetParameter(i)), NONE);
+  }
+  // Second fill all stack locals to the context extension.
+  for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
+    SetProperty(context_ext,
+                sinfo.stack_slot_name(i),
+                Handle<Object>(frame->GetExpression(i)), NONE);
+  }
+  // Third fill all context locals to the context extension.
+  Handle<Context> frame_context(Context::cast(frame->context()));
+  Handle<Context> function_context(frame_context->fcontext());
+  for (int i = Context::MIN_CONTEXT_SLOTS;
+       i < sinfo.number_of_context_slots();
+       ++i) {
+    int context_index =
+        ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
+    SetProperty(context_ext,
+                sinfo.context_slot_name(i),
+                Handle<Object>(function_context->get(context_index)), NONE);
+  }
+  // Finally copy any properties from the function context extension. This will
+  // be variables introduced by eval.
+  if (function_context->has_extension() &&
+      !function_context->IsGlobalContext()) {
+    Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+    Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
+    for (int i = 0; i < keys->length(); i++) {
+      // Names of variables introduced by eval are strings.
+      ASSERT(keys->get(i)->IsString());
+      Handle<String> key(String::cast(keys->get(i)));
+      SetProperty(context_ext, key, GetProperty(ext, key), NONE);
+    }
+  }
+
+  // Allocate a new context for the debug evaluation and set the extension
+  // object build.
+  Handle<Context> context =
+      Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
+  context->set_extension(*context_ext);
+  // Copy any with contexts present and chain them in front of this context.
+  context = CopyWithContextChain(frame_context, context);
+
+  // Wrap the evaluation statement in a new function compiled in the newly
+  // created context. The function has one parameter which has to be called
+  // 'arguments'. This it to have access to what would have been 'arguments' in
+  // the function beeing debugged.
+  // function(arguments,__source__) {return eval(__source__);}
+  static const char* source_str =
+      "function(arguments,__source__){return eval(__source__);}";
+  static const int source_str_length = strlen(source_str);
+  Handle<String> function_source =
+      Factory::NewStringFromAscii(Vector<const char>(source_str,
+                                                     source_str_length));
+  Handle<JSFunction> boilerplate =
+      Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
+  if (boilerplate.is_null()) return Failure::Exception();
+  Handle<JSFunction> compiled_function =
+      Factory::NewFunctionFromBoilerplate(boilerplate, context);
+
+  // Invoke the result of the compilation to get the evaluation function.
+  bool has_pending_exception;
+  Handle<Object> receiver(frame->receiver());
+  Handle<Object> evaluation_function =
+      Execution::Call(compiled_function, receiver, 0, NULL,
+                      &has_pending_exception);
+
+  Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
+                                                function_context);
+
+  // Invoke the evaluation function and return the result.
+  const int argc = 2;
+  Object** argv[argc] = { arguments.location(),
+                          Handle<Object>::cast(source).location() };
+  Handle<Object> result =
+      Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
+                      argc, argv, &has_pending_exception);
+  return *result;
+}
+
+
+static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
+  HandleScope scope;
+
+  // Check the execution state and decode arguments frame and source to be
+  // evaluated.
+  ASSERT(args.length() == 3);
+  Object* check_result = Runtime_CheckExecutionState(args);
+  if (check_result->IsFailure()) return check_result;
+  CONVERT_ARG_CHECKED(String, source, 1);
+  CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
+
+  // Handle the processing of break.
+  DisableBreak disable_break_save(disable_break);
+
+  // Enter the top context from before the debugger was invoked.
+  SaveContext save;
+  SaveContext* top = &save;
+  while (top != NULL && *top->context() == *Debug::debug_context()) {
+    top = top->prev();
+  }
+  if (top != NULL) {
+    Top::set_context(*top->context());
+  }
+
+  // Get the global context now set to the top context from before the
+  // debugger was invoked.
+  Handle<Context> context = Top::global_context();
+
+  // Compile the source to be evaluated.
+  Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
+  if (boilerplate.is_null()) return Failure::Exception();
+  Handle<JSFunction> compiled_function =
+      Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
+                                                             context));
+
+  // Invoke the result of the compilation to get the evaluation function.
+  bool has_pending_exception;
+  Handle<Object> receiver = Top::global();
+  Handle<Object> result =
+    Execution::Call(compiled_function, receiver, 0, NULL,
+                    &has_pending_exception);
+  return *result;
+}
+
+
+// Helper function used by Runtime_DebugGetLoadedScripts below.
+static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
+  NoHandleAllocation ha;
+  AssertNoAllocation no_alloc;
+
+  // Get hold of the current empty script.
+  Context* context = Top::context()->global_context();
+  Script* empty = context->empty_script();
+
+  // Scan heap for Script objects.
+  int count = 0;
+  HeapIterator iterator;
+  while (iterator.has_next()) {
+    HeapObject* obj = iterator.next();
+    ASSERT(obj != NULL);
+    if (obj->IsScript() && obj != empty) {
+      if (instances != NULL && count < instances_size) {
+        instances->set(count, obj);
+      }
+      count++;
+    }
+  }
+
+  return count;
+}
+
+
+static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 0);
+
+  // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
+  // rid of all the cached script wrappes and the second gets rid of the
+  // scripts which is no longer referenced.
+  Heap::CollectAllGarbage();
+  Heap::CollectAllGarbage();
+
+  // Get the number of scripts.
+  int count;
+  count = DebugGetLoadedScripts(NULL, 0);
+
+  // Allocate an array to hold the result.
+  Handle<FixedArray> instances = Factory::NewFixedArray(count);
+
+  // Fill the script objects.
+  count = DebugGetLoadedScripts(*instances, count);
+
+  // Convert the script objects to proper JS objects.
+  for (int i = 0; i < count; i++) {
+    Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
+    // Get the script wrapper in a local handle before calling GetScriptWrapper,
+    // because using
+    //   instances->set(i, *GetScriptWrapper(script))
+    // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
+    // already have deferenced the instances handle.
+    Handle<JSValue> wrapper = GetScriptWrapper(script);
+    instances->set(i, *wrapper);
+  }
+
+  // Return result as a JS array.
+  Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
+  Handle<JSArray>::cast(result)->SetContent(*instances);
+  return *result;
+}
+
+
+// Helper function used by Runtime_DebugReferencedBy below.
+static int DebugReferencedBy(JSObject* target,
+                             Object* instance_filter, int max_references,
+                             FixedArray* instances, int instances_size,
+                             JSFunction* context_extension_function,
+                             JSFunction* arguments_function) {
+  NoHandleAllocation ha;
+  AssertNoAllocation no_alloc;
+
+  // Iterate the heap.
+  int count = 0;
+  JSObject* last = NULL;
+  HeapIterator iterator;
+  while (iterator.has_next() &&
+         (max_references == 0 || count < max_references)) {
+    // Only look at all JSObjects.
+    HeapObject* heap_obj = iterator.next();
+    if (heap_obj->IsJSObject()) {
+      // Skip context extension objects and argument arrays as these are
+      // checked in the context of functions using them.
+      JSObject* obj = JSObject::cast(heap_obj);
+      if (obj->map()->constructor() == context_extension_function ||
+          obj->map()->constructor() == arguments_function) {
+        continue;
+      }
+
+      // Check if the JS object has a reference to the object looked for.
+      if (obj->ReferencesObject(target)) {
+        // Check instance filter if supplied. This is normally used to avoid
+        // references from mirror objects (see Runtime_IsInPrototypeChain).
+        if (!instance_filter->IsUndefined()) {
+          Object* V = obj;
+          while (true) {
+            Object* prototype = V->GetPrototype();
+            if (prototype->IsNull()) {
+              break;
+            }
+            if (instance_filter == prototype) {
+              obj = NULL;  // Don't add this object.
+              break;
+            }
+            V = prototype;
+          }
+        }
+
+        if (obj != NULL) {
+          // Valid reference found add to instance array if supplied an update
+          // count.
+          if (instances != NULL && count < instances_size) {
+            instances->set(count, obj);
+          }
+          last = obj;
+          count++;
+        }
+      }
+    }
+  }
+
+  // Check for circular reference only. This can happen when the object is only
+  // referenced from mirrors and has a circular reference in which case the
+  // object is not really alive and would have been garbage collected if not
+  // referenced from the mirror.
+  if (count == 1 && last == target) {
+    count = 0;
+  }
+
+  // Return the number of referencing objects found.
+  return count;
+}
+
+
+// Scan the heap for objects with direct references to an object
+// args[0]: the object to find references to
+// args[1]: constructor function for instances to exclude (Mirror)
+// args[2]: the the maximum number of objects to return
+static Object* Runtime_DebugReferencedBy(Arguments args) {
+  ASSERT(args.length() == 3);
+
+  // First perform a full GC in order to avoid references from dead objects.
+  Heap::CollectAllGarbage();
+
+  // Check parameters.
+  CONVERT_CHECKED(JSObject, target, args[0]);
+  Object* instance_filter = args[1];
+  RUNTIME_ASSERT(instance_filter->IsUndefined() ||
+                 instance_filter->IsJSObject());
+  CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
+  RUNTIME_ASSERT(max_references >= 0);
+
+  // Get the constructor function for context extension and arguments array.
+  JSFunction* context_extension_function =
+      Top::context()->global_context()->context_extension_function();
+  JSObject* arguments_boilerplate =
+      Top::context()->global_context()->arguments_boilerplate();
+  JSFunction* arguments_function =
+      JSFunction::cast(arguments_boilerplate->map()->constructor());
+
+  // Get the number of referencing objects.
+  int count;
+  count = DebugReferencedBy(target, instance_filter, max_references,
+                            NULL, 0,
+                            context_extension_function, arguments_function);
+
+  // Allocate an array to hold the result.
+  Object* object = Heap::AllocateFixedArray(count);
+  if (object->IsFailure()) return object;
+  FixedArray* instances = FixedArray::cast(object);
+
+  // Fill the referencing objects.
+  count = DebugReferencedBy(target, instance_filter, max_references,
+                            instances, count,
+                            context_extension_function, arguments_function);
+
+  // Return result as JS array.
+  Object* result =
+      Heap::AllocateJSObject(
+          Top::context()->global_context()->array_function());
+  if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
+  return result;
+}
+
+
+// Helper function used by Runtime_DebugConstructedBy below.
+static int DebugConstructedBy(JSFunction* constructor, int max_references,
+                              FixedArray* instances, int instances_size) {
+  AssertNoAllocation no_alloc;
+
+  // Iterate the heap.
+  int count = 0;
+  HeapIterator iterator;
+  while (iterator.has_next() &&
+         (max_references == 0 || count < max_references)) {
+    // Only look at all JSObjects.
+    HeapObject* heap_obj = iterator.next();
+    if (heap_obj->IsJSObject()) {
+      JSObject* obj = JSObject::cast(heap_obj);
+      if (obj->map()->constructor() == constructor) {
+        // Valid reference found add to instance array if supplied an update
+        // count.
+        if (instances != NULL && count < instances_size) {
+          instances->set(count, obj);
+        }
+        count++;
+      }
+    }
+  }
+
+  // Return the number of referencing objects found.
+  return count;
+}
+
+
+// Scan the heap for objects constructed by a specific function.
+// args[0]: the constructor to find instances of
+// args[1]: the the maximum number of objects to return
+static Object* Runtime_DebugConstructedBy(Arguments args) {
+  ASSERT(args.length() == 2);
+
+  // First perform a full GC in order to avoid dead objects.
+  Heap::CollectAllGarbage();
+
+  // Check parameters.
+  CONVERT_CHECKED(JSFunction, constructor, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
+  RUNTIME_ASSERT(max_references >= 0);
+
+  // Get the number of referencing objects.
+  int count;
+  count = DebugConstructedBy(constructor, max_references, NULL, 0);
+
+  // Allocate an array to hold the result.
+  Object* object = Heap::AllocateFixedArray(count);
+  if (object->IsFailure()) return object;
+  FixedArray* instances = FixedArray::cast(object);
+
+  // Fill the referencing objects.
+  count = DebugConstructedBy(constructor, max_references, instances, count);
+
+  // Return result as JS array.
+  Object* result =
+      Heap::AllocateJSObject(
+          Top::context()->global_context()->array_function());
+  if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
+  return result;
+}
+
+
+static Object* Runtime_GetPrototype(Arguments args) {
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSObject, obj, args[0]);
+
+  return obj->GetPrototype();
+}
+
+
+static Object* Runtime_SystemBreak(Arguments args) {
+  ASSERT(args.length() == 0);
+  CPU::DebugBreak();
+  return Heap::undefined_value();
+}
+
+
+// Finds the script object from the script data. NOTE: This operation uses
+// heap traversal to find the function generated for the source position
+// for the requested break point. For lazily compiled functions several heap
+// traversals might be required rendering this operation as a rather slow
+// operation. However for setting break points which is normally done through
+// some kind of user interaction the performance is not crucial.
+static Handle<Object> Runtime_GetScriptFromScriptName(
+    Handle<String> script_name) {
+  // Scan the heap for Script objects to find the script with the requested
+  // script data.
+  Handle<Script> script;
+  HeapIterator iterator;
+  while (script.is_null() && iterator.has_next()) {
+    HeapObject* obj = iterator.next();
+    // If a script is found check if it has the script data requested.
+    if (obj->IsScript()) {
+      if (Script::cast(obj)->name()->IsString()) {
+        if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
+          script = Handle<Script>(Script::cast(obj));
+        }
+      }
+    }
+  }
+
+  // If no script with the requested script data is found return undefined.
+  if (script.is_null()) return Factory::undefined_value();
+
+  // Return the script found.
+  return GetScriptWrapper(script);
+}
+
+
+// Get the script object from script data. NOTE: Regarding performance
+// see the NOTE for GetScriptFromScriptData.
+// args[0]: script data for the script to find the source for
+static Object* Runtime_GetScript(Arguments args) {
+  HandleScope scope;
+
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(String, script_name, args[0]);
+
+  // Find the requested script.
+  Handle<Object> result =
+      Runtime_GetScriptFromScriptName(Handle<String>(script_name));
+  return *result;
+}
+
+
+static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
+#ifdef DEBUG
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+  // Get the function and make sure it is compiled.
+  CONVERT_ARG_CHECKED(JSFunction, func, 0);
+  if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
+    return Failure::Exception();
+  }
+  func->code()->PrintLn();
+#endif  // DEBUG
+  return Heap::undefined_value();
+}
+
+
+static Object* Runtime_Abort(Arguments args) {
+  ASSERT(args.length() == 2);
+  OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
+                                    Smi::cast(args[1])->value());
+  Top::PrintStack();
+  OS::Abort();
+  UNREACHABLE();
+  return NULL;
+}
+
+
+#ifdef DEBUG
+// ListNatives is ONLY used by the fuzz-natives.js in debug mode
+// Exclude the code in release mode.
+static Object* Runtime_ListNatives(Arguments args) {
+  ASSERT(args.length() == 0);
+  HandleScope scope;
+  Handle<JSArray> result = Factory::NewJSArray(0);
+  int index = 0;
+#define ADD_ENTRY(Name, argc)                                                \
+  {                                                                          \
+    HandleScope inner;                                                       \
+    Handle<String> name =                                                    \
+      Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
+    Handle<JSArray> pair = Factory::NewJSArray(0);                           \
+    SetElement(pair, 0, name);                                               \
+    SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc)));                    \
+    SetElement(result, index++, pair);                                       \
+  }
+  RUNTIME_FUNCTION_LIST(ADD_ENTRY)
+#undef ADD_ENTRY
+  return *result;
+}
+#endif
+
+
+static Object* Runtime_IS_VAR(Arguments args) {
+  UNREACHABLE();  // implemented as macro in the parser
+  return NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of Runtime
+
+#define F(name, nargs)                                                 \
+  { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
+    static_cast<int>(Runtime::k##name) },
+
+static Runtime::Function Runtime_functions[] = {
+  RUNTIME_FUNCTION_LIST(F)
+  { NULL, NULL, NULL, 0, -1 }
+};
+
+#undef F
+
+
+Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
+  ASSERT(0 <= fid && fid < kNofFunctions);
+  return &Runtime_functions[fid];
+}
+
+
+Runtime::Function* Runtime::FunctionForName(const char* name) {
+  for (Function* f = Runtime_functions; f->name != NULL; f++) {
+    if (strcmp(f->name, name) == 0) {
+      return f;
+    }
+  }
+  return NULL;
+}
+
+
+void Runtime::PerformGC(Object* result) {
+  Failure* failure = Failure::cast(result);
+  // Try to do a garbage collection; ignore it if it fails. The C
+  // entry stub will throw an out-of-memory exception in that case.
+  Heap::CollectGarbage(failure->requested(), failure->allocation_space());
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/runtime.h b/regexp2000/src/runtime.h
new file mode 100644 (file)
index 0000000..463698c
--- /dev/null
@@ -0,0 +1,368 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_RUNTIME_H_
+#define V8_RUNTIME_H_
+
+namespace v8 { namespace internal {
+
+// The interface to C++ runtime functions.
+
+// ----------------------------------------------------------------------------
+// RUNTIME_FUNCTION_LIST_ALWAYS defines runtime calls available in both
+// release and debug mode.
+// This macro should only be used by the macro RUNTIME_FUNCTION_LIST.
+
+#define RUNTIME_FUNCTION_LIST_ALWAYS(F) \
+  /* Property access */ \
+  F(GetProperty, 2) \
+  F(KeyedGetProperty, 2) \
+  F(DeleteProperty, 2) \
+  F(HasLocalProperty, 2) \
+  F(HasProperty, 2) \
+  F(HasElement, 2) \
+  F(IsPropertyEnumerable, 2) \
+  F(GetPropertyNames, 1) \
+  F(GetPropertyNamesFast, 1) \
+  F(GetArgumentsProperty, 1) \
+  \
+  F(IsInPrototypeChain, 2) \
+  \
+  F(IsConstructCall, 0) \
+  \
+  /* Utilities */ \
+  F(GetCalledFunction, 0) \
+  F(GetFunctionDelegate, 1) \
+  F(NewArguments, 1) \
+  F(NewArgumentsFast, 3) \
+  F(LazyCompile, 1) \
+  F(SetNewFunctionAttributes, 1) \
+  \
+  /* Array join support */ \
+  F(PushIfAbsent, 2) \
+  \
+  /* ConsStrings */ \
+  F(ConsStringFst, 1) \
+  F(ConsStringSnd, 1) \
+  \
+  /* Conversions */ \
+  F(ToBool, 1) \
+  F(Typeof, 1) \
+  \
+  F(StringToNumber, 1) \
+  F(StringFromCharCodeArray, 1) \
+  F(StringParseInt, 2) \
+  F(StringParseFloat, 1) \
+  F(StringToLowerCase, 1) \
+  F(StringToUpperCase, 1) \
+  F(CharFromCode, 1) \
+  F(URIEscape, 1) \
+  F(URIUnescape, 1) \
+  \
+  F(NumberToString, 1) \
+  F(NumberToInteger, 1) \
+  F(NumberToJSUint32, 1) \
+  F(NumberToJSInt32, 1) \
+  \
+  /* Arithmetic operations */ \
+  F(NumberAdd, 2) \
+  F(NumberSub, 2) \
+  F(NumberMul, 2) \
+  F(NumberDiv, 2) \
+  F(NumberMod, 2) \
+  F(NumberUnaryMinus, 1) \
+  \
+  F(StringAdd, 2) \
+  F(StringBuilderConcat, 2) \
+  \
+  /* Bit operations */ \
+  F(NumberOr, 2) \
+  F(NumberAnd, 2) \
+  F(NumberXor, 2) \
+  F(NumberNot, 1) \
+  \
+  F(NumberShl, 2) \
+  F(NumberShr, 2) \
+  F(NumberSar, 2) \
+  \
+  /* Comparisons */ \
+  F(NumberEquals, 2) \
+  F(StringEquals, 2) \
+  \
+  F(NumberCompare, 3) \
+  F(SmiLexicographicCompare, 2) \
+  F(StringCompare, 2) \
+  \
+  /* Math */ \
+  F(Math_abs, 1) \
+  F(Math_acos, 1) \
+  F(Math_asin, 1) \
+  F(Math_atan, 1) \
+  F(Math_atan2, 2) \
+  F(Math_ceil, 1) \
+  F(Math_cos, 1) \
+  F(Math_exp, 1) \
+  F(Math_floor, 1) \
+  F(Math_log, 1) \
+  F(Math_pow, 2) \
+  F(Math_random, 0) \
+  F(Math_round, 1) \
+  F(Math_sin, 1) \
+  F(Math_sqrt, 1) \
+  F(Math_tan, 1) \
+  \
+  /* Regular expressions */ \
+  F(RegExpCompile, 3) \
+  F(RegExpExec, 3) \
+  F(RegExpExecGlobal, 2) \
+  \
+  /* Strings */ \
+  F(StringCharCodeAt, 2) \
+  F(StringIndexOf, 3) \
+  F(StringLastIndexOf, 3) \
+  F(StringLocaleCompare, 2) \
+  F(StringSlice, 3) \
+  \
+  /* Numbers */ \
+  F(NumberToRadixString, 2) \
+  F(NumberToFixed, 2) \
+  F(NumberToExponential, 2) \
+  F(NumberToPrecision, 2) \
+  \
+  /* Reflection */ \
+  F(FunctionSetInstanceClassName, 2) \
+  F(FunctionSetLength, 2) \
+  F(FunctionSetPrototype, 2) \
+  F(FunctionGetName, 1) \
+  F(FunctionSetName, 2) \
+  F(FunctionGetSourceCode, 1) \
+  F(FunctionGetScript, 1) \
+  F(FunctionGetScriptSourcePosition, 1) \
+  F(GetScript, 1) \
+  \
+  F(ClassOf, 1) \
+  F(HasDateClass, 1) \
+  F(HasStringClass, 1) \
+  F(HasArrayClass, 1) \
+  F(HasFunctionClass, 1) \
+  F(HasNumberClass, 1) \
+  F(HasBooleanClass, 1) \
+  F(HasArgumentsClass, 1) \
+  F(HasRegExpClass, 1) \
+  F(SetCode, 2) \
+  \
+  F(CreateApiFunction, 1) \
+  F(IsTemplate, 1) \
+  F(GetTemplateField, 2) \
+  \
+  /* Dates */ \
+  F(DateCurrentTime, 0) \
+  F(DateParseString, 1) \
+  F(DateLocalTimezone, 1) \
+  F(DateLocalTimeOffset, 0) \
+  F(DateDaylightSavingsOffset, 1) \
+  \
+  /* Numbers */ \
+  F(NumberIsFinite, 1) \
+  \
+  /* Globals */ \
+  F(CompileString, 3) \
+  F(CompileScript, 4) \
+  F(GlobalPrint, 1) \
+  \
+  /* Eval */ \
+  F(EvalReceiver, 1) \
+  F(GlobalReceiver, 1) \
+  \
+  F(SetProperty, -1 /* 3 or 4 */) \
+  F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */) \
+  \
+  /* Arrays */ \
+  F(RemoveArrayHoles, 1) \
+  F(GetArrayKeys, 2) \
+  F(MoveArrayContents, 2) \
+  F(EstimateNumberOfElements, 1) \
+  \
+  /* Getters and Setters */ \
+  F(DefineAccessor, -1 /* 4 or 5 */) \
+  F(LookupAccessor, 3) \
+  \
+  /* Debugging */ \
+  F(AddDebugEventListener, 2) \
+  F(RemoveDebugEventListener, 1) \
+  F(Break, 0) \
+  F(DebugGetPropertyDetails, 2) \
+  F(DebugGetProperty, 2) \
+  F(DebugLocalPropertyNames, 1) \
+  F(DebugLocalElementNames, 1) \
+  F(DebugPropertyTypeFromDetails, 1) \
+  F(DebugPropertyAttributesFromDetails, 1) \
+  F(DebugPropertyIndexFromDetails, 1) \
+  F(DebugInterceptorInfo, 1) \
+  F(DebugNamedInterceptorPropertyNames, 1) \
+  F(DebugIndexedInterceptorElementNames, 1) \
+  F(DebugNamedInterceptorPropertyValue, 2) \
+  F(DebugIndexedInterceptorElementValue, 2) \
+  F(CheckExecutionState, 1) \
+  F(GetFrameCount, 1) \
+  F(GetFrameDetails, 2) \
+  F(GetCFrames, 1) \
+  F(GetBreakLocations, 1) \
+  F(SetFunctionBreakPoint, 3) \
+  F(SetScriptBreakPoint, 3) \
+  F(ClearBreakPoint, 1) \
+  F(ChangeBreakOnException, 2) \
+  F(PrepareStep, 3) \
+  F(ClearStepping, 0) \
+  F(DebugEvaluate, 4) \
+  F(DebugEvaluateGlobal, 3) \
+  F(DebugGetLoadedScripts, 0) \
+  F(DebugReferencedBy, 3) \
+  F(DebugConstructedBy, 2) \
+  F(GetPrototype, 1) \
+  F(SystemBreak, 0) \
+  \
+  /* Literals */ \
+  F(MaterializeRegExpLiteral, 4)\
+  F(CreateArrayLiteral, 2) \
+  F(CreateObjectLiteralBoilerplate, 3) \
+  F(CloneObjectLiteralBoilerplate, 1) \
+  \
+  /* Statements */ \
+  F(NewClosure, 2) \
+  F(NewObject, 1) \
+  F(Throw, 1) \
+  F(ReThrow, 1) \
+  F(ThrowReferenceError, 1) \
+  F(StackGuard, 1) \
+  \
+  /* Contexts */ \
+  F(NewContext, 1) \
+  F(PushContext, 1) \
+  F(LookupContext, 2) \
+  F(LoadContextSlot, 2) \
+  F(LoadContextSlotNoReferenceError, 2) \
+  F(StoreContextSlot, 3) \
+  \
+  /* Declarations and initialization */ \
+  F(DeclareGlobals, 3) \
+  F(DeclareContextSlot, 4) \
+  F(InitializeVarGlobal, -1 /* 1 or 2 */) \
+  F(InitializeConstGlobal, 2) \
+  F(InitializeConstContextSlot, 3) \
+  \
+  /* Debugging */ \
+  F(DebugPrint, 1) \
+  F(DebugTrace, 0) \
+  F(TraceEnter, 0) \
+  F(TraceExit, 1) \
+  F(DebugBreak, 0) \
+  F(FunctionGetAssemblerCode, 1) \
+  F(Abort, 2) \
+  \
+  /* Pseudo functions - handled as macros by parser */ \
+  F(IS_VAR, 1)
+
+
+#ifdef DEBUG
+#define RUNTIME_FUNCTION_LIST_DEBUG(F) \
+  /* Testing */ \
+  F(ListNatives, 0)
+#else
+#define RUNTIME_FUNCTION_LIST_DEBUG(F)
+#endif
+
+
+// ----------------------------------------------------------------------------
+// RUNTIME_FUNCTION_LIST defines all runtime functions accessed
+// either directly by id (via the code generator), or indirectly
+// via a native call by name (from within JS code).
+
+#define RUNTIME_FUNCTION_LIST(F) \
+  RUNTIME_FUNCTION_LIST_ALWAYS(F) \
+  RUNTIME_FUNCTION_LIST_DEBUG(F)
+
+// ----------------------------------------------------------------------------
+// Runtime provides access to all C++ runtime functions.
+
+class Runtime : public AllStatic {
+ public:
+  enum FunctionId {
+#define F(name, nargs) k##name,
+    RUNTIME_FUNCTION_LIST(F)
+    kNofFunctions
+#undef F
+  };
+  static Object* CreateArrayLiteral(Arguments args);
+
+  // Runtime function descriptor.
+  struct Function {
+    // The JS name of the function.
+    const char* name;
+
+    // The name of the stub that calls the runtime function.
+    const char* stub_name;
+
+    // The C++ (native) entry point.
+    byte* entry;
+
+    // The number of arguments expected; nargs < 0 if variable no. of
+    // arguments.
+    int nargs;
+    int stub_id;
+  };
+
+  // Get the runtime function with the given function id.
+  static Function* FunctionForId(FunctionId fid);
+
+  // Get the runtime function with the given name.
+  static Function* FunctionForName(const char* name);
+
+  static int StringMatch(Handle<String> sub, Handle<String> pat, int index);
+
+  // TODO(1240886): The following three methods are *not* handle safe,
+  // but accept handle arguments. This seems fragile.
+
+  // Support getting the characters in a string using [] notation as
+  // in Firefox/SpiderMonkey, Safari and Opera.
+  static Object* GetElementOrCharAt(Handle<Object> object, uint32_t index);
+
+  static Object* SetObjectProperty(Handle<Object> object,
+                                   Handle<Object> key,
+                                   Handle<Object> value,
+                                   PropertyAttributes attr);
+
+  static Object* GetObjectProperty(Handle<Object> object, Handle<Object> key);
+
+  // Helper functions used stubs.
+  static void PerformGC(Object* result);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_RUNTIME_H_
diff --git a/regexp2000/src/runtime.js b/regexp2000/src/runtime.js
new file mode 100644 (file)
index 0000000..1355356
--- /dev/null
@@ -0,0 +1,524 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This files contains runtime support implemented in JavaScript.
+
+// CAUTION: Some of the functions specified in this file are called
+// directly from compiled code. These are the functions with names in
+// ALL CAPS. The compiled code passes the first argument in 'this' and
+// it does not push the function onto the stack. This means that you
+// cannot use contexts in all these functions.
+
+
+/* -----------------------------------
+   - - -   C o m p a r i s o n   - - -
+   -----------------------------------
+*/
+
+// The following const declarations are shared with other native JS files.
+// They are all declared at this one spot to avoid const redeclaration errors.
+const $Object = global.Object;
+const $Array = global.Array;
+const $String = global.String;
+const $Number = global.Number;
+const $Function = global.Function;
+const $Boolean = global.Boolean;
+const $NaN = 0/0;
+
+
+// ECMA-262, section 11.9.1, page 55.
+function EQUALS(y) {
+  if (IS_STRING(this) && IS_STRING(y)) return %StringEquals(this, y);
+  var x = this;
+
+  // NOTE: We use iteration instead of recursion, because it is
+  // difficult to call EQUALS with the correct setting of 'this' in
+  // an efficient way.
+  while (true) {
+    if (IS_NUMBER(x)) {
+      if (y == null) return 1;  // not equal
+      return %NumberEquals(x, %ToNumber(y));
+    } else if (IS_STRING(x)) {
+      if (IS_STRING(y)) return %StringEquals(x, y);
+      if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y);
+      if (IS_BOOLEAN(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y));
+      if (y == null) return 1;  // not equal
+      y = %ToPrimitive(y, NO_HINT);
+    } else if (IS_BOOLEAN(x)) {
+      if (IS_BOOLEAN(y)) {
+        return %_ObjectEquals(x, y) ? 0 : 1;
+      }
+      if (y == null) return 1;  // not equal
+      return %NumberEquals(%ToNumber(x), %ToNumber(y));
+    } else if (x == null) {
+      // NOTE: This checks for both null and undefined.
+      return (y == null) ? 0 : 1;
+    } else {
+      if (IS_OBJECT(y)) {
+        return %_ObjectEquals(x, y) ? 0 : 1;
+      }
+      if (IS_FUNCTION(y)) {
+        return %_ObjectEquals(x, y) ? 0 : 1;
+      }
+      x = %ToPrimitive(x, NO_HINT);
+    }
+  }
+}
+
+// ECMA-262, section 11.9.4, page 56.
+function STRICT_EQUALS(x) {
+  if (IS_STRING(this)) {
+    if (!IS_STRING(x)) return 1;  // not equal
+    return %StringEquals(this, x);
+  } 
+
+  if (IS_NUMBER(this)) {
+    if (!IS_NUMBER(x)) return 1;  // not equal
+    return %NumberEquals(this, x);
+  } 
+
+  if (IS_UNDEFINED(this)) {  
+    // Both undefined and undetectable.
+    return IS_UNDEFINED(x) ? 0 : 1;
+  }
+
+  // Objects, null, booleans and functions are all that's left.
+  // They can all be compared with a simple identity check.
+  return %_ObjectEquals(this, x) ? 0 : 1;
+}
+
+
+// ECMA-262, section 11.8.5, page 53. The 'ncr' parameter is used as
+// the result when either (or both) the operands are NaN.
+function COMPARE(x, ncr) {
+  // Fast case for numbers and strings.
+  if (IS_NUMBER(this) && IS_NUMBER(x)) {
+    return %NumberCompare(this, x, ncr);
+  }
+  if (IS_STRING(this) && IS_STRING(x)) {
+    return %StringCompare(this, x);
+  }
+
+  // Default implementation.
+  var a = %ToPrimitive(this, NUMBER_HINT);
+  var b = %ToPrimitive(x, NUMBER_HINT);
+  if (IS_STRING(a) && IS_STRING(b)) {
+    return %StringCompare(a, b);
+  } else {
+    return %NumberCompare(%ToNumber(a), %ToNumber(b), ncr);
+  }
+}
+
+
+
+/* -----------------------------------
+   - - -   A r i t h m e t i c   - - -
+   -----------------------------------
+*/
+
+// ECMA-262, section 11.6.1, page 50.
+function ADD(x) {
+  // Fast case: Check for number operands and do the addition.
+  if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x);
+  if (IS_STRING(this) && IS_STRING(x)) return %StringAdd(this, x);
+
+  // Default implementation.
+  var a = %ToPrimitive(this, NO_HINT);
+  var b = %ToPrimitive(x, NO_HINT);
+  
+  if (IS_STRING(a)) {
+    return %StringAdd(a, %ToString(b));
+  } else if (IS_STRING(b)) {
+    return %StringAdd(%ToString(a), b);
+  } else {
+    return %NumberAdd(%ToNumber(a), %ToNumber(b));
+  }
+}
+
+
+// ECMA-262, section 11.6.2, page 50.
+function SUB(x) {
+  return %NumberSub(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.5.1, page 48.
+function MUL(x) {
+  return %NumberMul(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.5.2, page 49.
+function DIV(x) {
+  return %NumberDiv(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.5.3, page 49.
+function MOD(x) {
+  return %NumberMod(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.4.4, page 47.
+function INC() {
+  return %NumberAdd(%ToNumber(this), 1);
+}
+
+
+// ECMA-262, section 11.4.5, page 48.
+function DEC() {
+  return %NumberSub(%ToNumber(this), 1);
+}
+
+
+
+/* -------------------------------------------
+   - - -   B i t   o p e r a t i o n s   - - -
+   -------------------------------------------
+*/
+
+// ECMA-262, section 11.10, page 57.
+function BIT_OR(x) {
+  return %NumberOr(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.10, page 57.
+function BIT_AND(x) {
+  return %NumberAnd(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.10, page 57.
+function BIT_XOR(x) {
+  return %NumberXor(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.4.7, page 47.
+function UNARY_MINUS() {
+  return %NumberUnaryMinus(%ToNumber(this));
+}
+
+
+// ECMA-262, section 11.4.8, page 48.
+function BIT_NOT() {
+  return %NumberNot(%ToNumber(this));
+}
+
+
+// ECMA-262, section 11.7.1, page 51.
+function SHL(x) {
+  return %NumberShl(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.7.2, page 51.
+function SAR(x) {
+  return %NumberSar(%ToNumber(this), %ToNumber(x));
+}
+
+
+// ECMA-262, section 11.7.3, page 52.
+function SHR(x) {
+  return %NumberShr(%ToNumber(this), %ToNumber(x));
+}
+
+
+
+/* -----------------------------
+   - - -   H e l p e r s   - - -
+   -----------------------------
+*/
+
+// ECMA-262, section 11.4.1, page 46.
+function DELETE(key) {
+  return %DeleteProperty(%ToObject(this), %ToString(key));
+}
+
+
+// ECMA-262, section 11.8.7, page 54.
+function IN(x) {
+  if (x == null || (!IS_OBJECT(x) && !IS_FUNCTION(x))) {
+    throw %MakeTypeError('invalid_in_operator_use', [this, x]);
+  }
+  return %_IsNonNegativeSmi(this) ? %HasElement(x, this) : %HasProperty(x, %ToString(this));
+}
+
+
+// ECMA-262, section 11.8.6, page 54. To make the implementation more
+// efficient, the return value should be zero if the 'this' is an 
+// instance of F, and non-zero if not. This makes it possible to avoid
+// an expensive ToBoolean conversion in the generated code.
+function INSTANCE_OF(F) {
+  var V = this;
+  if (!IS_FUNCTION(F)) {
+    throw %MakeTypeError('instanceof_function_expected', [V]);
+  }
+
+  // If V is not an object, return false.
+  if (IS_NULL(V) || (!IS_OBJECT(V) && !IS_FUNCTION(V))) {
+    return 1;
+  }
+
+  // Get the prototype of F; if it is not an object, throw an error.
+  var O = F.prototype;
+  if (IS_NULL(O) || (!IS_OBJECT(O) && !IS_FUNCTION(O))) {
+    throw %MakeTypeError('instanceof_nonobject_proto', [O]);
+  }
+
+  // Return whether or not O is in the prototype chain of V.
+  return %IsInPrototypeChain(O, V) ? 0 : 1;
+}
+
+
+// Get an array of property keys for the given object. Used in
+// for-in statements.
+function GET_KEYS() {
+  return %GetPropertyNames(this);
+}
+
+
+// Filter a given key against an object by checking if the object
+// has a property with the given key; return the key as a string if
+// it has. Otherwise returns null. Used in for-in statements.
+function FILTER_KEY(key) {
+  var string = %ToString(key);
+  if (%HasProperty(this, string)) return string;
+  return null;
+}
+
+
+function CALL_NON_FUNCTION() {
+  var callee = %GetCalledFunction();
+  var delegate = %GetFunctionDelegate(callee);
+  if (!IS_FUNCTION(delegate)) {
+    throw %MakeTypeError('called_non_callable', [typeof callee]);
+  }
+
+  var parameters = %NewArguments(delegate);
+  return delegate.apply(callee, parameters);
+}
+
+
+function APPLY_PREPARE(args) {
+  var length;
+  // First check whether length is a positive Smi and args is an array.  This is the
+  // fast case.  If this fails, we do the slow case that takes care of more eventualities
+  if (%_IsArray(args)) {
+    length = args.length;
+    if (%_IsSmi(length) && length >= 0 && length < 0x800000 && IS_FUNCTION(this)) {
+      return length;
+    }
+  }
+
+  length = (args == null) ? 0 : %ToUint32(args.length);
+
+  // We can handle any number of apply arguments if the stack is
+  // big enough, but sanity check the value to avoid overflow when
+  // multiplying with pointer size.
+  if (length > 0x800000) {
+    throw %MakeRangeError('apply_overflow', [length]);
+  }
+
+  if (!IS_FUNCTION(this)) {
+    throw %MakeTypeError('apply_non_function', [ %ToString(this), typeof this ]);
+  }
+
+  // Make sure the arguments list has the right type.
+  if (args != null &&
+      !%HasArrayClass(args) &&
+      !%HasArgumentsClass(args)) {
+    throw %MakeTypeError('apply_wrong_args', []);
+  }
+
+  // Return the length which is the number of arguments to copy to the
+  // stack. It is guaranteed to be a small integer at this point.
+  return length;
+}
+
+
+function APPLY_OVERFLOW(length) {
+  throw %MakeRangeError('apply_overflow', [length]);
+}
+
+
+// Convert the receiver to an object - forward to ToObject.
+function TO_OBJECT() {
+  return %ToObject(this);
+}
+
+
+// Convert the receiver to a number - forward to ToNumber.
+function TO_NUMBER() {
+  return %ToNumber(this);
+}
+
+
+// Convert the receiver to a string - forward to ToString.
+function TO_STRING() {
+  return %ToString(this);
+}
+
+
+/* -------------------------------------
+   - - -   C o n v e r s i o n s   - - -
+   -------------------------------------
+*/
+
+// ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
+// (1) for number hint, and (2) for string hint.
+function ToPrimitive(x, hint) {
+  // Fast case check.
+  if (IS_STRING(x)) return x;
+  // Normal behavior.
+  if (!IS_OBJECT(x) && !IS_FUNCTION(x)) return x;
+  if (x == null) return x;  // check for null, undefined
+  if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
+  return (hint == NUMBER_HINT) ? %DefaultNumber(x) : %DefaultString(x);
+}
+
+
+// ECMA-262, section 9.3, page 31.
+function ToNumber(x) {
+  if (IS_NUMBER(x)) return x;
+  if (IS_STRING(x)) return %StringToNumber(x);
+  if (IS_BOOLEAN(x)) return x ? 1 : 0;
+  if (IS_UNDEFINED(x)) return $NaN;
+  return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
+}
+
+
+// ECMA-262, section 9.8, page 35.
+function ToString(x) {
+  if (IS_STRING(x)) return x;
+  if (IS_NUMBER(x)) return %NumberToString(x);
+  if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
+  if (IS_UNDEFINED(x)) return 'undefined';
+  return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
+}
+
+
+// ... where did this come from?
+function ToBoolean(x) {
+  if (IS_BOOLEAN(x)) return x;
+  if (IS_STRING(x)) return x.length != 0;
+  if (x == null) return false;
+  if (IS_NUMBER(x)) return !((x == 0) || NUMBER_IS_NAN(x));
+  return true;
+}
+
+
+// ECMA-262, section 9.9, page 36.
+function ToObject(x) {
+  if (IS_STRING(x)) return new $String(x);
+  if (IS_NUMBER(x)) return new $Number(x);
+  if (IS_BOOLEAN(x)) return new $Boolean(x);
+  if (x == null) throw %MakeTypeError('null_to_object', []);
+  return x;
+}
+
+
+// ECMA-262, section 9.4, page 34.
+function ToInteger(x) {
+  if (%_IsSmi(x)) return x;
+  return %NumberToInteger(ToNumber(x));
+}
+
+
+// ECMA-262, section 9.6, page 34.
+function ToUint32(x) {
+  if (%_IsSmi(x) && x >= 0) return x;
+  return %NumberToJSUint32(ToNumber(x));
+}
+
+
+// ECMA-262, section 9.5, page 34
+function ToInt32(x) {
+  if (%_IsSmi(x)) return x;
+  return %NumberToJSInt32(ToNumber(x));
+}
+
+
+
+/* ---------------------------------
+   - - -   U t i l i t i e s   - - -
+   ---------------------------------
+*/
+
+// Returns if the given x is a primitive value - not an object or a
+// function.
+function IsPrimitive(x) {
+  if (!IS_OBJECT(x) && !IS_FUNCTION(x)) {
+    return true;
+  } else {
+    // Even though the type of null is "object", null is still
+    // considered a primitive value.
+    return IS_NULL(x);
+  }
+}
+
+
+// ECMA-262, section 8.6.2.6, page 28.
+function DefaultNumber(x) {
+  if (IS_FUNCTION(x.valueOf)) {
+    var v = x.valueOf();
+    if (%IsPrimitive(v)) return v;
+  }
+
+  if (IS_FUNCTION(x.toString)) {
+    var s = x.toString();
+    if (%IsPrimitive(s)) return s;
+  }
+
+  throw %MakeTypeError('cannot_convert_to_primitive', []);
+}
+
+
+// ECMA-262, section 8.6.2.6, page 28.
+function DefaultString(x) {
+  if (IS_FUNCTION(x.toString)) {
+    var s = x.toString();
+    if (%IsPrimitive(s)) return s;
+  }
+
+  if (IS_FUNCTION(x.valueOf)) {
+    var v = x.valueOf();
+    if (%IsPrimitive(v)) return v;
+  }
+
+  throw %MakeTypeError('cannot_convert_to_primitive', []);
+}
+
+
+// NOTE: Setting the prototype for Array must take place as early as
+// possible due to code generation for array literals.  When
+// generating code for a array literal a boilerplate array is created
+// that is cloned when running the code.  It is essiential that the
+// boilerplate gets the right prototype.
+%FunctionSetPrototype($Array, new $Array(0));
diff --git a/regexp2000/src/scanner.cc b/regexp2000/src/scanner.cc
new file mode 100644 (file)
index 0000000..a6cc74a
--- /dev/null
@@ -0,0 +1,826 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+#include "scanner.h"
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// Character predicates
+
+
+unibrow::Predicate<IdentifierStart, 128> Scanner::kIsIdentifierStart;
+unibrow::Predicate<IdentifierPart, 128> Scanner::kIsIdentifierPart;
+unibrow::Predicate<unibrow::LineTerminator, 128> Scanner::kIsLineTerminator;
+unibrow::Predicate<unibrow::WhiteSpace, 128> Scanner::kIsWhiteSpace;
+
+
+StaticResource<Scanner::Utf8Decoder> Scanner::utf8_decoder_;
+
+
+// ----------------------------------------------------------------------------
+// UTF8Buffer
+
+UTF8Buffer::UTF8Buffer() : data_(NULL) {
+  Initialize(NULL, 0);
+}
+
+
+UTF8Buffer::~UTF8Buffer() {
+  DeleteArray(data_);
+}
+
+
+void UTF8Buffer::Initialize(char* src, int length) {
+  DeleteArray(data_);
+  data_ = src;
+  size_ = length;
+  Reset();
+}
+
+
+void UTF8Buffer::AddChar(uc32 c) {
+  const int min_size = 1024;
+  if (pos_ + static_cast<int>(unibrow::Utf8::kMaxEncodedSize) > size_) {
+    int new_size = size_ * 2;
+    if (new_size < min_size) {
+      new_size = min_size;
+    }
+    char* new_data = NewArray<char>(new_size);
+    memcpy(new_data, data_, pos_);
+    DeleteArray(data_);
+    data_ = new_data;
+    size_ = new_size;
+  }
+  if (static_cast<unsigned>(c) < unibrow::Utf8::kMaxOneByteChar) {
+    data_[pos_++] = c;  // common case: 7bit ASCII
+  } else {
+    pos_ += unibrow::Utf8::Encode(&data_[pos_], c);
+  }
+  ASSERT(pos_ <= size_);
+}
+
+
+// ----------------------------------------------------------------------------
+// UTF16Buffer
+
+
+UTF16Buffer::UTF16Buffer()
+  : pos_(0),
+    pushback_buffer_(0),
+    last_(0),
+    stream_(NULL) { }
+
+
+void UTF16Buffer::Initialize(Handle<String> data,
+                             unibrow::CharacterStream* input) {
+  data_ = data;
+  pos_ = 0;
+  stream_ = input;
+}
+
+
+Handle<String> UTF16Buffer::SubString(int start, int end) {
+  return internal::SubString(data_, start, end);
+}
+
+
+void UTF16Buffer::PushBack(uc32 ch) {
+  pushback_buffer()->Add(last_);
+  last_ = ch;
+  pos_--;
+}
+
+
+uc32 UTF16Buffer::Advance() {
+  // NOTE: It is of importance to Persian / Farsi resources that we do
+  // *not* strip format control characters in the scanner; see
+  //
+  //    https://bugzilla.mozilla.org/show_bug.cgi?id=274152
+  //
+  // So, even though ECMA-262, section 7.1, page 11, dictates that we
+  // must remove Unicode format-control characters, we do not. This is
+  // in line with how IE and SpiderMonkey handles it.
+  if (!pushback_buffer()->is_empty()) {
+    pos_++;
+    return last_ = pushback_buffer()->RemoveLast();
+  } else if (stream_->has_more()) {
+    pos_++;
+    uc32 next = stream_->GetNext();
+    return last_ = next;
+  } else {
+    // note: currently the following increment is necessary to avoid a
+    // test-parser problem!
+    pos_++;
+    return last_ = static_cast<uc32>(-1);
+  }
+}
+
+
+void UTF16Buffer::SeekForward(int pos) {
+  pos_ = pos;
+  ASSERT(pushback_buffer()->is_empty());
+  stream_->Seek(pos);
+}
+
+
+// ----------------------------------------------------------------------------
+// Scanner
+
+Scanner::Scanner(bool pre) : stack_overflow_(false), is_pre_parsing_(pre) {
+  Token::Initialize();
+}
+
+
+void Scanner::Init(Handle<String> source, unibrow::CharacterStream* stream,
+    int position) {
+  // Initialize the source buffer.
+  source_.Initialize(source, stream);
+  position_ = position;
+
+  // Reset literals buffer
+  literals_.Reset();
+
+  // Set c0_ (one character ahead)
+  ASSERT(kCharacterLookaheadBufferSize == 1);
+  Advance();
+
+  // Skip initial whitespace (allowing HTML comment ends) and scan
+  // first token.
+  SkipWhiteSpace(true);
+  Scan();
+}
+
+
+Handle<String> Scanner::SubString(int start, int end) {
+  return source_.SubString(start - position_, end - position_);
+}
+
+
+Token::Value Scanner::Next() {
+  // BUG 1215673: Find a thread safe way to set a stack limit in
+  // pre-parse mode. Otherwise, we cannot safely pre-parse from other
+  // threads.
+  current_ = next_;
+  // Check for stack-overflow before returning any tokens.
+  StackLimitCheck check;
+  if (check.HasOverflowed()) {
+    stack_overflow_ = true;
+    next_.token = Token::ILLEGAL;
+  } else {
+    Scan();
+  }
+  return current_.token;
+}
+
+
+void Scanner::StartLiteral() {
+  next_.literal_pos = literals_.pos();
+}
+
+
+void Scanner::AddChar(uc32 c) {
+  literals_.AddChar(c);
+}
+
+
+void Scanner::TerminateLiteral() {
+  next_.literal_end = literals_.pos();
+  AddChar(0);
+}
+
+
+void Scanner::AddCharAdvance() {
+  AddChar(c0_);
+  Advance();
+}
+
+
+void Scanner::Advance() {
+  c0_ = source_.Advance();
+}
+
+
+void Scanner::PushBack(uc32 ch) {
+  source_.PushBack(ch);
+  c0_ = ch;
+}
+
+
+void Scanner::SkipWhiteSpace(bool initial) {
+  has_line_terminator_before_next_ = initial;
+
+  while (true) {
+    while (kIsWhiteSpace.get(c0_)) {
+      // IsWhiteSpace() includes line terminators!
+      if (kIsLineTerminator.get(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;
+  }
+}
+
+
+Token::Value Scanner::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, page 12).
+  while (c0_ >= 0 && !kIsLineTerminator.get(c0_)) {
+    Advance();
+  }
+
+  return Token::COMMENT;
+}
+
+
+Token::Value Scanner::SkipMultiLineComment() {
+  ASSERT(c0_ == '*');
+  Advance();
+
+  while (c0_ >= 0) {
+    char ch = c0_;
+    Advance();
+    // 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 - even the ones
+    // containing line terminators. This contradicts ECMA-262, section
+    // 7.4, page 12, that says that multi-line comments containing
+    // line terminators should be treated as a line terminator, but it
+    // matches the behaviour of SpiderMonkey and KJS.
+    if (ch == '*' && c0_ == '/') {
+      c0_ = ' ';
+      return Token::COMMENT;
+    }
+  }
+
+  // Unterminated multi-line comment.
+  return Token::ILLEGAL;
+}
+
+
+Token::Value Scanner::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 Scanner::Scan() {
+  Token::Value token;
+  bool has_line_terminator = false;
+  do {
+    SkipWhiteSpace(has_line_terminator);
+
+    // Remember the line terminator in previous loop
+    has_line_terminator = has_line_terminator_before_next();
+
+    // Remember the position of the next token
+    next_.location.beg_pos = source_pos();
+
+    token = ScanToken();
+  } while (token == Token::COMMENT);
+
+  next_.location.end_pos = source_pos();
+  next_.token = token;
+}
+
+
+void Scanner::SeekForward(int pos) {
+  source_.SeekForward(pos - 1);
+  Advance();
+  Scan();
+}
+
+
+uc32 Scanner::ScanHexEscape(uc32 c, int length) {
+  ASSERT(length <= 4);  // prevent overflow
+
+  uc32 digits[4];
+  uc32 x = 0;
+  for (int i = 0; i < 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 read, except the last one (in c0_).
+      for (int j = i-1; j >= 0; j--) {
+        PushBack(digits[j]);
+      }
+
+      return c;
+    }
+    x = x * 16 + d;
+    Advance();
+  }
+
+  return x;
+}
+
+
+// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
+// ECMA-262. Other JS VMs support them.
+uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
+  uc32 x = c - '0';
+  for (int i = 0; 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();
+  }
+  return x;
+}
+
+
+void Scanner::ScanEscape() {
+  uc32 c = c0_;
+  Advance();
+
+  // Skip escaped newlines.
+  if (kIsLineTerminator.get(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 = ScanHexEscape(c, 4); break;
+    case 'v' : c = '\v'; break;
+    case 'x' : c = ScanHexEscape(c, 2); 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.
+  AddChar(c);
+}
+
+
+Token::Value Scanner::ScanString() {
+  uc32 quote = c0_;
+  Advance();  // consume quote
+
+  StartLiteral();
+  while (c0_ != quote && c0_ >= 0 && !kIsLineTerminator.get(c0_)) {
+    uc32 c = c0_;
+    Advance();
+    if (c == '\\') {
+      if (c0_ < 0) return Token::ILLEGAL;
+      ScanEscape();
+    } else {
+      AddChar(c);
+    }
+  }
+  if (c0_ != quote) {
+    return Token::ILLEGAL;
+  }
+  TerminateLiteral();
+
+  Advance();  // consume quote
+  return Token::STRING;
+}
+
+
+Token::Value Scanner::Select(Token::Value tok) {
+  Advance();
+  return tok;
+}
+
+
+Token::Value Scanner::Select(uc32 next, Token::Value then, Token::Value else_) {
+  Advance();
+  if (c0_ == next) {
+    Advance();
+    return then;
+  } else {
+    return else_;
+  }
+}
+
+
+Token::Value Scanner::ScanToken() {
+  switch (c0_) {
+    // strings
+    case '"': case '\'':
+      return ScanString();
+
+    case '<':
+      // < <= << <<= <!--
+      Advance();
+      if (c0_ == '=') return Select(Token::LTE);
+      if (c0_ == '<') return Select('=', Token::ASSIGN_SHL, Token::SHL);
+      if (c0_ == '!') return ScanHtmlComment();
+      return Token::LT;
+
+    case '>':
+      // > >= >> >>= >>> >>>=
+      Advance();
+      if (c0_ == '=') return Select(Token::GTE);
+      if (c0_ == '>') {
+        // >> >>= >>> >>>=
+        Advance();
+        if (c0_ == '=') return Select(Token::ASSIGN_SAR);
+        if (c0_ == '>') return Select('=', Token::ASSIGN_SHR, Token::SHR);
+        return Token::SAR;
+      }
+      return Token::GT;
+
+    case '=':
+      // = == ===
+      Advance();
+      if (c0_ == '=') return Select('=', Token::EQ_STRICT, Token::EQ);
+      return Token::ASSIGN;
+
+    case '!':
+      // ! != !==
+      Advance();
+      if (c0_ == '=') return Select('=', Token::NE_STRICT, Token::NE);
+      return Token::NOT;
+
+    case '+':
+      // + ++ +=
+      Advance();
+      if (c0_ == '+') return Select(Token::INC);
+      if (c0_ == '=') return Select(Token::ASSIGN_ADD);
+      return Token::ADD;
+
+    case '-':
+      // - -- -=
+      Advance();
+      if (c0_ == '-') return Select(Token::DEC);
+      if (c0_ == '=') return Select(Token::ASSIGN_SUB);
+      return Token::SUB;
+
+    case '*':
+      // * *=
+      return Select('=', Token::ASSIGN_MUL, Token::MUL);
+
+    case '%':
+      // % %=
+      return Select('=', Token::ASSIGN_MOD, Token::MOD);
+
+    case '/':
+      // /  // /* /=
+      Advance();
+      if (c0_ == '/') return SkipSingleLineComment();
+      if (c0_ == '*') return SkipMultiLineComment();
+      if (c0_ == '=') return Select(Token::ASSIGN_DIV);
+      return Token::DIV;
+
+    case '&':
+      // & && &=
+      Advance();
+      if (c0_ == '&') return Select(Token::AND);
+      if (c0_ == '=') return Select(Token::ASSIGN_BIT_AND);
+      return Token::BIT_AND;
+
+    case '|':
+      // | || |=
+      Advance();
+      if (c0_ == '|') return Select(Token::OR);
+      if (c0_ == '=') return Select(Token::ASSIGN_BIT_OR);
+      return Token::BIT_OR;
+
+    case '^':
+      // ^ ^=
+      return Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
+
+    case '.':
+      // . Number
+      Advance();
+      if (IsDecimalDigit(c0_)) return ScanNumber(true);
+      return Token::PERIOD;
+
+    case ':':
+      return Select(Token::COLON);
+
+    case ';':
+      return Select(Token::SEMICOLON);
+
+    case ',':
+      return Select(Token::COMMA);
+
+    case '(':
+      return Select(Token::LPAREN);
+
+    case ')':
+      return Select(Token::RPAREN);
+
+    case '[':
+      return Select(Token::LBRACK);
+
+    case ']':
+      return Select(Token::RBRACK);
+
+    case '{':
+      return Select(Token::LBRACE);
+
+    case '}':
+      return Select(Token::RBRACE);
+
+    case '?':
+      return Select(Token::CONDITIONAL);
+
+    case '~':
+      return Select(Token::BIT_NOT);
+
+    default:
+      if (kIsIdentifierStart.get(c0_))
+        return ScanIdentifier();
+      if (IsDecimalDigit(c0_))
+        return ScanNumber(false);
+      if (c0_ < 0)
+        return Token::EOS;
+      return Select(Token::ILLEGAL);
+  }
+
+  UNREACHABLE();
+  return Token::ILLEGAL;
+}
+
+
+// Returns true if any decimal digits were scanned, returns false otherwise.
+void Scanner::ScanDecimalDigits() {
+  while (IsDecimalDigit(c0_))
+    AddCharAdvance();
+}
+
+
+Token::Value Scanner::ScanNumber(bool seen_period) {
+  ASSERT(IsDecimalDigit(c0_));  // the first digit of the number or the fraction
+
+  enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
+
+  StartLiteral();
+  if (seen_period) {
+    // we have already seen a decimal point of the float
+    AddChar('.');
+    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') {
+      AddCharAdvance();
+
+      // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
+      if (c0_ == 'x' || c0_ == 'X') {
+        // hex number
+        kind = HEX;
+        AddCharAdvance();
+        if (!IsHexDigit(c0_))
+          // we must have at least one hex digit after 'x'/'X'
+          return Token::ILLEGAL;
+        while (IsHexDigit(c0_))
+          AddCharAdvance();
+
+      } 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_) break;
+          AddCharAdvance();
+        }
+      }
+    }
+
+    // Parse decimal digits and allow trailing fractional part.
+    if (kind == DECIMAL) {
+      ScanDecimalDigits();  // optional
+      if (c0_ == '.') {
+        AddCharAdvance();
+        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
+    AddCharAdvance();
+    if (c0_ == '+' || c0_ == '-')
+      AddCharAdvance();
+    if (!IsDecimalDigit(c0_))
+      // we must have at least one decimal digit after 'e'/'E'
+      return Token::ILLEGAL;
+    ScanDecimalDigits();
+  }
+  TerminateLiteral();
+
+  // 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_) || kIsIdentifierStart.get(c0_))
+    return Token::ILLEGAL;
+
+  return Token::NUMBER;
+}
+
+
+uc32 Scanner::ScanIdentifierUnicodeEscape() {
+  Advance();
+  if (c0_ != 'u') return unibrow::Utf8::kBadChar;
+  Advance();
+  uc32 c = ScanHexEscape('u', 4);
+  // We do not allow a unicode escape sequence to start another
+  // unicode escape sequence.
+  if (c == '\\') return unibrow::Utf8::kBadChar;
+  return c;
+}
+
+
+Token::Value Scanner::ScanIdentifier() {
+  ASSERT(kIsIdentifierStart.get(c0_));
+
+  bool has_escapes = false;
+
+  StartLiteral();
+  // Scan identifier start character.
+  if (c0_ == '\\') {
+    has_escapes = true;
+    uc32 c = ScanIdentifierUnicodeEscape();
+    // Only allow legal identifier start characters.
+    if (!kIsIdentifierStart.get(c)) return Token::ILLEGAL;
+    AddChar(c);
+  } else {
+    AddCharAdvance();
+  }
+  // Scan the rest of the identifier characters.
+  while (kIsIdentifierPart.get(c0_)) {
+    if (c0_ == '\\') {
+      has_escapes = true;
+      uc32 c = ScanIdentifierUnicodeEscape();
+      // Only allow legal identifier part characters.
+      if (!kIsIdentifierPart.get(c)) return Token::ILLEGAL;
+      AddChar(c);
+    } else {
+      AddCharAdvance();
+    }
+  }
+  TerminateLiteral();
+
+  // We don't have any 1-letter keywords (this is probably a common case).
+  if ((next_.literal_end - next_.literal_pos) == 1)
+    return Token::IDENTIFIER;
+
+  // If the identifier contains unicode escapes, it must not be
+  // resolved to a keyword.
+  if (has_escapes)
+    return Token::IDENTIFIER;
+
+  return Token::Lookup(&literals_.data()[next_.literal_pos]);
+}
+
+
+
+bool Scanner::IsIdentifier(unibrow::CharacterStream* buffer) {
+  // Checks whether the buffer contains an identifier (no escapse).
+  if (!buffer->has_more()) return false;
+  if (!kIsIdentifierStart.get(buffer->GetNext())) return false;
+  while (buffer->has_more()) {
+    if (!kIsIdentifierPart.get(buffer->GetNext())) return false;
+  }
+  return true;
+}
+
+
+bool Scanner::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.
+  StartLiteral();
+  if (seen_equal)
+    AddChar('=');
+
+  while (c0_ != '/' || in_character_class) {
+    if (kIsLineTerminator.get(c0_) || c0_ < 0)
+      return false;
+    if (c0_ == '\\') {  // escaped character
+      AddCharAdvance();
+      if (kIsLineTerminator.get(c0_) || c0_ < 0)
+        return false;
+      AddCharAdvance();
+    } else {  // unescaped character
+      if (c0_ == '[')
+        in_character_class = true;
+      if (c0_ == ']')
+        in_character_class = false;
+      AddCharAdvance();
+    }
+  }
+  Advance();  // consume '/'
+
+  TerminateLiteral();
+
+  return true;
+}
+
+bool Scanner::ScanRegExpFlags() {
+  // Scan regular expression flags.
+  StartLiteral();
+  while (kIsIdentifierPart.get(c0_))
+    AddCharAdvance();
+  TerminateLiteral();
+
+  next_.location.end_pos = source_pos() - 1;
+  return true;
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/scanner.h b/regexp2000/src/scanner.h
new file mode 100644 (file)
index 0000000..79a4a4c
--- /dev/null
@@ -0,0 +1,239 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SCANNER_H_
+#define V8_SCANNER_H_
+
+#include "token.h"
+#include "char-predicates-inl.h"
+
+namespace v8 { namespace internal {
+
+
+class UTF8Buffer {
+ public:
+  UTF8Buffer();
+  ~UTF8Buffer();
+
+  void Initialize(char* src, int length);
+  void AddChar(uc32 c);
+  void Reset() { pos_ = 0; }
+  int pos() const { return pos_; }
+  char* data() const { return data_; }
+
+ private:
+  char* data_;
+  int size_;
+  int pos_;
+};
+
+
+class UTF16Buffer {
+ public:
+  UTF16Buffer();
+
+  void Initialize(Handle<String> data, unibrow::CharacterStream* stream);
+  void PushBack(uc32 ch);
+  uc32 Advance();  // returns a value < 0 when the buffer end is reached
+  uint16_t CharAt(int index);
+  int pos() const { return pos_; }
+  int size() const { return size_; }
+  Handle<String> SubString(int start, int end);
+  List<uc32>* pushback_buffer() { return &pushback_buffer_; }
+  void SeekForward(int pos);
+
+ private:
+  Handle<String> data_;
+  int pos_;
+  int size_;
+  List<uc32> pushback_buffer_;
+  uc32 last_;
+  unibrow::CharacterStream* stream_;
+};
+
+
+class Scanner {
+ public:
+
+  typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
+
+  // Construction
+  explicit Scanner(bool is_pre_parsing);
+
+  // Initialize the Scanner to scan source:
+  void Init(Handle<String> source,
+            unibrow::CharacterStream* stream,
+            int position);
+
+  // Returns the next token.
+  Token::Value Next();
+
+  // One token look-ahead (past the token returned by Next()).
+  Token::Value peek() const  { return next_.token; }
+
+  // Returns true if there was a line terminator before the peek'ed token.
+  bool has_line_terminator_before_next() const {
+    return has_line_terminator_before_next_;
+  }
+
+  struct Location {
+    Location(int b, int e) : beg_pos(b), end_pos(e) { }
+    Location() : beg_pos(0), end_pos(0) { }
+    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.
+  const char* literal_string() const {
+    return &literals_.data()[current_.literal_pos];
+  }
+  int literal_length() const {
+    return current_.literal_end - current_.literal_pos;
+  }
+
+  Vector<const char> next_literal() const {
+    return Vector<const char>(next_literal_string(), next_literal_length());
+  }
+
+  // Returns the literal string for the next token (the token that
+  // would be returned if Next() were called).
+  const char* next_literal_string() const {
+    return &literals_.data()[next_.literal_pos];
+  }
+  // Returns the length of the next token (that would be returned if
+  // Next() were called).
+  int next_literal_length() const {
+    return next_.literal_end - next_.literal_pos;
+  }
+
+  // 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();
+
+  // 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);
+
+  Handle<String> SubString(int start_pos, int end_pos);
+  bool stack_overflow() { return stack_overflow_; }
+
+  static StaticResource<Utf8Decoder>* utf8_decoder() { return &utf8_decoder_; }
+
+  // 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);
+
+  static unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
+  static unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
+  static unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
+  static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
+
+ private:
+  // Source.
+  UTF16Buffer source_;
+  int position_;
+
+  // Buffer to hold literal values (identifiers, strings, numbers)
+  // using 0-terminated UTF-8 encoding.
+  UTF8Buffer literals_;
+
+  bool stack_overflow_;
+  static StaticResource<Utf8Decoder> utf8_decoder_;
+
+  // One Unicode character look-ahead; c0_ < 0 at the end of the input.
+  uc32 c0_;
+
+  // The current and look-ahead token.
+  struct TokenDesc {
+    Token::Value token;
+    Location location;
+    int literal_pos, literal_end;
+  };
+
+  TokenDesc current_;  // desc for current token (as returned by Next())
+  TokenDesc next_;     // desc for next token (one token look-ahead)
+  bool has_line_terminator_before_next_;
+  bool is_pre_parsing_;
+
+  static const int kCharacterLookaheadBufferSize = 1;
+
+  // Literal buffer support
+  void StartLiteral();
+  void AddChar(uc32 ch);
+  void AddCharAdvance();
+  void TerminateLiteral();
+
+  // Low-level scanning support.
+  void Advance();
+  void PushBack(uc32 ch);
+
+  void SkipWhiteSpace(bool initial);
+  Token::Value SkipSingleLineComment();
+  Token::Value SkipMultiLineComment();
+
+  inline Token::Value Select(Token::Value tok);
+  inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_);
+
+  void Scan();
+  Token::Value ScanToken();
+  void ScanDecimalDigits();
+  Token::Value ScanNumber(bool seen_period);
+  Token::Value ScanIdentifier();
+  uc32 ScanHexEscape(uc32 c, int length);
+  uc32 ScanOctalEscape(uc32 c, int length);
+  void ScanEscape();
+  Token::Value ScanString();
+
+  // Scans a possible HTML comment -- begins with '<!'.
+  Token::Value ScanHtmlComment();
+
+  // Return the current source position.
+  int source_pos() {
+    return source_.pos() - kCharacterLookaheadBufferSize + position_;
+  }
+
+  // Decodes a unicode escape-sequence which is part of an identifier.
+  // If the escape sequence cannot be decoded the result is kBadRune.
+  uc32 ScanIdentifierUnicodeEscape();
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_SCANNER_H_
diff --git a/regexp2000/src/scopeinfo.cc b/regexp2000/src/scopeinfo.cc
new file mode 100644 (file)
index 0000000..64706b5
--- /dev/null
@@ -0,0 +1,571 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "scopeinfo.h"
+#include "scopes.h"
+
+namespace v8 { namespace internal {
+
+
+static int CompareLocal(Variable* const* v, Variable* const* w) {
+  Slot* s = (*v)->slot();
+  Slot* t = (*w)->slot();
+  // 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);
+  // Consider sorting them according to type as well?
+  return x - y;
+}
+
+
+template<class Allocator>
+ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
+    : function_name_(Factory::empty_symbol()),
+      supports_eval_(scope->SupportsEval()),
+      parameters_(scope->num_parameters()),
+      stack_slots_(scope->num_stack_slots()),
+      context_slots_(scope->num_heap_slots()),
+      context_modes_(scope->num_heap_slots()) {
+  // Add parameters.
+  for (int i = 0; i < scope->num_parameters(); i++) {
+    ASSERT(parameters_.length() == i);
+    parameters_.Add(scope->parameter(i)->name());
+  }
+
+  // Add stack locals and collect heap locals.
+  // We are assuming that the locals' slots are allocated in
+  // increasing order, so we can simply add them to the
+  // ScopeInfo lists. However, due to usage analysis, this is
+  // not true for context-allocated locals: Some of them
+  // may be parameters which are allocated before the
+  // non-parameter locals. When the non-parameter locals are
+  // sorted according to usage, the allocated slot indices may
+  // not be in increasing order with the variable list anymore.
+  // Thus, we first collect the context-allocated locals, and then
+  // sort them by context slot index before adding them to the
+  // ScopeInfo list.
+  List<Variable*, Allocator> locals(32);  // 32 is a wild guess
+  ASSERT(locals.is_empty());
+  scope->CollectUsedVariables(&locals);
+  locals.Sort(&CompareLocal);
+
+  List<Variable*, Allocator> heap_locals(locals.length());
+  for (int i = 0; i < locals.length(); i++) {
+    Variable* var = locals[i];
+    if (var->var_uses()->is_used()) {
+      Slot* slot = var->slot();
+      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:
+          case Slot::GLOBAL:
+            // these are currently not used
+            UNREACHABLE();
+            break;
+        }
+      }
+    }
+  }
+
+  // Add heap locals.
+  if (scope->num_heap_slots() > 0) {
+    // Add user-defined slots.
+    for (int i = 0; i < heap_locals.length(); i++) {
+      ASSERT(heap_locals[i]->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
+             context_slots_.length());
+      ASSERT(heap_locals[i]->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
+             context_modes_.length());
+      context_slots_.Add(heap_locals[i]->name());
+      context_modes_.Add(heap_locals[i]->mode());
+    }
+
+  } else {
+    ASSERT(heap_locals.length() == 0);
+  }
+
+  // Add the function context slot, if present.
+  // 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->var_uses()->is_used() &&
+        var->slot()->type() == Slot::CONTEXT) {
+      function_name_ = var->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->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
+             context_slots_.length());
+      ASSERT(var->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
+             context_modes_.length());
+      context_slots_.Add(Factory::empty_symbol());
+      context_modes_.Add(Variable::INTERNAL);
+    }
+  }
+}
+
+
+// Encoding format in the Code object:
+//
+// - function name
+// - supports eval info
+//
+// - number of variables in the context object (smi) (= function context
+//   slot index + 1)
+// - list of pairs (name, Var mode) of context-allocated variables (starting
+//   with context slot 0)
+// - NULL (sentinel)
+//
+// - number of parameters (smi)
+// - list of parameter names (starting with parameter 0 first)
+// - NULL (sentinel)
+//
+// - number of variables on the stack (smi)
+// - list of names of stack-allocated variables (starting with stack slot 0)
+// - NULL (sentinel)
+
+// The ScopeInfo representation could be simplified and the ScopeInfo
+// re-implemented (with almost the same interface). Here is a
+// suggestion for the new format:
+//
+// - have a single list with all variable names (parameters, stack locals,
+//   context locals), followed by a list of non-Object* values containing
+//   the variables information (what kind, index, attributes)
+// - searching the linear list of names is fast and yields an index into the
+//   list if the variable name is found
+// - that list index is then used to find the variable information in the
+//   subsequent list
+// - the list entries don't have to be in any particular order, so all the
+//   current sorting business can go away
+// - the ScopeInfo lookup routines can be reduced to perhaps a single lookup
+//   which returns all information at once
+// - when gathering the information from a Scope, we only need to iterate
+//   through the local variables (parameters and context info is already
+//   present)
+
+
+static inline Object** ReadInt(Object** p, int* x) {
+  *x = (reinterpret_cast<Smi*>(*p++))->value();
+  return p;
+}
+
+
+static inline Object** ReadBool(Object** p, bool* x) {
+  *x = (reinterpret_cast<Smi*>(*p++))->value() != 0;
+  return p;
+}
+
+
+static inline Object** ReadSymbol(Object** p, Handle<String>* s) {
+  *s = Handle<String>(reinterpret_cast<String*>(*p++));
+  return p;
+}
+
+
+static inline Object** ReadSentinel(Object** p) {
+  ASSERT(*p == NULL);
+  return p + 1;
+}
+
+
+template <class Allocator>
+static Object** ReadList(Object** p, List<Handle<String>, Allocator >* list) {
+  ASSERT(list->is_empty());
+  int n;
+  p = ReadInt(p, &n);
+  while (n-- > 0) {
+    Handle<String> s;
+    p = ReadSymbol(p, &s);
+    list->Add(s);
+  }
+  return ReadSentinel(p);
+}
+
+
+template <class Allocator>
+static Object** ReadList(Object** p,
+                         List<Handle<String>, Allocator>* list,
+                         List<Variable::Mode, Allocator>* modes) {
+  ASSERT(list->is_empty());
+  int n;
+  p = ReadInt(p, &n);
+  while (n-- > 0) {
+    Handle<String> s;
+    int m;
+    p = ReadSymbol(p, &s);
+    p = ReadInt(p, &m);
+    list->Add(s);
+    modes->Add(static_cast<Variable::Mode>(m));
+  }
+  return ReadSentinel(p);
+}
+
+
+template<class Allocator>
+ScopeInfo<Allocator>::ScopeInfo(Code* code)
+  : function_name_(Factory::empty_symbol()),
+    supports_eval_(false),
+    parameters_(4),
+    stack_slots_(8),
+    context_slots_(8),
+    context_modes_(8) {
+  if (code == NULL || code->sinfo_size() == 0) return;
+
+  Object** p0 = &Memory::Object_at(code->sinfo_start());
+  Object** p = p0;
+  p = ReadSymbol(p, &function_name_);
+  p = ReadBool(p, &supports_eval_);
+  p = ReadList<Allocator>(p, &context_slots_, &context_modes_);
+  p = ReadList<Allocator>(p, &parameters_);
+  p = ReadList<Allocator>(p, &stack_slots_);
+  ASSERT((p - p0) * kPointerSize == code->sinfo_size());
+}
+
+
+static inline Object** WriteInt(Object** p, int x) {
+  *p++ = Smi::FromInt(x);
+  return p;
+}
+
+
+static inline Object** WriteSymbol(Object** p, Handle<String> s) {
+  *p++ = *s;
+  return p;
+}
+
+
+static inline Object** WriteSentinel(Object** p) {
+  *p++ = NULL;
+  return p;
+}
+
+
+template <class Allocator>
+static Object** WriteList(Object** p, List<Handle<String>, Allocator >* list) {
+  const int n = list->length();
+  p = WriteInt(p, n);
+  for (int i = 0; i < n; i++) {
+    p = WriteSymbol(p, list->at(i));
+  }
+  return WriteSentinel(p);
+}
+
+
+template <class Allocator>
+static Object** WriteList(Object** p,
+                          List<Handle<String>, Allocator>* list,
+                          List<Variable::Mode, Allocator>* modes) {
+  const int n = list->length();
+  p = WriteInt(p, n);
+  for (int i = 0; i < n; i++) {
+    p = WriteSymbol(p, list->at(i));
+    p = WriteInt(p, modes->at(i));
+  }
+  return WriteSentinel(p);
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::Serialize(Code* code) {
+  // function name, supports eval, length & sentinel for 3 tables:
+  const int extra_slots = 1 + 1 + 2 * 3;
+  int size = (extra_slots +
+              context_slots_.length() * 2 +
+              parameters_.length() +
+              stack_slots_.length()) * kPointerSize;
+
+  if (code != NULL) {
+    CHECK(code->sinfo_size() == size);
+    Object** p0 = &Memory::Object_at(code->sinfo_start());
+    Object** p = p0;
+    p = WriteSymbol(p, function_name_);
+    p = WriteInt(p, supports_eval_);
+    p = WriteList(p, &context_slots_, &context_modes_);
+    p = WriteList(p, &parameters_);
+    p = WriteList(p, &stack_slots_);
+    ASSERT((p - p0) * kPointerSize == size);
+  }
+
+  return size;
+}
+
+
+template<class Allocator>
+void ScopeInfo<Allocator>::IterateScopeInfo(Code* code, ObjectVisitor* v) {
+  Object** start = &Memory::Object_at(code->sinfo_start());
+  Object** end = &Memory::Object_at(code->sinfo_start() + code->sinfo_size());
+  v->VisitPointers(start, end);
+}
+
+
+static Object** ContextEntriesAddr(Code* code) {
+  ASSERT(code->sinfo_size() > 0);
+  // +2 for function name, supports eval:
+  return &Memory::Object_at(code->sinfo_start()) + 2;
+}
+
+
+static Object** ParameterEntriesAddr(Code* code) {
+  ASSERT(code->sinfo_size() > 0);
+  Object** p = ContextEntriesAddr(code);
+  int n;  // number of context slots;
+  p = ReadInt(p, &n);
+  return p + n*2 + 1;  // *2 for pairs, +1 for sentinel
+}
+
+
+static Object** StackSlotEntriesAddr(Code* code) {
+  ASSERT(code->sinfo_size() > 0);
+  Object** p = ParameterEntriesAddr(code);
+  int n;  // number of parameter slots;
+  p = ReadInt(p, &n);
+  return p + n + 1;  // +1 for sentinel
+}
+
+
+template<class Allocator>
+bool ScopeInfo<Allocator>::SupportsEval(Code* code) {
+  bool result = false;
+  if (code->sinfo_size() > 0) {
+    ReadBool(&Memory::Object_at(code->sinfo_start()) + 1, &result);
+  }
+#ifdef DEBUG
+  { ScopeInfo info(code);
+    ASSERT(result == info.supports_eval_);
+  }
+#endif
+  return result;
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::NumberOfStackSlots(Code* code) {
+  if (code->sinfo_size() > 0) {
+    Object** p = StackSlotEntriesAddr(code);
+    int n;  // number of stack slots;
+    ReadInt(p, &n);
+    return n;
+  }
+  return 0;
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::NumberOfContextSlots(Code* code) {
+  if (code->sinfo_size() > 0) {
+    Object** p = ContextEntriesAddr(code);
+    int n;  // number of context slots;
+    ReadInt(p, &n);
+    return n + Context::MIN_CONTEXT_SLOTS;
+  }
+  return 0;
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::StackSlotIndex(Code* code, String* name) {
+  ASSERT(name->IsSymbol());
+  if (code->sinfo_size() > 0) {
+    // Loop below depends on the NULL sentinel after the stack slot names.
+    ASSERT(NumberOfStackSlots(code) > 0 ||
+           *(StackSlotEntriesAddr(code) + 1) == NULL);
+    // slots start after length entry
+    Object** p0 = StackSlotEntriesAddr(code) + 1;
+    Object** p = p0;
+    while (*p != NULL) {
+      if (*p == name) return p - p0;
+      p++;
+    }
+  }
+  return -1;
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::ContextSlotIndex(Code* code,
+                                           String* name,
+                                           Variable::Mode* mode) {
+  ASSERT(name->IsSymbol());
+  if (code->sinfo_size() > 0) {
+    // Loop below depends on the NULL sentinel after the context slot names.
+    ASSERT(NumberOfContextSlots(code) >= Context::MIN_CONTEXT_SLOTS ||
+           *(ContextEntriesAddr(code) + 1) == NULL);
+    // slots start after length entry
+    Object** p0 = ContextEntriesAddr(code) + 1;
+    Object** p = p0;
+    // contexts may have no variable slots (in the presence of eval()).
+    while (*p != NULL) {
+      if (*p == name) {
+        ASSERT(((p - p0) & 1) == 0);
+        if (mode != NULL) {
+          ReadInt(p + 1, reinterpret_cast<int*>(mode));
+        }
+        return ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS;
+      }
+      p += 2;
+    }
+  }
+  return -1;
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::ParameterIndex(Code* code, String* name) {
+  ASSERT(name->IsSymbol());
+  if (code->sinfo_size() > 0) {
+    // We must read parameters from the end since for
+    // multiply declared parameters the value of the
+    // last declaration of that parameter is used
+    // inside a function (and thus we need to look
+    // at the last index). Was bug# 1110337.
+    //
+    // Eventually, we should only register such parameters
+    // once, with corresponding index. This requires a new
+    // implementation of the ScopeInfo code. See also other
+    // comments in this file regarding this.
+    Object** p = ParameterEntriesAddr(code);
+    int n;  // number of parameters
+    Object** p0 = ReadInt(p, &n);
+    p = p0 + n;
+    while (p > p0) {
+      p--;
+      if (*p == name) return p - p0;
+    }
+  }
+  return -1;
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::FunctionContextSlotIndex(Code* code, String* name) {
+  ASSERT(name->IsSymbol());
+  if (code->sinfo_size() > 0) {
+    Object** p = &Memory::Object_at(code->sinfo_start());
+    if (*p == name) {
+      p = ContextEntriesAddr(code);
+      int n;  // number of context slots
+      ReadInt(p, &n);
+      ASSERT(n != 0);
+      // The function context slot is the last entry.
+      return n + Context::MIN_CONTEXT_SLOTS - 1;
+    }
+  }
+  return -1;
+}
+
+
+template<class Allocator>
+Handle<String> ScopeInfo<Allocator>::LocalName(int i) const {
+  // A local variable can be allocated either on the stack or in the context.
+  // For variables allocated in the context they are always preceded by the
+  // number Context::MIN_CONTEXT_SLOTS number of fixed allocated slots in the
+  // context.
+  if (i < number_of_stack_slots()) {
+    return stack_slot_name(i);
+  } else {
+    return context_slot_name(i - number_of_stack_slots() +
+                             Context::MIN_CONTEXT_SLOTS);
+  }
+}
+
+
+template<class Allocator>
+int ScopeInfo<Allocator>::NumberOfLocals() const {
+  int number_of_locals = number_of_stack_slots();
+  if (number_of_context_slots() > 0) {
+    ASSERT(number_of_context_slots() >= Context::MIN_CONTEXT_SLOTS);
+    number_of_locals += number_of_context_slots() - Context::MIN_CONTEXT_SLOTS;
+  }
+  return number_of_locals;
+}
+
+
+#ifdef DEBUG
+template <class Allocator>
+static void PrintList(const char* list_name,
+                      int nof_internal_slots,
+                      List<Handle<String>, Allocator>& list) {
+  if (list.length() > 0) {
+    PrintF("\n  // %s\n", list_name);
+    if (nof_internal_slots > 0) {
+      PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
+    }
+    for (int i = 0; i < list.length(); i++) {
+      PrintF("  %2d ", i + nof_internal_slots);
+      list[i]->ShortPrint();
+      PrintF("\n");
+    }
+  }
+}
+
+
+template<class Allocator>
+void ScopeInfo<Allocator>::Print() {
+  PrintF("ScopeInfo ");
+  if (function_name_->length() > 0)
+    function_name_->ShortPrint();
+  else
+    PrintF("/* no function name */");
+  PrintF("{");
+
+  if (supports_eval_)
+    PrintF("\n  // supports eval\n");
+
+  PrintList<Allocator>("parameters", 0, parameters_);
+  PrintList<Allocator>("stack slots", 0, stack_slots_);
+  PrintList<Allocator>("context slots", Context::MIN_CONTEXT_SLOTS,
+                       context_slots_);
+
+  PrintF("}\n");
+}
+#endif  // DEBUG
+
+
+// Make sure the classes get instantiated by the template system.
+template class ScopeInfo<FreeStoreAllocationPolicy>;
+template class ScopeInfo<PreallocatedStorage>;
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/scopeinfo.h b/regexp2000/src/scopeinfo.h
new file mode 100644 (file)
index 0000000..285280c
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SCOPEINFO_H_
+#define V8_SCOPEINFO_H_
+
+#include "variables.h"
+
+namespace v8 { namespace internal {
+
+// Scope information represents information about a functions's
+// scopes (currently only one, because we don't do any inlining)
+// and the allocation of the scope's variables. Scope information
+// is stored in a compressed form with Code objects and is used
+// at runtime (stack dumps, deoptimization, etc.).
+//
+// Historical note: In other VMs built by this team, ScopeInfo was
+// usually called DebugInfo since the information was used (among
+// other things) for on-demand debugging (Self, Smalltalk). However,
+// DebugInfo seems misleading, since this information is primarily used
+// in debugging-unrelated contexts.
+
+// Forward defined as
+// template <class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
+template<class Allocator>
+class ScopeInfo BASE_EMBEDDED {
+ public:
+  // Create a ScopeInfo instance from a scope.
+  explicit ScopeInfo(Scope* scope);
+
+  // Create a ScopeInfo instance from a Code object.
+  explicit ScopeInfo(Code* code);
+
+  // Write the ScopeInfo data into a Code object, and returns the
+  // amount of space that was needed. If no Code object is provided
+  // (NULL handle), Serialize() only returns the amount of space needed.
+  //
+  // This operations requires that the Code object has the correct amount
+  // of space for the ScopeInfo data; otherwise the operation fails (fatal
+  // error). Any existing scope info in the Code object is simply overwritten.
+  int Serialize(Code* code);
+
+  // Garbage collection support for scope info embedded in Code objects.
+  // This code is in ScopeInfo because only here we should have to know
+  // about the encoding.
+  static void IterateScopeInfo(Code* code, ObjectVisitor* v);
+
+
+  // --------------------------------------------------------------------------
+  // Lookup
+
+  Handle<String> function_name() const  { return function_name_; }
+
+  bool supports_eval() const  { return supports_eval_; }
+
+  Handle<String> parameter_name(int i) const  { return parameters_[i]; }
+  int number_of_parameters() const  { return parameters_.length(); }
+
+  Handle<String> stack_slot_name(int i) const  { return stack_slots_[i]; }
+  int number_of_stack_slots() const  { return stack_slots_.length(); }
+
+  Handle<String> context_slot_name(int i) const {
+    return context_slots_[i - Context::MIN_CONTEXT_SLOTS];
+  }
+  int number_of_context_slots() const {
+    int l = context_slots_.length();
+    return l == 0 ? 0 : l + Context::MIN_CONTEXT_SLOTS;
+  }
+
+  Handle<String> LocalName(int i) const;
+  int NumberOfLocals() const;
+
+
+  // --------------------------------------------------------------------------
+  // The following functions provide quick access to scope info details
+  // for runtime routines w/o the need to explicitly create a ScopeInfo
+  // object.
+  //
+  // ScopeInfo is the only class which should have to know about the
+  // encoding of it's information in a Code object, which is why these
+  // functions are in this class.
+
+  static bool SupportsEval(Code* code);
+
+  // Return the number of stack slots for code.
+  static int NumberOfStackSlots(Code* code);
+
+  // Return the number of context slots for code.
+  static int NumberOfContextSlots(Code* code);
+
+  // Lookup support for scope info embedded in Code objects. Returns
+  // the stack slot index for a given slot name if the slot is
+  // present; otherwise returns a value < 0. The name must be a symbol
+  // (canonicalized).
+  static int StackSlotIndex(Code* code, String* name);
+
+  // Lookup support for scope info embedded in Code objects. Returns the
+  // context slot index for a given slot name if the slot is present; otherwise
+  // returns a value < 0. The name must be a symbol (canonicalized).
+  // If the slot is present and mode != NULL, sets *mode to the corresponding
+  // mode for that variable.
+  static int ContextSlotIndex(Code* code, String* name, Variable::Mode* mode);
+
+  // Lookup support for scope info embedded in Code objects. Returns the
+  // parameter index for a given parameter name if the parameter is present;
+  // otherwise returns a value < 0. The name must be a symbol (canonicalized).
+  static int ParameterIndex(Code* code, String* name);
+
+  // Lookup support for scope info embedded in Code objects. Returns the
+  // function context slot index if the function name is present (named
+  // function expressions, only), otherwise returns a value < 0. The name
+  // must be a symbol (canonicalized).
+  static int FunctionContextSlotIndex(Code* code, String* name);
+
+
+  // --------------------------------------------------------------------------
+  // Debugging support
+
+#ifdef DEBUG
+  void Print();
+#endif
+
+ private:
+  Handle<String> function_name_;
+  bool supports_eval_;
+  List<Handle<String>, Allocator > parameters_;
+  List<Handle<String>, Allocator > stack_slots_;
+  List<Handle<String>, Allocator > context_slots_;
+  List<Variable::Mode, Allocator > context_modes_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_SCOPEINFO_H_
diff --git a/regexp2000/src/scopes.cc b/regexp2000/src/scopes.cc
new file mode 100644 (file)
index 0000000..4f84bbb
--- /dev/null
@@ -0,0 +1,895 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "prettyprinter.h"
+#include "scopeinfo.h"
+#include "scopes.h"
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// A Zone allocator for use with LocalsMap.
+
+class ZoneAllocator: public Allocator {
+ public:
+  /* nothing to do */
+  virtual ~ZoneAllocator()  {}
+
+  virtual void* New(size_t size)  { return Zone::New(size); }
+
+  /* ignored - Zone is freed in one fell swoop */
+  virtual void Delete(void* p)  {}
+};
+
+
+static ZoneAllocator LocalsMapAllocator;
+
+
+// ----------------------------------------------------------------------------
+// Implementation of LocalsMap
+//
+// Note: We are storing the handle locations as key values in the hash map.
+//       When inserting a new variable via Declare(), we rely on the fact that
+//       the handle location remains alive for the duration of that variable
+//       use. Because a Variable holding a handle with the same location exists
+//       this is ensured.
+
+static bool Match(void* key1, void* key2) {
+  String* name1 = *reinterpret_cast<String**>(key1);
+  String* name2 = *reinterpret_cast<String**>(key2);
+  ASSERT(name1->IsSymbol());
+  ASSERT(name2->IsSymbol());
+  return name1 == name2;
+}
+
+
+// Dummy constructor
+LocalsMap::LocalsMap(bool gotta_love_static_overloading) : HashMap()  {}
+
+LocalsMap::LocalsMap() : HashMap(Match, &LocalsMapAllocator, 8)  {}
+LocalsMap::~LocalsMap()  {}
+
+
+Variable* LocalsMap::Declare(Scope* scope,
+                             Handle<String> name,
+                             Variable::Mode mode,
+                             bool is_valid_LHS,
+                             bool is_this) {
+  HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), true);
+  if (p->value == NULL) {
+    // The variable has not been declared yet -> insert it.
+    ASSERT(p->key == name.location());
+    p->value = new Variable(scope, name, mode, is_valid_LHS, is_this);
+  }
+  return reinterpret_cast<Variable*>(p->value);
+}
+
+
+Variable* LocalsMap::Lookup(Handle<String> name) {
+  HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), false);
+  if (p != NULL) {
+    ASSERT(*reinterpret_cast<String**>(p->key) == *name);
+    ASSERT(p->value != NULL);
+    return reinterpret_cast<Variable*>(p->value);
+  }
+  return NULL;
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of Scope
+
+
+// Dummy constructor
+Scope::Scope()
+  : inner_scopes_(0),
+    locals_(false),
+    temps_(0),
+    params_(0),
+    nonlocals_(0),
+    unresolved_(0),
+    decls_(0) {
+}
+
+
+Scope::Scope(Scope* outer_scope, Type type)
+  : outer_scope_(outer_scope),
+    inner_scopes_(4),
+    type_(type),
+    scope_name_(Factory::empty_symbol()),
+    locals_(),
+    temps_(4),
+    params_(4),
+    nonlocals_(4),
+    unresolved_(16),
+    decls_(4),
+    receiver_(NULL),
+    function_(NULL),
+    arguments_(NULL),
+    arguments_shadow_(NULL),
+    illegal_redecl_(NULL),
+    scope_inside_with_(false),
+    scope_contains_with_(false),
+    scope_calls_eval_(false),
+    outer_scope_calls_eval_(false),
+    inner_scope_calls_eval_(false),
+    force_eager_compilation_(false),
+    num_stack_slots_(0),
+    num_heap_slots_(0) {
+  // At some point we might want to provide outer scopes to
+  // eval scopes (by walking the stack and reading the scope info).
+  // In that case, the ASSERT below needs to be adjusted.
+  ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
+  ASSERT(!HasIllegalRedeclaration());
+}
+
+
+void Scope::Initialize(bool inside_with) {
+  // Add this scope as a new inner scope of the outer scope.
+  if (outer_scope_ != NULL) {
+    outer_scope_->inner_scopes_.Add(this);
+    scope_inside_with_ = outer_scope_->scope_inside_with_ || inside_with;
+  } else {
+    scope_inside_with_ = inside_with;
+  }
+
+  // Declare convenience variables.
+  // Declare and allocate receiver (even for the global scope, and even
+  // if naccesses_ == 0).
+  // NOTE: When loading parameters in the global scope, we must take
+  // care not to access them as properties of the global object, but
+  // instead load them directly from the stack. Currently, the only
+  // such parameter is 'this' which is passed on the stack when
+  // invoking scripts
+  { Variable* var =
+      locals_.Declare(this, Factory::this_symbol(), Variable::VAR, false, true);
+    var->rewrite_ = new Slot(var, Slot::PARAMETER, -1);
+    receiver_ = new VariableProxy(Factory::this_symbol(), true, false);
+    receiver_->BindTo(var);
+  }
+
+  if (is_function_scope()) {
+    // Declare 'arguments' variable which exists in all functions.
+    // Note that it may never be accessed, in which case it won't
+    // be allocated during variable allocation.
+    Declare(Factory::arguments_symbol(), Variable::VAR);
+  }
+}
+
+
+
+Variable* Scope::Lookup(Handle<String> name) {
+  return locals_.Lookup(name);
+}
+
+
+Variable* Scope::DeclareFunctionVar(Handle<String> name) {
+  ASSERT(is_function_scope() && function_ == NULL);
+  function_ = new Variable(this, name, Variable::CONST, true, false);
+  return function_;
+}
+
+
+Variable* Scope::Declare(Handle<String> name, Variable::Mode mode) {
+  // DYNAMIC variables are introduces during variable allocation,
+  // INTERNAL variables are allocated explicitly, and TEMPORARY
+  // variables are allocated via NewTemporary().
+  ASSERT(mode == Variable::VAR || mode == Variable::CONST);
+  return locals_.Declare(this, name, mode, true, false);
+}
+
+
+void Scope::AddParameter(Variable* var) {
+  ASSERT(is_function_scope());
+  ASSERT(Lookup(var->name()) == var);
+  params_.Add(var);
+}
+
+
+VariableProxy* Scope::NewUnresolved(Handle<String> name, bool inside_with) {
+  // Note that we must not share the unresolved variables with
+  // the same name because they may be removed selectively via
+  // RemoveUnresolved().
+  VariableProxy* proxy = new VariableProxy(name, false, inside_with);
+  unresolved_.Add(proxy);
+  return proxy;
+}
+
+
+void Scope::RemoveUnresolved(VariableProxy* var) {
+  // Most likely (always?) any variable we want to remove
+  // was just added before, so we search backwards.
+  for (int i = unresolved_.length(); i-- > 0;) {
+    if (unresolved_[i] == var) {
+      unresolved_.Remove(i);
+      return;
+    }
+  }
+}
+
+
+VariableProxy* Scope::NewTemporary(Handle<String> name) {
+  Variable* var = new Variable(this, name, Variable::TEMPORARY, true, false);
+  VariableProxy* tmp = new VariableProxy(name, false, false);
+  tmp->BindTo(var);
+  temps_.Add(var);
+  return tmp;
+}
+
+
+void Scope::AddDeclaration(Declaration* declaration) {
+  decls_.Add(declaration);
+}
+
+
+void Scope::SetIllegalRedeclaration(Expression* expression) {
+  // Only set the illegal redeclaration expression the
+  // first time the function is called.
+  if (!HasIllegalRedeclaration()) {
+    illegal_redecl_ = expression;
+  }
+  ASSERT(HasIllegalRedeclaration());
+}
+
+
+void Scope::VisitIllegalRedeclaration(Visitor* visitor) {
+  ASSERT(HasIllegalRedeclaration());
+  illegal_redecl_->Accept(visitor);
+}
+
+
+template<class Allocator>
+void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
+  // Collect variables in this scope.
+  // Note that the function_ variable - if present - is not
+  // collected here but handled separately in ScopeInfo
+  // which is the current user of this function).
+  for (int i = 0; i < temps_.length(); i++) {
+    Variable* var = temps_[i];
+    if (var->var_uses()->is_used()) {
+      locals->Add(var);
+    }
+  }
+  for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
+    Variable* var = reinterpret_cast<Variable*>(p->value);
+    if (var->var_uses()->is_used()) {
+      locals->Add(var);
+    }
+  }
+}
+
+
+// Make sure the method gets instantiated by the template system.
+template void Scope::CollectUsedVariables(
+    List<Variable*, FreeStoreAllocationPolicy>* locals);
+template void Scope::CollectUsedVariables(
+    List<Variable*, PreallocatedStorage>* locals);
+
+
+void Scope::AllocateVariables() {
+  ASSERT(outer_scope_ == NULL);  // eval or global scopes only
+
+  // 1) Propagate scope information.
+  // If we are in an eval scope, we may have other outer scopes about
+  // which we don't know anything at this point. Thus we must be conservative
+  // and assume they may invoke eval themselves. Eventually we could capture
+  // this information in the ScopeInfo and then use it here (by traversing
+  // the call chain stack, at compile time).
+  PropagateScopeInfo(is_eval_scope());
+
+  // 2) Resolve variables.
+  Scope* global_scope = NULL;
+  if (is_global_scope()) global_scope = this;
+  ResolveVariablesRecursively(global_scope);
+
+  // 3) Allocate variables.
+  AllocateVariablesRecursively();
+}
+
+
+bool Scope::SupportsEval() const {
+  return scope_calls_eval_ || inner_scope_calls_eval_;
+}
+
+
+bool Scope::AllowsLazyCompilation() const {
+  return !force_eager_compilation_ && HasTrivialOuterContext();
+}
+
+
+bool Scope::HasTrivialContext() const {
+  // A function scope has a trivial context if it always is the global
+  // context. We iteratively scan out the context chain to see if
+  // there is anything that makes this scope non-trivial; otherwise we
+  // return true.
+  for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
+    if (scope->is_eval_scope()) return false;
+    if (scope->scope_inside_with_) return false;
+    if (scope->num_heap_slots_ > 0) return false;
+  }
+  return true;
+}
+
+
+bool Scope::HasTrivialOuterContext() const {
+  Scope* outer = outer_scope_;
+  if (outer == NULL) return true;
+  // Note that the outer context may be trivial in general, but the current
+  // scope may be inside a 'with' statement in which case the outer context
+  // for this scope is not trivial.
+  return !scope_inside_with_ && outer->HasTrivialContext();
+}
+
+
+int Scope::ContextChainLength(Scope* scope) {
+  int n = 0;
+  for (Scope* s = this; s != scope; s = s->outer_scope_) {
+    ASSERT(s != NULL);  // scope must be in the scope chain
+    if (s->num_heap_slots() > 0) n++;
+  }
+  return n;
+}
+
+
+#ifdef DEBUG
+static const char* Header(Scope::Type type) {
+  switch (type) {
+    case Scope::EVAL_SCOPE: return "eval";
+    case Scope::FUNCTION_SCOPE: return "function";
+    case Scope::GLOBAL_SCOPE: return "global";
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+static void Indent(int n, const char* str) {
+  PrintF("%*s%s", n, "", str);
+}
+
+
+static void PrintName(Handle<String> name) {
+  SmartPointer<char> s = name->ToCString(DISALLOW_NULLS);
+  PrintF("%s", *s);
+}
+
+
+static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
+  if (var->var_uses()->is_used() || var->rewrite() != NULL) {
+    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("inner scope access, ");
+    PrintF("var ");
+    var->var_uses()->Print();
+    PrintF(", obj ");
+    var->obj_uses()->Print();
+    PrintF("\n");
+  }
+}
+
+
+void Scope::Print(int n) {
+  int n0 = (n > 0 ? n : 0);
+  int n1 = n0 + 2;  // indentation
+
+  // Print header.
+  Indent(n0, Header(type_));
+  if (scope_name_->length() > 0) {
+    PrintF(" ");
+    PrintName(scope_name_);
+  }
+
+  // Print parameters, if any.
+  if (is_function_scope()) {
+    PrintF(" (");
+    for (int i = 0; i < params_.length(); i++) {
+      if (i > 0) PrintF(", ");
+      PrintName(params_[i]->name());
+    }
+    PrintF(")");
+  }
+
+  PrintF(" {\n");
+
+  // Function name, if any (named function literals, only).
+  if (function_ != NULL) {
+    Indent(n1, "// (local) function name: ");
+    PrintName(function_->name());
+    PrintF("\n");
+  }
+
+  // Scope info.
+  if (HasTrivialOuterContext()) {
+    Indent(n1, "// scope has trivial outer context\n");
+  }
+  if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
+  if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
+  if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
+  if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
+  if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
+  if (num_stack_slots_ > 0) { Indent(n1, "// ");
+  PrintF("%d stack slots\n", num_stack_slots_); }
+  if (num_heap_slots_ > 0) { Indent(n1, "// ");
+  PrintF("%d heap slots\n", num_heap_slots_); }
+
+  // Print locals.
+  PrettyPrinter printer;
+  Indent(n1, "// function var\n");
+  if (function_ != NULL) {
+    PrintVar(&printer, n1, function_);
+  }
+
+  Indent(n1, "// temporary vars\n");
+  for (int i = 0; i < temps_.length(); i++) {
+    PrintVar(&printer, n1, temps_[i]);
+  }
+
+  Indent(n1, "// local vars\n");
+  for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
+    Variable* var = reinterpret_cast<Variable*>(p->value);
+    PrintVar(&printer, n1, var);
+  }
+
+  Indent(n1, "// nonlocal vars\n");
+  for (int i = 0; i < nonlocals_.length(); i++)
+    PrintVar(&printer, n1, nonlocals_[i]);
+
+  // Print inner scopes (disable by providing negative n).
+  if (n >= 0) {
+    for (int i = 0; i < inner_scopes_.length(); i++) {
+      PrintF("\n");
+      inner_scopes_[i]->Print(n1);
+    }
+  }
+
+  Indent(n0, "}\n");
+}
+#endif  // DEBUG
+
+
+Variable* Scope::NonLocal(Handle<String> name) {
+  // Space optimization: reuse existing non-local with the same name.
+  for (int i = 0; i < nonlocals_.length(); i++) {
+    Variable* var = nonlocals_[i];
+    if (var->name().is_identical_to(name)) {
+      ASSERT(var->mode() == Variable::DYNAMIC);
+      return var;
+    }
+  }
+
+  // Otherwise create a new new-local and add it to the list.
+  Variable* var = new Variable(
+    NULL /* we don't know the scope */,
+    name, Variable::DYNAMIC, true, false);
+  nonlocals_.Add(var);
+
+  // Allocate it by giving it a dynamic lookup.
+  var->rewrite_ = new Slot(var, Slot::LOOKUP, -1);
+
+  return var;
+}
+
+
+// Lookup a variable starting with this scope. The result is either
+// the statically resolved (local!) variable belonging to an outer scope,
+// or NULL. It may be NULL because a) we couldn't find a variable, or b)
+// because the variable is just a guess (and may be shadowed by another
+// variable that is introduced dynamically via an 'eval' call or a 'with'
+// statement).
+Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) {
+  // If we find a variable, but the current scope calls 'eval', the found
+  // variable may not be the correct one (the 'eval' may introduce a
+  // property with the same name). In that case, remember that the variable
+  // found is just a guess.
+  bool guess = scope_calls_eval_;
+
+  // Try to find the variable in this scope.
+  Variable* var = Lookup(name);
+
+  if (var != NULL) {
+    // We found a variable. If this is not an inner lookup, we are done.
+    // (Even if there is an 'eval' in this scope which introduces the
+    // same variable again, the resulting variable remains the same.
+    // Note that enclosing 'with' statements are handled at the call site.)
+    if (!inner_lookup)
+      return var;
+
+  } else {
+    // We did not find a variable locally. Check against the function variable,
+    // if any. We can do this for all scopes, since the function variable is
+    // only present - if at all - for function scopes.
+    //
+    // This lookup corresponds to a lookup in the "intermediate" scope sitting
+    // between this scope and the outer scope. (ECMA-262, 3rd., requires that
+    // the name of named function literal is kept in an intermediate scope
+    // inbetween this scope and the next outer scope.)
+    if (function_ != NULL && function_->name().is_identical_to(name)) {
+      var = function_;
+
+    } else if (outer_scope_ != NULL) {
+      var = outer_scope_->LookupRecursive(name, true /* inner lookup */);
+      // We may have found a variable in an outer scope. However, if
+      // the current scope is inside a 'with', the actual variable may
+      // be a property introduced via the 'with' statement. Then, the
+      // variable we may have found is just a guess.
+      if (scope_inside_with_)
+        guess = true;
+    }
+
+    // If we did not find a variable, we are done.
+    if (var == NULL)
+      return NULL;
+  }
+
+  ASSERT(var != NULL);
+
+  // If this is a lookup from an inner scope, mark the variable.
+  if (inner_lookup)
+    var->is_accessed_from_inner_scope_ = true;
+
+  // If the variable we have found is just a guess, invalidate the result.
+  if (guess)
+    var = NULL;
+
+  return var;
+}
+
+
+void Scope::ResolveVariable(Scope* global_scope, VariableProxy* proxy) {
+  ASSERT(global_scope == NULL || global_scope->is_global_scope());
+
+  // If the proxy is already resolved there's nothing to do
+  // (functions and consts may be resolved by the parser).
+  if (proxy->var() != NULL) return;
+
+  // Otherwise, try to resolve the variable.
+  Variable* var = LookupRecursive(proxy->name(), false);
+
+  if (proxy->inside_with()) {
+    // If we are inside a local 'with' statement, all bets are off
+    // and we cannot resolve the proxy to a local variable even if
+    // we found an outer matching variable.
+    // Note that we must do a lookup anyway, because if we find one,
+    // we must mark that variable as potentially accessed from this
+    // inner scope (the property may not be in the 'with' object).
+    var = NonLocal(proxy->name());
+
+  } else {
+    // We are not inside a local 'with' statement.
+
+    if (var == NULL) {
+      // We did not find the variable. We have a global variable
+      // if we are in the global scope (we know already that we
+      // are outside a 'with' statement) or if there is no way
+      // that the variable might be introduced dynamically (through
+      // a local or outer eval() call, or an outer 'with' statement),
+      // or we don't know about the outer scope (because we are
+      // in an eval scope).
+      if (!is_global_scope() &&
+          (is_eval_scope() || outer_scope_calls_eval_ ||
+           scope_calls_eval_ || scope_inside_with_)) {
+        // We must look up the variable at runtime, and we don't
+        // know anything else.
+        var = NonLocal(proxy->name());
+
+      } else {
+        // We must have a global variable.
+        ASSERT(global_scope != NULL);
+        var = new Variable(global_scope, proxy->name(),
+                           Variable::DYNAMIC, true, false);
+        // Ideally we simply rewrite these variables into property
+        // accesses. Unfortunately, we cannot do this here at the
+        // moment because then we can't differentiate between
+        // global variable ('x') and global property ('this.x') access.
+        // If 'x' doesn't exist, the former leads to an error, while the
+        // latter returns undefined. Sigh...
+        // var->rewrite_ = new Property(new Literal(env_->global()),
+        //                              new Literal(proxy->name()));
+      }
+    }
+  }
+
+  proxy->BindTo(var);
+}
+
+
+void Scope::ResolveVariablesRecursively(Scope* global_scope) {
+  ASSERT(global_scope == NULL || global_scope->is_global_scope());
+
+  // Resolve unresolved variables for this scope.
+  for (int i = 0; i < unresolved_.length(); i++) {
+    ResolveVariable(global_scope, unresolved_[i]);
+  }
+
+  // Resolve unresolved variables for inner scopes.
+  for (int i = 0; i < inner_scopes_.length(); i++) {
+    inner_scopes_[i]->ResolveVariablesRecursively(global_scope);
+  }
+}
+
+
+bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval) {
+  if (outer_scope_calls_eval) {
+    outer_scope_calls_eval_ = true;
+  }
+
+  bool b = scope_calls_eval_ || outer_scope_calls_eval_;
+  for (int i = 0; i < inner_scopes_.length(); i++) {
+    Scope* inner_scope = inner_scopes_[i];
+    if (inner_scope->PropagateScopeInfo(b)) {
+      inner_scope_calls_eval_ = true;
+    }
+    if (inner_scope->force_eager_compilation_) {
+      force_eager_compilation_ = true;
+    }
+  }
+
+  return scope_calls_eval_ || inner_scope_calls_eval_;
+}
+
+
+bool Scope::MustAllocate(Variable* var) {
+  // Give var a read/write use if there is a chance it might be
+  // accessed via an eval() call, or if it is a global variable.
+  // This is only possible if the variable has a visible name.
+  if ((var->is_this() || var->name()->length() > 0) &&
+      (var->is_accessed_from_inner_scope_ ||
+       scope_calls_eval_ || inner_scope_calls_eval_ ||
+       scope_contains_with_ || var->is_global())) {
+    var->var_uses()->RecordAccess(1);
+  }
+  return var->var_uses()->is_used();
+}
+
+
+bool Scope::MustAllocateInContext(Variable* var) {
+  // If var is accessed from an inner scope, or if there is a
+  // possibility that it might be accessed from the current or
+  // an inner scope (through an eval() call), it must be allocated
+  // in the context.
+  // Exceptions: Global variables and temporary variables must
+  // never be allocated in the (FixedArray part of the) context.
+  return
+    var->mode() != Variable::TEMPORARY &&
+    (var->is_accessed_from_inner_scope_ ||
+     scope_calls_eval_ || inner_scope_calls_eval_ ||
+     scope_contains_with_ || var->is_global());
+}
+
+
+bool Scope::HasArgumentsParameter() {
+  for (int i = 0; i < params_.length(); i++) {
+    if (params_[i]->name().is_identical_to(Factory::arguments_symbol()))
+      return true;
+  }
+  return false;
+}
+
+
+void Scope::AllocateStackSlot(Variable* var) {
+  var->rewrite_ = new Slot(var, Slot::LOCAL, num_stack_slots_++);
+}
+
+
+void Scope::AllocateHeapSlot(Variable* var) {
+  var->rewrite_ = new Slot(var, Slot::CONTEXT, num_heap_slots_++);
+}
+
+
+void Scope::AllocateParameterLocals() {
+  ASSERT(is_function_scope());
+  Variable* arguments = Lookup(Factory::arguments_symbol());
+  ASSERT(arguments != NULL);  // functions have 'arguments' declared implicitly
+  if (MustAllocate(arguments) && !HasArgumentsParameter()) {
+    // 'arguments' is used. Unless there is also a parameter called
+    // 'arguments', we must be conservative and access all parameters via
+    // the arguments object: The i'th parameter is rewritten into
+    // '.arguments[i]' (*). If we have a parameter named 'arguments', a
+    // (new) value is always assigned to it via the function
+    // invocation. Then 'arguments' denotes that specific parameter value
+    // and cannot be used to access the parameters, which is why we don't
+    // need to rewrite in that case.
+    //
+    // (*) Instead of having a parameter called 'arguments', we may have an
+    // assignment to 'arguments' in the function body, at some arbitrary
+    // point in time (possibly through an 'eval()' call!). After that
+    // assignment any re-write of parameters would be invalid (was bug
+    // 881452). Thus, we introduce a shadow '.arguments'
+    // variable which also points to the arguments object. For rewrites we
+    // use '.arguments' which remains valid even if we assign to
+    // 'arguments'. To summarize: If we need to rewrite, we allocate an
+    // 'arguments' object dynamically upon function invocation. The compiler
+    // introduces 2 local variables 'arguments' and '.arguments', both of
+    // which originally point to the arguments object that was
+    // allocated. All parameters are rewritten into property accesses via
+    // the '.arguments' variable. Thus, any changes to properties of
+    // 'arguments' are reflected in the variables and vice versa. If the
+    // 'arguments' variable is changed, '.arguments' still points to the
+    // correct arguments object and the rewrites still work.
+
+    // We are using 'arguments'. Tell the code generator that is needs to
+    // allocate the arguments object by setting 'arguments_'.
+    arguments_ = new VariableProxy(Factory::arguments_symbol(), false, false);
+    arguments_->BindTo(arguments);
+
+    // We also need the '.arguments' shadow variable. Declare it and create
+    // and bind the corresponding proxy. It's ok to declare it only now
+    // because it's a local variable that is allocated after the parameters
+    // have been allocated.
+    //
+    // Note: This is "almost" at temporary variable but we cannot use
+    // NewTemporary() because the mode needs to be INTERNAL since this
+    // variable may be allocated in the heap-allocated context (temporaries
+    // are never allocated in the context).
+    Variable* arguments_shadow =
+        new Variable(this, Factory::arguments_shadow_symbol(),
+                     Variable::INTERNAL, true, false);
+    arguments_shadow_ =
+        new VariableProxy(Factory::arguments_shadow_symbol(), false, false);
+    arguments_shadow_->BindTo(arguments_shadow);
+    temps_.Add(arguments_shadow);
+
+    // Allocate the parameters by rewriting them into '.arguments[i]' accesses.
+    for (int i = 0; i < params_.length(); i++) {
+      Variable* var = params_[i];
+      ASSERT(var->scope() == this);
+      if (MustAllocate(var)) {
+        if (MustAllocateInContext(var)) {
+          // It is ok to set this only now, because arguments is a local
+          // variable that is allocated after the parameters have been
+          // allocated.
+          arguments_shadow->is_accessed_from_inner_scope_ = true;
+        }
+        var->rewrite_ =
+          new Property(arguments_shadow_,
+                       new Literal(Handle<Object>(Smi::FromInt(i))),
+                       RelocInfo::kNoPosition);
+        arguments_shadow->var_uses()->RecordUses(var->var_uses());
+      }
+    }
+
+  } else {
+    // The arguments object is not used, so we can access parameters directly.
+    // The same parameter may occur multiple times in the parameters_ list.
+    // If it does, and if it is not copied into the context object, it must
+    // receive the highest parameter index for that parameter; thus iteration
+    // order is relevant!
+    for (int i = 0; i < params_.length(); i++) {
+      Variable* var = params_[i];
+      ASSERT(var->scope() == this);
+      if (MustAllocate(var)) {
+        if (MustAllocateInContext(var)) {
+          ASSERT(var->rewrite_ == NULL ||
+                 (var->slot() != NULL && var->slot()->type() == Slot::CONTEXT));
+          if (var->rewrite_ == NULL) {
+            // Only set the heap allocation if the parameter has not
+            // been allocated yet.
+            AllocateHeapSlot(var);
+          }
+        } else {
+          ASSERT(var->rewrite_ == NULL ||
+                 (var->slot() != NULL &&
+                  var->slot()->type() == Slot::PARAMETER));
+          // Set the parameter index always, even if the parameter
+          // was seen before! (We need to access the actual parameter
+          // supplied for the last occurrence of a multiply declared
+          // parameter.)
+          var->rewrite_ = new Slot(var, Slot::PARAMETER, i);
+        }
+      }
+    }
+  }
+}
+
+
+void Scope::AllocateNonParameterLocal(Variable* var) {
+  ASSERT(var->scope() == this);
+  ASSERT(var->rewrite_ == NULL ||
+         (!var->IsVariable(Factory::result_symbol())) ||
+         (var->slot() == NULL || var->slot()->type() != Slot::LOCAL));
+  if (MustAllocate(var) && var->rewrite_ == NULL) {
+    if (MustAllocateInContext(var)) {
+      AllocateHeapSlot(var);
+    } else {
+      AllocateStackSlot(var);
+    }
+  }
+}
+
+
+void Scope::AllocateNonParameterLocals() {
+  // Each variable occurs exactly once in the locals_ list; all
+  // variables that have no rewrite yet are non-parameter locals.
+
+  // Sort them according to use such that the locals with more uses
+  // get allocated first.
+  if (FLAG_usage_computation) {
+    // This is currently not implemented.
+  }
+
+  for (int i = 0; i < temps_.length(); i++) {
+    AllocateNonParameterLocal(temps_[i]);
+  }
+
+  for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
+    Variable* var = reinterpret_cast<Variable*>(p->value);
+    AllocateNonParameterLocal(var);
+  }
+
+  // Note: For now, function_ must be allocated at the very end.  If
+  // it gets allocated in the context, it must be the last slot in the
+  // context, because of the current ScopeInfo implementation (see
+  // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
+  if (function_ != NULL) {
+    AllocateNonParameterLocal(function_);
+  }
+}
+
+
+void Scope::AllocateVariablesRecursively() {
+  // The number of slots required for variables.
+  num_stack_slots_ = 0;
+  num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
+
+  // Allocate variables for inner scopes.
+  for (int i = 0; i < inner_scopes_.length(); i++) {
+    inner_scopes_[i]->AllocateVariablesRecursively();
+  }
+
+  // Allocate variables for this scope.
+  // Parameters must be allocated first, if any.
+  if (is_function_scope()) AllocateParameterLocals();
+  AllocateNonParameterLocals();
+
+  // Allocate context if necessary.
+  bool must_have_local_context = false;
+  if (scope_calls_eval_ || scope_contains_with_) {
+    // The context for the eval() call or 'with' statement in this scope.
+    // Unless we are in the global or an eval scope, we need a local
+    // context even if we didn't statically allocate any locals in it,
+    // and the compiler will access the context variable. If we are
+    // not in an inner scope, the scope is provided from the outside.
+    must_have_local_context = is_function_scope();
+  }
+
+  // If we didn't allocate any locals in the local context, then we only
+  // need the minimal number of slots if we must have a local context.
+  if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
+      !must_have_local_context) {
+    num_heap_slots_ = 0;
+  }
+
+  // Allocation done.
+  ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/scopes.h b/regexp2000/src/scopes.h
new file mode 100644 (file)
index 0000000..05e462b
--- /dev/null
@@ -0,0 +1,346 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SCOPES_H_
+#define V8_SCOPES_H_
+
+#include "ast.h"
+#include "hashmap.h"
+
+namespace v8 { namespace internal {
+
+
+// A hash map to support fast local variable declaration and lookup.
+
+class LocalsMap: public HashMap {
+ public:
+  LocalsMap();
+
+  // Dummy constructor.  This constructor doesn't set up the map
+  // properly so don't use it unless you have a good reason.
+  explicit LocalsMap(bool gotta_love_static_overloading);
+
+  virtual ~LocalsMap();
+
+  Variable* Declare(Scope* scope, Handle<String> name, Variable::Mode mode,
+                    bool is_valid_LHS, bool is_this);
+
+  Variable* Lookup(Handle<String> name);
+};
+
+
+// Global invariants after AST construction: Each reference (i.e. identifier)
+// to a JavaScript variable (including global properties) is represented by a
+// VariableProxy node. Immediately after AST construction and before variable
+// allocation, most VariableProxy nodes are "unresolved", i.e. not bound to a
+// corresponding variable (though some are bound during parse time). Variable
+// allocation binds each unresolved VariableProxy to one Variable and assigns
+// a location. Note that many VariableProxy nodes may refer to the same Java-
+// Script variable.
+
+class Scope: public ZoneObject {
+ public:
+  // ---------------------------------------------------------------------------
+  // Construction
+
+  enum Type {
+    EVAL_SCOPE,     // the top-level scope for an 'eval' source
+    FUNCTION_SCOPE,  // the top-level scope for a function
+    GLOBAL_SCOPE    // the top-level scope for a program or a top-level eval
+  };
+
+  Scope();
+  Scope(Scope* outer_scope, Type type);
+
+  virtual ~Scope() { }
+
+  // The scope name is only used for printing/debugging.
+  void SetScopeName(Handle<String> scope_name)  { scope_name_ = scope_name; }
+
+  void Initialize(bool inside_with);
+
+
+  // ---------------------------------------------------------------------------
+  // Declarations
+
+  // Lookup a variable in this scope. Returns the variable or NULL if not found.
+  virtual Variable* Lookup(Handle<String> name);
+
+  // Declare the function variable for a function literal. This variable
+  // is in an intermediate scope between this function scope and the the
+  // outer scope. Only possible for function scopes; at most one variable.
+  Variable* DeclareFunctionVar(Handle<String> name);
+
+  // Declare a variable in this scope. If the variable has been
+  // declared before, the previously declared variable is returned.
+  virtual Variable* Declare(Handle<String> name, Variable::Mode mode);
+
+  // Add a parameter to the parameter list. The parameter must have been
+  // declared via Declare. The same parameter may occur more then once in
+  // the parameter list; they must be added in source order, from left to
+  // right.
+  void AddParameter(Variable* var);
+
+  // Create a new unresolved variable.
+  virtual VariableProxy* NewUnresolved(Handle<String> name, bool inside_with);
+
+  // Remove a unresolved variable. During parsing, an unresolved variable
+  // may have been added optimistically, but then only the variable name
+  // was used (typically for labels). If the variable was not declared, the
+  // addition introduced a new unresolved variable which may end up being
+  // allocated globally as a "ghost" variable. RemoveUnresolved removes
+  // such a variable again if it was added; otherwise this is a no-op.
+  void RemoveUnresolved(VariableProxy* var);
+
+  // Creates a new temporary variable in this scope and binds a proxy to it.
+  // The name is only used for printing and cannot be used to find the variable.
+  // In particular, the only way to get hold of the temporary is by keeping the
+  // VariableProxy* around.
+  virtual VariableProxy* NewTemporary(Handle<String> name);
+
+  // Adds the specific declaration node to the list of declarations in
+  // this scope. The declarations are processed as part of entering
+  // the scope; see codegen.cc:ProcessDeclarations.
+  void AddDeclaration(Declaration* declaration);
+
+  // ---------------------------------------------------------------------------
+  // Illegal redeclaration support.
+
+  // Set an expression node that will be executed when the scope is
+  // entered. We only keep track of one illegal redeclaration node per
+  // scope - the first one - so if you try to set it multiple times
+  // the additional requests will be silently ignored.
+  void SetIllegalRedeclaration(Expression* expression);
+
+  // Visit the illegal redeclaration expression. Do not call if the
+  // scope doesn't have an illegal redeclaration node.
+  void VisitIllegalRedeclaration(Visitor* visitor);
+
+  // Check if the scope has (at least) one illegal redeclaration.
+  bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }
+
+
+  // ---------------------------------------------------------------------------
+  // Scope-specific info.
+
+  // Inform the scope that the corresponding code contains a with statement.
+  void RecordWithStatement()  { scope_contains_with_ = true; }
+
+  // Inform the scope that the corresponding code contains an eval call.
+  void RecordEvalCall()  { scope_calls_eval_ = true; }
+
+
+  // ---------------------------------------------------------------------------
+  // Predicates.
+
+  // Specific scope types.
+  bool is_eval_scope() const  { return type_ == EVAL_SCOPE; }
+  bool is_function_scope() const  { return type_ == FUNCTION_SCOPE; }
+  bool is_global_scope() const  { return type_ == GLOBAL_SCOPE; }
+
+  // The scope immediately surrounding this scope, or NULL.
+  Scope* outer_scope() const  { return outer_scope_; }
+
+
+  // ---------------------------------------------------------------------------
+  // Accessors.
+
+  // The variable corresponding to the (function) receiver.
+  VariableProxy* receiver() const  { return receiver_; }
+
+  // The variable holding the function literal for named function
+  // literals, or NULL.
+  // Only valid for function scopes.
+  Variable* function() const  {
+    ASSERT(is_function_scope());
+    return function_;
+  }
+
+  // Parameters. The left-most parameter has index 0.
+  // Only valid for function scopes.
+  Variable* parameter(int index) const  {
+    ASSERT(is_function_scope());
+    return params_[index];
+  }
+
+  int num_parameters() const  { return params_.length(); }
+
+  // The local variable 'arguments' if we need to allocate it; NULL otherwise.
+  // If arguments() exist, arguments_shadow() exists, too.
+  VariableProxy* arguments()  const  { return arguments_; }
+
+  // The '.arguments' shadow variable if we need to allocate it; NULL otherwise.
+  // If arguments_shadow() exist, arguments() exists, too.
+  VariableProxy* arguments_shadow()  const  { return arguments_shadow_; }
+
+  // Declarations list.
+  ZoneList<Declaration*>* declarations() { return &decls_; }
+
+
+
+  // ---------------------------------------------------------------------------
+  // Variable allocation.
+
+  // Collect all used locals in this scope.
+  template<class Allocator>
+  void CollectUsedVariables(List<Variable*, Allocator>* locals);
+
+  // Resolve and fill in the allocation information for all variables in
+  // this scopes. Must be called *after* all scopes have been processed
+  // (parsed) to ensure that unresolved variables can be resolved properly.
+  void AllocateVariables();
+
+  // Result of variable allocation.
+  int num_stack_slots() const  { return num_stack_slots_; }
+  int num_heap_slots() const  { return num_heap_slots_; }
+
+  // True if this scope supports calling eval (has a properly
+  // initialized context).
+  bool SupportsEval() const;
+
+  // Make sure this scope and all outer scopes are eagerly compiled.
+  void ForceEagerCompilation()  { force_eager_compilation_ = true; }
+
+  // Determine if we can use lazy compilation for this scope.
+  bool AllowsLazyCompilation() const;
+
+  // True if the outer context of this scope is always the global context.
+  bool HasTrivialOuterContext() const;
+
+  // The number of contexts between this and scope; zero if this == scope.
+  int ContextChainLength(Scope* scope);
+
+
+  // ---------------------------------------------------------------------------
+  // Debugging.
+
+#ifdef DEBUG
+  void Print(int n = 0);  // n = indentation; n < 0 => don't print recursively
+#endif
+
+  // ---------------------------------------------------------------------------
+  // Implementation.
+ protected:
+  friend class ParserFactory;
+
+  // Scope tree.
+  Scope* outer_scope_;  // the immediately enclosing outer scope, or NULL
+  ZoneList<Scope*> inner_scopes_;  // the immediately enclosed inner scopes
+
+  // The scope type.
+  Type type_;
+
+  // Debugging support.
+  Handle<String> scope_name_;
+
+  // The variables declared in this scope:
+  // all user-declared variables (incl. parameters)
+  LocalsMap locals_;
+  // compiler-allocated (user-invisible) temporaries
+  ZoneList<Variable*> temps_;
+  // parameter list in source order
+  ZoneList<Variable*> params_;
+  // variables that must be looked up dynamically
+  ZoneList<Variable*> nonlocals_;
+  // unresolved variables referred to from this scope
+  ZoneList<VariableProxy*> unresolved_;
+  // declarations
+  ZoneList<Declaration*> decls_;
+  // convenience variable
+  VariableProxy* receiver_;
+  // function variable, if any; function scopes only
+  Variable* function_;
+  // convenience variable; function scopes only
+  VariableProxy* arguments_;
+  // convenience variable; function scopes only
+  VariableProxy* arguments_shadow_;
+
+  // Illegal redeclaration.
+  Expression* illegal_redecl_;
+
+  // Scope-specific information.
+  bool scope_inside_with_;  // this scope is inside a 'with' of some outer scope
+  bool scope_contains_with_;  // this scope contains a 'with' statement
+  bool scope_calls_eval_;  // this scope contains an 'eval' call
+
+  // Computed via PropagateScopeInfo.
+  bool outer_scope_calls_eval_;
+  bool inner_scope_calls_eval_;
+  bool force_eager_compilation_;
+
+  // Computed via AllocateVariables; function scopes only.
+  int num_stack_slots_;
+  int num_heap_slots_;
+
+  // Create a non-local variable with a given name.
+  // These variables are looked up dynamically at runtime.
+  Variable* NonLocal(Handle<String> name);
+
+  // Variable resolution.
+  Variable* LookupRecursive(Handle<String> name, bool inner_lookup);
+  void ResolveVariable(Scope* global_scope, VariableProxy* proxy);
+  void ResolveVariablesRecursively(Scope* global_scope);
+
+  // Scope analysis.
+  bool PropagateScopeInfo(bool outer_scope_calls_eval);
+  bool HasTrivialContext() const;
+
+  // Predicates.
+  bool MustAllocate(Variable* var);
+  bool MustAllocateInContext(Variable* var);
+  bool HasArgumentsParameter();
+
+  // Variable allocation.
+  void AllocateStackSlot(Variable* var);
+  void AllocateHeapSlot(Variable* var);
+  void AllocateParameterLocals();
+  void AllocateNonParameterLocal(Variable* var);
+  void AllocateNonParameterLocals();
+  void AllocateVariablesRecursively();
+};
+
+
+class DummyScope : public Scope {
+ public:
+  DummyScope() {
+    outer_scope_ = this;
+  }
+
+  virtual Variable* Lookup(Handle<String> name)  { return NULL; }
+  virtual Variable* Declare(Handle<String> name, Variable::Mode mode) {
+    return NULL;
+  }
+  virtual VariableProxy* NewUnresolved(Handle<String> name, bool inside_with) {
+    return NULL;
+  }
+  virtual VariableProxy* NewTemporary(Handle<String> name)  { return NULL; }
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_SCOPES_H_
diff --git a/regexp2000/src/serialize.cc b/regexp2000/src/serialize.cc
new file mode 100644 (file)
index 0000000..1fd94ab
--- /dev/null
@@ -0,0 +1,1516 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "accessors.h"
+#include "api.h"
+#include "execution.h"
+#include "global-handles.h"
+#include "ic-inl.h"
+#include "natives.h"
+#include "platform.h"
+#include "runtime.h"
+#include "serialize.h"
+#include "stub-cache.h"
+#include "v8threads.h"
+
+namespace v8 { namespace internal {
+
+// Encoding: a RelativeAddress must be able to fit in a pointer:
+// it is encoded as an Address with (from MS to LS bits):
+// 27 bits identifying a word in the space, in one of three formats:
+// - MAP and OLD spaces: 16 bits of page number, 11 bits of word offset in page
+// - NEW space:          27 bits of word offset
+// - LO space:           27 bits of page number
+// 3 bits to encode the AllocationSpace (special values for code in LO space)
+// 2 bits identifying this as a HeapObject
+
+const int kSpaceShift = kHeapObjectTagSize;
+const int kSpaceBits = kSpaceTagSize;
+const int kSpaceMask = kSpaceTagMask;
+
+// These value are used instead of space numbers when serializing/
+// deserializing.  They indicate an object that is in large object space, but
+// should be treated specially.
+// Make the pages executable on platforms that support it:
+const int kLOSpaceExecutable = LAST_SPACE + 1;
+// Reserve space for write barrier bits (for objects that can contain
+// references to new space):
+const int kLOSpacePointer = LAST_SPACE + 2;
+
+
+const int kOffsetShift = kSpaceShift + kSpaceBits;
+const int kOffsetBits = 11;
+const int kOffsetMask = (1 << kOffsetBits) - 1;
+
+const int kPageBits = 32 - (kOffsetBits + kSpaceBits + kHeapObjectTagSize);
+const int kPageShift = kOffsetShift + kOffsetBits;
+const int kPageMask = (1 << kPageBits) - 1;
+
+const int kPageAndOffsetShift = kOffsetShift;
+const int kPageAndOffsetBits = kPageBits + kOffsetBits;
+const int kPageAndOffsetMask = (1 << kPageAndOffsetBits) - 1;
+
+
+static inline AllocationSpace GetSpace(Address addr) {
+  const int encoded = reinterpret_cast<int>(addr);
+  int space_number = ((encoded >> kSpaceShift) & kSpaceMask);
+  if (space_number == kLOSpaceExecutable) space_number = LO_SPACE;
+  else if (space_number == kLOSpacePointer) space_number = LO_SPACE;
+  return static_cast<AllocationSpace>(space_number);
+}
+
+
+static inline bool IsLargeExecutableObject(Address addr) {
+  const int encoded = reinterpret_cast<int>(addr);
+  const int space_number = ((encoded >> kSpaceShift) & kSpaceMask);
+  if (space_number == kLOSpaceExecutable) return true;
+  return false;
+}
+
+
+static inline bool IsLargeFixedArray(Address addr) {
+  const int encoded = reinterpret_cast<int>(addr);
+  const int space_number = ((encoded >> kSpaceShift) & kSpaceMask);
+  if (space_number == kLOSpacePointer) return true;
+  return false;
+}
+
+
+static inline int PageIndex(Address addr) {
+  const int encoded = reinterpret_cast<int>(addr);
+  return (encoded >> kPageShift) & kPageMask;
+}
+
+
+static inline int PageOffset(Address addr) {
+  const int encoded = reinterpret_cast<int>(addr);
+  return ((encoded >> kOffsetShift) & kOffsetMask) << kObjectAlignmentBits;
+}
+
+
+static inline int NewSpaceOffset(Address addr) {
+  const int encoded = reinterpret_cast<int>(addr);
+  return ((encoded >> kPageAndOffsetShift) & kPageAndOffsetMask) <<
+      kObjectAlignmentBits;
+}
+
+
+static inline int LargeObjectIndex(Address addr) {
+  const int encoded = reinterpret_cast<int>(addr);
+  return (encoded >> kPageAndOffsetShift) & kPageAndOffsetMask;
+}
+
+
+// A RelativeAddress encodes a heap address that is independent of
+// the actual memory addresses in real heap. The general case (for the
+// OLD, CODE and MAP spaces) is as a (space id, page number, page offset)
+// triple. The NEW space has page number == 0, because there are no
+// pages. The LARGE_OBJECT space has page offset = 0, since there is
+// exactly one object per page.  RelativeAddresses are encodable as
+// Addresses, so that they can replace the map() pointers of
+// HeapObjects. The encoded Addresses are also encoded as HeapObjects
+// and allow for marking (is_marked() see mark(), clear_mark()...) as
+// used by the Mark-Compact collector.
+
+class RelativeAddress {
+ public:
+  RelativeAddress(AllocationSpace space,
+                  int page_index,
+                  int page_offset)
+  : space_(space), page_index_(page_index), page_offset_(page_offset)  {
+    ASSERT(space <= LAST_SPACE && space >= 0);
+  }
+
+  // Return the encoding of 'this' as an Address. Decode with constructor.
+  Address Encode() const;
+
+  AllocationSpace space() const {
+    if (space_ == kLOSpaceExecutable) return LO_SPACE;
+    if (space_ == kLOSpacePointer) return LO_SPACE;
+    return static_cast<AllocationSpace>(space_);
+  }
+  int page_index() const { return page_index_; }
+  int page_offset() const { return page_offset_; }
+
+  bool in_paged_space() const {
+    return space_ == CODE_SPACE ||
+           space_ == OLD_POINTER_SPACE ||
+           space_ == OLD_DATA_SPACE ||
+           space_ == MAP_SPACE;
+  }
+
+  void next_address(int offset) { page_offset_ += offset; }
+  void next_page(int init_offset = 0) {
+    page_index_++;
+    page_offset_ = init_offset;
+  }
+
+#ifdef DEBUG
+  void Verify();
+#endif
+
+  void set_to_large_code_object() {
+    ASSERT(space_ == LO_SPACE);
+    space_ = kLOSpaceExecutable;
+  }
+  void set_to_large_fixed_array() {
+    ASSERT(space_ == LO_SPACE);
+    space_ = kLOSpacePointer;
+  }
+
+
+ private:
+  int space_;
+  int page_index_;
+  int page_offset_;
+};
+
+
+Address RelativeAddress::Encode() const {
+  ASSERT(page_index_ >= 0);
+  int word_offset = 0;
+  int result = 0;
+  switch (space_) {
+    case MAP_SPACE:
+    case OLD_POINTER_SPACE:
+    case OLD_DATA_SPACE:
+    case CODE_SPACE:
+      ASSERT_EQ(0, page_index_ & ~kPageMask);
+      word_offset = page_offset_ >> kObjectAlignmentBits;
+      ASSERT_EQ(0, word_offset & ~kOffsetMask);
+      result = (page_index_ << kPageShift) | (word_offset << kOffsetShift);
+      break;
+    case NEW_SPACE:
+      ASSERT_EQ(0, page_index_);
+      word_offset = page_offset_ >> kObjectAlignmentBits;
+      ASSERT_EQ(0, word_offset & ~kPageAndOffsetMask);
+      result = word_offset << kPageAndOffsetShift;
+      break;
+    case LO_SPACE:
+    case kLOSpaceExecutable:
+    case kLOSpacePointer:
+      ASSERT_EQ(0, page_offset_);
+      ASSERT_EQ(0, page_index_ & ~kPageAndOffsetMask);
+      result = page_index_ << kPageAndOffsetShift;
+      break;
+  }
+  // OR in AllocationSpace and kHeapObjectTag
+  ASSERT_EQ(0, space_ & ~kSpaceMask);
+  result |= (space_ << kSpaceShift) | kHeapObjectTag;
+  return reinterpret_cast<Address>(result);
+}
+
+
+#ifdef DEBUG
+void RelativeAddress::Verify() {
+  ASSERT(page_offset_ >= 0 && page_index_ >= 0);
+  switch (space_) {
+    case MAP_SPACE:
+    case OLD_POINTER_SPACE:
+    case OLD_DATA_SPACE:
+    case CODE_SPACE:
+      ASSERT(Page::kObjectStartOffset <= page_offset_ &&
+             page_offset_ <= Page::kPageSize);
+      break;
+    case NEW_SPACE:
+      ASSERT(page_index_ == 0);
+      break;
+    case LO_SPACE:
+    case kLOSpaceExecutable:
+    case kLOSpacePointer:
+      ASSERT(page_offset_ == 0);
+      break;
+  }
+}
+#endif
+
+enum GCTreatment {
+  DataObject,     // Object that cannot contain a reference to new space.
+  PointerObject,  // Object that can contain a reference to new space.
+  CodeObject      // Object that contains executable code.
+};
+
+// A SimulatedHeapSpace simulates the allocation of objects in a page in
+// the heap. It uses linear allocation - that is, it doesn't simulate the
+// use of a free list. This simulated
+// allocation must exactly match that done by Heap.
+
+class SimulatedHeapSpace {
+ public:
+  // The default constructor initializes to an invalid state.
+  SimulatedHeapSpace(): current_(LAST_SPACE, -1, -1) {}
+
+  // Sets 'this' to the first address in 'space' that would be
+  // returned by allocation in an empty heap.
+  void InitEmptyHeap(AllocationSpace space);
+
+  // Sets 'this' to the next address in 'space' that would be returned
+  // by allocation in the current heap. Intended only for testing
+  // serialization and deserialization in the current address space.
+  void InitCurrentHeap(AllocationSpace space);
+
+  // Returns the RelativeAddress where the next
+  // object of 'size' bytes will be allocated, and updates 'this' to
+  // point to the next free address beyond that object.
+  RelativeAddress Allocate(int size, GCTreatment special_gc_treatment);
+
+ private:
+  RelativeAddress current_;
+};
+
+
+void SimulatedHeapSpace::InitEmptyHeap(AllocationSpace space) {
+  switch (space) {
+    case MAP_SPACE:
+    case OLD_POINTER_SPACE:
+    case OLD_DATA_SPACE:
+    case CODE_SPACE:
+      current_ = RelativeAddress(space, 0, Page::kObjectStartOffset);
+      break;
+    case NEW_SPACE:
+    case LO_SPACE:
+      current_ = RelativeAddress(space, 0, 0);
+      break;
+  }
+}
+
+
+void SimulatedHeapSpace::InitCurrentHeap(AllocationSpace space) {
+  switch (space) {
+    case MAP_SPACE:
+    case OLD_POINTER_SPACE:
+    case OLD_DATA_SPACE:
+    case CODE_SPACE: {
+      PagedSpace* ps;
+      if (space == MAP_SPACE) {
+        ps = Heap::map_space();
+      } else if (space == OLD_POINTER_SPACE) {
+        ps = Heap::old_pointer_space();
+      } else if (space == OLD_DATA_SPACE) {
+        ps = Heap::old_data_space();
+      } else {
+        ASSERT(space == CODE_SPACE);
+        ps = Heap::code_space();
+      }
+      Address top = ps->top();
+      Page* top_page = Page::FromAllocationTop(top);
+      int page_index = 0;
+      PageIterator it(ps, PageIterator::PAGES_IN_USE);
+      while (it.has_next()) {
+        if (it.next() == top_page) break;
+        page_index++;
+      }
+      current_ = RelativeAddress(space,
+                                 page_index,
+                                 top_page->Offset(top));
+      break;
+    }
+    case NEW_SPACE:
+      current_ = RelativeAddress(space,
+                                 0,
+                                 Heap::NewSpaceTop() - Heap::NewSpaceStart());
+      break;
+    case LO_SPACE:
+      int page_index = 0;
+      for (LargeObjectIterator it(Heap::lo_space()); it.has_next(); it.next()) {
+        page_index++;
+      }
+      current_ = RelativeAddress(space, page_index, 0);
+      break;
+  }
+}
+
+
+RelativeAddress SimulatedHeapSpace::Allocate(int size,
+                                             GCTreatment special_gc_treatment) {
+#ifdef DEBUG
+  current_.Verify();
+#endif
+  int alloc_size = OBJECT_SIZE_ALIGN(size);
+  if (current_.in_paged_space() &&
+      current_.page_offset() + alloc_size > Page::kPageSize) {
+    ASSERT(alloc_size <= Page::kMaxHeapObjectSize);
+    current_.next_page(Page::kObjectStartOffset);
+  }
+  RelativeAddress result = current_;
+  if (current_.space() == LO_SPACE) {
+    current_.next_page();
+    if (special_gc_treatment == CodeObject) {
+      result.set_to_large_code_object();
+    } else if (special_gc_treatment == PointerObject) {
+      result.set_to_large_fixed_array();
+    }
+  } else {
+    current_.next_address(alloc_size);
+  }
+#ifdef DEBUG
+  current_.Verify();
+  result.Verify();
+#endif
+  return result;
+}
+
+// -----------------------------------------------------------------------------
+// Coding of external references.
+
+// The encoding of an external reference. The type is in the high word.
+// The id is in the low word.
+static uint32_t EncodeExternal(TypeCode type, uint16_t id) {
+  return static_cast<uint32_t>(type) << 16 | id;
+}
+
+
+static int* GetInternalPointer(StatsCounter* counter) {
+  // All counters refer to dummy_counter, if deserializing happens without
+  // setting up counters.
+  static int dummy_counter = 0;
+  return counter->Enabled() ? counter->GetInternalPointer() : &dummy_counter;
+}
+
+
+// ExternalReferenceTable is a helper class that defines the relationship
+// between external references and their encodings. It is used to build
+// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
+class ExternalReferenceTable {
+ public:
+  static ExternalReferenceTable* instance() {
+    if (!instance_) instance_ = new ExternalReferenceTable();
+    return instance_;
+  }
+
+  int size() const { return refs_.length(); }
+
+  Address address(int i) { return refs_[i].address; }
+
+  uint32_t code(int i) { return refs_[i].code; }
+
+  const char* name(int i) { return refs_[i].name; }
+
+  int max_id(int code) { return max_id_[code]; }
+
+ private:
+  static ExternalReferenceTable* instance_;
+
+  ExternalReferenceTable();
+
+  struct ExternalReferenceEntry {
+    Address address;
+    uint32_t code;
+    const char* name;
+  };
+
+  void Add(Address address, TypeCode type, uint16_t id, const char* name) {
+    CHECK_NE(NULL, address);
+    ExternalReferenceEntry entry;
+    entry.address = address;
+    entry.code = EncodeExternal(type, id);
+    entry.name = name;
+    CHECK_NE(0, entry.code);
+    refs_.Add(entry);
+    if (id > max_id_[type]) max_id_[type] = id;
+  }
+
+  List<ExternalReferenceEntry> refs_;
+  int max_id_[kTypeCodeCount];
+};
+
+
+ExternalReferenceTable* ExternalReferenceTable::instance_ = NULL;
+
+
+ExternalReferenceTable::ExternalReferenceTable() : refs_(64) {
+  for (int type_code = 0; type_code < kTypeCodeCount; type_code++) {
+    max_id_[type_code] = 0;
+  }
+
+  // Define all entries in the table.
+
+  // Builtins
+#define DEF_ENTRY_C(name) \
+  Add(Builtins::c_function_address(Builtins::c_##name), \
+      C_BUILTIN, \
+      Builtins::c_##name, \
+      "Builtins::" #name);
+
+  BUILTIN_LIST_C(DEF_ENTRY_C)
+#undef DEF_ENTRY_C
+
+#define DEF_ENTRY_C(name) \
+  Add(Builtins::builtin_address(Builtins::name), \
+      BUILTIN, \
+      Builtins::name, \
+      "Builtins::" #name);
+#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name)
+
+  BUILTIN_LIST_C(DEF_ENTRY_C)
+  BUILTIN_LIST_A(DEF_ENTRY_A)
+#undef DEF_ENTRY_C
+#undef DEF_ENTRY_A
+
+  // Runtime functions
+#define RUNTIME_ENTRY(name, nargs) \
+  Add(Runtime::FunctionForId(Runtime::k##name)->entry, \
+      RUNTIME_FUNCTION, \
+      Runtime::k##name, \
+      "Runtime::" #name);
+
+  RUNTIME_FUNCTION_LIST(RUNTIME_ENTRY)
+#undef RUNTIME_ENTRY
+
+  // IC utilities
+#define IC_ENTRY(name) \
+  Add(IC::AddressFromUtilityId(IC::k##name), \
+      IC_UTILITY, \
+      IC::k##name, \
+      "IC::" #name);
+
+  IC_UTIL_LIST(IC_ENTRY)
+#undef IC_ENTRY
+
+  // Debug addresses
+  Add(Debug_Address(Debug::k_after_break_target_address).address(),
+      DEBUG_ADDRESS,
+      Debug::k_after_break_target_address << kDebugIdShift,
+      "Debug::after_break_target_address()");
+  Add(Debug_Address(Debug::k_debug_break_return_address).address(),
+      DEBUG_ADDRESS,
+      Debug::k_debug_break_return_address << kDebugIdShift,
+      "Debug::debug_break_return_address()");
+  const char* debug_register_format = "Debug::register_address(%i)";
+  size_t dr_format_length = strlen(debug_register_format);
+  for (int i = 0; i < kNumJSCallerSaved; ++i) {
+    Vector<char> name = Vector<char>::New(dr_format_length + 1);
+    OS::SNPrintF(name, debug_register_format, i);
+    Add(Debug_Address(Debug::k_register_address, i).address(),
+        DEBUG_ADDRESS,
+        Debug::k_register_address << kDebugIdShift | i,
+        name.start());
+  }
+
+  // Stat counters
+#define COUNTER_ENTRY(name, caption) \
+  Add(reinterpret_cast<Address>(GetInternalPointer(&Counters::name)), \
+      STATS_COUNTER, \
+      Counters::k_##name, \
+      "Counters::" #name);
+
+  STATS_COUNTER_LIST_1(COUNTER_ENTRY)
+  STATS_COUNTER_LIST_2(COUNTER_ENTRY)
+#undef COUNTER_ENTRY
+
+  // Top addresses
+  const char* top_address_format = "Top::get_address_from_id(%i)";
+  size_t top_format_length = strlen(top_address_format);
+  for (uint16_t i = 0; i < Top::k_top_address_count; ++i) {
+    Vector<char> name = Vector<char>::New(top_format_length + 1);
+    const char* chars = name.start();
+    OS::SNPrintF(name, top_address_format, i);
+    Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
+  }
+
+  // Extensions
+  Add(FUNCTION_ADDR(GCExtension::GC), EXTENSION, 1,
+      "GCExtension::GC");
+
+  // Accessors
+#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
+  Add((Address)&Accessors::name, \
+      ACCESSOR, \
+      Accessors::k##name, \
+      "Accessors::" #name);
+
+  ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
+#undef ACCESSOR_DESCRIPTOR_DECLARATION
+
+  // Stub cache tables
+  Add(SCTableReference::keyReference(StubCache::kPrimary).address(),
+      STUB_CACHE_TABLE,
+      1,
+      "StubCache::primary_->key");
+  Add(SCTableReference::valueReference(StubCache::kPrimary).address(),
+      STUB_CACHE_TABLE,
+      2,
+      "StubCache::primary_->value");
+  Add(SCTableReference::keyReference(StubCache::kSecondary).address(),
+      STUB_CACHE_TABLE,
+      3,
+      "StubCache::secondary_->key");
+  Add(SCTableReference::valueReference(StubCache::kSecondary).address(),
+      STUB_CACHE_TABLE,
+      4,
+      "StubCache::secondary_->value");
+
+  // Runtime entries
+  Add(FUNCTION_ADDR(Runtime::PerformGC),
+      RUNTIME_ENTRY,
+      1,
+      "Runtime::PerformGC");
+
+  // Miscellaneous
+  Add(ExternalReference::builtin_passed_function().address(),
+      UNCLASSIFIED,
+      1,
+      "Builtins::builtin_passed_function");
+  Add(ExternalReference::the_hole_value_location().address(),
+      UNCLASSIFIED,
+      2,
+      "Factory::the_hole_value().location()");
+  Add(ExternalReference::address_of_stack_guard_limit().address(),
+      UNCLASSIFIED,
+      3,
+      "StackGuard::address_of_limit()");
+  Add(ExternalReference::debug_break().address(),
+      UNCLASSIFIED,
+      4,
+      "Debug::Break()");
+  Add(ExternalReference::new_space_start().address(),
+      UNCLASSIFIED,
+      5,
+      "Heap::NewSpaceStart()");
+  Add(ExternalReference::new_space_allocation_limit_address().address(),
+      UNCLASSIFIED,
+      6,
+      "Heap::NewSpaceAllocationLimitAddress()");
+  Add(ExternalReference::new_space_allocation_top_address().address(),
+      UNCLASSIFIED,
+      7,
+      "Heap::NewSpaceAllocationTopAddress()");
+  Add(ExternalReference::debug_step_in_fp_address().address(),
+      UNCLASSIFIED,
+      8,
+      "Debug::step_in_fp_addr()");
+}
+
+
+ExternalReferenceEncoder::ExternalReferenceEncoder()
+    : encodings_(Match) {
+  ExternalReferenceTable* external_references =
+      ExternalReferenceTable::instance();
+  for (int i = 0; i < external_references->size(); ++i) {
+    Put(external_references->address(i), i);
+  }
+}
+
+
+uint32_t ExternalReferenceEncoder::Encode(Address key) const {
+  int index = IndexOf(key);
+  return index >=0 ? ExternalReferenceTable::instance()->code(index) : 0;
+}
+
+
+const char* ExternalReferenceEncoder::NameOfAddress(Address key) const {
+  int index = IndexOf(key);
+  return index >=0 ? ExternalReferenceTable::instance()->name(index) : NULL;
+}
+
+
+int ExternalReferenceEncoder::IndexOf(Address key) const {
+  if (key == NULL) return -1;
+  HashMap::Entry* entry =
+      const_cast<HashMap &>(encodings_).Lookup(key, Hash(key), false);
+  return entry == NULL ? -1 : reinterpret_cast<int>(entry->value);
+}
+
+
+void ExternalReferenceEncoder::Put(Address key, int index) {
+  HashMap::Entry* entry = encodings_.Lookup(key, Hash(key), true);
+  entry->value = reinterpret_cast<void *>(index);
+}
+
+
+ExternalReferenceDecoder::ExternalReferenceDecoder()
+  : encodings_(NewArray<Address*>(kTypeCodeCount)) {
+  ExternalReferenceTable* external_references =
+      ExternalReferenceTable::instance();
+  for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
+    int max = external_references->max_id(type) + 1;
+    encodings_[type] = NewArray<Address>(max + 1);
+  }
+  for (int i = 0; i < external_references->size(); ++i) {
+    Put(external_references->code(i), external_references->address(i));
+  }
+}
+
+
+ExternalReferenceDecoder::~ExternalReferenceDecoder() {
+  for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
+    DeleteArray(encodings_[type]);
+  }
+  DeleteArray(encodings_);
+}
+
+
+//------------------------------------------------------------------------------
+// Implementation of Serializer
+
+
+// Helper class to write the bytes of the serialized heap.
+
+class SnapshotWriter {
+ public:
+  SnapshotWriter() {
+    len_ = 0;
+    max_ = 8 << 10;  // 8K initial size
+    str_ = NewArray<char>(max_);
+  }
+
+  ~SnapshotWriter() {
+    DeleteArray(str_);
+  }
+
+  void GetString(char** str, int* len) {
+    *str = NewArray<char>(len_);
+    memcpy(*str, str_, len_);
+    *len = len_;
+  }
+
+  void Reserve(int bytes, int pos);
+
+  void PutC(char c) {
+    InsertC(c, len_);
+  }
+
+  void PutInt(int i) {
+    InsertInt(i, len_);
+  }
+
+  void PutBytes(const byte* a, int size) {
+    InsertBytes(a, len_, size);
+  }
+
+  void PutString(const char* s) {
+    InsertString(s, len_);
+  }
+
+  int InsertC(char c, int pos) {
+    Reserve(1, pos);
+    str_[pos] = c;
+    len_++;
+    return pos + 1;
+  }
+
+  int InsertInt(int i, int pos) {
+    return InsertBytes(reinterpret_cast<byte*>(&i), pos, sizeof(i));
+  }
+
+  int InsertBytes(const byte* a, int pos, int size) {
+    Reserve(size, pos);
+    memcpy(&str_[pos], a, size);
+    len_ += size;
+    return pos + size;
+  }
+
+  int InsertString(const char* s, int pos);
+
+  int length() { return len_; }
+
+  Address position() { return reinterpret_cast<Address>(&str_[len_]); }
+
+ private:
+  char* str_;  // the snapshot
+  int len_;   // the curent length of str_
+  int max_;   // the allocated size of str_
+};
+
+
+void SnapshotWriter::Reserve(int bytes, int pos) {
+  CHECK(0 <= pos && pos <= len_);
+  while (len_ + bytes >= max_) {
+    max_ *= 2;
+    char* old = str_;
+    str_ = NewArray<char>(max_);
+    memcpy(str_, old, len_);
+    DeleteArray(old);
+  }
+  if (pos < len_) {
+    char* old = str_;
+    str_ = NewArray<char>(max_);
+    memcpy(str_, old, pos);
+    memcpy(str_ + pos + bytes, old + pos, len_ - pos);
+    DeleteArray(old);
+  }
+}
+
+int SnapshotWriter::InsertString(const char* s, int pos) {
+  int size = strlen(s);
+  pos = InsertC('[', pos);
+  pos = InsertInt(size, pos);
+  pos = InsertC(']', pos);
+  return InsertBytes(reinterpret_cast<const byte*>(s), pos, size);
+}
+
+
+class ReferenceUpdater: public ObjectVisitor {
+ public:
+  ReferenceUpdater(HeapObject* obj, Serializer* serializer)
+    : obj_address_(obj->address()),
+      serializer_(serializer),
+      reference_encoder_(serializer->reference_encoder_),
+      offsets_(8),
+      addresses_(8) {
+  }
+
+  virtual void VisitPointers(Object** start, Object** end) {
+    for (Object** p = start; p < end; ++p) {
+      if ((*p)->IsHeapObject()) {
+        offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
+        Address a = serializer_->GetSavedAddress(HeapObject::cast(*p));
+        addresses_.Add(a);
+      }
+    }
+  }
+
+  virtual void VisitExternalReferences(Address* start, Address* end) {
+    for (Address* p = start; p < end; ++p) {
+      uint32_t code = reference_encoder_->Encode(*p);
+      CHECK(*p == NULL ? code == 0 : code != 0);
+      offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
+      addresses_.Add(reinterpret_cast<Address>(code));
+    }
+  }
+
+  virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
+    Address target = rinfo->target_address();
+    uint32_t encoding = reference_encoder_->Encode(target);
+    CHECK(target == NULL ? encoding == 0 : encoding != 0);
+    offsets_.Add(reinterpret_cast<Address>(rinfo->pc()) - obj_address_);
+    addresses_.Add(reinterpret_cast<Address>(encoding));
+  }
+
+  void Update(Address start_address) {
+    for (int i = 0; i < offsets_.length(); i++) {
+      Address* p = reinterpret_cast<Address*>(start_address + offsets_[i]);
+      *p = addresses_[i];
+    }
+  }
+
+ private:
+  Address obj_address_;
+  Serializer* serializer_;
+  ExternalReferenceEncoder* reference_encoder_;
+  List<int> offsets_;
+  List<Address> addresses_;
+};
+
+
+// Helper functions for a map of encoded heap object addresses.
+static uint32_t HeapObjectHash(HeapObject* key) {
+  return reinterpret_cast<uint32_t>(key) >> 2;
+}
+
+
+static bool MatchHeapObject(void* key1, void* key2) {
+  return key1 == key2;
+}
+
+
+Serializer::Serializer()
+  : global_handles_(4),
+    saved_addresses_(MatchHeapObject) {
+  root_ = true;
+  roots_ = 0;
+  objects_ = 0;
+  reference_encoder_ = NULL;
+  writer_ = new SnapshotWriter();
+  for (int i = 0; i <= LAST_SPACE; i++) {
+    allocator_[i] = new SimulatedHeapSpace();
+  }
+}
+
+
+Serializer::~Serializer() {
+  for (int i = 0; i <= LAST_SPACE; i++) {
+    delete allocator_[i];
+  }
+  if (reference_encoder_) delete reference_encoder_;
+  delete writer_;
+}
+
+
+bool Serializer::serialization_enabled_ = true;
+
+
+#ifdef DEBUG
+static const int kMaxTagLength = 32;
+
+void Serializer::Synchronize(const char* tag) {
+  if (FLAG_debug_serialization) {
+    int length = strlen(tag);
+    ASSERT(length <= kMaxTagLength);
+    writer_->PutC('S');
+    writer_->PutInt(length);
+    writer_->PutBytes(reinterpret_cast<const byte*>(tag), length);
+  }
+}
+#endif
+
+
+void Serializer::InitializeAllocators() {
+  for (int i = 0; i <= LAST_SPACE; i++) {
+    allocator_[i]->InitEmptyHeap(static_cast<AllocationSpace>(i));
+  }
+}
+
+
+bool Serializer::IsVisited(HeapObject* obj) {
+  HashMap::Entry* entry =
+    saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
+  return entry != NULL;
+}
+
+
+Address Serializer::GetSavedAddress(HeapObject* obj) {
+  HashMap::Entry* entry
+  = saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
+  ASSERT(entry != NULL);
+  return reinterpret_cast<Address>(entry->value);
+}
+
+
+void Serializer::SaveAddress(HeapObject* obj, Address addr) {
+  HashMap::Entry* entry =
+    saved_addresses_.Lookup(obj, HeapObjectHash(obj), true);
+  entry->value = addr;
+}
+
+
+void Serializer::Serialize() {
+  // No active threads.
+  CHECK_EQ(NULL, ThreadState::FirstInUse());
+  // No active or weak handles.
+  CHECK(HandleScopeImplementer::instance()->Blocks()->is_empty());
+  CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
+  // We need a counter function during serialization to resolve the
+  // references to counters in the code on the heap.
+  CHECK(StatsTable::HasCounterFunction());
+  CHECK(enabled());
+  InitializeAllocators();
+  reference_encoder_ = new ExternalReferenceEncoder();
+  PutHeader();
+  Heap::IterateRoots(this);
+  PutLog();
+  PutContextStack();
+  disable();
+}
+
+
+void Serializer::Finalize(char** str, int* len) {
+  writer_->GetString(str, len);
+}
+
+
+// Serialize objects by writing them into the stream.
+
+void Serializer::VisitPointers(Object** start, Object** end) {
+  bool root = root_;
+  root_ = false;
+  for (Object** p = start; p < end; ++p) {
+    bool serialized;
+    Address a = Encode(*p, &serialized);
+    if (root) {
+      roots_++;
+      // If the object was not just serialized,
+      // write its encoded address instead.
+      if (!serialized) PutEncodedAddress(a);
+    }
+  }
+  root_ = root;
+}
+
+
+class GlobalHandlesRetriever: public ObjectVisitor {
+ public:
+  explicit GlobalHandlesRetriever(List<Object**>* handles)
+  : global_handles_(handles) {}
+
+  virtual void VisitPointers(Object** start, Object** end) {
+    for (; start != end; ++start) {
+      global_handles_->Add(start);
+    }
+  }
+
+ private:
+  List<Object**>* global_handles_;
+};
+
+
+void Serializer::PutFlags() {
+  writer_->PutC('F');
+  List<char*>* argv = FlagList::argv();
+  writer_->PutInt(argv->length());
+  writer_->PutC('[');
+  for (int i = 0; i < argv->length(); i++) {
+    if (i > 0) writer_->PutC('|');
+    writer_->PutString((*argv)[i]);
+    DeleteArray((*argv)[i]);
+  }
+  writer_->PutC(']');
+  flags_end_ = writer_->length();
+  delete argv;
+}
+
+
+void Serializer::PutHeader() {
+  PutFlags();
+  writer_->PutC('D');
+#ifdef DEBUG
+  writer_->PutC(FLAG_debug_serialization ? '1' : '0');
+#else
+  writer_->PutC('0');
+#endif
+  // Write sizes of paged memory spaces. Allocate extra space for the old
+  // and code spaces, because objects in new space will be promoted to them.
+  writer_->PutC('S');
+  writer_->PutC('[');
+  writer_->PutInt(Heap::old_pointer_space()->Size() +
+                  Heap::new_space()->Size());
+  writer_->PutC('|');
+  writer_->PutInt(Heap::old_data_space()->Size() + Heap::new_space()->Size());
+  writer_->PutC('|');
+  writer_->PutInt(Heap::code_space()->Size() + Heap::new_space()->Size());
+  writer_->PutC('|');
+  writer_->PutInt(Heap::map_space()->Size());
+  writer_->PutC(']');
+  // Write global handles.
+  writer_->PutC('G');
+  writer_->PutC('[');
+  GlobalHandlesRetriever ghr(&global_handles_);
+  GlobalHandles::IterateRoots(&ghr);
+  for (int i = 0; i < global_handles_.length(); i++) {
+    writer_->PutC('N');
+  }
+  writer_->PutC(']');
+}
+
+
+void Serializer::PutLog() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (FLAG_log_code) {
+    Logger::TearDown();
+    int pos = writer_->InsertC('L', flags_end_);
+    bool exists;
+    Vector<const char> log = ReadFile(FLAG_logfile, &exists);
+    writer_->InsertString(log.start(), pos);
+    log.Dispose();
+  }
+#endif
+}
+
+
+static int IndexOf(const List<Object**>& list, Object** element) {
+  for (int i = 0; i < list.length(); i++) {
+    if (list[i] == element) return i;
+  }
+  return -1;
+}
+
+
+void Serializer::PutGlobalHandleStack(const List<Handle<Object> >& stack) {
+  writer_->PutC('[');
+  writer_->PutInt(stack.length());
+  for (int i = stack.length() - 1; i >= 0; i--) {
+    writer_->PutC('|');
+    int gh_index = IndexOf(global_handles_, stack[i].location());
+    CHECK_GE(gh_index, 0);
+    writer_->PutInt(gh_index);
+  }
+  writer_->PutC(']');
+}
+
+
+void Serializer::PutContextStack() {
+  List<Handle<Object> > contexts(2);
+  while (HandleScopeImplementer::instance()->HasSavedContexts()) {
+    Handle<Object> context =
+      HandleScopeImplementer::instance()->RestoreContext();
+    contexts.Add(context);
+  }
+  for (int i = contexts.length() - 1; i >= 0; i--) {
+    HandleScopeImplementer::instance()->SaveContext(contexts[i]);
+  }
+  PutGlobalHandleStack(contexts);
+}
+
+
+void Serializer::PutEncodedAddress(Address addr) {
+  writer_->PutC('P');
+  writer_->PutInt(reinterpret_cast<int>(addr));
+}
+
+
+Address Serializer::Encode(Object* o, bool* serialized) {
+  *serialized = false;
+  if (o->IsSmi()) {
+    return reinterpret_cast<Address>(o);
+  } else {
+    HeapObject* obj = HeapObject::cast(o);
+    if (IsVisited(obj)) {
+      return GetSavedAddress(obj);
+    } else {
+      // First visit: serialize the object.
+      *serialized = true;
+      return PutObject(obj);
+    }
+  }
+}
+
+
+Address Serializer::PutObject(HeapObject* obj) {
+  Map* map = obj->map();
+  InstanceType type = map->instance_type();
+  int size = obj->SizeFromMap(map);
+
+  // Simulate the allocation of obj to predict where it will be
+  // allocated during deserialization.
+  Address addr = Allocate(obj).Encode();
+
+  SaveAddress(obj, addr);
+
+  if (type == CODE_TYPE) {
+    Code* code = Code::cast(obj);
+    // Ensure Code objects contain Object pointers, not Addresses.
+    code->ConvertICTargetsFromAddressToObject();
+    LOG(CodeMoveEvent(code->address(), addr));
+  }
+
+  // Write out the object prologue: type, size, and simulated address of obj.
+  writer_->PutC('[');
+  CHECK_EQ(0, size & kObjectAlignmentMask);
+  writer_->PutInt(type);
+  writer_->PutInt(size >> kObjectAlignmentBits);
+  PutEncodedAddress(addr);  // encodes AllocationSpace
+
+  // Visit all the pointers in the object other than the map. This
+  // will recursively serialize any as-yet-unvisited objects.
+  obj->Iterate(this);
+
+  // Mark end of recursively embedded objects, start of object body.
+  writer_->PutC('|');
+  // Write out the raw contents of the object. No compression, but
+  // fast to deserialize.
+  writer_->PutBytes(obj->address(), size);
+  // Update pointers and external references in the written object.
+  ReferenceUpdater updater(obj, this);
+  obj->Iterate(&updater);
+  updater.Update(writer_->position() - size);
+
+#ifdef DEBUG
+  if (FLAG_debug_serialization) {
+    // Write out the object epilogue to catch synchronization errors.
+    PutEncodedAddress(addr);
+    writer_->PutC(']');
+  }
+#endif
+
+  if (type == CODE_TYPE) {
+    Code* code = Code::cast(obj);
+    // Convert relocations from Object* to Address in Code objects
+    code->ConvertICTargetsFromObjectToAddress();
+  }
+
+  objects_++;
+  return addr;
+}
+
+
+RelativeAddress Serializer::Allocate(HeapObject* obj) {
+  // Find out which AllocationSpace 'obj' is in.
+  AllocationSpace s;
+  bool found = false;
+  for (int i = FIRST_SPACE; !found && i <= LAST_SPACE; i++) {
+    s = static_cast<AllocationSpace>(i);
+    found = Heap::InSpace(obj, s);
+  }
+  CHECK(found);
+  if (s == NEW_SPACE) {
+    Space* space = Heap::TargetSpace(obj);
+    ASSERT(space == Heap::old_pointer_space() ||
+           space == Heap::old_data_space());
+    s = (space == Heap::old_pointer_space()) ?
+        OLD_POINTER_SPACE :
+        OLD_DATA_SPACE;
+  }
+  int size = obj->Size();
+  GCTreatment gc_treatment = DataObject;
+  if (obj->IsFixedArray()) gc_treatment = PointerObject;
+  else if (obj->IsCode()) gc_treatment = CodeObject;
+  return allocator_[s]->Allocate(size, gc_treatment);
+}
+
+
+//------------------------------------------------------------------------------
+// Implementation of Deserializer
+
+
+static const int kInitArraySize = 32;
+
+
+Deserializer::Deserializer(const char* str, int len)
+  : reader_(str, len),
+    map_pages_(kInitArraySize),
+    old_pointer_pages_(kInitArraySize),
+    old_data_pages_(kInitArraySize),
+    code_pages_(kInitArraySize),
+    large_objects_(kInitArraySize),
+    global_handles_(4) {
+  root_ = true;
+  roots_ = 0;
+  objects_ = 0;
+  reference_decoder_ = NULL;
+#ifdef DEBUG
+  expect_debug_information_ = false;
+#endif
+}
+
+
+Deserializer::~Deserializer() {
+  if (reference_decoder_) delete reference_decoder_;
+}
+
+
+void Deserializer::ExpectEncodedAddress(Address expected) {
+  Address a = GetEncodedAddress();
+  USE(a);
+  ASSERT(a == expected);
+}
+
+
+#ifdef DEBUG
+void Deserializer::Synchronize(const char* tag) {
+  if (expect_debug_information_) {
+    char buf[kMaxTagLength];
+    reader_.ExpectC('S');
+    int length = reader_.GetInt();
+    ASSERT(length <= kMaxTagLength);
+    reader_.GetBytes(reinterpret_cast<Address>(buf), length);
+    ASSERT_EQ(strlen(tag), length);
+    ASSERT(strncmp(tag, buf, length) == 0);
+  }
+}
+#endif
+
+
+void Deserializer::Deserialize() {
+  // No active threads.
+  ASSERT_EQ(NULL, ThreadState::FirstInUse());
+  // No active handles.
+  ASSERT(HandleScopeImplementer::instance()->Blocks()->is_empty());
+  reference_decoder_ = new ExternalReferenceDecoder();
+  // By setting linear allocation only, we forbid the use of free list
+  // allocation which is not predicted by SimulatedAddress.
+  GetHeader();
+  Heap::IterateRoots(this);
+  GetContextStack();
+}
+
+
+void Deserializer::VisitPointers(Object** start, Object** end) {
+  bool root = root_;
+  root_ = false;
+  for (Object** p = start; p < end; ++p) {
+    if (root) {
+      roots_++;
+      // Read the next object or pointer from the stream
+      // pointer in the stream.
+      int c = reader_.GetC();
+      if (c == '[') {
+        *p = GetObject();  // embedded object
+      } else {
+        ASSERT(c == 'P');  // pointer to previously serialized object
+        *p = Resolve(reinterpret_cast<Address>(reader_.GetInt()));
+      }
+    } else {
+      // A pointer internal to a HeapObject that we've already
+      // read: resolve it to a true address (or Smi)
+      *p = Resolve(reinterpret_cast<Address>(*p));
+    }
+  }
+  root_ = root;
+}
+
+
+void Deserializer::VisitExternalReferences(Address* start, Address* end) {
+  for (Address* p = start; p < end; ++p) {
+    uint32_t code = reinterpret_cast<uint32_t>(*p);
+    *p = reference_decoder_->Decode(code);
+  }
+}
+
+
+void Deserializer::VisitRuntimeEntry(RelocInfo* rinfo) {
+  uint32_t* pc = reinterpret_cast<uint32_t*>(rinfo->pc());
+  uint32_t encoding = *pc;
+  Address target = reference_decoder_->Decode(encoding);
+  rinfo->set_target_address(target);
+}
+
+
+void Deserializer::GetFlags() {
+  reader_.ExpectC('F');
+  int argc = reader_.GetInt() + 1;
+  char** argv = NewArray<char*>(argc);
+  reader_.ExpectC('[');
+  for (int i = 1; i < argc; i++) {
+    if (i > 1) reader_.ExpectC('|');
+    argv[i] = reader_.GetString();
+  }
+  reader_.ExpectC(']');
+  has_log_ = false;
+  for (int i = 1; i < argc; i++) {
+    if (strcmp("--log_code", argv[i]) == 0) {
+      has_log_ = true;
+    } else if (strcmp("--nouse_ic", argv[i]) == 0) {
+      FLAG_use_ic = false;
+    } else if (strcmp("--debug_code", argv[i]) == 0) {
+      FLAG_debug_code = true;
+    } else if (strcmp("--nolazy", argv[i]) == 0) {
+      FLAG_lazy = false;
+    }
+    DeleteArray(argv[i]);
+  }
+
+  DeleteArray(argv);
+}
+
+
+void Deserializer::GetLog() {
+  if (has_log_) {
+    reader_.ExpectC('L');
+    char* snapshot_log = reader_.GetString();
+#ifdef ENABLE_LOGGING_AND_PROFILING
+    if (FLAG_log_code) {
+      LOG(Preamble(snapshot_log));
+    }
+#endif
+    DeleteArray(snapshot_log);
+  }
+}
+
+
+static void InitPagedSpace(PagedSpace* space,
+                           int capacity,
+                           List<Page*>* page_list) {
+  space->EnsureCapacity(capacity);
+  // TODO(1240712): PagedSpace::EnsureCapacity can return false due to
+  // a failure to allocate from the OS to expand the space.
+  PageIterator it(space, PageIterator::ALL_PAGES);
+  while (it.has_next()) page_list->Add(it.next());
+}
+
+
+void Deserializer::GetHeader() {
+  reader_.ExpectC('D');
+#ifdef DEBUG
+  expect_debug_information_ = reader_.GetC() == '1';
+#else
+  // In release mode, don't attempt to read a snapshot containing
+  // synchronization tags.
+  if (reader_.GetC() != '0') FATAL("Snapshot contains synchronization tags.");
+#endif
+  // Ensure sufficient capacity in paged memory spaces to avoid growth
+  // during deserialization.
+  reader_.ExpectC('S');
+  reader_.ExpectC('[');
+  InitPagedSpace(Heap::old_pointer_space(),
+                 reader_.GetInt(),
+                 &old_pointer_pages_);
+  reader_.ExpectC('|');
+  InitPagedSpace(Heap::old_data_space(), reader_.GetInt(), &old_data_pages_);
+  reader_.ExpectC('|');
+  InitPagedSpace(Heap::code_space(), reader_.GetInt(), &code_pages_);
+  reader_.ExpectC('|');
+  InitPagedSpace(Heap::map_space(), reader_.GetInt(), &map_pages_);
+  reader_.ExpectC(']');
+  // Create placeholders for global handles later to be fill during
+  // IterateRoots.
+  reader_.ExpectC('G');
+  reader_.ExpectC('[');
+  int c = reader_.GetC();
+  while (c != ']') {
+    ASSERT(c == 'N');
+    global_handles_.Add(GlobalHandles::Create(NULL).location());
+    c = reader_.GetC();
+  }
+}
+
+
+void Deserializer::GetGlobalHandleStack(List<Handle<Object> >* stack) {
+  reader_.ExpectC('[');
+  int length = reader_.GetInt();
+  for (int i = 0; i < length; i++) {
+    reader_.ExpectC('|');
+    int gh_index = reader_.GetInt();
+    stack->Add(global_handles_[gh_index]);
+  }
+  reader_.ExpectC(']');
+}
+
+
+void Deserializer::GetContextStack() {
+  List<Handle<Object> > entered_contexts(2);
+  GetGlobalHandleStack(&entered_contexts);
+  for (int i = 0; i < entered_contexts.length(); i++) {
+    HandleScopeImplementer::instance()->SaveContext(entered_contexts[i]);
+  }
+}
+
+
+Address Deserializer::GetEncodedAddress() {
+  reader_.ExpectC('P');
+  return reinterpret_cast<Address>(reader_.GetInt());
+}
+
+
+Object* Deserializer::GetObject() {
+  // Read the prologue: type, size and encoded address.
+  InstanceType type = static_cast<InstanceType>(reader_.GetInt());
+  int size = reader_.GetInt() << kObjectAlignmentBits;
+  Address a = GetEncodedAddress();
+
+  // Get a raw object of the right size in the right space.
+  AllocationSpace space = GetSpace(a);
+  Object* o;
+  if (IsLargeExecutableObject(a)) {
+    o = Heap::lo_space()->AllocateRawCode(size);
+  } else if (IsLargeFixedArray(a)) {
+    o = Heap::lo_space()->AllocateRawFixedArray(size);
+  } else {
+    o = Heap::AllocateRaw(size, space);
+  }
+  ASSERT(!o->IsFailure());
+  // Check that the simulation of heap allocation was correct.
+  ASSERT(o == Resolve(a));
+
+  // Read any recursively embedded objects.
+  int c = reader_.GetC();
+  while (c == '[') {
+    GetObject();
+    c = reader_.GetC();
+  }
+  ASSERT(c == '|');
+
+  HeapObject* obj = reinterpret_cast<HeapObject*>(o);
+  // Read the uninterpreted contents of the object after the map
+  reader_.GetBytes(obj->address(), size);
+#ifdef DEBUG
+  if (expect_debug_information_) {
+    // Read in the epilogue to check that we're still synchronized
+    ExpectEncodedAddress(a);
+    reader_.ExpectC(']');
+  }
+#endif
+
+  // Resolve the encoded pointers we just read in.
+  // Same as obj->Iterate(this), but doesn't rely on the map pointer being set.
+  VisitPointer(reinterpret_cast<Object**>(obj->address()));
+  obj->IterateBody(type, size, this);
+
+  if (type == CODE_TYPE) {
+    Code* code = Code::cast(obj);
+    // Convert relocations from Object* to Address in Code objects
+    code->ConvertICTargetsFromObjectToAddress();
+    LOG(CodeMoveEvent(a, code->address()));
+  }
+  objects_++;
+  return o;
+}
+
+
+static inline Object* ResolvePaged(int page_index,
+                                   int page_offset,
+                                   PagedSpace* space,
+                                   List<Page*>* page_list) {
+  ASSERT(page_index < page_list->length());
+  Address address = (*page_list)[page_index]->OffsetToAddress(page_offset);
+  return HeapObject::FromAddress(address);
+}
+
+
+template<typename T>
+void ConcatReversed(List<T>* target, const List<T>& source) {
+  for (int i = source.length() - 1; i >= 0; i--) {
+    target->Add(source[i]);
+  }
+}
+
+
+Object* Deserializer::Resolve(Address encoded) {
+  Object* o = reinterpret_cast<Object*>(encoded);
+  if (o->IsSmi()) return o;
+
+  // Encoded addresses of HeapObjects always have 'HeapObject' tags.
+  ASSERT(o->IsHeapObject());
+
+  switch (GetSpace(encoded)) {
+    // For Map space and Old space, we cache the known Pages in map_pages,
+    // old_pointer_pages and old_data_pages. Even though MapSpace keeps a list
+    // of page addresses, we don't rely on it since GetObject uses AllocateRaw,
+    // and that appears not to update the page list.
+    case MAP_SPACE:
+      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
+                          Heap::map_space(), &map_pages_);
+    case OLD_POINTER_SPACE:
+      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
+                          Heap::old_pointer_space(), &old_pointer_pages_);
+    case OLD_DATA_SPACE:
+      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
+                          Heap::old_data_space(), &old_data_pages_);
+    case CODE_SPACE:
+      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
+                          Heap::code_space(), &code_pages_);
+    case NEW_SPACE:
+      return HeapObject::FromAddress(Heap::NewSpaceStart() +
+                                     NewSpaceOffset(encoded));
+    case LO_SPACE:
+      // Cache the known large_objects, allocated one per 'page'
+      int index = LargeObjectIndex(encoded);
+      if (index >= large_objects_.length()) {
+        int new_object_count =
+          Heap::lo_space()->PageCount() - large_objects_.length();
+        List<Object*> new_objects(new_object_count);
+        LargeObjectIterator it(Heap::lo_space());
+        for (int i = 0; i < new_object_count; i++) {
+          new_objects.Add(it.next());
+        }
+#ifdef DEBUG
+        for (int i = large_objects_.length() - 1; i >= 0; i--) {
+          ASSERT(it.next() == large_objects_[i]);
+        }
+#endif
+        ConcatReversed(&large_objects_, new_objects);
+        ASSERT(index < large_objects_.length());
+      }
+      return large_objects_[index];  // s.page_offset() is ignored.
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/serialize.h b/regexp2000/src/serialize.h
new file mode 100644 (file)
index 0000000..e17ee15
--- /dev/null
@@ -0,0 +1,334 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SERIALIZE_H_
+#define V8_SERIALIZE_H_
+
+#include "hashmap.h"
+
+namespace v8 { namespace internal {
+
+// A TypeCode is used to distinguish different kinds of external reference.
+// It is a single bit to make testing for types easy.
+enum TypeCode {
+  UNCLASSIFIED,        // One-of-a-kind references.
+  BUILTIN,
+  RUNTIME_FUNCTION,
+  IC_UTILITY,
+  DEBUG_ADDRESS,
+  STATS_COUNTER,
+  TOP_ADDRESS,
+  C_BUILTIN,
+  EXTENSION,
+  ACCESSOR,
+  RUNTIME_ENTRY,
+  STUB_CACHE_TABLE
+};
+
+const int kTypeCodeCount = STUB_CACHE_TABLE + 1;
+const int kFirstTypeCode = UNCLASSIFIED;
+
+const int kReferenceIdBits = 16;
+const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
+const int kReferenceTypeShift = kReferenceIdBits;
+const int kDebugRegisterBits = 4;
+const int kDebugIdShift = kDebugRegisterBits;
+
+
+class ExternalReferenceEncoder {
+ public:
+  ExternalReferenceEncoder();
+
+  uint32_t Encode(Address key) const;
+
+  const char* NameOfAddress(Address key) const;
+
+ private:
+  HashMap encodings_;
+  static uint32_t Hash(Address key) {
+    return reinterpret_cast<uint32_t>(key) >> 2;
+  }
+
+  int IndexOf(Address key) const;
+
+  static bool Match(void* key1, void* key2) { return key1 == key2; }
+
+  void Put(Address key, int index);
+};
+
+
+class ExternalReferenceDecoder {
+ public:
+  ExternalReferenceDecoder();
+  ~ExternalReferenceDecoder();
+
+  Address Decode(uint32_t key) const {
+    if (key == 0) return NULL;
+    return *Lookup(key);
+  }
+
+ private:
+  Address** encodings_;
+
+  Address* Lookup(uint32_t key) const {
+    int type = key >> kReferenceTypeShift;
+    ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount);
+    int id = key & kReferenceIdMask;
+    return &encodings_[type][id];
+  }
+
+  void Put(uint32_t key, Address value) {
+    *Lookup(key) = value;
+  }
+};
+
+
+// A Serializer recursively visits objects to construct a serialized
+// representation of the Heap stored in a string. Serialization is
+// destructive. We use a similar mechanism to the GC to ensure that
+// each object is visited once, namely, we modify the map pointer of
+// each visited object to contain the relative address in the
+// appropriate space where that object will be allocated when the heap
+// is deserialized.
+
+
+// Helper classes defined in serialize.cc.
+class RelativeAddress;
+class SimulatedHeapSpace;
+class SnapshotWriter;
+class ReferenceUpdater;
+
+
+class Serializer: public ObjectVisitor {
+ public:
+  Serializer();
+
+  virtual ~Serializer();
+
+  // Serialize the current state of the heap. This operation destroys the
+  // heap contents and the contents of the roots into the heap.
+  void Serialize();
+
+  // Returns the serialized buffer. Ownership is transferred to the
+  // caller. Only the destructor and getters may be called after this call.
+  void Finalize(char** str, int* len);
+
+  int roots() { return roots_; }
+  int objects() { return objects_; }
+
+#ifdef DEBUG
+  // insert "tag" into the serialized stream
+  virtual void Synchronize(const char* tag);
+#endif
+
+  static bool enabled() { return serialization_enabled_; }
+
+  static void disable() { serialization_enabled_ = false; }
+
+ private:
+  friend class ReferenceUpdater;
+
+  virtual void VisitPointers(Object** start, Object** end);
+
+  bool IsVisited(HeapObject* obj);
+
+  Address GetSavedAddress(HeapObject* obj);
+
+  void SaveAddress(HeapObject* obj, Address addr);
+
+  void PutEncodedAddress(Address addr);
+  // Write the global flags into the file.
+  void PutFlags();
+  // Write global information into the header of the file.
+  void PutHeader();
+  // Write the contents of the log into the file.
+  void PutLog();
+  // Serialize 'obj', and return its encoded RelativeAddress.
+  Address PutObject(HeapObject* obj);
+  // Write a stack of handles to the file bottom first.
+  void PutGlobalHandleStack(const List<Handle<Object> >& stack);
+  // Write the context stack into the file.
+  void PutContextStack();
+
+  // Return the encoded RelativeAddress where this object will be
+  // allocated on deserialization. On the first visit of 'o',
+  // serialize its contents. On return, *serialized will be true iff
+  // 'o' has just been serialized.
+  Address Encode(Object* o, bool* serialized);
+
+  // Simulate the allocation of 'obj', returning the address where it will
+  // be allocated on deserialization
+  RelativeAddress Allocate(HeapObject* obj);
+
+  void InitializeAllocators();
+
+  SnapshotWriter* writer_;
+  bool root_;  // serializing a root?
+  int roots_;  // number of roots visited
+  int objects_;  // number of objects serialized
+
+  static bool serialization_enabled_;
+
+  int flags_end_;  // The position right after the flags.
+
+  // An array of per-space SimulatedHeapSpacees used as memory allocators.
+  SimulatedHeapSpace* allocator_[LAST_SPACE+1];
+  // A list of global handles at serialization time.
+  List<Object**> global_handles_;
+
+  ExternalReferenceEncoder* reference_encoder_;
+
+  HashMap saved_addresses_;
+
+  DISALLOW_COPY_AND_ASSIGN(Serializer);
+};
+
+// Helper class to read the bytes of the serialized heap.
+
+class SnapshotReader {
+ public:
+  SnapshotReader(const char* str, int len): str_(str), end_(str + len) {}
+
+  void ExpectC(char expected) {
+    int c = GetC();
+    USE(c);
+    ASSERT(c == expected);
+  }
+
+  int GetC() {
+    if (str_ >= end_) return EOF;
+    return *str_++;
+  }
+
+  int GetInt() {
+    int result = *reinterpret_cast<const int*>(str_);
+    str_ += sizeof(result);
+    return result;
+  }
+
+  void GetBytes(Address a, int size) {
+    ASSERT(str_ + size <= end_);
+    memcpy(a, str_, size);
+    str_ += size;
+  }
+
+  char* GetString() {
+    ExpectC('[');
+    int size = GetInt();
+    ExpectC(']');
+    char* s = NewArray<char>(size + 1);
+    GetBytes(reinterpret_cast<Address>(s), size);
+    s[size] = 0;
+    return s;
+  }
+
+ private:
+  const char* str_;
+  const char* end_;
+};
+
+
+// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
+
+class Deserializer: public ObjectVisitor {
+ public:
+  // Create a deserializer. The snapshot is held in str and has size len.
+  Deserializer(const char* str, int len);
+
+  virtual ~Deserializer();
+
+  // Read the flags from the header of the file, and set those that
+  // should be inhereted from the snapshot.
+  void GetFlags();
+
+  // Read saved profiling information from the file and log it if required.
+  void GetLog();
+
+  // Deserialize the snapshot into an empty heap.
+  void Deserialize();
+
+  int roots() { return roots_; }
+  int objects() { return objects_; }
+
+#ifdef DEBUG
+  // Check for the presence of "tag" in the serialized stream
+  virtual void Synchronize(const char* tag);
+#endif
+
+ private:
+  virtual void VisitPointers(Object** start, Object** end);
+  virtual void VisitExternalReferences(Address* start, Address* end);
+  virtual void VisitRuntimeEntry(RelocInfo* rinfo);
+
+  Address GetEncodedAddress();
+
+  // Read other global information (except flags) from the header of the file.
+  void GetHeader();
+  // Read a stack of handles from the file bottom first.
+  void GetGlobalHandleStack(List<Handle<Object> >* stack);
+  // Read the context stack from the file.
+  void GetContextStack();
+
+  Object* GetObject();
+
+  // Get the encoded address. In debug mode we make sure
+  // it matches the given expectations.
+  void ExpectEncodedAddress(Address expected);
+
+  // Given an encoded address (the result of
+  // RelativeAddress::Encode), return the object to which it points,
+  // which will be either an Smi or a HeapObject in the current heap.
+  Object* Resolve(Address encoded_address);
+
+  SnapshotReader reader_;
+  bool root_;  // Deserializing a root?
+  int roots_;  // number of roots visited
+  int objects_;  // number of objects serialized
+
+  bool has_log_;  // The file has log information.
+
+  // Resolve caches the following:
+  List<Page*> map_pages_;          // All pages in the map space.
+  List<Page*> old_pointer_pages_;  // All pages in the old pointer space.
+  List<Page*> old_data_pages_;     // All pages in the old data space.
+  List<Page*> code_pages_;
+  List<Object*> large_objects_;    // All known large objects.
+  // A list of global handles at deserialization time.
+  List<Object**> global_handles_;
+
+  ExternalReferenceDecoder* reference_decoder_;
+
+#ifdef DEBUG
+  bool expect_debug_information_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(Deserializer);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_SERIALIZE_H_
diff --git a/regexp2000/src/shell.h b/regexp2000/src/shell.h
new file mode 100644 (file)
index 0000000..4042c07
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// A simple interactive shell.  Enable with --shell.
+
+#include "../public/debug.h"
+
+namespace v8 { namespace internal {
+
+// Debug event handler for interactive debugging.
+void handle_debug_event(v8::DebugEvent event,
+                        v8::Handle<v8::Object> exec_state,
+                        v8::Handle<v8::Object> event_data,
+                        v8::Handle<Value> data);
+
+
+class Shell {
+ public:
+  static void PrintObject(v8::Handle<v8::Value> obj);
+  // Run the read-eval loop, executing code in the specified
+  // environment.
+  static void Run(v8::Handle<v8::Context> context);
+};
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/simulator-arm.cc b/regexp2000/src/simulator-arm.cc
new file mode 100644 (file)
index 0000000..321ab06
--- /dev/null
@@ -0,0 +1,1506 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "disasm.h"
+#include "constants-arm.h"
+#include "simulator-arm.h"
+
+#if !defined(__arm__)
+
+// Only build the simulator if not compiling for real ARM hardware.
+namespace assembler { namespace arm {
+
+using ::v8::internal::Object;
+using ::v8::internal::PrintF;
+using ::v8::internal::OS;
+using ::v8::internal::ReadLine;
+using ::v8::internal::DeleteArray;
+
+// This macro provides a platform independent use of sscanf. The reason for
+// SScanF not beeing implemented in a platform independent was through
+// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
+// Library does not provide vsscanf.
+#ifdef WIN32
+#define SScanF sscanf_s
+#else
+#define SScanF sscanf  // NOLINT
+#endif
+
+// The Debugger class is used by the simulator while debugging simulated ARM
+// code.
+class Debugger {
+ public:
+  explicit Debugger(Simulator* sim);
+  ~Debugger();
+
+  void Stop(Instr* instr);
+  void Debug();
+
+ private:
+  static const instr_t kBreakpointInstr =
+      ((AL << 28) | (7 << 25) | (1 << 24) | break_point);
+  static const instr_t kNopInstr =
+      ((AL << 28) | (13 << 21));
+
+  Simulator* sim_;
+
+  bool GetValue(char* desc, int32_t* value);
+
+  // Set or delete a breakpoint. Returns true if successful.
+  bool SetBreakpoint(Instr* breakpc);
+  bool DeleteBreakpoint(Instr* breakpc);
+
+  // Undo and redo all breakpoints. This is needed to bracket disassembly and
+  // execution to skip past breakpoints when run from the debugger.
+  void UndoBreakpoints();
+  void RedoBreakpoints();
+};
+
+
+Debugger::Debugger(Simulator* sim) {
+  sim_ = sim;
+}
+
+
+Debugger::~Debugger() {
+}
+
+
+void Debugger::Stop(Instr* instr) {
+  const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff);
+  PrintF("Simulator hit %s\n", str);
+  sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
+  Debug();
+}
+
+
+static const char* reg_names[] = {  "r0",  "r1",  "r2",  "r3",
+                                    "r4",  "r5",  "r6",  "r7",
+                                    "r8",  "r9", "r10", "r11",
+                                   "r12", "r13", "r14", "r15",
+                                    "pc",  "lr",  "sp",  "ip",
+                                    "fp",  "sl", ""};
+
+static int   reg_nums[]  = {           0,     1,     2,     3,
+                                       4,     5,     6,     7,
+                                       8,     9,    10,    11,
+                                      12,    13,    14,    15,
+                                      15,    14,    13,    12,
+                                      11,    10};
+
+
+static int RegNameToRegNum(char* name) {
+  int reg = 0;
+  while (*reg_names[reg] != 0) {
+    if (strcmp(reg_names[reg], name) == 0) {
+      return reg_nums[reg];
+    }
+    reg++;
+  }
+  return -1;
+}
+
+
+bool Debugger::GetValue(char* desc, int32_t* value) {
+  int regnum = RegNameToRegNum(desc);
+  if (regnum >= 0) {
+    if (regnum == 15) {
+      *value = sim_->get_pc();
+    } else {
+      *value = sim_->get_register(regnum);
+    }
+    return true;
+  } else {
+    return SScanF(desc, "%i", value) == 1;
+  }
+  return false;
+}
+
+
+bool Debugger::SetBreakpoint(Instr* breakpc) {
+  // Check if a breakpoint can be set. If not return without any side-effects.
+  if (sim_->break_pc_ != NULL) {
+    return false;
+  }
+
+  // Set the breakpoint.
+  sim_->break_pc_ = breakpc;
+  sim_->break_instr_ = breakpc->InstructionBits();
+  // Not setting the breakpoint instruction in the code itself. It will be set
+  // when the debugger shell continues.
+  return true;
+}
+
+
+bool Debugger::DeleteBreakpoint(Instr* breakpc) {
+  if (sim_->break_pc_ != NULL) {
+    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
+  }
+
+  sim_->break_pc_ = NULL;
+  sim_->break_instr_ = 0;
+  return true;
+}
+
+
+void Debugger::UndoBreakpoints() {
+  if (sim_->break_pc_ != NULL) {
+    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
+  }
+}
+
+
+void Debugger::RedoBreakpoints() {
+  if (sim_->break_pc_ != NULL) {
+    sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
+  }
+}
+
+
+void Debugger::Debug() {
+  intptr_t last_pc = -1;
+  bool done = false;
+
+#define COMMAND_SIZE 63
+#define ARG_SIZE 255
+
+#define STR(a) #a
+#define XSTR(a) STR(a)
+
+  char cmd[COMMAND_SIZE + 1];
+  char arg1[ARG_SIZE + 1];
+  char arg2[ARG_SIZE + 1];
+
+  // make sure to have a proper terminating character if reaching the limit
+  cmd[COMMAND_SIZE] = 0;
+  arg1[ARG_SIZE] = 0;
+  arg2[ARG_SIZE] = 0;
+
+  // Undo all set breakpoints while running in the debugger shell. This will
+  // make them invisible to all commands.
+  UndoBreakpoints();
+
+  while (!done) {
+    if (last_pc != sim_->get_pc()) {
+      disasm::Disassembler dasm;
+      // use a reasonably large buffer
+      v8::internal::EmbeddedVector<char, 256> buffer;
+      dasm.InstructionDecode(buffer,
+                             reinterpret_cast<byte*>(sim_->get_pc()));
+      PrintF("  0x%x  %s\n", sim_->get_pc(), buffer.start());
+      last_pc = sim_->get_pc();
+    }
+    char* line = ReadLine("sim> ");
+    if (line == NULL) {
+      break;
+    } else {
+      // Use sscanf to parse the individual parts of the command line. At the
+      // moment no command expects more than two parameters.
+      int args = SScanF(line,
+                        "%" XSTR(COMMAND_SIZE) "s "
+                        "%" XSTR(ARG_SIZE) "s "
+                        "%" XSTR(ARG_SIZE) "s",
+                        cmd, arg1, arg2);
+      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
+        sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
+      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
+        // Execute the one instruction we broke at with breakpoints disabled.
+        sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
+        // Leave the debugger shell.
+        done = true;
+      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
+        if (args == 2) {
+          int32_t value;
+          if (GetValue(arg1, &value)) {
+            PrintF("%s: %d 0x%x\n", arg1, value, value);
+          } else {
+            PrintF("%s unrecognized\n", arg1);
+          }
+        } else {
+          PrintF("print value\n");
+        }
+      } else if ((strcmp(cmd, "po") == 0)
+                 || (strcmp(cmd, "printobject") == 0)) {
+        if (args == 2) {
+          int32_t value;
+          if (GetValue(arg1, &value)) {
+            Object* obj = reinterpret_cast<Object*>(value);
+            USE(obj);
+            PrintF("%s: \n", arg1);
+#if defined(DEBUG)
+            obj->PrintLn();
+#endif  // defined(DEBUG)
+          } else {
+            PrintF("%s unrecognized\n", arg1);
+          }
+        } else {
+          PrintF("printobject value\n");
+        }
+      } else if (strcmp(cmd, "disasm") == 0) {
+        disasm::Disassembler dasm;
+        // use a reasonably large buffer
+        v8::internal::EmbeddedVector<char, 256> buffer;
+
+        byte* cur = NULL;
+        byte* end = NULL;
+
+        if (args == 1) {
+          cur = reinterpret_cast<byte*>(sim_->get_pc());
+          end = cur + (10 * Instr::kInstrSize);
+        } else if (args == 2) {
+          int32_t value;
+          if (GetValue(arg1, &value)) {
+            cur = reinterpret_cast<byte*>(value);
+            // no length parameter passed, assume 10 instructions
+            end = cur + (10 * Instr::kInstrSize);
+          }
+        } else {
+          int32_t value1;
+          int32_t value2;
+          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
+            cur = reinterpret_cast<byte*>(value1);
+            end = cur + (value2 * Instr::kInstrSize);
+          }
+        }
+
+        while (cur < end) {
+          dasm.InstructionDecode(buffer, cur);
+          PrintF("  0x%x  %s\n", cur, buffer.start());
+          cur += Instr::kInstrSize;
+        }
+      } else if (strcmp(cmd, "gdb") == 0) {
+        PrintF("relinquishing control to gdb\n");
+        v8::internal::OS::DebugBreak();
+        PrintF("regaining control from gdb\n");
+      } else if (strcmp(cmd, "break") == 0) {
+        if (args == 2) {
+          int32_t value;
+          if (GetValue(arg1, &value)) {
+            if (!SetBreakpoint(reinterpret_cast<Instr*>(value))) {
+              PrintF("setting breakpoint failed\n");
+            }
+          } else {
+            PrintF("%s unrecognized\n", arg1);
+          }
+        } else {
+          PrintF("break addr\n");
+        }
+      } else if (strcmp(cmd, "del") == 0) {
+        if (!DeleteBreakpoint(NULL)) {
+          PrintF("deleting breakpoint failed\n");
+        }
+      } else if (strcmp(cmd, "flags") == 0) {
+        PrintF("N flag: %d; ", sim_->n_flag_);
+        PrintF("Z flag: %d; ", sim_->z_flag_);
+        PrintF("C flag: %d; ", sim_->c_flag_);
+        PrintF("V flag: %d\n", sim_->v_flag_);
+      } else if (strcmp(cmd, "unstop") == 0) {
+        intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
+        Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
+        if (stop_instr->ConditionField() == special_condition) {
+          stop_instr->SetInstructionBits(kNopInstr);
+        } else {
+          PrintF("Not at debugger stop.");
+        }
+      } else {
+        PrintF("Unknown command: %s\n", cmd);
+      }
+    }
+    DeleteArray(line);
+  }
+
+  // Add all the breakpoints back to stop execution and enter the debugger
+  // shell when hit.
+  RedoBreakpoints();
+
+#undef COMMAND_SIZE
+#undef ARG_SIZE
+
+#undef STR
+#undef XSTR
+}
+
+
+Simulator::Simulator() {
+  // Setup simulator support first. Some of this information is needed to
+  // setup the architecture state.
+  size_t stack_size = 1 * 1024*1024;  // allocate 1MB for stack
+  stack_ = reinterpret_cast<char*>(malloc(stack_size));
+  pc_modified_ = false;
+  icount_ = 0;
+  break_pc_ = NULL;
+  break_instr_ = 0;
+
+  // Setup architecture state.
+  // All registers are initialized to zero to start with.
+  for (int i = 0; i < num_registers; i++) {
+    registers_[i] = 0;
+  }
+  n_flag_ = false;
+  z_flag_ = false;
+  c_flag_ = false;
+  v_flag_ = false;
+
+  // The sp is initialized to point to the bottom (high address) of the
+  // allocated stack area. To be safe in potential stack underflows we leave
+  // some buffer below.
+  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size - 64;
+  // The lr and pc are initialized to a known bad value that will cause an
+  // access violation if the simulator ever tries to execute it.
+  registers_[pc] = bad_lr;
+  registers_[lr] = bad_lr;
+}
+
+
+// This is the Simulator singleton. Currently only one thread is supported by
+// V8. If we had multiple threads, then we should have a Simulator instance on
+// a per thread basis.
+static Simulator* the_sim = NULL;
+
+
+// Get the active Simulator for the current thread. See comment above about
+// using a singleton currently.
+Simulator* Simulator::current() {
+  if (the_sim == NULL) {
+    the_sim = new Simulator();
+  }
+  return the_sim;
+}
+
+
+// Sets the register in the architecture state. It will also deal with updating
+// Simulator internal state for special registers such as PC.
+void Simulator::set_register(int reg, int32_t value) {
+  ASSERT((reg >= 0) && (reg < num_registers));
+  if (reg == pc) {
+    pc_modified_ = true;
+  }
+  registers_[reg] = value;
+}
+
+
+// Get the register from the architecture state. This function does handle
+// the special case of accessing the PC register.
+int32_t Simulator::get_register(int reg) const {
+  ASSERT((reg >= 0) && (reg < num_registers));
+  return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0);
+}
+
+
+// Raw access to the PC register.
+void Simulator::set_pc(int32_t value) {
+  pc_modified_ = true;
+  registers_[pc] = value;
+}
+
+
+// Raw access to the PC register without the special adjustment when reading.
+int32_t Simulator::get_pc() const {
+  return registers_[pc];
+}
+
+
+// Returns the limit of the stack area to enable checking for stack overflows.
+uintptr_t Simulator::StackLimit() const {
+  // Leave a safety margin of 256 bytes to prevent overrunning the stack when
+  // pushing values.
+  return reinterpret_cast<uintptr_t>(stack_) + 256;
+}
+
+
+// Unsupported instructions use Format to print an error and stop execution.
+void Simulator::Format(Instr* instr, const char* format) {
+  PrintF("Simulator found unsupported instruction:\n 0x%x: %s\n",
+         instr, format);
+  UNIMPLEMENTED();
+}
+
+
+// Checks if the current instruction should be executed based on its
+// condition bits.
+bool Simulator::ConditionallyExecute(Instr* instr) {
+  switch (instr->ConditionField()) {
+    case EQ: return z_flag_;
+    case NE: return !z_flag_;
+    case CS: return c_flag_;
+    case CC: return !c_flag_;
+    case MI: return n_flag_;
+    case PL: return !n_flag_;
+    case VS: return v_flag_;
+    case VC: return !v_flag_;
+    case HI: return c_flag_ && !z_flag_;
+    case LS: return !c_flag_ || z_flag_;
+    case GE: return n_flag_ == v_flag_;
+    case LT: return n_flag_ != v_flag_;
+    case GT: return !z_flag_ && (n_flag_ == v_flag_);
+    case LE: return z_flag_ || (n_flag_ != v_flag_);
+    case AL: return true;
+    default: UNREACHABLE();
+  }
+  return false;
+}
+
+
+// Calculate and set the Negative and Zero flags.
+void Simulator::SetNZFlags(int32_t val) {
+  n_flag_ = (val < 0);
+  z_flag_ = (val == 0);
+}
+
+
+// Set the Carry flag.
+void Simulator::SetCFlag(bool val) {
+  c_flag_ = val;
+}
+
+
+// Set the oVerflow flag.
+void Simulator::SetVFlag(bool val) {
+  v_flag_ = val;
+}
+
+
+// Calculate C flag value for additions.
+bool Simulator::CarryFrom(int32_t left, int32_t right) {
+  uint32_t uleft = static_cast<uint32_t>(left);
+  uint32_t uright = static_cast<uint32_t>(right);
+  uint32_t urest  = 0xffffffffU - uleft;
+
+  return (uright > urest);
+}
+
+
+// Calculate C flag value for subtractions.
+bool Simulator::BorrowFrom(int32_t left, int32_t right) {
+  uint32_t uleft = static_cast<uint32_t>(left);
+  uint32_t uright = static_cast<uint32_t>(right);
+
+  return (uright > uleft);
+}
+
+
+// Calculate V flag value for additions and subtractions.
+bool Simulator::OverflowFrom(int32_t alu_out,
+                             int32_t left, int32_t right, bool addition) {
+  bool overflow;
+  if (addition) {
+               // operands have the same sign
+    overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
+               // and operands and result have different sign
+               && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+  } else {
+               // operands have different signs
+    overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
+               // and first operand and result have different signs
+               && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+  }
+  return overflow;
+}
+
+
+// Addressing Mode 1 - Data-processing operands:
+// Get the value based on the shifter_operand with register.
+int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) {
+  Shift shift = instr->ShiftField();
+  int shift_amount = instr->ShiftAmountField();
+  int32_t result = get_register(instr->RmField());
+  if (instr->Bit(4) == 0) {
+    // by immediate
+    if ((shift == ROR) && (shift_amount == 0)) {
+      UNIMPLEMENTED();
+      return result;
+    } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
+      shift_amount = 32;
+    }
+    switch (shift) {
+      case ASR: {
+        if (shift_amount == 0) {
+          if (result < 0) {
+            result = 0xffffffff;
+            *carry_out = true;
+          } else {
+            result = 0;
+            *carry_out = false;
+          }
+        } else {
+          result >>= (shift_amount - 1);
+          *carry_out = (result & 1) == 1;
+          result >>= 1;
+        }
+        break;
+      }
+
+      case LSL: {
+        if (shift_amount == 0) {
+          *carry_out = c_flag_;
+        } else {
+          result <<= (shift_amount - 1);
+          *carry_out = (result < 0);
+          result <<= 1;
+        }
+        break;
+      }
+
+      case LSR: {
+        if (shift_amount == 0) {
+          result = 0;
+          *carry_out = c_flag_;
+        } else {
+          uint32_t uresult = static_cast<uint32_t>(result);
+          uresult >>= (shift_amount - 1);
+          *carry_out = (uresult & 1) == 1;
+          uresult >>= 1;
+          result = static_cast<int32_t>(uresult);
+        }
+        break;
+      }
+
+      case ROR: {
+        UNIMPLEMENTED();
+        break;
+      }
+
+      default: {
+        UNREACHABLE();
+        break;
+      }
+    }
+  } else {
+    // by register
+    int rs = instr->RsField();
+    shift_amount = get_register(rs) &0xff;
+    switch (shift) {
+      case ASR: {
+        if (shift_amount == 0) {
+          *carry_out = c_flag_;
+        } else if (shift_amount < 32) {
+          result >>= (shift_amount - 1);
+          *carry_out = (result & 1) == 1;
+          result >>= 1;
+        } else {
+          ASSERT(shift_amount >= 32);
+          if (result < 0) {
+            *carry_out = true;
+            result = 0xffffffff;
+          } else {
+            *carry_out = false;
+            result = 0;
+          }
+        }
+        break;
+      }
+
+      case LSL: {
+        if (shift_amount == 0) {
+          *carry_out = c_flag_;
+        } else if (shift_amount < 32) {
+          result <<= (shift_amount - 1);
+          *carry_out = (result < 0);
+          result <<= 1;
+        } else if (shift_amount == 32) {
+          *carry_out = (result & 1) == 1;
+          result = 0;
+        } else {
+          ASSERT(shift_amount > 32);
+          *carry_out = false;
+          result = 0;
+        }
+        break;
+      }
+
+      case LSR: {
+        if (shift_amount == 0) {
+          *carry_out = c_flag_;
+        } else if (shift_amount < 32) {
+          uint32_t uresult = static_cast<uint32_t>(result);
+          uresult >>= (shift_amount - 1);
+          *carry_out = (uresult & 1) == 1;
+          uresult >>= 1;
+          result = static_cast<int32_t>(uresult);
+        } else if (shift_amount == 32) {
+          *carry_out = (result < 0);
+          result = 0;
+        } else {
+          *carry_out = false;
+          result = 0;
+        }
+        break;
+      }
+
+      case ROR: {
+        UNIMPLEMENTED();
+        break;
+      }
+
+      default: {
+        UNREACHABLE();
+        break;
+      }
+    }
+  }
+  return result;
+}
+
+
+// Addressing Mode 1 - Data-processing operands:
+// Get the value based on the shifter_operand with immediate.
+int32_t Simulator::GetImm(Instr* instr, bool* carry_out) {
+  int rotate = instr->RotateField() * 2;
+  int immed8 = instr->Immed8Field();
+  int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
+  *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
+  return imm;
+}
+
+
+static int count_bits(int bit_vector) {
+  int count = 0;
+  while (bit_vector != 0) {
+    if ((bit_vector & 1) != 0) {
+      count++;
+    }
+    bit_vector >>= 1;
+  }
+  return count;
+}
+
+
+// Addressing Mode 4 - Load and Store Multiple
+void Simulator::HandleRList(Instr* instr, bool load) {
+  int rn = instr->RnField();
+  int32_t rn_val = get_register(rn);
+  int rlist = instr->RlistField();
+  int num_regs = count_bits(rlist);
+
+  intptr_t start_address = 0;
+  intptr_t end_address = 0;
+  switch (instr->PUField()) {
+    case 0: {
+      // Print("da");
+      UNIMPLEMENTED();
+      break;
+    }
+    case 1: {
+      // Print("ia");
+      start_address = rn_val;
+      end_address = rn_val + (num_regs * 4) - 4;
+      rn_val = rn_val + (num_regs * 4);
+      break;
+    }
+    case 2: {
+      // Print("db");
+      start_address = rn_val - (num_regs * 4);
+      end_address = rn_val - 4;
+      rn_val = start_address;
+      break;
+    }
+    case 3: {
+      // Print("ib");
+      UNIMPLEMENTED();
+      break;
+    }
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+  if (instr->HasW()) {
+    set_register(rn, rn_val);
+  }
+  intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
+  int reg = 0;
+  while (rlist != 0) {
+    if ((rlist & 1) != 0) {
+      if (load) {
+        set_register(reg, *address);
+      } else {
+        *address = get_register(reg);
+      }
+      address += 1;
+    }
+    reg++;
+    rlist >>= 1;
+  }
+  ASSERT(end_address == ((intptr_t)address) - 4);
+}
+
+
+// Calls into the V8 runtime are based on this very simple interface.
+// Note: To be able to return two values from some calls the code in runtime.cc
+// uses the ObjectPair which is essentially two 32-bit values stuffed into a
+// 64-bit value. With the code below we assume that all runtime calls return
+// 64 bits of result. If they don't, the r1 result register contains a bogus
+// value, which is fine because it is caller-saved.
+typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1);
+
+
+// Software interrupt instructions are used by the simulator to call into the
+// C-based V8 runtime.
+void Simulator::SoftwareInterrupt(Instr* instr) {
+  switch (instr->SwiField()) {
+    case call_rt_r5: {
+      SimulatorRuntimeCall target =
+          reinterpret_cast<SimulatorRuntimeCall>(get_register(r5));
+      intptr_t arg0 = get_register(r0);
+      intptr_t arg1 = get_register(r1);
+      int64_t result = target(arg0, arg1);
+      int32_t lo_res = static_cast<int32_t>(result);
+      int32_t hi_res = static_cast<int32_t>(result >> 32);
+      set_register(r0, lo_res);
+      set_register(r1, hi_res);
+      set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
+      break;
+    }
+    case call_rt_r2: {
+      SimulatorRuntimeCall target =
+          reinterpret_cast<SimulatorRuntimeCall>(get_register(r2));
+      intptr_t arg0 = get_register(r0);
+      intptr_t arg1 = get_register(r1);
+      int64_t result = target(arg0, arg1);
+      int32_t lo_res = static_cast<int32_t>(result);
+      int32_t hi_res = static_cast<int32_t>(result >> 32);
+      set_register(r0, lo_res);
+      set_register(r1, hi_res);
+      set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
+      break;
+    }
+    case break_point: {
+      Debugger dbg(this);
+      dbg.Debug();
+      break;
+    }
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+}
+
+
+// Handle execution based on instruction types.
+
+// Instruction types 0 and 1 are both rolled into one function because they
+// only differ in the handling of the shifter_operand.
+void Simulator::DecodeType01(Instr* instr) {
+  int type = instr->TypeField();
+  if ((type == 0) && instr->IsSpecialType0()) {
+    // multiply instruction or extra loads and stores
+    if (instr->Bits(7, 4) == 9) {
+      if (instr->Bit(24) == 0) {
+        // multiply instructions
+        int rd = instr->RdField();
+        int rm = instr->RmField();
+        int rs = instr->RsField();
+        int32_t rs_val = get_register(rs);
+        int32_t rm_val = get_register(rm);
+        if (instr->Bit(23) == 0) {
+          if (instr->Bit(21) == 0) {
+            // Format(instr, "mul'cond's 'rd, 'rm, 'rs");
+            int32_t alu_out = rm_val * rs_val;
+            set_register(rd, alu_out);
+            if (instr->HasS()) {
+              SetNZFlags(alu_out);
+            }
+          } else {
+            Format(instr, "mla'cond's 'rd, 'rm, 'rs, 'rn");
+          }
+        } else {
+          // Format(instr, "'um'al'cond's 'rn, 'rd, 'rs, 'rm");
+          int rn = instr->RnField();
+          int32_t hi_res = 0;
+          int32_t lo_res = 0;
+          if (instr->Bit(22) == 0) {
+            // signed multiply
+            UNIMPLEMENTED();
+          } else {
+            // unsigned multiply
+            uint64_t left_op  = rm_val;
+            uint64_t right_op = rs_val;
+            uint64_t result = left_op * right_op;
+            hi_res = static_cast<int32_t>(result >> 32);
+            lo_res = static_cast<int32_t>(result & 0xffffffff);
+          }
+          set_register(rn, hi_res);
+          set_register(rd, lo_res);
+          if (instr->HasS()) {
+            UNIMPLEMENTED();
+          }
+        }
+      } else {
+        UNIMPLEMENTED();  // not used by V8
+      }
+    } else {
+      // extra load/store instructions
+      int rd = instr->RdField();
+      int rn = instr->RnField();
+      int32_t rn_val = get_register(rn);
+      int32_t addr = 0;
+      if (instr->Bit(22) == 0) {
+        int rm = instr->RmField();
+        int32_t rm_val = get_register(rm);
+        switch (instr->PUField()) {
+          case 0: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
+            ASSERT(!instr->HasW());
+            addr = rn_val;
+            rn_val -= rm_val;
+            set_register(rn, rn_val);
+            break;
+          }
+          case 1: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
+            ASSERT(!instr->HasW());
+            addr = rn_val;
+            rn_val += rm_val;
+            set_register(rn, rn_val);
+            break;
+          }
+          case 2: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
+            rn_val -= rm_val;
+            addr = rn_val;
+            if (instr->HasW()) {
+              set_register(rn, rn_val);
+            }
+            break;
+          }
+          case 3: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
+            rn_val += rm_val;
+            addr = rn_val;
+            if (instr->HasW()) {
+              set_register(rn, rn_val);
+            }
+            break;
+          }
+          default: {
+            // The PU field is a 2-bit field.
+            UNREACHABLE();
+            break;
+          }
+        }
+      } else {
+        int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField();
+        switch (instr->PUField()) {
+          case 0: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
+            ASSERT(!instr->HasW());
+            addr = rn_val;
+            rn_val -= imm_val;
+            set_register(rn, rn_val);
+            break;
+          }
+          case 1: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
+            ASSERT(!instr->HasW());
+            addr = rn_val;
+            rn_val += imm_val;
+            set_register(rn, rn_val);
+            break;
+          }
+          case 2: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
+            rn_val -= imm_val;
+            addr = rn_val;
+            if (instr->HasW()) {
+              set_register(rn, rn_val);
+            }
+            break;
+          }
+          case 3: {
+            // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
+            rn_val += imm_val;
+            addr = rn_val;
+            if (instr->HasW()) {
+              set_register(rn, rn_val);
+            }
+            break;
+          }
+          default: {
+            // The PU field is a 2-bit field.
+            UNREACHABLE();
+            break;
+          }
+        }
+      }
+      if (instr->HasH()) {
+        if (instr->HasSign()) {
+          int16_t* haddr = reinterpret_cast<int16_t*>(addr);
+          if (instr->HasL()) {
+            int16_t val = *haddr;
+            set_register(rd, val);
+          } else {
+            int16_t val = get_register(rd);
+            *haddr = val;
+          }
+        } else {
+          uint16_t* haddr = reinterpret_cast<uint16_t*>(addr);
+          if (instr->HasL()) {
+            uint16_t val = *haddr;
+            set_register(rd, val);
+          } else {
+            uint16_t val = get_register(rd);
+            *haddr = val;
+          }
+        }
+      } else {
+        // signed byte loads
+        ASSERT(instr->HasSign());
+        ASSERT(instr->HasL());
+        int8_t* baddr = reinterpret_cast<int8_t*>(addr);
+        int8_t val = *baddr;
+        set_register(rd, val);
+      }
+      return;
+    }
+  } else {
+    int rd = instr->RdField();
+    int rn = instr->RnField();
+    int32_t rn_val = get_register(rn);
+    int32_t shifter_operand = 0;
+    bool shifter_carry_out = 0;
+    if (type == 0) {
+      shifter_operand = GetShiftRm(instr, &shifter_carry_out);
+    } else {
+      ASSERT(instr->TypeField() == 1);
+      shifter_operand = GetImm(instr, &shifter_carry_out);
+    }
+    int32_t alu_out;
+
+    switch (instr->OpcodeField()) {
+      case AND: {
+        // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
+        // Format(instr, "and'cond's 'rd, 'rn, 'imm");
+        alu_out = rn_val & shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        }
+        break;
+      }
+
+      case EOR: {
+        // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
+        // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
+        alu_out = rn_val ^ shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        }
+        break;
+      }
+
+      case SUB: {
+        // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
+        // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
+        alu_out = rn_val - shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(!BorrowFrom(rn_val, shifter_operand));
+          SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
+        }
+        break;
+      }
+
+      case RSB: {
+        // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
+        // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
+        alu_out = shifter_operand - rn_val;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(!BorrowFrom(shifter_operand, rn_val));
+          SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
+        }
+        break;
+      }
+
+      case ADD: {
+        // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
+        // Format(instr, "add'cond's 'rd, 'rn, 'imm");
+        alu_out = rn_val + shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(CarryFrom(rn_val, shifter_operand));
+          SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
+        }
+        break;
+      }
+
+      case ADC: {
+        Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
+        Format(instr, "adc'cond's 'rd, 'rn, 'imm");
+        break;
+      }
+
+      case SBC: {
+        Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
+        Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
+        break;
+      }
+
+      case RSC: {
+        Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
+        Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
+        break;
+      }
+
+      case TST: {
+        if (instr->HasS()) {
+          // Format(instr, "tst'cond 'rn, 'shift_rm");
+          // Format(instr, "tst'cond 'rn, 'imm");
+          alu_out = rn_val & shifter_operand;
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        } else {
+          UNIMPLEMENTED();
+        }
+        break;
+      }
+
+      case TEQ: {
+        if (instr->HasS()) {
+          // Format(instr, "teq'cond 'rn, 'shift_rm");
+          // Format(instr, "teq'cond 'rn, 'imm");
+          alu_out = rn_val ^ shifter_operand;
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        } else {
+          UNIMPLEMENTED();
+        }
+        break;
+      }
+
+      case CMP: {
+        if (instr->HasS()) {
+          // Format(instr, "cmp'cond 'rn, 'shift_rm");
+          // Format(instr, "cmp'cond 'rn, 'imm");
+          alu_out = rn_val - shifter_operand;
+          SetNZFlags(alu_out);
+          SetCFlag(!BorrowFrom(rn_val, shifter_operand));
+          SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
+        } else {
+          UNIMPLEMENTED();
+        }
+        break;
+      }
+
+      case CMN: {
+        if (instr->HasS()) {
+          Format(instr, "cmn'cond 'rn, 'shift_rm");
+          Format(instr, "cmn'cond 'rn, 'imm");
+        } else {
+          UNIMPLEMENTED();
+        }
+        break;
+      }
+
+      case ORR: {
+        // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
+        // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
+        alu_out = rn_val | shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        }
+        break;
+      }
+
+      case MOV: {
+        // Format(instr, "mov'cond's 'rd, 'shift_rm");
+        // Format(instr, "mov'cond's 'rd, 'imm");
+        alu_out = shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        }
+        break;
+      }
+
+      case BIC: {
+        // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
+        // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
+        alu_out = rn_val & ~shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        }
+        break;
+      }
+
+      case MVN: {
+        // Format(instr, "mvn'cond's 'rd, 'shift_rm");
+        // Format(instr, "mvn'cond's 'rd, 'imm");
+        alu_out = ~shifter_operand;
+        set_register(rd, alu_out);
+        if (instr->HasS()) {
+          SetNZFlags(alu_out);
+          SetCFlag(shifter_carry_out);
+        }
+        break;
+      }
+
+      default: {
+        UNREACHABLE();
+        break;
+      }
+    }
+  }
+}
+
+
+void Simulator::DecodeType2(Instr* instr) {
+  int rd = instr->RdField();
+  int rn = instr->RnField();
+  int32_t rn_val = get_register(rn);
+  int32_t im_val = instr->Offset12Field();
+  int32_t addr = 0;
+  switch (instr->PUField()) {
+    case 0: {
+      // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
+      ASSERT(!instr->HasW());
+      addr = rn_val;
+      rn_val -= im_val;
+      set_register(rn, rn_val);
+      break;
+    }
+    case 1: {
+      // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
+      ASSERT(!instr->HasW());
+      addr = rn_val;
+      rn_val += im_val;
+      set_register(rn, rn_val);
+      break;
+    }
+    case 2: {
+      // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
+      rn_val -= im_val;
+      addr = rn_val;
+      if (instr->HasW()) {
+        set_register(rn, rn_val);
+      }
+      break;
+    }
+    case 3: {
+      // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
+      rn_val += im_val;
+      addr = rn_val;
+      if (instr->HasW()) {
+        set_register(rn, rn_val);
+      }
+      break;
+    }
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+  if (instr->HasB()) {
+    byte* baddr = reinterpret_cast<byte*>(addr);
+    if (instr->HasL()) {
+      byte val = *baddr;
+      set_register(rd, val);
+    } else {
+      byte val = get_register(rd);
+      *baddr = val;
+    }
+  } else {
+    intptr_t* iaddr = reinterpret_cast<intptr_t*>(addr);
+    if (instr->HasL()) {
+      set_register(rd, *iaddr);
+    } else {
+      *iaddr = get_register(rd);
+    }
+  }
+}
+
+
+void Simulator::DecodeType3(Instr* instr) {
+  int rd = instr->RdField();
+  int rn = instr->RnField();
+  int32_t rn_val = get_register(rn);
+  bool shifter_carry_out = 0;
+  int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
+  int32_t addr = 0;
+  switch (instr->PUField()) {
+    case 0: {
+      ASSERT(!instr->HasW());
+      Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
+      break;
+    }
+    case 1: {
+      ASSERT(!instr->HasW());
+      Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
+      break;
+    }
+    case 2: {
+      // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
+      addr = rn_val - shifter_operand;
+      if (instr->HasW()) {
+        set_register(rn, addr);
+      }
+      break;
+    }
+    case 3: {
+      // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
+      addr = rn_val + shifter_operand;
+      if (instr->HasW()) {
+        set_register(rn, addr);
+      }
+      break;
+    }
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+  if (instr->HasB()) {
+    UNIMPLEMENTED();
+  } else {
+    intptr_t* iaddr = reinterpret_cast<intptr_t*>(addr);
+    if (instr->HasL()) {
+      set_register(rd, *iaddr);
+    } else {
+      *iaddr = get_register(rd);
+    }
+  }
+}
+
+
+void Simulator::DecodeType4(Instr* instr) {
+  ASSERT(instr->Bit(22) == 0);  // only allowed to be set in privileged mode
+  if (instr->HasL()) {
+    // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
+    HandleRList(instr, true);
+  } else {
+    // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
+    HandleRList(instr, false);
+  }
+}
+
+
+void Simulator::DecodeType5(Instr* instr) {
+  // Format(instr, "b'l'cond 'target");
+  int off = (instr->SImmed24Field() << 2) + 8;
+  intptr_t pc = get_pc();
+  if (instr->HasLink()) {
+    set_register(lr, pc + Instr::kInstrSize);
+  }
+  set_pc(pc+off);
+}
+
+
+void Simulator::DecodeType6(Instr* instr) {
+  UNIMPLEMENTED();
+}
+
+
+void Simulator::DecodeType7(Instr* instr) {
+  if (instr->Bit(24) == 1) {
+    // Format(instr, "swi 'swi");
+    SoftwareInterrupt(instr);
+  } else {
+    UNIMPLEMENTED();
+  }
+}
+
+
+// Executes the current instruction.
+void Simulator::InstructionDecode(Instr* instr) {
+  pc_modified_ = false;
+  if (instr->ConditionField() == special_condition) {
+    Debugger dbg(this);
+    dbg.Stop(instr);
+    return;
+  }
+  if (::v8::internal::FLAG_trace_sim) {
+    disasm::Disassembler dasm;
+    // use a reasonably large buffer
+    v8::internal::EmbeddedVector<char, 256> buffer;
+    dasm.InstructionDecode(buffer,
+                           reinterpret_cast<byte*>(instr));
+    PrintF("  0x%x  %s\n", instr, buffer.start());
+  }
+  if (ConditionallyExecute(instr)) {
+    switch (instr->TypeField()) {
+      case 0:
+      case 1: {
+        DecodeType01(instr);
+        break;
+      }
+      case 2: {
+        DecodeType2(instr);
+        break;
+      }
+      case 3: {
+        DecodeType3(instr);
+        break;
+      }
+      case 4: {
+        DecodeType4(instr);
+        break;
+      }
+      case 5: {
+        DecodeType5(instr);
+        break;
+      }
+      case 6: {
+        DecodeType6(instr);
+        break;
+      }
+      case 7: {
+        DecodeType7(instr);
+        break;
+      }
+      default: {
+        UNIMPLEMENTED();
+        break;
+      }
+    }
+  }
+  if (!pc_modified_) {
+    set_register(pc, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
+  }
+}
+
+
+//
+void Simulator::execute() {
+  // Get the PC to simulate. Cannot use the accessor here as we need the
+  // raw PC value and not the one used as input to arithmetic instructions.
+  int program_counter = get_pc();
+
+  if (::v8::internal::FLAG_stop_sim_at == 0) {
+    // Fast version of the dispatch loop without checking whether the simulator
+    // should be stopping at a particular executed instruction.
+    while (program_counter != end_sim_pc) {
+      Instr* instr = reinterpret_cast<Instr*>(program_counter);
+      icount_++;
+      InstructionDecode(instr);
+      program_counter = get_pc();
+    }
+  } else {
+    // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
+    // we reach the particular instuction count.
+    while (program_counter != end_sim_pc) {
+      Instr* instr = reinterpret_cast<Instr*>(program_counter);
+      icount_++;
+      if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
+        Debugger dbg(this);
+        dbg.Debug();
+      } else {
+        InstructionDecode(instr);
+      }
+      program_counter = get_pc();
+    }
+  }
+}
+
+
+Object* Simulator::call(int32_t entry, int32_t p0, int32_t p1, int32_t p2,
+                           int32_t p3, int32_t p4) {
+  // Setup parameters
+  set_register(r0, p0);
+  set_register(r1, p1);
+  set_register(r2, p2);
+  set_register(r3, p3);
+  intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp));
+  *(--stack_pointer) = p4;
+  set_register(sp, reinterpret_cast<int32_t>(stack_pointer));
+
+  // Prepare to execute the code at entry
+  set_register(pc, entry);
+  // Put down marker for end of simulation. The simulator will stop simulation
+  // when the PC reaches this value. By saving the "end simulation" value into
+  // the LR the simulation stops when returning to this call point.
+  set_register(lr, end_sim_pc);
+
+  // Remember the values of callee-saved registers.
+  // The code below assumes that r9 is not used as sb (static base) in
+  // simulator code and therefore is regarded as a callee-saved register.
+  int32_t r4_val = get_register(r4);
+  int32_t r5_val = get_register(r5);
+  int32_t r6_val = get_register(r6);
+  int32_t r7_val = get_register(r7);
+  int32_t r8_val = get_register(r8);
+  int32_t r9_val = get_register(r9);
+  int32_t r10_val = get_register(r10);
+  int32_t r11_val = get_register(r11);
+
+  // Setup the callee-saved registers with a known value. To be able to check
+  // that they are preserved properly across JS execution.
+  int32_t callee_saved_value = icount_;
+  set_register(r4, callee_saved_value);
+  set_register(r5, callee_saved_value);
+  set_register(r6, callee_saved_value);
+  set_register(r7, callee_saved_value);
+  set_register(r8, callee_saved_value);
+  set_register(r9, callee_saved_value);
+  set_register(r10, callee_saved_value);
+  set_register(r11, callee_saved_value);
+
+  // Start the simulation
+  execute();
+
+  // Check that the callee-saved registers have been preserved.
+  CHECK_EQ(get_register(r4), callee_saved_value);
+  CHECK_EQ(get_register(r5), callee_saved_value);
+  CHECK_EQ(get_register(r6), callee_saved_value);
+  CHECK_EQ(get_register(r7), callee_saved_value);
+  CHECK_EQ(get_register(r8), callee_saved_value);
+  CHECK_EQ(get_register(r9), callee_saved_value);
+  CHECK_EQ(get_register(r10), callee_saved_value);
+  CHECK_EQ(get_register(r11), callee_saved_value);
+
+  // Restore callee-saved registers with the original value.
+  set_register(r4, r4_val);
+  set_register(r5, r5_val);
+  set_register(r6, r6_val);
+  set_register(r7, r7_val);
+  set_register(r8, r8_val);
+  set_register(r9, r9_val);
+  set_register(r10, r10_val);
+  set_register(r11, r11_val);
+
+  int result = get_register(r0);
+  return reinterpret_cast<Object*>(result);
+}
+
+} }  // namespace assembler::arm
+
+#endif  // !defined(__arm__)
diff --git a/regexp2000/src/simulator-arm.h b/regexp2000/src/simulator-arm.h
new file mode 100644 (file)
index 0000000..1ccd856
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Declares a Simulator for ARM instructions if we are not generating a native
+// ARM binary. This Simulator allows us to run and debug ARM code generation on
+// regular desktop machines.
+// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
+// which will start execution in the Simulator or forwards to the real entry
+// on a ARM HW platform.
+
+#ifndef V8_SIMULATOR_ARM_H_
+#define V8_SIMULATOR_ARM_H_
+
+#if defined(__arm__)
+
+// When running without a simulator we call the entry directly.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
+  entry(p0, p1, p2, p3, p4)
+
+// Calculated the stack limit beyond which we will throw stack overflow errors.
+// This macro must be called from a C++ method. It relies on being able to take
+// the address of "this" to get a value on the current execution stack and then
+// calculates the stack limit based on that value.
+#define GENERATED_CODE_STACK_LIMIT(limit) \
+  (reinterpret_cast<uintptr_t>(this) - limit)
+
+#else  // defined(__arm__)
+
+// When running with the simulator transition into simulated execution at this
+// point.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
+  assembler::arm::Simulator::current()->call((int32_t)entry, (int32_t)p0, \
+    (int32_t)p1, (int32_t)p2, (int32_t)p3, (int32_t)p4)
+
+// The simulator has its own stack. Thus it has a different stack limit from
+// the C-based native code.
+#define GENERATED_CODE_STACK_LIMIT(limit) \
+  (assembler::arm::Simulator::current()->StackLimit())
+
+
+#include "constants-arm.h"
+
+
+namespace assembler { namespace arm {
+
+class Simulator {
+ public:
+  friend class Debugger;
+
+  enum Register {
+    no_reg = -1,
+    r0 = 0, r1, r2, r3, r4, r5, r6, r7,
+    r8, r9, r10, r11, r12, r13, r14, r15,
+    num_registers,
+    sp = 13,
+    lr = 14,
+    pc = 15
+  };
+
+  Simulator();
+  ~Simulator();
+
+  // The currently executing Simulator instance. Potentially there can be one
+  // for each native thread.
+  static Simulator* current();
+
+  // Accessors for register state. Reading the pc value adheres to the ARM
+  // architecture specification and is off by a 8 from the currently executing
+  // instruction.
+  void set_register(int reg, int32_t value);
+  int32_t get_register(int reg) const;
+
+  // Special case of set_register and get_register to access the raw PC value.
+  void set_pc(int32_t value);
+  int32_t get_pc() const;
+
+  // Accessor to the internal simulator stack area.
+  uintptr_t StackLimit() const;
+
+  // Executes ARM instructions until the PC reaches end_sim_pc.
+  void execute();
+
+  // V8 generally calls into generated code with 5 parameters. This is a
+  // convenience funtion, which sets up the simulator state and grabs the
+  // result on return.
+  v8::internal::Object* call(int32_t entry, int32_t p0, int32_t p1,
+                             int32_t p2, int32_t p3, int32_t p4);
+
+ private:
+  enum special_values {
+    // Known bad pc value to ensure that the simulator does not execute
+    // without being properly setup.
+    bad_lr = -1,
+    // A pc value used to signal the simulator to stop execution.  Generally
+    // the lr is set to this value on transition from native C code to
+    // simulated execution, so that the simulator can "return" to the native
+    // C code.
+    end_sim_pc = -2
+  };
+
+  // Unsupported instructions use Format to print an error and stop execution.
+  void Format(Instr* instr, const char* format);
+
+  // Checks if the current instruction should be executed based on its
+  // condition bits.
+  bool ConditionallyExecute(Instr* instr);
+
+  // Helper functions to set the conditional flags in the architecture state.
+  void SetNZFlags(int32_t val);
+  void SetCFlag(bool val);
+  void SetVFlag(bool val);
+  bool CarryFrom(int32_t left, int32_t right);
+  bool BorrowFrom(int32_t left, int32_t right);
+  bool OverflowFrom(int32_t alu_out,
+                    int32_t left,
+                    int32_t right,
+                    bool addition);
+
+  // Helper functions to decode common "addressing" modes
+  int32_t GetShiftRm(Instr* instr, bool* carry_out);
+  int32_t GetImm(Instr* instr, bool* carry_out);
+  void HandleRList(Instr* instr, bool load);
+  void SoftwareInterrupt(Instr* instr);
+
+  // Executing is handled based on the instruction type.
+  void DecodeType01(Instr* instr);  // both type 0 and type 1 rolled into one
+  void DecodeType2(Instr* instr);
+  void DecodeType3(Instr* instr);
+  void DecodeType4(Instr* instr);
+  void DecodeType5(Instr* instr);
+  void DecodeType6(Instr* instr);
+  void DecodeType7(Instr* instr);
+
+  // Executes one instruction.
+  void InstructionDecode(Instr* instr);
+
+  // architecture state
+  int32_t registers_[16];
+  bool n_flag_;
+  bool z_flag_;
+  bool c_flag_;
+  bool v_flag_;
+
+  // simulator support
+  char* stack_;
+  bool pc_modified_;
+  int icount_;
+
+  // registered breakpoints
+  Instr* break_pc_;
+  instr_t break_instr_;
+};
+
+} }  // namespace assembler::arm
+
+#endif  // defined(__arm__)
+
+#endif  // V8_SIMULATOR_ARM_H_
diff --git a/regexp2000/src/simulator-ia32.cc b/regexp2000/src/simulator-ia32.cc
new file mode 100644 (file)
index 0000000..ab81693
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Since there is no simulator for the ia32 architecture this file is empty.
+
diff --git a/regexp2000/src/simulator-ia32.h b/regexp2000/src/simulator-ia32.h
new file mode 100644 (file)
index 0000000..2267721
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SIMULATOR_IA32_H_
+#define V8_SIMULATOR_IA32_H_
+
+
+// Since there is no simulator for the ia32 architecture the only thing we can
+// do is to call the entry directly.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
+  entry(p0, p1, p2, p3, p4);
+
+// Calculated the stack limit beyond which we will throw stack overflow errors.
+// This macro must be called from a C++ method. It relies on being able to take
+// the address of "this" to get a value on the current execution stack and then
+// calculates the stack limit based on that value.
+// NOTE: The check for overflow is not safe as there is no guarantee that the
+// running thread has its stack in all memory up to address 0x00000000.
+#define GENERATED_CODE_STACK_LIMIT(limit) \
+  (reinterpret_cast<uintptr_t>(this) >= limit ? \
+      reinterpret_cast<uintptr_t>(this) - limit : 0)
+
+#endif  // V8_SIMULATOR_IA32_H_
diff --git a/regexp2000/src/smart-pointer.h b/regexp2000/src/smart-pointer.h
new file mode 100644 (file)
index 0000000..c39df16
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SMART_POINTER_H_
+#define V8_SMART_POINTER_H_
+
+namespace v8 { namespace internal {
+
+
+// A 'scoped array pointer' that calls DeleteArray on its pointer when the
+// destructor is called.
+template<typename T>
+class SmartPointer {
+ public:
+
+  // 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) {}
+
+
+  // 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;
+  }
+
+
+  // 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); }
+
+
+  // You can get the underlying pointer out with the * operator.
+  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];
+  }
+
+  // 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.
+
+
+  // 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;
+    return temp;
+  }
+
+
+  // Assignment requires an empty (NULL) SmartPointer 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) {
+    ASSERT(is_empty());
+    T* tmp = rhs.p;  // swap to handle self-assignment
+    const_cast<SmartPointer<T>&>(rhs).p = NULL;
+    p = tmp;
+    return *this;
+  }
+
+
+  inline bool is_empty() {
+    return p == NULL;
+  }
+
+
+ private:
+  T* p;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_SMART_POINTER_H_
diff --git a/regexp2000/src/snapshot-common.cc b/regexp2000/src/snapshot-common.cc
new file mode 100644 (file)
index 0000000..b0e9323
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The common functionality when building with or without snapshots.
+
+#include "v8.h"
+
+#include "api.h"
+#include "serialize.h"
+#include "snapshot.h"
+
+namespace v8 { namespace internal {
+
+bool Snapshot::Deserialize(const char* content, int len) {
+  Deserializer des(content, len);
+  des.GetFlags();
+  return V8::Initialize(&des);
+}
+
+
+bool Snapshot::Initialize(const char* snapshot_file) {
+  if (snapshot_file) {
+    int len;
+    char* str = ReadChars(snapshot_file, &len);
+    if (!str) return false;
+    bool result = Deserialize(str, len);
+    DeleteArray(str);
+    return result;
+  } else if (size_ > 0) {
+    return Deserialize(data_, size_);
+  }
+  return false;
+}
+
+
+bool Snapshot::WriteToFile(const char* snapshot_file) {
+  Serializer ser;
+  ser.Serialize();
+  char* str;
+  int len;
+  ser.Finalize(&str, &len);
+
+  int written = WriteChars(snapshot_file, str, len);
+
+  DeleteArray(str);
+  return written == len;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/snapshot-empty.cc b/regexp2000/src/snapshot-empty.cc
new file mode 100644 (file)
index 0000000..1c8ec5f
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Used for building without snapshots.
+
+#include "v8.h"
+
+#include "snapshot.h"
+
+namespace v8 { namespace internal {
+
+const char Snapshot::data_[] = { 0 };
+int Snapshot::size_ = 0;
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/snapshot.h b/regexp2000/src/snapshot.h
new file mode 100644 (file)
index 0000000..2d8b9ac
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SNAPSHOT_H_
+#define V8_SNAPSHOT_H_
+
+namespace v8 { namespace internal {
+
+class Snapshot {
+ public:
+  // Initialize the VM from the given snapshot file. If snapshot_file is
+  // NULL, use the internal snapshot instead. Returns false if no snapshot
+  // could be found.
+  static bool Initialize(const char* snapshot_file = NULL);
+
+  // Returns whether or not the snapshot is enabled.
+  static bool IsEnabled() { return size_ != 0; }
+
+  // Write snapshot to the given file. Returns true if snapshot was written
+  // successfully.
+  static bool WriteToFile(const char* snapshot_file);
+
+ private:
+  static const char data_[];
+  static int size_;
+
+  static bool Deserialize(const char* content, int len);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_SNAPSHOT_H_
diff --git a/regexp2000/src/spaces-inl.h b/regexp2000/src/spaces-inl.h
new file mode 100644 (file)
index 0000000..7a81db3
--- /dev/null
@@ -0,0 +1,319 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SPACES_INL_H_
+#define V8_SPACES_INL_H_
+
+#include "memory.h"
+#include "spaces.h"
+
+namespace v8 { namespace internal {
+
+
+// -----------------------------------------------------------------------------
+// HeapObjectIterator
+
+bool HeapObjectIterator::has_next() {
+  if (cur_addr_ < cur_limit_) {
+    return true;  // common case
+  }
+  ASSERT(cur_addr_ == cur_limit_);
+  return HasNextInNextPage();  // slow path
+}
+
+
+HeapObject* HeapObjectIterator::next() {
+  ASSERT(has_next());
+
+  HeapObject* obj = HeapObject::FromAddress(cur_addr_);
+  int obj_size = (size_func_ == NULL) ? obj->Size() : size_func_(obj);
+  ASSERT_OBJECT_SIZE(obj_size);
+
+  cur_addr_ += obj_size;
+  ASSERT(cur_addr_ <= cur_limit_);
+
+  return obj;
+}
+
+
+// -----------------------------------------------------------------------------
+// PageIterator
+
+bool PageIterator::has_next() {
+  return cur_page_ != stop_page_;
+}
+
+
+Page* PageIterator::next() {
+  ASSERT(has_next());
+  Page* result = cur_page_;
+  cur_page_ = cur_page_->next_page();
+  return result;
+}
+
+
+// -----------------------------------------------------------------------------
+// Page
+
+Page* Page::next_page() {
+  return MemoryAllocator::GetNextPage(this);
+}
+
+
+Address Page::AllocationTop() {
+  PagedSpace* owner = MemoryAllocator::PageOwner(this);
+  return owner->PageAllocationTop(this);
+}
+
+
+void Page::ClearRSet() {
+  // This method can be called in all rset states.
+  memset(RSetStart(), 0, kRSetEndOffset - kRSetStartOffset);
+}
+
+
+// Give an address a (32-bits):
+// | page address | words (6) | bit offset (5) | pointer alignment (2) |
+// The rset address is computed as:
+//    page_address + words * 4
+
+Address Page::ComputeRSetBitPosition(Address address, int offset,
+                                     uint32_t* bitmask) {
+  ASSERT(Page::is_rset_in_use());
+
+  Page* page = Page::FromAddress(address);
+  uint32_t bit_offset = ArithmeticShiftRight(page->Offset(address) + offset,
+                                             kObjectAlignmentBits);
+  *bitmask = 1 << (bit_offset % kBitsPerInt);
+
+  Address rset_address =
+      page->address() + (bit_offset / kBitsPerInt) * kIntSize;
+  // The remembered set address is either in the normal remembered set range
+  // of a page or else we have a large object page.
+  ASSERT((page->RSetStart() <= rset_address && rset_address < page->RSetEnd())
+         || page->IsLargeObjectPage());
+
+  if (rset_address >= page->RSetEnd()) {
+    // We have a large object page, and the remembered set address is actually
+    // past the end of the object.  The address of the remembered set in this
+    // case is the extra remembered set start address at the address of the
+    // end of the object:
+    //   (page->ObjectAreaStart() + object size)
+    // plus the offset of the computed remembered set address from the start
+    // of the object:
+    //   (rset_address - page->ObjectAreaStart()).
+    // Ie, we can just add the object size.
+    ASSERT(HeapObject::FromAddress(address)->IsFixedArray());
+    rset_address +=
+        FixedArray::SizeFor(Memory::int_at(page->ObjectAreaStart()
+                                           + Array::kLengthOffset));
+  }
+  return rset_address;
+}
+
+
+void Page::SetRSet(Address address, int offset) {
+  uint32_t bitmask = 0;
+  Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask);
+  Memory::uint32_at(rset_address) |= bitmask;
+
+  ASSERT(IsRSetSet(address, offset));
+}
+
+
+// Clears the corresponding remembered set bit for a given address.
+void Page::UnsetRSet(Address address, int offset) {
+  uint32_t bitmask = 0;
+  Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask);
+  Memory::uint32_at(rset_address) &= ~bitmask;
+
+  ASSERT(!IsRSetSet(address, offset));
+}
+
+
+bool Page::IsRSetSet(Address address, int offset) {
+  uint32_t bitmask = 0;
+  Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask);
+  return (Memory::uint32_at(rset_address) & bitmask) != 0;
+}
+
+
+// -----------------------------------------------------------------------------
+// MemoryAllocator
+
+bool MemoryAllocator::IsValidChunk(int chunk_id) {
+  if (!IsValidChunkId(chunk_id)) return false;
+
+  ChunkInfo& c = chunks_[chunk_id];
+  return (c.address() != NULL) && (c.size() != 0) && (c.owner() != NULL);
+}
+
+
+bool MemoryAllocator::IsValidChunkId(int chunk_id) {
+  return (0 <= chunk_id) && (chunk_id < max_nof_chunks_);
+}
+
+
+bool MemoryAllocator::IsPageInSpace(Page* p, PagedSpace* space) {
+  ASSERT(p->is_valid());
+
+  int chunk_id = GetChunkId(p);
+  if (!IsValidChunkId(chunk_id)) return false;
+
+  ChunkInfo& c = chunks_[chunk_id];
+  return (c.address() <= p->address()) &&
+         (p->address() < c.address() + c.size()) &&
+         (space == c.owner());
+}
+
+
+Page* MemoryAllocator::GetNextPage(Page* p) {
+  ASSERT(p->is_valid());
+  int raw_addr = p->opaque_header & ~Page::kPageAlignmentMask;
+  return Page::FromAddress(AddressFrom<Address>(raw_addr));
+}
+
+
+int MemoryAllocator::GetChunkId(Page* p) {
+  ASSERT(p->is_valid());
+  return p->opaque_header & Page::kPageAlignmentMask;
+}
+
+
+void MemoryAllocator::SetNextPage(Page* prev, Page* next) {
+  ASSERT(prev->is_valid());
+  int chunk_id = prev->opaque_header & Page::kPageAlignmentMask;
+  ASSERT_PAGE_ALIGNED(next->address());
+  prev->opaque_header = OffsetFrom(next->address()) | chunk_id;
+}
+
+
+PagedSpace* MemoryAllocator::PageOwner(Page* page) {
+  int chunk_id = GetChunkId(page);
+  ASSERT(IsValidChunk(chunk_id));
+  return chunks_[chunk_id].owner();
+}
+
+
+// --------------------------------------------------------------------------
+// PagedSpace
+
+bool PagedSpace::Contains(Address addr) {
+  Page* p = Page::FromAddress(addr);
+  ASSERT(p->is_valid());
+
+  return MemoryAllocator::IsPageInSpace(p, this);
+}
+
+
+// Try linear allocation in the page of alloc_info's allocation top.  Does
+// not contain slow case logic (eg, move to the next page or try free list
+// allocation) so it can be used by all the allocation functions and for all
+// the paged spaces.
+HeapObject* PagedSpace::AllocateLinearly(AllocationInfo* alloc_info,
+                                         int size_in_bytes) {
+  Address current_top = alloc_info->top;
+  Address new_top = current_top + size_in_bytes;
+  if (new_top > alloc_info->limit) return NULL;
+
+  alloc_info->top = new_top;
+  ASSERT(alloc_info->VerifyPagedAllocation());
+  accounting_stats_.AllocateBytes(size_in_bytes);
+  return HeapObject::FromAddress(current_top);
+}
+
+
+// Raw allocation.
+Object* PagedSpace::AllocateRaw(int size_in_bytes) {
+  ASSERT(HasBeenSetup());
+  ASSERT_OBJECT_SIZE(size_in_bytes);
+  HeapObject* object = AllocateLinearly(&allocation_info_, size_in_bytes);
+  if (object != NULL) return object;
+
+  object = SlowAllocateRaw(size_in_bytes);
+  if (object != NULL) return object;
+
+  return Failure::RetryAfterGC(size_in_bytes, identity());
+}
+
+
+// Reallocating (and promoting) objects during a compacting collection.
+Object* PagedSpace::MCAllocateRaw(int size_in_bytes) {
+  ASSERT(HasBeenSetup());
+  ASSERT_OBJECT_SIZE(size_in_bytes);
+  HeapObject* object = AllocateLinearly(&mc_forwarding_info_, size_in_bytes);
+  if (object != NULL) return object;
+
+  object = SlowMCAllocateRaw(size_in_bytes);
+  if (object != NULL) return object;
+
+  return Failure::RetryAfterGC(size_in_bytes, identity());
+}
+
+
+// -----------------------------------------------------------------------------
+// LargeObjectChunk
+
+HeapObject* LargeObjectChunk::GetObject() {
+  // Round the chunk address up to the nearest page-aligned address
+  // and return the heap object in that page.
+  Page* page = Page::FromAddress(RoundUp(address(), Page::kPageSize));
+  return HeapObject::FromAddress(page->ObjectAreaStart());
+}
+
+
+// -----------------------------------------------------------------------------
+// LargeObjectSpace
+
+int LargeObjectSpace::ExtraRSetBytesFor(int object_size) {
+  int extra_rset_bits =
+      RoundUp((object_size - Page::kObjectAreaSize) / kPointerSize,
+              kBitsPerInt);
+  return extra_rset_bits / kBitsPerByte;
+}
+
+
+Object* NewSpace::AllocateRawInternal(int size_in_bytes,
+                                      AllocationInfo* alloc_info) {
+  Address new_top = alloc_info->top + size_in_bytes;
+  if (new_top > alloc_info->limit) return Failure::RetryAfterGC(size_in_bytes);
+
+  Object* obj = HeapObject::FromAddress(alloc_info->top);
+  alloc_info->top = new_top;
+#ifdef DEBUG
+  SemiSpace* space =
+      (alloc_info == &allocation_info_) ? &to_space_ : &from_space_;
+  ASSERT(space->low() <= alloc_info->top
+         && alloc_info->top <= space->high()
+         && alloc_info->limit == space->high());
+#endif
+  return obj;
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_SPACES_INL_H_
diff --git a/regexp2000/src/spaces.cc b/regexp2000/src/spaces.cc
new file mode 100644 (file)
index 0000000..7894f24
--- /dev/null
@@ -0,0 +1,2527 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "macro-assembler.h"
+#include "mark-compact.h"
+#include "platform.h"
+
+namespace v8 { namespace internal {
+
+// For contiguous spaces, top should be in the space (or at the end) and limit
+// should be the end of the space.
+#define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \
+  ASSERT((space).low() <= (info).top                 \
+         && (info).top <= (space).high()             \
+         && (info).limit == (space).high())
+
+
+// ----------------------------------------------------------------------------
+// HeapObjectIterator
+
+HeapObjectIterator::HeapObjectIterator(PagedSpace* space) {
+  Initialize(space->bottom(), space->top(), NULL);
+}
+
+
+HeapObjectIterator::HeapObjectIterator(PagedSpace* space,
+                                       HeapObjectCallback size_func) {
+  Initialize(space->bottom(), space->top(), size_func);
+}
+
+
+HeapObjectIterator::HeapObjectIterator(PagedSpace* space, Address start) {
+  Initialize(start, space->top(), NULL);
+}
+
+
+HeapObjectIterator::HeapObjectIterator(PagedSpace* space, Address start,
+                                       HeapObjectCallback size_func) {
+  Initialize(start, space->top(), size_func);
+}
+
+
+void HeapObjectIterator::Initialize(Address cur, Address end,
+                                    HeapObjectCallback size_f) {
+  cur_addr_ = cur;
+  end_addr_ = end;
+  end_page_ = Page::FromAllocationTop(end);
+  size_func_ = size_f;
+  Page* p = Page::FromAllocationTop(cur_addr_);
+  cur_limit_ = (p == end_page_) ? end_addr_ : p->AllocationTop();
+
+#ifdef DEBUG
+  Verify();
+#endif
+}
+
+
+bool HeapObjectIterator::HasNextInNextPage() {
+  if (cur_addr_ == end_addr_) return false;
+
+  Page* cur_page = Page::FromAllocationTop(cur_addr_);
+  cur_page = cur_page->next_page();
+  ASSERT(cur_page->is_valid());
+
+  cur_addr_ = cur_page->ObjectAreaStart();
+  cur_limit_ = (cur_page == end_page_) ? end_addr_ : cur_page->AllocationTop();
+
+  ASSERT(cur_addr_ < cur_limit_);
+#ifdef DEBUG
+  Verify();
+#endif
+  return true;
+}
+
+
+#ifdef DEBUG
+void HeapObjectIterator::Verify() {
+  Page* p = Page::FromAllocationTop(cur_addr_);
+  ASSERT(p == Page::FromAllocationTop(cur_limit_));
+  ASSERT(p->Offset(cur_addr_) <= p->Offset(cur_limit_));
+}
+#endif
+
+
+// -----------------------------------------------------------------------------
+// PageIterator
+
+PageIterator::PageIterator(PagedSpace* space, Mode mode) {
+  cur_page_ = space->first_page_;
+  switch (mode) {
+    case PAGES_IN_USE:
+      stop_page_ = space->AllocationTopPage()->next_page();
+      break;
+    case PAGES_USED_BY_MC:
+      stop_page_ = space->MCRelocationTopPage()->next_page();
+      break;
+    case ALL_PAGES:
+      stop_page_ = Page::FromAddress(NULL);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Page
+
+#ifdef DEBUG
+Page::RSetState Page::rset_state_ = Page::IN_USE;
+#endif
+
+// -----------------------------------------------------------------------------
+// MemoryAllocator
+//
+int MemoryAllocator::capacity_   = 0;
+int MemoryAllocator::size_       = 0;
+
+VirtualMemory* MemoryAllocator::initial_chunk_ = NULL;
+
+// 270 is an estimate based on the static default heap size of a pair of 256K
+// semispaces and a 64M old generation.
+const int kEstimatedNumberOfChunks = 270;
+List<MemoryAllocator::ChunkInfo> MemoryAllocator::chunks_(
+    kEstimatedNumberOfChunks);
+List<int> MemoryAllocator::free_chunk_ids_(kEstimatedNumberOfChunks);
+int MemoryAllocator::max_nof_chunks_ = 0;
+int MemoryAllocator::top_ = 0;
+
+
+void MemoryAllocator::Push(int free_chunk_id) {
+  ASSERT(max_nof_chunks_ > 0);
+  ASSERT(top_ < max_nof_chunks_);
+  free_chunk_ids_[top_++] = free_chunk_id;
+}
+
+
+int MemoryAllocator::Pop() {
+  ASSERT(top_ > 0);
+  return free_chunk_ids_[--top_];
+}
+
+
+bool MemoryAllocator::Setup(int capacity) {
+  capacity_ = RoundUp(capacity, Page::kPageSize);
+
+  // Over-estimate the size of chunks_ array.  It assumes the expansion of old
+  // space is always in the unit of a chunk (kChunkSize) except the last
+  // expansion.
+  //
+  // Due to alignment, allocated space might be one page less than required
+  // number (kPagesPerChunk) of pages for old spaces.
+  //
+  // Reserve two chunk ids for semispaces, one for map space, one for old
+  // space, and one for code space.
+  max_nof_chunks_ = (capacity_ / (kChunkSize - Page::kPageSize)) + 5;
+  if (max_nof_chunks_ > kMaxNofChunks) return false;
+
+  size_ = 0;
+  ChunkInfo info;  // uninitialized element.
+  for (int i = max_nof_chunks_ - 1; i >= 0; i--) {
+    chunks_.Add(info);
+    free_chunk_ids_.Add(i);
+  }
+  top_ = max_nof_chunks_;
+  return true;
+}
+
+
+void MemoryAllocator::TearDown() {
+  for (int i = 0; i < max_nof_chunks_; i++) {
+    if (chunks_[i].address() != NULL) DeleteChunk(i);
+  }
+  chunks_.Clear();
+  free_chunk_ids_.Clear();
+
+  if (initial_chunk_ != NULL) {
+    LOG(DeleteEvent("InitialChunk", initial_chunk_->address()));
+    delete initial_chunk_;
+    initial_chunk_ = NULL;
+  }
+
+  ASSERT(top_ == max_nof_chunks_);  // all chunks are free
+  top_ = 0;
+  capacity_ = 0;
+  size_ = 0;
+  max_nof_chunks_ = 0;
+}
+
+
+void* MemoryAllocator::AllocateRawMemory(const size_t requested,
+                                         size_t* allocated,
+                                         Executability executable) {
+  if (size_ + static_cast<int>(requested) > capacity_) return NULL;
+
+  void* mem = OS::Allocate(requested, allocated, executable == EXECUTABLE);
+  int alloced = *allocated;
+  size_ += alloced;
+  Counters::memory_allocated.Increment(alloced);
+  return mem;
+}
+
+
+void MemoryAllocator::FreeRawMemory(void* mem, size_t length) {
+  OS::Free(mem, length);
+  Counters::memory_allocated.Decrement(length);
+  size_ -= length;
+  ASSERT(size_ >= 0);
+}
+
+
+void* MemoryAllocator::ReserveInitialChunk(const size_t requested) {
+  ASSERT(initial_chunk_ == NULL);
+
+  initial_chunk_ = new VirtualMemory(requested);
+  CHECK(initial_chunk_ != NULL);
+  if (!initial_chunk_->IsReserved()) {
+    delete initial_chunk_;
+    initial_chunk_ = NULL;
+    return NULL;
+  }
+
+  // We are sure that we have mapped a block of requested addresses.
+  ASSERT(initial_chunk_->size() == requested);
+  LOG(NewEvent("InitialChunk", initial_chunk_->address(), requested));
+  size_ += requested;
+  return initial_chunk_->address();
+}
+
+
+static int PagesInChunk(Address start, size_t size) {
+  // The first page starts on the first page-aligned address from start onward
+  // and the last page ends on the last page-aligned address before
+  // start+size.  Page::kPageSize is a power of two so we can divide by
+  // shifting.
+  return (RoundDown(start + size, Page::kPageSize)
+          - RoundUp(start, Page::kPageSize)) >> Page::kPageSizeBits;
+}
+
+
+Page* MemoryAllocator::AllocatePages(int requested_pages, int* allocated_pages,
+                                     PagedSpace* owner) {
+  if (requested_pages <= 0) return Page::FromAddress(NULL);
+  size_t chunk_size = requested_pages * Page::kPageSize;
+
+  // There is not enough space to guarantee the desired number pages can be
+  // allocated.
+  if (size_ + static_cast<int>(chunk_size) > capacity_) {
+    // Request as many pages as we can.
+    chunk_size = capacity_ - size_;
+    requested_pages = chunk_size >> Page::kPageSizeBits;
+
+    if (requested_pages <= 0) return Page::FromAddress(NULL);
+  }
+  void* chunk = AllocateRawMemory(chunk_size, &chunk_size, owner->executable());
+  if (chunk == NULL) return Page::FromAddress(NULL);
+  LOG(NewEvent("PagedChunk", chunk, chunk_size));
+
+  *allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size);
+  if (*allocated_pages == 0) {
+    FreeRawMemory(chunk, chunk_size);
+    LOG(DeleteEvent("PagedChunk", chunk));
+    return Page::FromAddress(NULL);
+  }
+
+  int chunk_id = Pop();
+  chunks_[chunk_id].init(static_cast<Address>(chunk), chunk_size, owner);
+
+  return InitializePagesInChunk(chunk_id, *allocated_pages, owner);
+}
+
+
+Page* MemoryAllocator::CommitPages(Address start, size_t size,
+                                   PagedSpace* owner, int* num_pages) {
+  ASSERT(start != NULL);
+  *num_pages = PagesInChunk(start, size);
+  ASSERT(*num_pages > 0);
+  ASSERT(initial_chunk_ != NULL);
+  ASSERT(initial_chunk_->address() <= start);
+  ASSERT(start + size <= reinterpret_cast<Address>(initial_chunk_->address())
+                             + initial_chunk_->size());
+  if (!initial_chunk_->Commit(start, size, owner->executable() == EXECUTABLE)) {
+    return Page::FromAddress(NULL);
+  }
+  Counters::memory_allocated.Increment(size);
+
+  // So long as we correctly overestimated the number of chunks we should not
+  // run out of chunk ids.
+  CHECK(!OutOfChunkIds());
+  int chunk_id = Pop();
+  chunks_[chunk_id].init(start, size, owner);
+  return InitializePagesInChunk(chunk_id, *num_pages, owner);
+}
+
+
+bool MemoryAllocator::CommitBlock(Address start,
+                                  size_t size,
+                                  Executability executable) {
+  ASSERT(start != NULL);
+  ASSERT(size > 0);
+  ASSERT(initial_chunk_ != NULL);
+  ASSERT(initial_chunk_->address() <= start);
+  ASSERT(start + size <= reinterpret_cast<Address>(initial_chunk_->address())
+                             + initial_chunk_->size());
+
+  if (!initial_chunk_->Commit(start, size, executable)) return false;
+  Counters::memory_allocated.Increment(size);
+  return true;
+}
+
+
+Page* MemoryAllocator::InitializePagesInChunk(int chunk_id, int pages_in_chunk,
+                                              PagedSpace* owner) {
+  ASSERT(IsValidChunk(chunk_id));
+  ASSERT(pages_in_chunk > 0);
+
+  Address chunk_start = chunks_[chunk_id].address();
+
+  Address low = RoundUp(chunk_start, Page::kPageSize);
+
+#ifdef DEBUG
+  size_t chunk_size = chunks_[chunk_id].size();
+  Address high = RoundDown(chunk_start + chunk_size, Page::kPageSize);
+  ASSERT(pages_in_chunk <=
+        ((OffsetFrom(high) - OffsetFrom(low)) / Page::kPageSize));
+#endif
+
+  Address page_addr = low;
+  for (int i = 0; i < pages_in_chunk; i++) {
+    Page* p = Page::FromAddress(page_addr);
+    p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id;
+    p->is_normal_page = 1;
+    page_addr += Page::kPageSize;
+  }
+
+  // Set the next page of the last page to 0.
+  Page* last_page = Page::FromAddress(page_addr - Page::kPageSize);
+  last_page->opaque_header = OffsetFrom(0) | chunk_id;
+
+  return Page::FromAddress(low);
+}
+
+
+Page* MemoryAllocator::FreePages(Page* p) {
+  if (!p->is_valid()) return p;
+
+  // Find the first page in the same chunk as 'p'
+  Page* first_page = FindFirstPageInSameChunk(p);
+  Page* page_to_return = Page::FromAddress(NULL);
+
+  if (p != first_page) {
+    // Find the last page in the same chunk as 'prev'.
+    Page* last_page = FindLastPageInSameChunk(p);
+    first_page = GetNextPage(last_page);  // first page in next chunk
+
+    // set the next_page of last_page to NULL
+    SetNextPage(last_page, Page::FromAddress(NULL));
+    page_to_return = p;  // return 'p' when exiting
+  }
+
+  while (first_page->is_valid()) {
+    int chunk_id = GetChunkId(first_page);
+    ASSERT(IsValidChunk(chunk_id));
+
+    // Find the first page of the next chunk before deleting this chunk.
+    first_page = GetNextPage(FindLastPageInSameChunk(first_page));
+
+    // Free the current chunk.
+    DeleteChunk(chunk_id);
+  }
+
+  return page_to_return;
+}
+
+
+void MemoryAllocator::DeleteChunk(int chunk_id) {
+  ASSERT(IsValidChunk(chunk_id));
+
+  ChunkInfo& c = chunks_[chunk_id];
+
+  // We cannot free a chunk contained in the initial chunk because it was not
+  // allocated with AllocateRawMemory.  Instead we uncommit the virtual
+  // memory.
+  bool in_initial_chunk = false;
+  if (initial_chunk_ != NULL) {
+    Address start = static_cast<Address>(initial_chunk_->address());
+    Address end = start + initial_chunk_->size();
+    in_initial_chunk = (start <= c.address()) && (c.address() < end);
+  }
+
+  if (in_initial_chunk) {
+    // TODO(1240712): VirtualMemory::Uncommit has a return value which
+    // is ignored here.
+    initial_chunk_->Uncommit(c.address(), c.size());
+    Counters::memory_allocated.Decrement(c.size());
+  } else {
+    LOG(DeleteEvent("PagedChunk", c.address()));
+    FreeRawMemory(c.address(), c.size());
+  }
+  c.init(NULL, 0, NULL);
+  Push(chunk_id);
+}
+
+
+Page* MemoryAllocator::FindFirstPageInSameChunk(Page* p) {
+  int chunk_id = GetChunkId(p);
+  ASSERT(IsValidChunk(chunk_id));
+
+  Address low = RoundUp(chunks_[chunk_id].address(), Page::kPageSize);
+  return Page::FromAddress(low);
+}
+
+
+Page* MemoryAllocator::FindLastPageInSameChunk(Page* p) {
+  int chunk_id = GetChunkId(p);
+  ASSERT(IsValidChunk(chunk_id));
+
+  Address chunk_start = chunks_[chunk_id].address();
+  size_t chunk_size = chunks_[chunk_id].size();
+
+  Address high = RoundDown(chunk_start + chunk_size, Page::kPageSize);
+  ASSERT(chunk_start <= p->address() && p->address() < high);
+
+  return Page::FromAddress(high - Page::kPageSize);
+}
+
+
+#ifdef DEBUG
+void MemoryAllocator::ReportStatistics() {
+  float pct = static_cast<float>(capacity_ - size_) / capacity_;
+  PrintF("  capacity: %d, used: %d, available: %%%d\n\n",
+         capacity_, size_, static_cast<int>(pct*100));
+}
+#endif
+
+
+// -----------------------------------------------------------------------------
+// PagedSpace implementation
+
+PagedSpace::PagedSpace(int max_capacity,
+                       AllocationSpace id,
+                       Executability executable)
+    : Space(id, executable) {
+  max_capacity_ = (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize)
+                  * Page::kObjectAreaSize;
+  accounting_stats_.Clear();
+
+  allocation_info_.top = NULL;
+  allocation_info_.limit = NULL;
+
+  mc_forwarding_info_.top = NULL;
+  mc_forwarding_info_.limit = NULL;
+}
+
+
+bool PagedSpace::Setup(Address start, size_t size) {
+  if (HasBeenSetup()) return false;
+
+  int num_pages = 0;
+  // Try to use the virtual memory range passed to us.  If it is too small to
+  // contain at least one page, ignore it and allocate instead.
+  int pages_in_chunk = PagesInChunk(start, size);
+  if (pages_in_chunk > 0) {
+    first_page_ = MemoryAllocator::CommitPages(RoundUp(start, Page::kPageSize),
+                                               Page::kPageSize * pages_in_chunk,
+                                               this, &num_pages);
+  } else {
+    int requested_pages = Min(MemoryAllocator::kPagesPerChunk,
+                              max_capacity_ / Page::kObjectAreaSize);
+    first_page_ =
+        MemoryAllocator::AllocatePages(requested_pages, &num_pages, this);
+    if (!first_page_->is_valid()) return false;
+  }
+
+  // We are sure that the first page is valid and that we have at least one
+  // page.
+  ASSERT(first_page_->is_valid());
+  ASSERT(num_pages > 0);
+  accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize);
+  ASSERT(Capacity() <= max_capacity_);
+
+  for (Page* p = first_page_; p->is_valid(); p = p->next_page()) {
+    p->ClearRSet();
+  }
+
+  // Use first_page_ for allocation.
+  SetAllocationInfo(&allocation_info_, first_page_);
+
+  return true;
+}
+
+
+bool PagedSpace::HasBeenSetup() {
+  return (Capacity() > 0);
+}
+
+
+void PagedSpace::TearDown() {
+  first_page_ = MemoryAllocator::FreePages(first_page_);
+  ASSERT(!first_page_->is_valid());
+
+  accounting_stats_.Clear();
+}
+
+
+void PagedSpace::ClearRSet() {
+  PageIterator it(this, PageIterator::ALL_PAGES);
+  while (it.has_next()) {
+    it.next()->ClearRSet();
+  }
+}
+
+
+Object* PagedSpace::FindObject(Address addr) {
+#ifdef DEBUG
+  // Note: this function can only be called before or after mark-compact GC
+  // because it accesses map pointers.
+  ASSERT(!MarkCompactCollector::in_use());
+#endif
+
+  if (!Contains(addr)) return Failure::Exception();
+
+  Page* p = Page::FromAddress(addr);
+  ASSERT(IsUsed(p));
+  Address cur = p->ObjectAreaStart();
+  Address end = p->AllocationTop();
+  while (cur < end) {
+    HeapObject* obj = HeapObject::FromAddress(cur);
+    Address next = cur + obj->Size();
+    if ((cur <= addr) && (addr < next)) return obj;
+    cur = next;
+  }
+
+  UNREACHABLE();
+  return Failure::Exception();
+}
+
+
+bool PagedSpace::IsUsed(Page* page) {
+  PageIterator it(this, PageIterator::PAGES_IN_USE);
+  while (it.has_next()) {
+    if (page == it.next()) return true;
+  }
+  return false;
+}
+
+
+void PagedSpace::SetAllocationInfo(AllocationInfo* alloc_info, Page* p) {
+  alloc_info->top = p->ObjectAreaStart();
+  alloc_info->limit = p->ObjectAreaEnd();
+  ASSERT(alloc_info->VerifyPagedAllocation());
+}
+
+
+void PagedSpace::MCResetRelocationInfo() {
+  // Set page indexes.
+  int i = 0;
+  PageIterator it(this, PageIterator::ALL_PAGES);
+  while (it.has_next()) {
+    Page* p = it.next();
+    p->mc_page_index = i++;
+  }
+
+  // Set mc_forwarding_info_ to the first page in the space.
+  SetAllocationInfo(&mc_forwarding_info_, first_page_);
+  // All the bytes in the space are 'available'.  We will rediscover
+  // allocated and wasted bytes during GC.
+  accounting_stats_.Reset();
+}
+
+
+int PagedSpace::MCSpaceOffsetForAddress(Address addr) {
+#ifdef DEBUG
+  // The Contains function considers the address at the beginning of a
+  // page in the page, MCSpaceOffsetForAddress considers it is in the
+  // previous page.
+  if (Page::IsAlignedToPageSize(addr)) {
+    ASSERT(Contains(addr - kPointerSize));
+  } else {
+    ASSERT(Contains(addr));
+  }
+#endif
+
+  // If addr is at the end of a page, it belongs to previous page
+  Page* p = Page::IsAlignedToPageSize(addr)
+            ? Page::FromAllocationTop(addr)
+            : Page::FromAddress(addr);
+  int index = p->mc_page_index;
+  return (index * Page::kPageSize) + p->Offset(addr);
+}
+
+
+// Slow case for reallocating and promoting objects during a compacting
+// collection.  This function is not space-specific.
+HeapObject* PagedSpace::SlowMCAllocateRaw(int size_in_bytes) {
+  Page* current_page = TopPageOf(mc_forwarding_info_);
+  if (!current_page->next_page()->is_valid()) {
+    if (!Expand(current_page)) {
+      return NULL;
+    }
+  }
+
+  // There are surely more pages in the space now.
+  ASSERT(current_page->next_page()->is_valid());
+  // We do not add the top of page block for current page to the space's
+  // free list---the block may contain live objects so we cannot write
+  // bookkeeping information to it.  Instead, we will recover top of page
+  // blocks when we move objects to their new locations.
+  //
+  // We do however write the allocation pointer to the page.  The encoding
+  // of forwarding addresses is as an offset in terms of live bytes, so we
+  // need quick access to the allocation top of each page to decode
+  // forwarding addresses.
+  current_page->mc_relocation_top = mc_forwarding_info_.top;
+  SetAllocationInfo(&mc_forwarding_info_, current_page->next_page());
+  return AllocateLinearly(&mc_forwarding_info_, size_in_bytes);
+}
+
+
+bool PagedSpace::Expand(Page* last_page) {
+  ASSERT(max_capacity_ % Page::kObjectAreaSize == 0);
+  ASSERT(Capacity() % Page::kObjectAreaSize == 0);
+
+  if (Capacity() == max_capacity_) return false;
+
+  ASSERT(Capacity() < max_capacity_);
+  // Last page must be valid and its next page is invalid.
+  ASSERT(last_page->is_valid() && !last_page->next_page()->is_valid());
+
+  int available_pages = (max_capacity_ - Capacity()) / Page::kObjectAreaSize;
+  if (available_pages <= 0) return false;
+
+  int desired_pages = Min(available_pages, MemoryAllocator::kPagesPerChunk);
+  Page* p = MemoryAllocator::AllocatePages(desired_pages, &desired_pages, this);
+  if (!p->is_valid()) return false;
+
+  accounting_stats_.ExpandSpace(desired_pages * Page::kObjectAreaSize);
+  ASSERT(Capacity() <= max_capacity_);
+
+  MemoryAllocator::SetNextPage(last_page, p);
+
+  // Clear remembered set of new pages.
+  while (p->is_valid()) {
+    p->ClearRSet();
+    p = p->next_page();
+  }
+
+  return true;
+}
+
+
+#ifdef DEBUG
+int PagedSpace::CountTotalPages() {
+  int count = 0;
+  for (Page* p = first_page_; p->is_valid(); p = p->next_page()) {
+    count++;
+  }
+  return count;
+}
+#endif
+
+
+void PagedSpace::Shrink() {
+  // Release half of free pages.
+  Page* top_page = AllocationTopPage();
+  ASSERT(top_page->is_valid());
+
+  // Loop over the pages from the top page to the end of the space to count
+  // the number of pages to keep and find the last page to keep.
+  int free_pages = 0;
+  int pages_to_keep = 0;  // Of the free pages.
+  Page* last_page_to_keep = top_page;
+  Page* current_page = top_page->next_page();
+  // Loop over the pages to the end of the space.
+  while (current_page->is_valid()) {
+    // Advance last_page_to_keep every other step to end up at the midpoint.
+    if ((free_pages & 0x1) == 1) {
+      pages_to_keep++;
+      last_page_to_keep = last_page_to_keep->next_page();
+    }
+    free_pages++;
+    current_page = current_page->next_page();
+  }
+
+  // Free pages after last_page_to_keep, and adjust the next_page link.
+  Page* p = MemoryAllocator::FreePages(last_page_to_keep->next_page());
+  MemoryAllocator::SetNextPage(last_page_to_keep, p);
+
+  // Since pages are only freed in whole chunks, we may have kept more than
+  // pages_to_keep.
+  while (p->is_valid()) {
+    pages_to_keep++;
+    p = p->next_page();
+  }
+
+  // The difference between free_pages and pages_to_keep is the number of
+  // pages actually freed.
+  ASSERT(pages_to_keep <= free_pages);
+  int bytes_freed = (free_pages - pages_to_keep) * Page::kObjectAreaSize;
+  accounting_stats_.ShrinkSpace(bytes_freed);
+
+  ASSERT(Capacity() == CountTotalPages() * Page::kObjectAreaSize);
+}
+
+
+bool PagedSpace::EnsureCapacity(int capacity) {
+  if (Capacity() >= capacity) return true;
+
+  // Start from the allocation top and loop to the last page in the space.
+  Page* last_page = AllocationTopPage();
+  Page* next_page = last_page->next_page();
+  while (next_page->is_valid()) {
+    last_page = MemoryAllocator::FindLastPageInSameChunk(next_page);
+    next_page = last_page->next_page();
+  }
+
+  // Expand the space until it has the required capacity or expansion fails.
+  do {
+    if (!Expand(last_page)) return false;
+    ASSERT(last_page->next_page()->is_valid());
+    last_page =
+        MemoryAllocator::FindLastPageInSameChunk(last_page->next_page());
+  } while (Capacity() < capacity);
+
+  return true;
+}
+
+
+#ifdef DEBUG
+void PagedSpace::Print() { }
+#endif
+
+
+// -----------------------------------------------------------------------------
+// NewSpace implementation
+
+
+bool NewSpace::Setup(Address start, int size) {
+  // Setup new space based on the preallocated memory block defined by
+  // start and size. The provided space is divided into two semi-spaces.
+  // To support fast containment testing in the new space, the size of
+  // this chunk must be a power of two and it must be aligned to its size.
+  int initial_semispace_capacity = Heap::InitialSemiSpaceSize();
+  int maximum_semispace_capacity = Heap::SemiSpaceSize();
+
+  ASSERT(initial_semispace_capacity <= maximum_semispace_capacity);
+  ASSERT(IsPowerOf2(maximum_semispace_capacity));
+  maximum_capacity_ = maximum_semispace_capacity;
+  capacity_ = initial_semispace_capacity;
+
+  // Allocate and setup the histogram arrays if necessary.
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  allocated_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1);
+  promoted_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1);
+
+#define SET_NAME(name) allocated_histogram_[name].set_name(#name); \
+                       promoted_histogram_[name].set_name(#name);
+  INSTANCE_TYPE_LIST(SET_NAME)
+#undef SET_NAME
+#endif
+
+  ASSERT(size == 2 * maximum_capacity_);
+  ASSERT(IsAddressAligned(start, size, 0));
+
+  if (!to_space_.Setup(start, capacity_, maximum_capacity_)) {
+    return false;
+  }
+  if (!from_space_.Setup(start + maximum_capacity_,
+                         capacity_,
+                         maximum_capacity_)) {
+    return false;
+  }
+
+  start_ = start;
+  address_mask_ = ~(size - 1);
+  object_mask_ = address_mask_ | kHeapObjectTag;
+  object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;
+
+  allocation_info_.top = to_space_.low();
+  allocation_info_.limit = to_space_.high();
+  mc_forwarding_info_.top = NULL;
+  mc_forwarding_info_.limit = NULL;
+
+  ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+  return true;
+}
+
+
+void NewSpace::TearDown() {
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  if (allocated_histogram_) {
+    DeleteArray(allocated_histogram_);
+    allocated_histogram_ = NULL;
+  }
+  if (promoted_histogram_) {
+    DeleteArray(promoted_histogram_);
+    promoted_histogram_ = NULL;
+  }
+#endif
+
+  start_ = NULL;
+  capacity_ = 0;
+  allocation_info_.top = NULL;
+  allocation_info_.limit = NULL;
+  mc_forwarding_info_.top = NULL;
+  mc_forwarding_info_.limit = NULL;
+
+  to_space_.TearDown();
+  from_space_.TearDown();
+}
+
+
+void NewSpace::Flip() {
+  SemiSpace tmp = from_space_;
+  from_space_ = to_space_;
+  to_space_ = tmp;
+}
+
+
+bool NewSpace::Double() {
+  ASSERT(capacity_ <= maximum_capacity_ / 2);
+  // TODO(1240712): Failure to double the from space can result in
+  // semispaces of different sizes.  In the event of that failure, the
+  // to space doubling should be rolled back before returning false.
+  if (!to_space_.Double() || !from_space_.Double()) return false;
+  capacity_ *= 2;
+  allocation_info_.limit = to_space_.high();
+  ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+  return true;
+}
+
+
+void NewSpace::ResetAllocationInfo() {
+  allocation_info_.top = to_space_.low();
+  allocation_info_.limit = to_space_.high();
+  ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+}
+
+
+void NewSpace::MCResetRelocationInfo() {
+  mc_forwarding_info_.top = from_space_.low();
+  mc_forwarding_info_.limit = from_space_.high();
+  ASSERT_SEMISPACE_ALLOCATION_INFO(mc_forwarding_info_, from_space_);
+}
+
+
+void NewSpace::MCCommitRelocationInfo() {
+  // Assumes that the spaces have been flipped so that mc_forwarding_info_ is
+  // valid allocation info for the to space.
+  allocation_info_.top = mc_forwarding_info_.top;
+  allocation_info_.limit = to_space_.high();
+  ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+}
+
+
+#ifdef DEBUG
+// We do not use the SemispaceIterator because verification doesn't assume
+// that it works (it depends on the invariants we are checking).
+void NewSpace::Verify() {
+  // The allocation pointer should be in the space or at the very end.
+  ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+
+  // There should be objects packed in from the low address up to the
+  // allocation pointer.
+  Address current = to_space_.low();
+  while (current < top()) {
+    HeapObject* object = HeapObject::FromAddress(current);
+
+    // The first word should be a map, and we expect all map pointers to
+    // be in map space.
+    Map* map = object->map();
+    ASSERT(map->IsMap());
+    ASSERT(Heap::map_space()->Contains(map));
+
+    // The object should not be code or a map.
+    ASSERT(!object->IsMap());
+    ASSERT(!object->IsCode());
+
+    // The object itself should look OK.
+    object->Verify();
+
+    // All the interior pointers should be contained in the heap.
+    VerifyPointersVisitor visitor;
+    int size = object->Size();
+    object->IterateBody(map->instance_type(), size, &visitor);
+
+    current += size;
+  }
+
+  // The allocation pointer should not be in the middle of an object.
+  ASSERT(current == top());
+}
+#endif
+
+
+// -----------------------------------------------------------------------------
+// SemiSpace implementation
+
+bool SemiSpace::Setup(Address start,
+                      int initial_capacity,
+                      int maximum_capacity) {
+  // Creates a space in the young generation. The constructor does not
+  // allocate memory from the OS.  A SemiSpace is given a contiguous chunk of
+  // memory of size 'capacity' when set up, and does not grow or shrink
+  // otherwise.  In the mark-compact collector, the memory region of the from
+  // space is used as the marking stack. It requires contiguous memory
+  // addresses.
+  capacity_ = initial_capacity;
+  maximum_capacity_ = maximum_capacity;
+
+  if (!MemoryAllocator::CommitBlock(start, capacity_, executable())) {
+    return false;
+  }
+
+  start_ = start;
+  address_mask_ = ~(maximum_capacity - 1);
+  object_mask_ = address_mask_ | kHeapObjectTag;
+  object_expected_ = reinterpret_cast<uint32_t>(start) | kHeapObjectTag;
+
+  age_mark_ = start_;
+  return true;
+}
+
+
+void SemiSpace::TearDown() {
+  start_ = NULL;
+  capacity_ = 0;
+}
+
+
+bool SemiSpace::Double() {
+  if (!MemoryAllocator::CommitBlock(high(), capacity_, executable())) {
+    return false;
+  }
+  capacity_ *= 2;
+  return true;
+}
+
+
+#ifdef DEBUG
+void SemiSpace::Print() { }
+
+
+void SemiSpace::Verify() { }
+#endif
+
+
+// -----------------------------------------------------------------------------
+// SemiSpaceIterator implementation.
+SemiSpaceIterator::SemiSpaceIterator(NewSpace* space) {
+  Initialize(space, space->bottom(), space->top(), NULL);
+}
+
+
+SemiSpaceIterator::SemiSpaceIterator(NewSpace* space,
+                                     HeapObjectCallback size_func) {
+  Initialize(space, space->bottom(), space->top(), size_func);
+}
+
+
+SemiSpaceIterator::SemiSpaceIterator(NewSpace* space, Address start) {
+  Initialize(space, start, space->top(), NULL);
+}
+
+
+void SemiSpaceIterator::Initialize(NewSpace* space, Address start,
+                                   Address end,
+                                   HeapObjectCallback size_func) {
+  ASSERT(space->ToSpaceContains(start));
+  ASSERT(space->ToSpaceLow() <= end
+         && end <= space->ToSpaceHigh());
+  space_ = &space->to_space_;
+  current_ = start;
+  limit_ = end;
+  size_func_ = size_func;
+}
+
+
+#ifdef DEBUG
+// A static array of histogram info for each type.
+static HistogramInfo heap_histograms[LAST_TYPE+1];
+static JSObject::SpillInformation js_spill_information;
+
+// heap_histograms is shared, always clear it before using it.
+static void ClearHistograms() {
+  // We reset the name each time, though it hasn't changed.
+#define DEF_TYPE_NAME(name) heap_histograms[name].set_name(#name);
+  INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
+#undef DEF_TYPE_NAME
+
+#define CLEAR_HISTOGRAM(name) heap_histograms[name].clear();
+  INSTANCE_TYPE_LIST(CLEAR_HISTOGRAM)
+#undef CLEAR_HISTOGRAM
+
+  js_spill_information.Clear();
+}
+
+
+static int code_kind_statistics[Code::NUMBER_OF_KINDS];
+
+
+static void ClearCodeKindStatistics() {
+  for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
+    code_kind_statistics[i] = 0;
+  }
+}
+
+
+static void ReportCodeKindStatistics() {
+  const char* table[Code::NUMBER_OF_KINDS];
+
+#define CASE(name)                            \
+  case Code::name: table[Code::name] = #name; \
+  break
+
+  for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
+    switch (static_cast<Code::Kind>(i)) {
+      CASE(FUNCTION);
+      CASE(STUB);
+      CASE(BUILTIN);
+      CASE(LOAD_IC);
+      CASE(KEYED_LOAD_IC);
+      CASE(STORE_IC);
+      CASE(KEYED_STORE_IC);
+      CASE(CALL_IC);
+    }
+  }
+
+#undef CASE
+
+  PrintF("\n   Code kind histograms: \n");
+  for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
+    if (code_kind_statistics[i] > 0) {
+      PrintF("     %-20s: %10d bytes\n", table[i], code_kind_statistics[i]);
+    }
+  }
+  PrintF("\n");
+}
+
+
+static int CollectHistogramInfo(HeapObject* obj) {
+  InstanceType type = obj->map()->instance_type();
+  ASSERT(0 <= type && type <= LAST_TYPE);
+  ASSERT(heap_histograms[type].name() != NULL);
+  heap_histograms[type].increment_number(1);
+  heap_histograms[type].increment_bytes(obj->Size());
+
+  if (FLAG_collect_heap_spill_statistics && obj->IsJSObject()) {
+    JSObject::cast(obj)->IncrementSpillStatistics(&js_spill_information);
+  }
+
+  return obj->Size();
+}
+
+
+static void ReportHistogram(bool print_spill) {
+  PrintF("\n  Object Histogram:\n");
+  for (int i = 0; i <= LAST_TYPE; i++) {
+    if (heap_histograms[i].number() > 0) {
+      PrintF("    %-33s%10d (%10d bytes)\n",
+             heap_histograms[i].name(),
+             heap_histograms[i].number(),
+             heap_histograms[i].bytes());
+    }
+  }
+  PrintF("\n");
+
+  // Summarize string types.
+  int string_number = 0;
+  int string_bytes = 0;
+#define INCREMENT(type, size, name)                  \
+    string_number += heap_histograms[type].number(); \
+    string_bytes += heap_histograms[type].bytes();
+  STRING_TYPE_LIST(INCREMENT)
+#undef INCREMENT
+  if (string_number > 0) {
+    PrintF("    %-33s%10d (%10d bytes)\n\n", "STRING_TYPE", string_number,
+           string_bytes);
+  }
+
+  if (FLAG_collect_heap_spill_statistics && print_spill) {
+    js_spill_information.Print();
+  }
+}
+#endif  // DEBUG
+
+
+// Support for statistics gathering for --heap-stats and --log-gc.
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+void NewSpace::ClearHistograms() {
+  for (int i = 0; i <= LAST_TYPE; i++) {
+    allocated_histogram_[i].clear();
+    promoted_histogram_[i].clear();
+  }
+}
+
+// Because the copying collector does not touch garbage objects, we iterate
+// the new space before a collection to get a histogram of allocated objects.
+// This only happens (1) when compiled with DEBUG and the --heap-stats flag is
+// set, or when compiled with ENABLE_LOGGING_AND_PROFILING and the --log-gc
+// flag is set.
+void NewSpace::CollectStatistics() {
+  ClearHistograms();
+  SemiSpaceIterator it(this);
+  while (it.has_next()) RecordAllocation(it.next());
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+static void DoReportStatistics(HistogramInfo* info, const char* description) {
+  LOG(HeapSampleBeginEvent("NewSpace", description));
+  // Lump all the string types together.
+  int string_number = 0;
+  int string_bytes = 0;
+#define INCREMENT(type, size, name)       \
+    string_number += info[type].number(); \
+    string_bytes += info[type].bytes();
+  STRING_TYPE_LIST(INCREMENT)
+#undef INCREMENT
+  if (string_number > 0) {
+    LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
+  }
+
+  // Then do the other types.
+  for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
+    if (info[i].number() > 0) {
+      LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
+                              info[i].bytes()));
+    }
+  }
+  LOG(HeapSampleEndEvent("NewSpace", description));
+}
+#endif  // ENABLE_LOGGING_AND_PROFILING
+
+
+void NewSpace::ReportStatistics() {
+#ifdef DEBUG
+  if (FLAG_heap_stats) {
+    float pct = static_cast<float>(Available()) / Capacity();
+    PrintF("  capacity: %d, available: %d, %%%d\n",
+           Capacity(), Available(), static_cast<int>(pct*100));
+    PrintF("\n  Object Histogram:\n");
+    for (int i = 0; i <= LAST_TYPE; i++) {
+      if (allocated_histogram_[i].number() > 0) {
+        PrintF("    %-33s%10d (%10d bytes)\n",
+               allocated_histogram_[i].name(),
+               allocated_histogram_[i].number(),
+               allocated_histogram_[i].bytes());
+      }
+    }
+    PrintF("\n");
+  }
+#endif  // DEBUG
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+  if (FLAG_log_gc) {
+    DoReportStatistics(allocated_histogram_, "allocated");
+    DoReportStatistics(promoted_histogram_, "promoted");
+  }
+#endif  // ENABLE_LOGGING_AND_PROFILING
+}
+
+
+void NewSpace::RecordAllocation(HeapObject* obj) {
+  InstanceType type = obj->map()->instance_type();
+  ASSERT(0 <= type && type <= LAST_TYPE);
+  allocated_histogram_[type].increment_number(1);
+  allocated_histogram_[type].increment_bytes(obj->Size());
+}
+
+
+void NewSpace::RecordPromotion(HeapObject* obj) {
+  InstanceType type = obj->map()->instance_type();
+  ASSERT(0 <= type && type <= LAST_TYPE);
+  promoted_histogram_[type].increment_number(1);
+  promoted_histogram_[type].increment_bytes(obj->Size());
+}
+#endif  // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+
+
+// -----------------------------------------------------------------------------
+// Free lists for old object spaces implementation
+
+void FreeListNode::set_size(int size_in_bytes) {
+  ASSERT(size_in_bytes > 0);
+  ASSERT(IsAligned(size_in_bytes, kPointerSize));
+
+  // We write a map and possibly size information to the block.  If the block
+  // is big enough to be a ByteArray with at least one extra word (the next
+  // pointer), we set its map to be the byte array map and its size to an
+  // appropriate array length for the desired size from HeapObject::Size().
+  // If the block is too small (eg, one or two words), to hold both a size
+  // field and a next pointer, we give it a filler map that gives it the
+  // correct size.
+  if (size_in_bytes > Array::kHeaderSize) {
+    set_map(Heap::byte_array_map());
+    ByteArray::cast(this)->set_length(ByteArray::LengthFor(size_in_bytes));
+  } else if (size_in_bytes == kPointerSize) {
+    set_map(Heap::one_word_filler_map());
+  } else if (size_in_bytes == 2 * kPointerSize) {
+    set_map(Heap::two_word_filler_map());
+  } else {
+    UNREACHABLE();
+  }
+  ASSERT(Size() == size_in_bytes);
+}
+
+
+Address FreeListNode::next() {
+  ASSERT(map() == Heap::byte_array_map());
+  ASSERT(Size() >= kNextOffset + kPointerSize);
+  return Memory::Address_at(address() + kNextOffset);
+}
+
+
+void FreeListNode::set_next(Address next) {
+  ASSERT(map() == Heap::byte_array_map());
+  ASSERT(Size() >= kNextOffset + kPointerSize);
+  Memory::Address_at(address() + kNextOffset) = next;
+}
+
+
+OldSpaceFreeList::OldSpaceFreeList(AllocationSpace owner) : owner_(owner) {
+  Reset();
+}
+
+
+void OldSpaceFreeList::Reset() {
+  available_ = 0;
+  for (int i = 0; i < kFreeListsLength; i++) {
+    free_[i].head_node_ = NULL;
+  }
+  needs_rebuild_ = false;
+  finger_ = kHead;
+  free_[kHead].next_size_ = kEnd;
+}
+
+
+void OldSpaceFreeList::RebuildSizeList() {
+  ASSERT(needs_rebuild_);
+  int cur = kHead;
+  for (int i = cur + 1; i < kFreeListsLength; i++) {
+    if (free_[i].head_node_ != NULL) {
+      free_[cur].next_size_ = i;
+      cur = i;
+    }
+  }
+  free_[cur].next_size_ = kEnd;
+  needs_rebuild_ = false;
+}
+
+
+int OldSpaceFreeList::Free(Address start, int size_in_bytes) {
+#ifdef DEBUG
+  for (int i = 0; i < size_in_bytes; i += kPointerSize) {
+    Memory::Address_at(start + i) = kZapValue;
+  }
+#endif
+  FreeListNode* node = FreeListNode::FromAddress(start);
+  node->set_size(size_in_bytes);
+
+  // Early return to drop too-small blocks on the floor (one or two word
+  // blocks cannot hold a map pointer, a size field, and a pointer to the
+  // next block in the free list).
+  if (size_in_bytes < kMinBlockSize) {
+    return size_in_bytes;
+  }
+
+  // Insert other blocks at the head of an exact free list.
+  int index = size_in_bytes >> kPointerSizeLog2;
+  node->set_next(free_[index].head_node_);
+  free_[index].head_node_ = node->address();
+  available_ += size_in_bytes;
+  needs_rebuild_ = true;
+  return 0;
+}
+
+
+Object* OldSpaceFreeList::Allocate(int size_in_bytes, int* wasted_bytes) {
+  ASSERT(0 < size_in_bytes);
+  ASSERT(size_in_bytes <= kMaxBlockSize);
+  ASSERT(IsAligned(size_in_bytes, kPointerSize));
+
+  if (needs_rebuild_) RebuildSizeList();
+  int index = size_in_bytes >> kPointerSizeLog2;
+  // Check for a perfect fit.
+  if (free_[index].head_node_ != NULL) {
+    FreeListNode* node = FreeListNode::FromAddress(free_[index].head_node_);
+    // If this was the last block of its size, remove the size.
+    if ((free_[index].head_node_ = node->next()) == NULL) RemoveSize(index);
+    available_ -= size_in_bytes;
+    *wasted_bytes = 0;
+    return node;
+  }
+  // Search the size list for the best fit.
+  int prev = finger_ < index ? finger_ : kHead;
+  int cur = FindSize(index, &prev);
+  ASSERT(index < cur);
+  if (cur == kEnd) {
+    // No large enough size in list.
+    *wasted_bytes = 0;
+    return Failure::RetryAfterGC(size_in_bytes, owner_);
+  }
+  int rem = cur - index;
+  int rem_bytes = rem << kPointerSizeLog2;
+  FreeListNode* cur_node = FreeListNode::FromAddress(free_[cur].head_node_);
+  ASSERT(cur_node->Size() == (cur << kPointerSizeLog2));
+  FreeListNode* rem_node = FreeListNode::FromAddress(free_[cur].head_node_ +
+                                                     size_in_bytes);
+  // Distinguish the cases prev < rem < cur and rem <= prev < cur
+  // to avoid many redundant tests and calls to Insert/RemoveSize.
+  if (prev < rem) {
+    // Simple case: insert rem between prev and cur.
+    finger_ = prev;
+    free_[prev].next_size_ = rem;
+    // If this was the last block of size cur, remove the size.
+    if ((free_[cur].head_node_ = cur_node->next()) == NULL) {
+      free_[rem].next_size_ = free_[cur].next_size_;
+    } else {
+      free_[rem].next_size_ = cur;
+    }
+    // Add the remainder block.
+    rem_node->set_size(rem_bytes);
+    rem_node->set_next(free_[rem].head_node_);
+    free_[rem].head_node_ = rem_node->address();
+  } else {
+    // If this was the last block of size cur, remove the size.
+    if ((free_[cur].head_node_ = cur_node->next()) == NULL) {
+      finger_ = prev;
+      free_[prev].next_size_ = free_[cur].next_size_;
+    }
+    if (rem_bytes < kMinBlockSize) {
+      // Too-small remainder is wasted.
+      rem_node->set_size(rem_bytes);
+      available_ -= size_in_bytes + rem_bytes;
+      *wasted_bytes = rem_bytes;
+      return cur_node;
+    }
+    // Add the remainder block and, if needed, insert its size.
+    rem_node->set_size(rem_bytes);
+    rem_node->set_next(free_[rem].head_node_);
+    free_[rem].head_node_ = rem_node->address();
+    if (rem_node->next() == NULL) InsertSize(rem);
+  }
+  available_ -= size_in_bytes;
+  *wasted_bytes = 0;
+  return cur_node;
+}
+
+
+#ifdef DEBUG
+bool OldSpaceFreeList::Contains(FreeListNode* node) {
+  for (int i = 0; i < kFreeListsLength; i++) {
+    Address cur_addr = free_[i].head_node_;
+    while (cur_addr != NULL) {
+      FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
+      if (cur_node == node) return true;
+      cur_addr = cur_node->next();
+    }
+  }
+  return false;
+}
+#endif
+
+
+MapSpaceFreeList::MapSpaceFreeList(AllocationSpace owner) {
+  owner_ = owner;
+  Reset();
+}
+
+
+void MapSpaceFreeList::Reset() {
+  available_ = 0;
+  head_ = NULL;
+}
+
+
+void MapSpaceFreeList::Free(Address start) {
+#ifdef DEBUG
+  for (int i = 0; i < Map::kSize; i += kPointerSize) {
+    Memory::Address_at(start + i) = kZapValue;
+  }
+#endif
+  FreeListNode* node = FreeListNode::FromAddress(start);
+  node->set_size(Map::kSize);
+  node->set_next(head_);
+  head_ = node->address();
+  available_ += Map::kSize;
+}
+
+
+Object* MapSpaceFreeList::Allocate() {
+  if (head_ == NULL) {
+    return Failure::RetryAfterGC(Map::kSize, owner_);
+  }
+
+  FreeListNode* node = FreeListNode::FromAddress(head_);
+  head_ = node->next();
+  available_ -= Map::kSize;
+  return node;
+}
+
+
+// -----------------------------------------------------------------------------
+// OldSpace implementation
+
+void OldSpace::PrepareForMarkCompact(bool will_compact) {
+  if (will_compact) {
+    // Reset relocation info.  During a compacting collection, everything in
+    // the space is considered 'available' and we will rediscover live data
+    // and waste during the collection.
+    MCResetRelocationInfo();
+    mc_end_of_relocation_ = bottom();
+    ASSERT(Available() == Capacity());
+  } else {
+    // During a non-compacting collection, everything below the linear
+    // allocation pointer is considered allocated (everything above is
+    // available) and we will rediscover available and wasted bytes during
+    // the collection.
+    accounting_stats_.AllocateBytes(free_list_.available());
+    accounting_stats_.FillWastedBytes(Waste());
+  }
+
+  // Clear the free list before a full GC---it will be rebuilt afterward.
+  free_list_.Reset();
+}
+
+
+void OldSpace::MCAdjustRelocationEnd(Address address, int size_in_bytes) {
+  ASSERT(Contains(address));
+  Address current_top = mc_end_of_relocation_;
+  Page* current_page = Page::FromAllocationTop(current_top);
+
+  // No more objects relocated to this page?  Move to the next.
+  ASSERT(current_top <= current_page->mc_relocation_top);
+  if (current_top == current_page->mc_relocation_top) {
+    // The space should already be properly expanded.
+    Page* next_page = current_page->next_page();
+    CHECK(next_page->is_valid());
+    mc_end_of_relocation_ = next_page->ObjectAreaStart();
+  }
+  ASSERT(mc_end_of_relocation_ == address);
+  mc_end_of_relocation_ += size_in_bytes;
+}
+
+
+void OldSpace::MCCommitRelocationInfo() {
+  // Update fast allocation info.
+  allocation_info_.top = mc_forwarding_info_.top;
+  allocation_info_.limit = mc_forwarding_info_.limit;
+  ASSERT(allocation_info_.VerifyPagedAllocation());
+
+  // The space is compacted and we haven't yet built free lists or
+  // wasted any space.
+  ASSERT(Waste() == 0);
+  ASSERT(AvailableFree() == 0);
+
+  // Build the free list for the space.
+  int computed_size = 0;
+  PageIterator it(this, PageIterator::PAGES_USED_BY_MC);
+  while (it.has_next()) {
+    Page* p = it.next();
+    // Space below the relocation pointer is allocated.
+    computed_size += p->mc_relocation_top - p->ObjectAreaStart();
+    if (it.has_next()) {
+      // Free the space at the top of the page.  We cannot use
+      // p->mc_relocation_top after the call to Free (because Free will clear
+      // remembered set bits).
+      int extra_size = p->ObjectAreaEnd() - p->mc_relocation_top;
+      if (extra_size > 0) {
+        int wasted_bytes = free_list_.Free(p->mc_relocation_top, extra_size);
+        // The bytes we have just "freed" to add to the free list were
+        // already accounted as available.
+        accounting_stats_.WasteBytes(wasted_bytes);
+      }
+    }
+  }
+
+  // Make sure the computed size - based on the used portion of the pages in
+  // use - matches the size obtained while computing forwarding addresses.
+  ASSERT(computed_size == Size());
+}
+
+
+// Slow case for normal allocation.  Try in order: (1) allocate in the next
+// page in the space, (2) allocate off the space's free list, (3) expand the
+// space, (4) fail.
+HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) {
+  // Linear allocation in this space has failed.  If there is another page
+  // in the space, move to that page and allocate there.  This allocation
+  // should succeed (size_in_bytes should not be greater than a page's
+  // object area size).
+  Page* current_page = TopPageOf(allocation_info_);
+  if (current_page->next_page()->is_valid()) {
+    return AllocateInNextPage(current_page, size_in_bytes);
+  }
+
+  // There is no next page in this space.  Try free list allocation.
+  int wasted_bytes;
+  Object* result = free_list_.Allocate(size_in_bytes, &wasted_bytes);
+  accounting_stats_.WasteBytes(wasted_bytes);
+  if (!result->IsFailure()) {
+    accounting_stats_.AllocateBytes(size_in_bytes);
+    return HeapObject::cast(result);
+  }
+
+  // Free list allocation failed and there is no next page.  Try to expand
+  // the space and allocate in the new next page.
+  ASSERT(!current_page->next_page()->is_valid());
+  if (Expand(current_page)) {
+    return AllocateInNextPage(current_page, size_in_bytes);
+  }
+
+  // Finally, fail.
+  return NULL;
+}
+
+
+// Add the block at the top of the page to the space's free list, set the
+// allocation info to the next page (assumed to be one), and allocate
+// linearly there.
+HeapObject* OldSpace::AllocateInNextPage(Page* current_page,
+                                         int size_in_bytes) {
+  ASSERT(current_page->next_page()->is_valid());
+  // Add the block at the top of this page to the free list.
+  int free_size = current_page->ObjectAreaEnd() - allocation_info_.top;
+  if (free_size > 0) {
+    int wasted_bytes = free_list_.Free(allocation_info_.top, free_size);
+    accounting_stats_.WasteBytes(wasted_bytes);
+  }
+  SetAllocationInfo(&allocation_info_, current_page->next_page());
+  return AllocateLinearly(&allocation_info_, size_in_bytes);
+}
+
+
+#ifdef DEBUG
+// We do not assume that the PageIterator works, because it depends on the
+// invariants we are checking during verification.
+void OldSpace::Verify() {
+  // The allocation pointer should be valid, and it should be in a page in the
+  // space.
+  ASSERT(allocation_info_.VerifyPagedAllocation());
+  Page* top_page = Page::FromAllocationTop(allocation_info_.top);
+  ASSERT(MemoryAllocator::IsPageInSpace(top_page, this));
+
+  // Loop over all the pages.
+  bool above_allocation_top = false;
+  Page* current_page = first_page_;
+  while (current_page->is_valid()) {
+    if (above_allocation_top) {
+      // We don't care what's above the allocation top.
+    } else {
+      // Unless this is the last page in the space containing allocated
+      // objects, the allocation top should be at the object area end.
+      Address top = current_page->AllocationTop();
+      if (current_page == top_page) {
+        ASSERT(top == allocation_info_.top);
+        // The next page will be above the allocation top.
+        above_allocation_top = true;
+      } else {
+        ASSERT(top == current_page->ObjectAreaEnd());
+      }
+
+      // It should be packed with objects from the bottom to the top.
+      Address current = current_page->ObjectAreaStart();
+      while (current < top) {
+        HeapObject* object = HeapObject::FromAddress(current);
+
+        // The first word should be a map, and we expect all map pointers to
+        // be in map space.
+        Map* map = object->map();
+        ASSERT(map->IsMap());
+        ASSERT(Heap::map_space()->Contains(map));
+
+        // The object should not be a map.
+        ASSERT(!object->IsMap());
+
+        // The object itself should look OK.
+        object->Verify();
+
+        // All the interior pointers should be contained in the heap and have
+        // their remembered set bits set if they point to new space.  Code
+        // objects do not have remembered set bits that we care about.
+        VerifyPointersAndRSetVisitor rset_visitor;
+        VerifyPointersVisitor no_rset_visitor;
+        int size = object->Size();
+        if (object->IsCode()) {
+          Code::cast(object)->ConvertICTargetsFromAddressToObject();
+          object->IterateBody(map->instance_type(), size, &no_rset_visitor);
+          Code::cast(object)->ConvertICTargetsFromObjectToAddress();
+        } else {
+          object->IterateBody(map->instance_type(), size, &rset_visitor);
+        }
+
+        current += size;
+      }
+
+      // The allocation pointer should not be in the middle of an object.
+      ASSERT(current == top);
+    }
+
+    current_page = current_page->next_page();
+  }
+}
+
+
+struct CommentStatistic {
+  const char* comment;
+  int size;
+  int count;
+  void Clear() {
+    comment = NULL;
+    size = 0;
+    count = 0;
+  }
+};
+
+
+// must be small, since an iteration is used for lookup
+const int kMaxComments = 64;
+static CommentStatistic comments_statistics[kMaxComments+1];
+
+
+void PagedSpace::ReportCodeStatistics() {
+  ReportCodeKindStatistics();
+  PrintF("Code comment statistics (\"   [ comment-txt   :    size/   "
+         "count  (average)\"):\n");
+  for (int i = 0; i <= kMaxComments; i++) {
+    const CommentStatistic& cs = comments_statistics[i];
+    if (cs.size > 0) {
+      PrintF("   %-30s: %10d/%6d     (%d)\n", cs.comment, cs.size, cs.count,
+             cs.size/cs.count);
+    }
+  }
+  PrintF("\n");
+}
+
+
+void PagedSpace::ResetCodeStatistics() {
+  ClearCodeKindStatistics();
+  for (int i = 0; i < kMaxComments; i++) comments_statistics[i].Clear();
+  comments_statistics[kMaxComments].comment = "Unknown";
+  comments_statistics[kMaxComments].size = 0;
+  comments_statistics[kMaxComments].count = 0;
+}
+
+
+// Adds comment to 'comment_statistics' table. Performance OK sa long as
+// 'kMaxComments' is small
+static void EnterComment(const char* comment, int delta) {
+  // Do not count empty comments
+  if (delta <= 0) return;
+  CommentStatistic* cs = &comments_statistics[kMaxComments];
+  // Search for a free or matching entry in 'comments_statistics': 'cs'
+  // points to result.
+  for (int i = 0; i < kMaxComments; i++) {
+    if (comments_statistics[i].comment == NULL) {
+      cs = &comments_statistics[i];
+      cs->comment = comment;
+      break;
+    } else if (strcmp(comments_statistics[i].comment, comment) == 0) {
+      cs = &comments_statistics[i];
+      break;
+    }
+  }
+  // Update entry for 'comment'
+  cs->size += delta;
+  cs->count += 1;
+}
+
+
+// Call for each nested comment start (start marked with '[ xxx', end marked
+// with ']'.  RelocIterator 'it' must point to a comment reloc info.
+static void CollectCommentStatistics(RelocIterator* it) {
+  ASSERT(!it->done());
+  ASSERT(it->rinfo()->rmode() == RelocInfo::COMMENT);
+  const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data());
+  if (tmp[0] != '[') {
+    // Not a nested comment; skip
+    return;
+  }
+
+  // Search for end of nested comment or a new nested comment
+  const char* const comment_txt =
+      reinterpret_cast<const char*>(it->rinfo()->data());
+  const byte* prev_pc = it->rinfo()->pc();
+  int flat_delta = 0;
+  it->next();
+  while (true) {
+    // All nested comments must be terminated properly, and therefore exit
+    // from loop.
+    ASSERT(!it->done());
+    if (it->rinfo()->rmode() == RelocInfo::COMMENT) {
+      const char* const txt =
+          reinterpret_cast<const char*>(it->rinfo()->data());
+      flat_delta += it->rinfo()->pc() - prev_pc;
+      if (txt[0] == ']') break;  // End of nested  comment
+      // A new comment
+      CollectCommentStatistics(it);
+      // Skip code that was covered with previous comment
+      prev_pc = it->rinfo()->pc();
+    }
+    it->next();
+  }
+  EnterComment(comment_txt, flat_delta);
+}
+
+
+// Collects code size statistics:
+// - by code kind
+// - by code comment
+void PagedSpace::CollectCodeStatistics() {
+  HeapObjectIterator obj_it(this);
+  while (obj_it.has_next()) {
+    HeapObject* obj = obj_it.next();
+    if (obj->IsCode()) {
+      Code* code = Code::cast(obj);
+      code_kind_statistics[code->kind()] += code->Size();
+      RelocIterator it(code);
+      int delta = 0;
+      const byte* prev_pc = code->instruction_start();
+      while (!it.done()) {
+        if (it.rinfo()->rmode() == RelocInfo::COMMENT) {
+          delta += it.rinfo()->pc() - prev_pc;
+          CollectCommentStatistics(&it);
+          prev_pc = it.rinfo()->pc();
+        }
+        it.next();
+      }
+
+      ASSERT(code->instruction_start() <= prev_pc &&
+             prev_pc <= code->relocation_start());
+      delta += code->relocation_start() - prev_pc;
+      EnterComment("NoComment", delta);
+    }
+  }
+}
+
+
+void OldSpace::ReportStatistics() {
+  int pct = Available() * 100 / Capacity();
+  PrintF("  capacity: %d, waste: %d, available: %d, %%%d\n",
+         Capacity(), Waste(), Available(), pct);
+
+  // Report remembered set statistics.
+  int rset_marked_pointers = 0;
+  int rset_marked_arrays = 0;
+  int rset_marked_array_elements = 0;
+  int cross_gen_pointers = 0;
+  int cross_gen_array_elements = 0;
+
+  PageIterator page_it(this, PageIterator::PAGES_IN_USE);
+  while (page_it.has_next()) {
+    Page* p = page_it.next();
+
+    for (Address rset_addr = p->RSetStart();
+         rset_addr < p->RSetEnd();
+         rset_addr += kIntSize) {
+      int rset = Memory::int_at(rset_addr);
+      if (rset != 0) {
+        // Bits were set
+        int intoff = rset_addr - p->address();
+        int bitoff = 0;
+        for (; bitoff < kBitsPerInt; ++bitoff) {
+          if ((rset & (1 << bitoff)) != 0) {
+            int bitpos = intoff*kBitsPerByte + bitoff;
+            Address slot = p->OffsetToAddress(bitpos << kObjectAlignmentBits);
+            Object** obj = reinterpret_cast<Object**>(slot);
+            if (*obj == Heap::fixed_array_map()) {
+              rset_marked_arrays++;
+              FixedArray* fa = FixedArray::cast(HeapObject::FromAddress(slot));
+
+              rset_marked_array_elements += fa->length();
+              // Manually inline FixedArray::IterateBody
+              Address elm_start = slot + FixedArray::kHeaderSize;
+              Address elm_stop = elm_start + fa->length() * kPointerSize;
+              for (Address elm_addr = elm_start;
+                   elm_addr < elm_stop; elm_addr += kPointerSize) {
+                // Filter non-heap-object pointers
+                Object** elm_p = reinterpret_cast<Object**>(elm_addr);
+                if (Heap::InNewSpace(*elm_p))
+                  cross_gen_array_elements++;
+              }
+            } else {
+              rset_marked_pointers++;
+              if (Heap::InNewSpace(*obj))
+                cross_gen_pointers++;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  pct = rset_marked_pointers == 0 ?
+        0 : cross_gen_pointers * 100 / rset_marked_pointers;
+  PrintF("  rset-marked pointers %d, to-new-space %d (%%%d)\n",
+            rset_marked_pointers, cross_gen_pointers, pct);
+  PrintF("  rset_marked arrays %d, ", rset_marked_arrays);
+  PrintF("  elements %d, ", rset_marked_array_elements);
+  pct = rset_marked_array_elements == 0 ? 0
+           : cross_gen_array_elements * 100 / rset_marked_array_elements;
+  PrintF("  pointers to new space %d (%%%d)\n", cross_gen_array_elements, pct);
+  PrintF("  total rset-marked bits %d\n",
+            (rset_marked_pointers + rset_marked_arrays));
+  pct = (rset_marked_pointers + rset_marked_array_elements) == 0 ? 0
+        : (cross_gen_pointers + cross_gen_array_elements) * 100 /
+          (rset_marked_pointers + rset_marked_array_elements);
+  PrintF("  total rset pointers %d, true cross generation ones %d (%%%d)\n",
+         (rset_marked_pointers + rset_marked_array_elements),
+         (cross_gen_pointers + cross_gen_array_elements),
+         pct);
+
+  ClearHistograms();
+  HeapObjectIterator obj_it(this);
+  while (obj_it.has_next()) { CollectHistogramInfo(obj_it.next()); }
+  ReportHistogram(true);
+}
+
+
+// Dump the range of remembered set words between [start, end) corresponding
+// to the pointers starting at object_p.  The allocation_top is an object
+// pointer which should not be read past.  This is important for large object
+// pages, where some bits in the remembered set range do not correspond to
+// allocated addresses.
+static void PrintRSetRange(Address start, Address end, Object** object_p,
+                           Address allocation_top) {
+  Address rset_address = start;
+
+  // If the range starts on on odd numbered word (eg, for large object extra
+  // remembered set ranges), print some spaces.
+  if ((reinterpret_cast<uint32_t>(start) / kIntSize) % 2 == 1) {
+    PrintF("                                    ");
+  }
+
+  // Loop over all the words in the range.
+  while (rset_address < end) {
+    uint32_t rset_word = Memory::uint32_at(rset_address);
+    int bit_position = 0;
+
+    // Loop over all the bits in the word.
+    while (bit_position < kBitsPerInt) {
+      if (object_p == reinterpret_cast<Object**>(allocation_top)) {
+        // Print a bar at the allocation pointer.
+        PrintF("|");
+      } else if (object_p > reinterpret_cast<Object**>(allocation_top)) {
+        // Do not dereference object_p past the allocation pointer.
+        PrintF("#");
+      } else if ((rset_word & (1 << bit_position)) == 0) {
+        // Print a dot for zero bits.
+        PrintF(".");
+      } else if (Heap::InNewSpace(*object_p)) {
+        // Print an X for one bits for pointers to new space.
+        PrintF("X");
+      } else {
+        // Print a circle for one bits for pointers to old space.
+        PrintF("o");
+      }
+
+      // Print a space after every 8th bit except the last.
+      if (bit_position % 8 == 7 && bit_position != (kBitsPerInt - 1)) {
+        PrintF(" ");
+      }
+
+      // Advance to next bit.
+      bit_position++;
+      object_p++;
+    }
+
+    // Print a newline after every odd numbered word, otherwise a space.
+    if ((reinterpret_cast<uint32_t>(rset_address) / kIntSize) % 2 == 1) {
+      PrintF("\n");
+    } else {
+      PrintF(" ");
+    }
+
+    // Advance to next remembered set word.
+    rset_address += kIntSize;
+  }
+}
+
+
+void PagedSpace::DoPrintRSet(const char* space_name) {
+  PageIterator it(this, PageIterator::PAGES_IN_USE);
+  while (it.has_next()) {
+    Page* p = it.next();
+    PrintF("%s page 0x%x:\n", space_name, p);
+    PrintRSetRange(p->RSetStart(), p->RSetEnd(),
+                   reinterpret_cast<Object**>(p->ObjectAreaStart()),
+                   p->AllocationTop());
+    PrintF("\n");
+  }
+}
+
+
+void OldSpace::PrintRSet() { DoPrintRSet("old"); }
+#endif
+
+// -----------------------------------------------------------------------------
+// MapSpace implementation
+
+void MapSpace::PrepareForMarkCompact(bool will_compact) {
+  if (will_compact) {
+    // Reset relocation info.
+    MCResetRelocationInfo();
+
+    // Initialize map index entry.
+    int page_count = 0;
+    PageIterator it(this, PageIterator::ALL_PAGES);
+    while (it.has_next()) {
+      ASSERT_MAP_PAGE_INDEX(page_count);
+
+      Page* p = it.next();
+      ASSERT(p->mc_page_index == page_count);
+
+      page_addresses_[page_count++] = p->address();
+    }
+
+    // During a compacting collection, everything in the space is considered
+    // 'available' (set by the call to MCResetRelocationInfo) and we will
+    // rediscover live and wasted bytes during the collection.
+    ASSERT(Available() == Capacity());
+  } else {
+    // During a non-compacting collection, everything below the linear
+    // allocation pointer except wasted top-of-page blocks is considered
+    // allocated and we will rediscover available bytes during the
+    // collection.
+    accounting_stats_.AllocateBytes(free_list_.available());
+  }
+
+  // Clear the free list before a full GC---it will be rebuilt afterward.
+  free_list_.Reset();
+}
+
+
+void MapSpace::MCCommitRelocationInfo() {
+  // Update fast allocation info.
+  allocation_info_.top = mc_forwarding_info_.top;
+  allocation_info_.limit = mc_forwarding_info_.limit;
+  ASSERT(allocation_info_.VerifyPagedAllocation());
+
+  // The space is compacted and we haven't yet wasted any space.
+  ASSERT(Waste() == 0);
+
+  // Update allocation_top of each page in use and compute waste.
+  int computed_size = 0;
+  PageIterator it(this, PageIterator::PAGES_USED_BY_MC);
+  while (it.has_next()) {
+    Page* page = it.next();
+    Address page_top = page->AllocationTop();
+    computed_size += page_top - page->ObjectAreaStart();
+    if (it.has_next()) {
+      accounting_stats_.WasteBytes(page->ObjectAreaEnd() - page_top);
+    }
+  }
+
+  // Make sure the computed size - based on the used portion of the
+  // pages in use - matches the size we adjust during allocation.
+  ASSERT(computed_size == Size());
+}
+
+
+// Slow case for normal allocation. Try in order: (1) allocate in the next
+// page in the space, (2) allocate off the space's free list, (3) expand the
+// space, (4) fail.
+HeapObject* MapSpace::SlowAllocateRaw(int size_in_bytes) {
+  // Linear allocation in this space has failed.  If there is another page
+  // in the space, move to that page and allocate there.  This allocation
+  // should succeed.
+  Page* current_page = TopPageOf(allocation_info_);
+  if (current_page->next_page()->is_valid()) {
+    return AllocateInNextPage(current_page, size_in_bytes);
+  }
+
+  // There is no next page in this space.  Try free list allocation.  The
+  // map space free list implicitly assumes that all free blocks are map
+  // sized.
+  if (size_in_bytes == Map::kSize) {
+    Object* result = free_list_.Allocate();
+    if (!result->IsFailure()) {
+      accounting_stats_.AllocateBytes(size_in_bytes);
+      return HeapObject::cast(result);
+    }
+  }
+
+  // Free list allocation failed and there is no next page.  Try to expand
+  // the space and allocate in the new next page.
+  ASSERT(!current_page->next_page()->is_valid());
+  if (Expand(current_page)) {
+    return AllocateInNextPage(current_page, size_in_bytes);
+  }
+
+  // Finally, fail.
+  return NULL;
+}
+
+
+// Move to the next page (there is assumed to be one) and allocate there.
+// The top of page block is always wasted, because it is too small to hold a
+// map.
+HeapObject* MapSpace::AllocateInNextPage(Page* current_page,
+                                         int size_in_bytes) {
+  ASSERT(current_page->next_page()->is_valid());
+  ASSERT(current_page->ObjectAreaEnd() - allocation_info_.top == kPageExtra);
+  accounting_stats_.WasteBytes(kPageExtra);
+  SetAllocationInfo(&allocation_info_, current_page->next_page());
+  return AllocateLinearly(&allocation_info_, size_in_bytes);
+}
+
+
+#ifdef DEBUG
+// We do not assume that the PageIterator works, because it depends on the
+// invariants we are checking during verification.
+void MapSpace::Verify() {
+  // The allocation pointer should be valid, and it should be in a page in the
+  // space.
+  ASSERT(allocation_info_.VerifyPagedAllocation());
+  Page* top_page = Page::FromAllocationTop(allocation_info_.top);
+  ASSERT(MemoryAllocator::IsPageInSpace(top_page, this));
+
+  // Loop over all the pages.
+  bool above_allocation_top = false;
+  Page* current_page = first_page_;
+  while (current_page->is_valid()) {
+    if (above_allocation_top) {
+      // We don't care what's above the allocation top.
+    } else {
+      // Unless this is the last page in the space containing allocated
+      // objects, the allocation top should be at a constant offset from the
+      // object area end.
+      Address top = current_page->AllocationTop();
+      if (current_page == top_page) {
+        ASSERT(top == allocation_info_.top);
+        // The next page will be above the allocation top.
+        above_allocation_top = true;
+      } else {
+        ASSERT(top == current_page->ObjectAreaEnd() - kPageExtra);
+      }
+
+      // It should be packed with objects from the bottom to the top.
+      Address current = current_page->ObjectAreaStart();
+      while (current < top) {
+        HeapObject* object = HeapObject::FromAddress(current);
+
+        // The first word should be a map, and we expect all map pointers to
+        // be in map space.
+        Map* map = object->map();
+        ASSERT(map->IsMap());
+        ASSERT(Heap::map_space()->Contains(map));
+
+        // The object should be a map or a byte array.
+        ASSERT(object->IsMap() || object->IsByteArray());
+
+        // The object itself should look OK.
+        object->Verify();
+
+        // All the interior pointers should be contained in the heap and
+        // have their remembered set bits set if they point to new space.
+        VerifyPointersAndRSetVisitor visitor;
+        int size = object->Size();
+        object->IterateBody(map->instance_type(), size, &visitor);
+
+        current += size;
+      }
+
+      // The allocation pointer should not be in the middle of an object.
+      ASSERT(current == top);
+    }
+
+    current_page = current_page->next_page();
+  }
+}
+
+
+void MapSpace::ReportStatistics() {
+  int pct = Available() * 100 / Capacity();
+  PrintF("  capacity: %d, waste: %d, available: %d, %%%d\n",
+         Capacity(), Waste(), Available(), pct);
+
+  // Report remembered set statistics.
+  int rset_marked_pointers = 0;
+  int cross_gen_pointers = 0;
+
+  PageIterator page_it(this, PageIterator::PAGES_IN_USE);
+  while (page_it.has_next()) {
+    Page* p = page_it.next();
+
+    for (Address rset_addr = p->RSetStart();
+         rset_addr < p->RSetEnd();
+         rset_addr += kIntSize) {
+      int rset = Memory::int_at(rset_addr);
+      if (rset != 0) {
+        // Bits were set
+        int intoff = rset_addr - p->address();
+        int bitoff = 0;
+        for (; bitoff < kBitsPerInt; ++bitoff) {
+          if ((rset & (1 << bitoff)) != 0) {
+            int bitpos = intoff*kBitsPerByte + bitoff;
+            Address slot = p->OffsetToAddress(bitpos << kObjectAlignmentBits);
+            Object** obj = reinterpret_cast<Object**>(slot);
+            rset_marked_pointers++;
+            if (Heap::InNewSpace(*obj))
+              cross_gen_pointers++;
+          }
+        }
+      }
+    }
+  }
+
+  pct = rset_marked_pointers == 0 ?
+          0 : cross_gen_pointers * 100 / rset_marked_pointers;
+  PrintF("  rset-marked pointers %d, to-new-space %d (%%%d)\n",
+            rset_marked_pointers, cross_gen_pointers, pct);
+
+  ClearHistograms();
+  HeapObjectIterator obj_it(this);
+  while (obj_it.has_next()) { CollectHistogramInfo(obj_it.next()); }
+  ReportHistogram(false);
+}
+
+
+void MapSpace::PrintRSet() { DoPrintRSet("map"); }
+#endif
+
+
+// -----------------------------------------------------------------------------
+// LargeObjectIterator
+
+LargeObjectIterator::LargeObjectIterator(LargeObjectSpace* space) {
+  current_ = space->first_chunk_;
+  size_func_ = NULL;
+}
+
+
+LargeObjectIterator::LargeObjectIterator(LargeObjectSpace* space,
+                                         HeapObjectCallback size_func) {
+  current_ = space->first_chunk_;
+  size_func_ = size_func;
+}
+
+
+HeapObject* LargeObjectIterator::next() {
+  ASSERT(has_next());
+  HeapObject* object = current_->GetObject();
+  current_ = current_->next();
+  return object;
+}
+
+
+// -----------------------------------------------------------------------------
+// LargeObjectChunk
+
+LargeObjectChunk* LargeObjectChunk::New(int size_in_bytes,
+                                        size_t* chunk_size,
+                                        Executability executable) {
+  size_t requested = ChunkSizeFor(size_in_bytes);
+  void* mem = MemoryAllocator::AllocateRawMemory(requested,
+                                                 chunk_size,
+                                                 executable);
+  if (mem == NULL) return NULL;
+  LOG(NewEvent("LargeObjectChunk", mem, *chunk_size));
+  if (*chunk_size < requested) {
+    MemoryAllocator::FreeRawMemory(mem, *chunk_size);
+    LOG(DeleteEvent("LargeObjectChunk", mem));
+    return NULL;
+  }
+  return reinterpret_cast<LargeObjectChunk*>(mem);
+}
+
+
+int LargeObjectChunk::ChunkSizeFor(int size_in_bytes) {
+  int os_alignment = OS::AllocateAlignment();
+  if (os_alignment < Page::kPageSize)
+    size_in_bytes += (Page::kPageSize - os_alignment);
+  return size_in_bytes + Page::kObjectStartOffset;
+}
+
+// -----------------------------------------------------------------------------
+// LargeObjectSpace
+
+LargeObjectSpace::LargeObjectSpace(AllocationSpace id)
+    : Space(id, NOT_EXECUTABLE),  // Managed on a per-allocation basis
+      first_chunk_(NULL),
+      size_(0),
+      page_count_(0) {}
+
+
+bool LargeObjectSpace::Setup() {
+  first_chunk_ = NULL;
+  size_ = 0;
+  page_count_ = 0;
+  return true;
+}
+
+
+void LargeObjectSpace::TearDown() {
+  while (first_chunk_ != NULL) {
+    LargeObjectChunk* chunk = first_chunk_;
+    first_chunk_ = first_chunk_->next();
+    LOG(DeleteEvent("LargeObjectChunk", chunk->address()));
+    MemoryAllocator::FreeRawMemory(chunk->address(), chunk->size());
+  }
+
+  size_ = 0;
+  page_count_ = 0;
+}
+
+
+Object* LargeObjectSpace::AllocateRawInternal(int requested_size,
+                                              int object_size,
+                                              Executability executable) {
+  ASSERT(0 < object_size && object_size <= requested_size);
+  size_t chunk_size;
+  LargeObjectChunk* chunk =
+      LargeObjectChunk::New(requested_size, &chunk_size, executable);
+  if (chunk == NULL) {
+    return Failure::RetryAfterGC(requested_size, identity());
+  }
+
+  size_ += chunk_size;
+  page_count_++;
+  chunk->set_next(first_chunk_);
+  chunk->set_size(chunk_size);
+  first_chunk_ = chunk;
+
+  // Set the object address and size in the page header and clear its
+  // remembered set.
+  Page* page = Page::FromAddress(RoundUp(chunk->address(), Page::kPageSize));
+  Address object_address = page->ObjectAreaStart();
+  // Clear the low order bit of the second word in the page to flag it as a
+  // large object page.  If the chunk_size happened to be written there, its
+  // low order bit should already be clear.
+  ASSERT((chunk_size & 0x1) == 0);
+  page->is_normal_page &= ~0x1;
+  page->ClearRSet();
+  int extra_bytes = requested_size - object_size;
+  if (extra_bytes > 0) {
+    // The extra memory for the remembered set should be cleared.
+    memset(object_address + object_size, 0, extra_bytes);
+  }
+
+  return HeapObject::FromAddress(object_address);
+}
+
+
+Object* LargeObjectSpace::AllocateRawCode(int size_in_bytes) {
+  ASSERT(0 < size_in_bytes);
+  return AllocateRawInternal(size_in_bytes,
+                             size_in_bytes,
+                             EXECUTABLE);
+}
+
+
+Object* LargeObjectSpace::AllocateRawFixedArray(int size_in_bytes) {
+  ASSERT(0 < size_in_bytes);
+  int extra_rset_bytes = ExtraRSetBytesFor(size_in_bytes);
+  return AllocateRawInternal(size_in_bytes + extra_rset_bytes,
+                             size_in_bytes,
+                             NOT_EXECUTABLE);
+}
+
+
+Object* LargeObjectSpace::AllocateRaw(int size_in_bytes) {
+  ASSERT(0 < size_in_bytes);
+  return AllocateRawInternal(size_in_bytes,
+                             size_in_bytes,
+                             NOT_EXECUTABLE);
+}
+
+
+// GC support
+Object* LargeObjectSpace::FindObject(Address a) {
+  for (LargeObjectChunk* chunk = first_chunk_;
+       chunk != NULL;
+       chunk = chunk->next()) {
+    Address chunk_address = chunk->address();
+    if (chunk_address <= a && a < chunk_address + chunk->size()) {
+      return chunk->GetObject();
+    }
+  }
+  return Failure::Exception();
+}
+
+
+void LargeObjectSpace::ClearRSet() {
+  ASSERT(Page::is_rset_in_use());
+
+  LargeObjectIterator it(this);
+  while (it.has_next()) {
+    HeapObject* object = it.next();
+    // We only have code, sequential strings, or fixed arrays in large
+    // object space, and only fixed arrays need remembered set support.
+    if (object->IsFixedArray()) {
+      // Clear the normal remembered set region of the page;
+      Page* page = Page::FromAddress(object->address());
+      page->ClearRSet();
+
+      // Clear the extra remembered set.
+      int size = object->Size();
+      int extra_rset_bytes = ExtraRSetBytesFor(size);
+      memset(object->address() + size, 0, extra_rset_bytes);
+    }
+  }
+}
+
+
+void LargeObjectSpace::IterateRSet(ObjectSlotCallback copy_object_func) {
+  ASSERT(Page::is_rset_in_use());
+
+  LargeObjectIterator it(this);
+  while (it.has_next()) {
+    // We only have code, sequential strings, or fixed arrays in large
+    // object space, and only fixed arrays can possibly contain pointers to
+    // the young generation.
+    HeapObject* object = it.next();
+    if (object->IsFixedArray()) {
+      // Iterate the normal page remembered set range.
+      Page* page = Page::FromAddress(object->address());
+      Address object_end = object->address() + object->Size();
+      Heap::IterateRSetRange(page->ObjectAreaStart(),
+                             Min(page->ObjectAreaEnd(), object_end),
+                             page->RSetStart(),
+                             copy_object_func);
+
+      // Iterate the extra array elements.
+      if (object_end > page->ObjectAreaEnd()) {
+        Heap::IterateRSetRange(page->ObjectAreaEnd(), object_end,
+                               object_end, copy_object_func);
+      }
+    }
+  }
+}
+
+
+void LargeObjectSpace::FreeUnmarkedObjects() {
+  LargeObjectChunk* previous = NULL;
+  LargeObjectChunk* current = first_chunk_;
+  while (current != NULL) {
+    HeapObject* object = current->GetObject();
+    if (object->IsMarked()) {
+      object->ClearMark();
+      MarkCompactCollector::tracer()->decrement_marked_count();
+      previous = current;
+      current = current->next();
+    } else {
+      Address chunk_address = current->address();
+      size_t chunk_size = current->size();
+
+      // Cut the chunk out from the chunk list.
+      current = current->next();
+      if (previous == NULL) {
+        first_chunk_ = current;
+      } else {
+        previous->set_next(current);
+      }
+
+      // Free the chunk.
+      if (object->IsCode()) {
+        LOG(CodeDeleteEvent(object->address()));
+      }
+      size_ -= chunk_size;
+      page_count_--;
+      MemoryAllocator::FreeRawMemory(chunk_address, chunk_size);
+      LOG(DeleteEvent("LargeObjectChunk", chunk_address));
+    }
+  }
+}
+
+
+bool LargeObjectSpace::Contains(HeapObject* object) {
+  Address address = object->address();
+  Page* page = Page::FromAddress(address);
+
+  SLOW_ASSERT(!page->IsLargeObjectPage()
+              || !FindObject(address)->IsFailure());
+
+  return page->IsLargeObjectPage();
+}
+
+
+#ifdef DEBUG
+// We do not assume that the large object iterator works, because it depends
+// on the invariants we are checking during verification.
+void LargeObjectSpace::Verify() {
+  for (LargeObjectChunk* chunk = first_chunk_;
+       chunk != NULL;
+       chunk = chunk->next()) {
+    // Each chunk contains an object that starts at the large object page's
+    // object area start.
+    HeapObject* object = chunk->GetObject();
+    Page* page = Page::FromAddress(object->address());
+    ASSERT(object->address() == page->ObjectAreaStart());
+
+    // The first word should be a map, and we expect all map pointers to be
+    // in map space.
+    Map* map = object->map();
+    ASSERT(map->IsMap());
+    ASSERT(Heap::map_space()->Contains(map));
+
+    // We have only code, sequential strings, fixed arrays, and byte arrays
+    // in large object space.
+    ASSERT(object->IsCode() || object->IsSeqString()
+           || object->IsFixedArray() || object->IsByteArray());
+
+    // The object itself should look OK.
+    object->Verify();
+
+    // Byte arrays and strings don't have interior pointers.
+    if (object->IsCode()) {
+      VerifyPointersVisitor code_visitor;
+      Code::cast(object)->ConvertICTargetsFromAddressToObject();
+      object->IterateBody(map->instance_type(),
+                          object->Size(),
+                          &code_visitor);
+      Code::cast(object)->ConvertICTargetsFromObjectToAddress();
+    } else if (object->IsFixedArray()) {
+      // We loop over fixed arrays ourselves, rather then using the visitor,
+      // because the visitor doesn't support the start/offset iteration
+      // needed for IsRSetSet.
+      FixedArray* array = FixedArray::cast(object);
+      for (int j = 0; j < array->length(); j++) {
+        Object* element = array->get(j);
+        if (element->IsHeapObject()) {
+          HeapObject* element_object = HeapObject::cast(element);
+          ASSERT(Heap::Contains(element_object));
+          ASSERT(element_object->map()->IsMap());
+          if (Heap::InNewSpace(element_object)) {
+            ASSERT(Page::IsRSetSet(object->address(),
+                                   FixedArray::kHeaderSize + j * kPointerSize));
+          }
+        }
+      }
+    }
+  }
+}
+
+
+void LargeObjectSpace::Print() {
+  LargeObjectIterator it(this);
+  while (it.has_next()) {
+    it.next()->Print();
+  }
+}
+
+
+void LargeObjectSpace::ReportStatistics() {
+  PrintF("  size: %d\n", size_);
+  int num_objects = 0;
+  ClearHistograms();
+  LargeObjectIterator it(this);
+  while (it.has_next()) {
+    num_objects++;
+    CollectHistogramInfo(it.next());
+  }
+
+  PrintF("  number of objects %d\n", num_objects);
+  if (num_objects > 0) ReportHistogram(false);
+}
+
+
+void LargeObjectSpace::CollectCodeStatistics() {
+  LargeObjectIterator obj_it(this);
+  while (obj_it.has_next()) {
+    HeapObject* obj = obj_it.next();
+    if (obj->IsCode()) {
+      Code* code = Code::cast(obj);
+      code_kind_statistics[code->kind()] += code->Size();
+    }
+  }
+}
+
+
+void LargeObjectSpace::PrintRSet() {
+  LargeObjectIterator it(this);
+  while (it.has_next()) {
+    HeapObject* object = it.next();
+    if (object->IsFixedArray()) {
+      Page* page = Page::FromAddress(object->address());
+
+      Address allocation_top = object->address() + object->Size();
+      PrintF("large page 0x%x:\n", page);
+      PrintRSetRange(page->RSetStart(), page->RSetEnd(),
+                     reinterpret_cast<Object**>(object->address()),
+                     allocation_top);
+      int extra_array_bytes = object->Size() - Page::kObjectAreaSize;
+      int extra_rset_bits = RoundUp(extra_array_bytes / kPointerSize,
+                                    kBitsPerInt);
+      PrintF("------------------------------------------------------------"
+             "-----------\n");
+      PrintRSetRange(allocation_top,
+                     allocation_top + extra_rset_bits / kBitsPerByte,
+                     reinterpret_cast<Object**>(object->address()
+                                                + Page::kObjectAreaSize),
+                     allocation_top);
+      PrintF("\n");
+    }
+  }
+}
+#endif  // DEBUG
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/spaces.h b/regexp2000/src/spaces.h
new file mode 100644 (file)
index 0000000..718f888
--- /dev/null
@@ -0,0 +1,1663 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SPACES_H_
+#define V8_SPACES_H_
+
+#include "list-inl.h"
+#include "log.h"
+
+namespace v8 { namespace internal {
+
+// -----------------------------------------------------------------------------
+// Heap structures:
+//
+// A JS heap consists of a young generation, an old generation, and a large
+// object space. The young generation is divided into two semispaces. A
+// scavenger implements Cheney's copying algorithm. The old generation is
+// separated into a map space and an old object space. The map space contains
+// all (and only) map objects, the rest of old objects go into the old space.
+// The old generation is collected by a mark-sweep-compact collector.
+//
+// The semispaces of the young generation are contiguous.  The old and map
+// spaces consists of a list of pages. A page has a page header, a remembered
+// set area, and an object area. A page size is deliberately chosen as 8K
+// bytes. The first word of a page is an opaque page header that has the
+// address of the next page and its ownership information. The second word may
+// have the allocation top address of this page. The next 248 bytes are
+// remembered sets. Heap objects are aligned to the pointer size (4 bytes). A
+// remembered set bit corresponds to a pointer in the object area.
+//
+// There is a separate large object space for objects larger than
+// Page::kMaxHeapObjectSize, so that they do not have to move during
+// collection.  The large object space is paged and uses the same remembered
+// set implementation.  Pages in large object space may be larger than 8K.
+//
+// NOTE: The mark-compact collector rebuilds the remembered set after a
+// collection. It reuses first a few words of the remembered set for
+// bookkeeping relocation information.
+
+
+// Some assertion macros used in the debugging mode.
+
+#define ASSERT_PAGE_ALIGNED(address)                  \
+  ASSERT((OffsetFrom(address) & Page::kPageAlignmentMask) == 0)
+
+#define ASSERT_OBJECT_ALIGNED(address)                \
+  ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0)
+
+#define ASSERT_OBJECT_SIZE(size)                      \
+  ASSERT((0 < size) && (size <= Page::kMaxHeapObjectSize))
+
+#define ASSERT_PAGE_OFFSET(offset)                    \
+  ASSERT((Page::kObjectStartOffset <= offset)         \
+      && (offset <= Page::kPageSize))
+
+#define ASSERT_MAP_PAGE_INDEX(index)                            \
+  ASSERT((0 <= index) && (index <= MapSpace::kMaxMapPageIndex))
+
+
+class PagedSpace;
+class MemoryAllocator;
+class AllocationInfo;
+
+// -----------------------------------------------------------------------------
+// A page normally has 8K bytes. Large object pages may be larger.  A page
+// address is always aligned to the 8K page size.  A page is divided into
+// three areas: the first two words are used for bookkeeping, the next 248
+// bytes are used as remembered set, and the rest of the page is the object
+// area.
+//
+// Pointers are aligned to the pointer size (4 bytes), only 1 bit is needed
+// for a pointer in the remembered set. Given an address, its remembered set
+// bit position (offset from the start of the page) is calculated by dividing
+// its page offset by 32. Therefore, the object area in a page starts at the
+// 256th byte (8K/32). Bytes 0 to 255 do not need the remembered set, so that
+// the first two words (64 bits) in a page can be used for other purposes.
+//
+// The mark-compact collector transforms a map pointer into a page index and a
+// page offset. The map space can have up to 1024 pages, and 8M bytes (1024 *
+// 8K) in total.  Because a map pointer is aligned to the pointer size (4
+// bytes), 11 bits are enough to encode the page offset. 21 bits (10 for the
+// page index + 11 for the offset in the page) are required to encode a map
+// pointer.
+//
+// The only way to get a page pointer is by calling factory methods:
+//   Page* p = Page::FromAddress(addr); or
+//   Page* p = Page::FromAllocationTop(top);
+class Page {
+ public:
+  // Returns the page containing a given address. The address ranges
+  // from [page_addr .. page_addr + kPageSize[
+  //
+  // Note that this function only works for addresses in normal paged
+  // spaces and addresses in the first 8K of large object pages (ie,
+  // the start of large objects but not necessarily derived pointers
+  // within them).
+  INLINE(static Page* FromAddress(Address a)) {
+    return reinterpret_cast<Page*>(OffsetFrom(a) & ~kPageAlignmentMask);
+  }
+
+  // Returns the page containing an allocation top. Because an allocation
+  // top address can be the upper bound of the page, we need to subtract
+  // it with kPointerSize first. The address ranges from
+  // [page_addr + kObjectStartOffset .. page_addr + kPageSize].
+  INLINE(static Page* FromAllocationTop(Address top)) {
+    Page* p = FromAddress(top - kPointerSize);
+    ASSERT_PAGE_OFFSET(p->Offset(top));
+    return p;
+  }
+
+  // Returns the start address of this page.
+  Address address() { return reinterpret_cast<Address>(this); }
+
+  // Checks whether this is a valid page address.
+  bool is_valid() { return address() != NULL; }
+
+  // Returns the next page of this page.
+  inline Page* next_page();
+
+  // Return the end of allocation in this page. Undefined for unused pages.
+  inline Address AllocationTop();
+
+  // Returns the start address of the object area in this page.
+  Address ObjectAreaStart() { return address() + kObjectStartOffset; }
+
+  // Returns the end address (exclusive) of the object area in this page.
+  Address ObjectAreaEnd() { return address() + Page::kPageSize; }
+
+  // Returns the start address of the remembered set area.
+  Address RSetStart() { return address() + kRSetStartOffset; }
+
+  // Returns the end address of the remembered set area (exclusive).
+  Address RSetEnd() { return address() + kRSetEndOffset; }
+
+  // Checks whether an address is page aligned.
+  static bool IsAlignedToPageSize(Address a) {
+    return 0 == (OffsetFrom(a) & kPageAlignmentMask);
+  }
+
+  // True if this page is a large object page.
+  bool IsLargeObjectPage() { return (is_normal_page & 0x1) == 0; }
+
+  // Returns the offset of a given address to this page.
+  INLINE(int Offset(Address a)) {
+    int offset = a - address();
+    ASSERT_PAGE_OFFSET(offset);
+    return offset;
+  }
+
+  // Returns the address for a given offset to the this page.
+  Address OffsetToAddress(int offset) {
+    ASSERT_PAGE_OFFSET(offset);
+    return address() + offset;
+  }
+
+  // ---------------------------------------------------------------------
+  // Remembered set support
+
+  // Clears remembered set in this page.
+  inline void ClearRSet();
+
+  // Return the address of the remembered set word corresponding to an
+  // object address/offset pair, and the bit encoded as a single-bit
+  // mask in the output parameter 'bitmask'.
+  INLINE(static Address ComputeRSetBitPosition(Address address, int offset,
+                                               uint32_t* bitmask));
+
+  // Sets the corresponding remembered set bit for a given address.
+  INLINE(static void SetRSet(Address address, int offset));
+
+  // Clears the corresponding remembered set bit for a given address.
+  static inline void UnsetRSet(Address address, int offset);
+
+  // Checks whether the remembered set bit for a given address is set.
+  static inline bool IsRSetSet(Address address, int offset);
+
+#ifdef DEBUG
+  // Use a state to mark whether remembered set space can be used for other
+  // purposes.
+  enum RSetState { IN_USE,  NOT_IN_USE };
+  static bool is_rset_in_use() { return rset_state_ == IN_USE; }
+  static void set_rset_state(RSetState state) { rset_state_ = state; }
+#endif
+
+  // 8K bytes per page.
+  static const int kPageSizeBits = 13;
+
+  // Page size in bytes.  This must be a multiple of the OS page size.
+  static const int kPageSize = 1 << kPageSizeBits;
+
+  // Page size mask.
+  static const int kPageAlignmentMask = (1 << kPageSizeBits) - 1;
+
+  // The end offset of the remembered set in a page
+  // (heaps are aligned to pointer size).
+  static const int kRSetEndOffset= kPageSize / kBitsPerPointer;
+
+  // The start offset of the remembered set in a page.
+  static const int kRSetStartOffset = kRSetEndOffset / kBitsPerPointer;
+
+  // The start offset of the object area in a page.
+  static const int kObjectStartOffset = kRSetEndOffset;
+
+  // Object area size in bytes.
+  static const int kObjectAreaSize = kPageSize - kObjectStartOffset;
+
+  // Maximum object size that fits in a page.
+  static const int kMaxHeapObjectSize = kObjectAreaSize;
+
+  //---------------------------------------------------------------------------
+  // Page header description.
+  //
+  // If a page is not in the large object space, the first word,
+  // opaque_header, encodes the next page address (aligned to kPageSize 8K)
+  // and the chunk number (0 ~ 8K-1).  Only MemoryAllocator should use
+  // opaque_header. The value range of the opaque_header is [0..kPageSize[,
+  // or [next_page_start, next_page_end[. It cannot point to a valid address
+  // in the current page.  If a page is in the large object space, the first
+  // word *may* (if the page start and large object chunk start are the
+  // same) contain the address of the next large object chunk.
+  int opaque_header;
+
+  // If the page is not in the large object space, the low-order bit of the
+  // second word is set. If the page is in the large object space, the
+  // second word *may* (if the page start and large object chunk start are
+  // the same) contain the large object chunk size.  In either case, the
+  // low-order bit for large object pages will be cleared.
+  int is_normal_page;
+
+  // The following fields overlap with remembered set, they can only
+  // be used in the mark-compact collector when remembered set is not
+  // used.
+
+  // The allocation pointer after relocating objects to this page.
+  Address mc_relocation_top;
+
+  // The index of the page in its owner space.
+  int mc_page_index;
+
+  // The forwarding address of the first live object in this page.
+  Address mc_first_forwarded;
+
+#ifdef DEBUG
+ private:
+  static RSetState rset_state_;  // state of the remembered set
+#endif
+};
+
+
+// ----------------------------------------------------------------------------
+// Space is the abstract superclass for all allocation spaces.
+class Space : public Malloced {
+ public:
+  Space(AllocationSpace id, Executability executable)
+      : id_(id), executable_(executable) {}
+  virtual ~Space() {}
+  // Does the space need executable memory?
+  Executability executable() { return executable_; }
+  // Identity used in error reporting.
+  AllocationSpace identity() { return id_; }
+  virtual int Size() = 0;
+#ifdef DEBUG
+  virtual void Verify() = 0;
+  virtual void Print() = 0;
+#endif
+ private:
+  AllocationSpace id_;
+  Executability executable_;
+};
+
+
+// ----------------------------------------------------------------------------
+// A space acquires chunks of memory from the operating system. The memory
+// allocator manages chunks for the paged heap spaces (old space and map
+// space).  A paged chunk consists of pages. Pages in a chunk have contiguous
+// addresses and are linked as a list.
+//
+// The allocator keeps an initial chunk which is used for the new space.  The
+// leftover regions of the initial chunk are used for the initial chunks of
+// old space and map space if they are big enough to hold at least one page.
+// The allocator assumes that there is one old space and one map space, each
+// expands the space by allocating kPagesPerChunk pages except the last
+// expansion (before running out of space).  The first chunk may contain fewer
+// than kPagesPerChunk pages as well.
+//
+// The memory allocator also allocates chunks for the large object space, but
+// they are managed by the space itself.  The new space does not expand.
+
+class MemoryAllocator : public AllStatic {
+ public:
+  // Initializes its internal bookkeeping structures.
+  // Max capacity of the total space.
+  static bool Setup(int max_capacity);
+
+  // Deletes valid chunks.
+  static void TearDown();
+
+  // Reserves an initial address range of virtual memory to be split between
+  // the two new space semispaces, the old space, and the map space.  The
+  // memory is not yet committed or assigned to spaces and split into pages.
+  // The initial chunk is unmapped when the memory allocator is torn down.
+  // This function should only be called when there is not already a reserved
+  // initial chunk (initial_chunk_ should be NULL).  It returns the start
+  // address of the initial chunk if successful, with the side effect of
+  // setting the initial chunk, or else NULL if unsuccessful and leaves the
+  // initial chunk NULL.
+  static void* ReserveInitialChunk(const size_t requested);
+
+  // Commits pages from an as-yet-unmanaged block of virtual memory into a
+  // paged space.  The block should be part of the initial chunk reserved via
+  // a call to ReserveInitialChunk.  The number of pages is always returned in
+  // the output parameter num_pages.  This function assumes that the start
+  // address is non-null and that it is big enough to hold at least one
+  // page-aligned page.  The call always succeeds, and num_pages is always
+  // greater than zero.
+  static Page* CommitPages(Address start, size_t size, PagedSpace* owner,
+                           int* num_pages);
+
+  // Commit a contiguous block of memory from the initial chunk.  Assumes that
+  // the address is not NULL, the size is greater than zero, and that the
+  // block is contained in the initial chunk.  Returns true if it succeeded
+  // and false otherwise.
+  static bool CommitBlock(Address start, size_t size, Executability executable);
+
+  // Attempts to allocate the requested (non-zero) number of pages from the
+  // OS.  Fewer pages might be allocated than requested. If it fails to
+  // allocate memory for the OS or cannot allocate a single page, this
+  // function returns an invalid page pointer (NULL). The caller must check
+  // whether the returned page is valid (by calling Page::is_valid()).  It is
+  // guaranteed that allocated pages have contiguous addresses.  The actual
+  // number of allocated page is returned in the output parameter
+  // allocated_pages.
+  static Page* AllocatePages(int requested_pages, int* allocated_pages,
+                             PagedSpace* owner);
+
+  // Frees pages from a given page and after. If 'p' is the first page
+  // of a chunk, pages from 'p' are freed and this function returns an
+  // invalid page pointer. Otherwise, the function searches a page
+  // after 'p' that is the first page of a chunk. Pages after the
+  // found page are freed and the function returns 'p'.
+  static Page* FreePages(Page* p);
+
+  // Allocates and frees raw memory of certain size.
+  // These are just thin wrappers around OS::Allocate and OS::Free,
+  // but keep track of allocated bytes as part of heap.
+  static void* AllocateRawMemory(const size_t requested,
+                                 size_t* allocated,
+                                 Executability executable);
+  static void FreeRawMemory(void* buf, size_t length);
+
+  // Returns the maximum available bytes of heaps.
+  static int Available() { return capacity_ < size_ ? 0 : capacity_ - size_; }
+
+  // Returns maximum available bytes that the old space can have.
+  static int MaxAvailable() {
+    return (Available() / Page::kPageSize) * Page::kObjectAreaSize;
+  }
+
+  // Links two pages.
+  static inline void SetNextPage(Page* prev, Page* next);
+
+  // Returns the next page of a given page.
+  static inline Page* GetNextPage(Page* p);
+
+  // Checks whether a page belongs to a space.
+  static inline bool IsPageInSpace(Page* p, PagedSpace* space);
+
+  // Returns the space that owns the given page.
+  static inline PagedSpace* PageOwner(Page* page);
+
+  // Finds the first/last page in the same chunk as a given page.
+  static Page* FindFirstPageInSameChunk(Page* p);
+  static Page* FindLastPageInSameChunk(Page* p);
+
+#ifdef DEBUG
+  // Reports statistic info of the space.
+  static void ReportStatistics();
+#endif
+
+  // Due to encoding limitation, we can only have 8K chunks.
+  static const int kMaxNofChunks = 1 << Page::kPageSizeBits;
+  // If a chunk has at least 32 pages, the maximum heap size is about
+  // 8 * 1024 * 32 * 8K = 2G bytes.
+  static const int kPagesPerChunk = 64;
+  static const int kChunkSize = kPagesPerChunk * Page::kPageSize;
+
+ private:
+  // Maximum space size in bytes.
+  static int capacity_;
+
+  // Allocated space size in bytes.
+  static int size_;
+
+  // The initial chunk of virtual memory.
+  static VirtualMemory* initial_chunk_;
+
+  // Allocated chunk info: chunk start address, chunk size, and owning space.
+  class ChunkInfo BASE_EMBEDDED {
+   public:
+    ChunkInfo() : address_(NULL), size_(0), owner_(NULL) {}
+    void init(Address a, size_t s, PagedSpace* o) {
+      address_ = a;
+      size_ = s;
+      owner_ = o;
+    }
+    Address address() { return address_; }
+    size_t size() { return size_; }
+    PagedSpace* owner() { return owner_; }
+
+   private:
+    Address address_;
+    size_t size_;
+    PagedSpace* owner_;
+  };
+
+  // Chunks_, free_chunk_ids_ and top_ act as a stack of free chunk ids.
+  static List<ChunkInfo> chunks_;
+  static List<int> free_chunk_ids_;
+  static int max_nof_chunks_;
+  static int top_;
+
+  // Push/pop a free chunk id onto/from the stack.
+  static void Push(int free_chunk_id);
+  static int Pop();
+  static bool OutOfChunkIds() { return top_ == 0; }
+
+  // Frees a chunk.
+  static void DeleteChunk(int chunk_id);
+
+  // Basic check whether a chunk id is in the valid range.
+  static inline bool IsValidChunkId(int chunk_id);
+
+  // Checks whether a chunk id identifies an allocated chunk.
+  static inline bool IsValidChunk(int chunk_id);
+
+  // Returns the chunk id that a page belongs to.
+  static inline int GetChunkId(Page* p);
+
+  // Initializes pages in a chunk. Returns the first page address.
+  // This function and GetChunkId() are provided for the mark-compact
+  // collector to rebuild page headers in the from space, which is
+  // used as a marking stack and its page headers are destroyed.
+  static Page* InitializePagesInChunk(int chunk_id, int pages_in_chunk,
+                                      PagedSpace* owner);
+};
+
+
+// -----------------------------------------------------------------------------
+// Interface for heap object iterator to be implemented by all object space
+// object iterators.
+//
+// NOTE: The space specific object iterators also implements the own has_next()
+//       and next() methods which are used to avoid using virtual functions
+//       iterating a specific space.
+
+class ObjectIterator : public Malloced {
+ public:
+  virtual ~ObjectIterator() { }
+
+  virtual bool has_next_object() = 0;
+  virtual HeapObject* next_object() = 0;
+};
+
+
+// -----------------------------------------------------------------------------
+// Heap object iterator in new/old/map spaces.
+//
+// A HeapObjectIterator iterates objects from a given address to the
+// top of a space. The given address must be below the current
+// allocation pointer (space top). If the space top changes during
+// iteration (because of allocating new objects), the iterator does
+// not iterate new objects. The caller function must create a new
+// iterator starting from the old top in order to visit these new
+// objects. Heap::Scavenage() is such an example.
+
+class HeapObjectIterator: public ObjectIterator {
+ public:
+  // Creates a new object iterator in a given space. If a start
+  // address is not given, the iterator starts from the space bottom.
+  // If the size function is not given, the iterator calls the default
+  // Object::Size().
+  explicit HeapObjectIterator(PagedSpace* space);
+  HeapObjectIterator(PagedSpace* space, HeapObjectCallback size_func);
+  HeapObjectIterator(PagedSpace* space, Address start);
+  HeapObjectIterator(PagedSpace* space,
+                     Address start,
+                     HeapObjectCallback size_func);
+
+  inline bool has_next();
+  inline HeapObject* next();
+
+  // implementation of ObjectIterator.
+  virtual bool has_next_object() { return has_next(); }
+  virtual HeapObject* next_object() { return next(); }
+
+ private:
+  Address cur_addr_;  // current iteration point
+  Address end_addr_;  // end iteration point
+  Address cur_limit_;  // current page limit
+  HeapObjectCallback size_func_;  // size function
+  Page* end_page_;  // caches the page of the end address
+
+  // Slow path of has_next, checks whether there are more objects in
+  // the next page.
+  bool HasNextInNextPage();
+
+  // Initializes fields.
+  void Initialize(Address start, Address end, HeapObjectCallback size_func);
+
+#ifdef DEBUG
+  // Verifies whether fields have valid values.
+  void Verify();
+#endif
+};
+
+
+// -----------------------------------------------------------------------------
+// A PageIterator iterates pages in a space.
+//
+// The PageIterator class provides three modes for iterating pages in a space:
+//   PAGES_IN_USE iterates pages that are in use by the allocator;
+//   PAGES_USED_BY_GC iterates pages that hold relocated objects during a
+//                    mark-compact collection;
+//   ALL_PAGES iterates all pages in the space.
+
+class PageIterator BASE_EMBEDDED {
+ public:
+  enum Mode {PAGES_IN_USE, PAGES_USED_BY_MC, ALL_PAGES};
+
+  PageIterator(PagedSpace* space, Mode mode);
+
+  inline bool has_next();
+  inline Page* next();
+
+ private:
+  Page* cur_page_;  // next page to return
+  Page* stop_page_;  // page where to stop
+};
+
+
+// -----------------------------------------------------------------------------
+// A space has a list of pages. The next page can be accessed via
+// Page::next_page() call. The next page of the last page is an
+// invalid page pointer. A space can expand and shrink dynamically.
+
+// An abstraction of allocation and relocation pointers in a page-structured
+// space.
+class AllocationInfo {
+ public:
+  Address top;  // current allocation top
+  Address limit;  // current allocation limit
+
+#ifdef DEBUG
+  bool VerifyPagedAllocation() {
+    return (Page::FromAllocationTop(top) == Page::FromAllocationTop(limit))
+        && (top <= limit);
+  }
+#endif
+};
+
+
+// An abstraction of the accounting statistics of a page-structured space.
+// The 'capacity' of a space is the number of object-area bytes (ie, not
+// including page bookkeeping structures) currently in the space. The 'size'
+// of a space is the number of allocated bytes, the 'waste' in the space is
+// the number of bytes that are not allocated and not available to
+// allocation without reorganizing the space via a GC (eg, small blocks due
+// to internal fragmentation, top of page areas in map space), and the bytes
+// 'available' is the number of unallocated bytes that are not waste.  The
+// capacity is the sum of size, waste, and available.
+//
+// The stats are only set by functions that ensure they stay balanced. These
+// functions increase or decrease one of the non-capacity stats in
+// conjunction with capacity, or else they always balance increases and
+// decreases to the non-capacity stats.
+class AllocationStats BASE_EMBEDDED {
+ public:
+  AllocationStats() { Clear(); }
+
+  // Zero out all the allocation statistics (ie, no capacity).
+  void Clear() {
+    capacity_ = 0;
+    available_ = 0;
+    size_ = 0;
+    waste_ = 0;
+  }
+
+  // Reset the allocation statistics (ie, available = capacity with no
+  // wasted or allocated bytes).
+  void Reset() {
+    available_ = capacity_;
+    size_ = 0;
+    waste_ = 0;
+  }
+
+  // Accessors for the allocation statistics.
+  int Capacity() { return capacity_; }
+  int Available() { return available_; }
+  int Size() { return size_; }
+  int Waste() { return waste_; }
+
+  // Grow the space by adding available bytes.
+  void ExpandSpace(int size_in_bytes) {
+    capacity_ += size_in_bytes;
+    available_ += size_in_bytes;
+  }
+
+  // Shrink the space by removing available bytes.
+  void ShrinkSpace(int size_in_bytes) {
+    capacity_ -= size_in_bytes;
+    available_ -= size_in_bytes;
+  }
+
+  // Allocate from available bytes (available -> size).
+  void AllocateBytes(int size_in_bytes) {
+    available_ -= size_in_bytes;
+    size_ += size_in_bytes;
+  }
+
+  // Free allocated bytes, making them available (size -> available).
+  void DeallocateBytes(int size_in_bytes) {
+    size_ -= size_in_bytes;
+    available_ += size_in_bytes;
+  }
+
+  // Waste free bytes (available -> waste).
+  void WasteBytes(int size_in_bytes) {
+    available_ -= size_in_bytes;
+    waste_ += size_in_bytes;
+  }
+
+  // Consider the wasted bytes to be allocated, as they contain filler
+  // objects (waste -> size).
+  void FillWastedBytes(int size_in_bytes) {
+    waste_ -= size_in_bytes;
+    size_ += size_in_bytes;
+  }
+
+ private:
+  int capacity_;
+  int available_;
+  int size_;
+  int waste_;
+};
+
+
+class PagedSpace : public Space {
+  friend class PageIterator;
+ public:
+  // Creates a space with a maximum capacity, and an id.
+  PagedSpace(int max_capacity, AllocationSpace id, Executability executable);
+
+  virtual ~PagedSpace() {}
+
+  // Set up the space using the given address range of virtual memory (from
+  // the memory allocator's initial chunk) if possible.  If the block of
+  // addresses is not big enough to contain a single page-aligned page, a
+  // fresh chunk will be allocated.
+  bool Setup(Address start, size_t size);
+
+  // Returns true if the space has been successfully set up and not
+  // subsequently torn down.
+  bool HasBeenSetup();
+
+  // Cleans up the space, frees all pages in this space except those belonging
+  // to the initial chunk, uncommits addresses in the initial chunk.
+  void TearDown();
+
+  // Checks whether an object/address is in this space.
+  inline bool Contains(Address a);
+  bool Contains(HeapObject* o) { return Contains(o->address()); }
+
+  // Given an address occupied by a live object, return that object if it is
+  // in this space, or Failure::Exception() if it is not. The implementation
+  // iterates over objects in the page containing the address, the cost is
+  // linear in the number of objects in the page. It may be slow.
+  Object* FindObject(Address addr);
+
+  // Checks whether page is currently in use by this space.
+  bool IsUsed(Page* page);
+
+  // Clears remembered sets of pages in this space.
+  void ClearRSet();
+
+  // Prepares for a mark-compact GC.
+  virtual void PrepareForMarkCompact(bool will_compact) = 0;
+
+  virtual Address PageAllocationTop(Page* page) = 0;
+
+  // Current capacity without growing (Size() + Available() + Waste()).
+  int Capacity() { return accounting_stats_.Capacity(); }
+
+  // Available bytes without growing.
+  int Available() { return accounting_stats_.Available(); }
+
+  // Allocated bytes in this space.
+  virtual int Size() { return accounting_stats_.Size(); }
+
+  // Wasted bytes due to fragmentation and not recoverable until the
+  // next GC of this space.
+  int Waste() { return accounting_stats_.Waste(); }
+
+  // Returns the address of the first object in this space.
+  Address bottom() { return first_page_->ObjectAreaStart(); }
+
+  // Returns the allocation pointer in this space.
+  Address top() { return allocation_info_.top; }
+
+  // Allocate the requested number of bytes in the space if possible, return a
+  // failure object if not.
+  inline Object* AllocateRaw(int size_in_bytes);
+
+  // Allocate the requested number of bytes for relocation during mark-compact
+  // collection.
+  inline Object* MCAllocateRaw(int size_in_bytes);
+
+
+  // ---------------------------------------------------------------------------
+  // Mark-compact collection support functions
+
+  // Set the relocation point to the beginning of the space.
+  void MCResetRelocationInfo();
+
+  // Writes relocation info to the top page.
+  void MCWriteRelocationInfoToPage() {
+    TopPageOf(mc_forwarding_info_)->mc_relocation_top = mc_forwarding_info_.top;
+  }
+
+  // Computes the offset of a given address in this space to the beginning
+  // of the space.
+  int MCSpaceOffsetForAddress(Address addr);
+
+  // Updates the allocation pointer to the relocation top after a mark-compact
+  // collection.
+  virtual void MCCommitRelocationInfo() = 0;
+
+  // Releases half of unused pages.
+  void Shrink();
+
+  // Ensures that the capacity is at least 'capacity'. Returns false on failure.
+  bool EnsureCapacity(int capacity);
+
+#ifdef DEBUG
+  // Print meta info and objects in this space.
+  virtual void Print();
+
+  // Report code object related statistics
+  void CollectCodeStatistics();
+  static void ReportCodeStatistics();
+  static void ResetCodeStatistics();
+#endif
+
+ protected:
+  // Maximum capacity of this space.
+  int max_capacity_;
+
+  // Accounting information for this space.
+  AllocationStats accounting_stats_;
+
+  // The first page in this space.
+  Page* first_page_;
+
+  // Normal allocation information.
+  AllocationInfo allocation_info_;
+
+  // Relocation information during mark-compact collections.
+  AllocationInfo mc_forwarding_info_;
+
+  // Sets allocation pointer to a page bottom.
+  static void SetAllocationInfo(AllocationInfo* alloc_info, Page* p);
+
+  // Returns the top page specified by an allocation info structure.
+  static Page* TopPageOf(AllocationInfo alloc_info) {
+    return Page::FromAllocationTop(alloc_info.limit);
+  }
+
+  // Expands the space by allocating a fixed number of pages. Returns false if
+  // it cannot allocate requested number of pages from OS. Newly allocated
+  // pages are appened to the last_page;
+  bool Expand(Page* last_page);
+
+  // Generic fast case allocation function that tries linear allocation in
+  // the top page of 'alloc_info'.  Returns NULL on failure.
+  inline HeapObject* AllocateLinearly(AllocationInfo* alloc_info,
+                                      int size_in_bytes);
+
+  // During normal allocation or deserialization, roll to the next page in
+  // the space (there is assumed to be one) and allocate there.  This
+  // function is space-dependent.
+  virtual HeapObject* AllocateInNextPage(Page* current_page,
+                                         int size_in_bytes) = 0;
+
+  // Slow path of AllocateRaw.  This function is space-dependent.
+  virtual HeapObject* SlowAllocateRaw(int size_in_bytes) = 0;
+
+  // Slow path of MCAllocateRaw.
+  HeapObject* SlowMCAllocateRaw(int size_in_bytes);
+
+#ifdef DEBUG
+  void DoPrintRSet(const char* space_name);
+#endif
+ private:
+  // Returns the page of the allocation pointer.
+  Page* AllocationTopPage() { return TopPageOf(allocation_info_); }
+
+  // Returns a pointer to the page of the relocation pointer.
+  Page* MCRelocationTopPage() { return TopPageOf(mc_forwarding_info_); }
+
+#ifdef DEBUG
+  // Returns the number of total pages in this space.
+  int CountTotalPages();
+#endif
+};
+
+
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+// HistogramInfo class for recording a single "bar" of a histogram.  This
+// class is used for collecting statistics to print to stdout (when compiled
+// with DEBUG) or to the log file (when compiled with
+// ENABLE_LOGGING_AND_PROFILING).
+class HistogramInfo BASE_EMBEDDED {
+ public:
+  HistogramInfo() : number_(0), bytes_(0) {}
+
+  const char* name() { return name_; }
+  void set_name(const char* name) { name_ = name; }
+
+  int number() { return number_; }
+  void increment_number(int num) { number_ += num; }
+
+  int bytes() { return bytes_; }
+  void increment_bytes(int size) { bytes_ += size; }
+
+  // Clear the number of objects and size fields, but not the name.
+  void clear() {
+    number_ = 0;
+    bytes_ = 0;
+  }
+
+ private:
+  const char* name_;
+  int number_;
+  int bytes_;
+};
+#endif
+
+
+// -----------------------------------------------------------------------------
+// SemiSpace in young generation
+//
+// A semispace is a contiguous chunk of memory. The mark-compact collector
+// uses the memory in the from space as a marking stack when tracing live
+// objects.
+
+class SemiSpace : public Space {
+ public:
+  // Constructor.
+  SemiSpace() :Space(NEW_SPACE, NOT_EXECUTABLE) {
+    start_ = NULL;
+    age_mark_ = NULL;
+  }
+
+  // Sets up the semispace using the given chunk.
+  bool Setup(Address start, int initial_capacity, int maximum_capacity);
+
+  // Tear down the space.  Heap memory was not allocated by the space, so it
+  // is not deallocated here.
+  void TearDown();
+
+  // True if the space has been set up but not torn down.
+  bool HasBeenSetup() { return start_ != NULL; }
+
+  // Double the size of the semispace by committing extra virtual memory.
+  // Assumes that the caller has checked that the semispace has not reached
+  // its maxmimum capacity (and thus there is space available in the reserved
+  // address range to grow).
+  bool Double();
+
+  // Returns the start address of the space.
+  Address low() { return start_; }
+  // Returns one past the end address of the space.
+  Address high() { return low() + capacity_; }
+
+  // Age mark accessors.
+  Address age_mark() { return age_mark_; }
+  void set_age_mark(Address mark) { age_mark_ = mark; }
+
+  // True if the address is in the address range of this semispace (not
+  // necessarily below the allocation pointer).
+  bool Contains(Address a) {
+    return (reinterpret_cast<uint32_t>(a) & address_mask_)
+           == reinterpret_cast<uint32_t>(start_);
+  }
+
+  // True if the object is a heap object in the address range of this
+  // semispace (not necessarily below the allocation pointer).
+  bool Contains(Object* o) {
+    return (reinterpret_cast<uint32_t>(o) & object_mask_) == object_expected_;
+  }
+
+  // The offset of an address from the begining of the space.
+  int SpaceOffsetForAddress(Address addr) { return addr - low(); }
+
+  // If we don't have this here then SemiSpace will be abstract.  However
+  // it should never be called.
+  virtual int Size() {
+    UNREACHABLE();
+    return 0;
+  }
+
+#ifdef DEBUG
+  virtual void Print();
+  virtual void Verify();
+#endif
+
+ private:
+  // The current and maximum capacity of the space.
+  int capacity_;
+  int maximum_capacity_;
+
+  // The start address of the space.
+  Address start_;
+  // Used to govern object promotion during mark-compact collection.
+  Address age_mark_;
+
+  // Masks and comparison values to test for containment in this semispace.
+  uint32_t address_mask_;
+  uint32_t object_mask_;
+  uint32_t object_expected_;
+
+ public:
+  TRACK_MEMORY("SemiSpace")
+};
+
+
+// A SemiSpaceIterator is an ObjectIterator that iterates over the active
+// semispace of the heap's new space.  It iterates over the objects in the
+// semispace from a given start address (defaulting to the bottom of the
+// semispace) to the top of the semispace.  New objects allocated after the
+// iterator is created are not iterated.
+class SemiSpaceIterator : public ObjectIterator {
+ public:
+  // Create an iterator over the objects in the given space.  If no start
+  // address is given, the iterator starts from the bottom of the space.  If
+  // no size function is given, the iterator calls Object::Size().
+  explicit SemiSpaceIterator(NewSpace* space);
+  SemiSpaceIterator(NewSpace* space, HeapObjectCallback size_func);
+  SemiSpaceIterator(NewSpace* space, Address start);
+
+  bool has_next() {return current_ < limit_; }
+
+  HeapObject* next() {
+    ASSERT(has_next());
+
+    HeapObject* object = HeapObject::FromAddress(current_);
+    int size = (size_func_ == NULL) ? object->Size() : size_func_(object);
+    ASSERT_OBJECT_SIZE(size);
+
+    current_ += size;
+    return object;
+  }
+
+  // Implementation of the ObjectIterator functions.
+  virtual bool has_next_object() { return has_next(); }
+  virtual HeapObject* next_object() { return next(); }
+
+ private:
+  void Initialize(NewSpace* space, Address start, Address end,
+                  HeapObjectCallback size_func);
+
+  // The semispace.
+  SemiSpace* space_;
+  // The current iteration point.
+  Address current_;
+  // The end of iteration.
+  Address limit_;
+  // The callback function.
+  HeapObjectCallback size_func_;
+};
+
+
+// -----------------------------------------------------------------------------
+// The young generation space.
+//
+// The new space consists of a contiguous pair of semispaces.  It simply
+// forwards most functions to the appropriate semispace.
+
+class NewSpace : public Space {
+ public:
+  // Constructor.
+  NewSpace() : Space(NEW_SPACE, NOT_EXECUTABLE) {}
+
+  // Sets up the new space using the given chunk.
+  bool Setup(Address start, int size);
+
+  // Tears down the space.  Heap memory was not allocated by the space, so it
+  // is not deallocated here.
+  void TearDown();
+
+  // True if the space has been set up but not torn down.
+  bool HasBeenSetup() {
+    return to_space_.HasBeenSetup() && from_space_.HasBeenSetup();
+  }
+
+  // Flip the pair of spaces.
+  void Flip();
+
+  // Doubles the capacity of the semispaces.  Assumes that they are not at
+  // their maximum capacity.  Returns a flag indicating success or failure.
+  bool Double();
+
+  // True if the address or object lies in the address range of either
+  // semispace (not necessarily below the allocation pointer).
+  bool Contains(Address a) {
+    return (reinterpret_cast<uint32_t>(a) & address_mask_)
+        == reinterpret_cast<uint32_t>(start_);
+  }
+  bool Contains(Object* o) {
+    return (reinterpret_cast<uint32_t>(o) & object_mask_) == object_expected_;
+  }
+
+  // Return the allocated bytes in the active semispace.
+  virtual int Size() { return top() - bottom(); }
+  // Return the current capacity of a semispace.
+  int Capacity() { return capacity_; }
+  // Return the available bytes without growing in the active semispace.
+  int Available() { return Capacity() - Size(); }
+
+  // Return the maximum capacity of a semispace.
+  int MaximumCapacity() { return maximum_capacity_; }
+
+  // Return the address of the allocation pointer in the active semispace.
+  Address top() { return allocation_info_.top; }
+  // Return the address of the first object in the active semispace.
+  Address bottom() { return to_space_.low(); }
+
+  // Get the age mark of the inactive semispace.
+  Address age_mark() { return from_space_.age_mark(); }
+  // Set the age mark in the active semispace.
+  void set_age_mark(Address mark) { to_space_.set_age_mark(mark); }
+
+  // The start address of the space and a bit mask. Anding an address in the
+  // new space with the mask will result in the start address.
+  Address start() { return start_; }
+  uint32_t mask() { return address_mask_; }
+
+  // The allocation top and limit addresses.
+  Address* allocation_top_address() { return &allocation_info_.top; }
+  Address* allocation_limit_address() { return &allocation_info_.limit; }
+
+  Object* AllocateRaw(int size_in_bytes) {
+    return AllocateRawInternal(size_in_bytes, &allocation_info_);
+  }
+
+  // Allocate the requested number of bytes for relocation during mark-compact
+  // collection.
+  Object* MCAllocateRaw(int size_in_bytes) {
+    return AllocateRawInternal(size_in_bytes, &mc_forwarding_info_);
+  }
+
+  // Reset the allocation pointer to the beginning of the active semispace.
+  void ResetAllocationInfo();
+  // Reset the reloction pointer to the bottom of the inactive semispace in
+  // preparation for mark-compact collection.
+  void MCResetRelocationInfo();
+  // Update the allocation pointer in the active semispace after a
+  // mark-compact collection.
+  void MCCommitRelocationInfo();
+
+  // Get the extent of the inactive semispace (for use as a marking stack).
+  Address FromSpaceLow() { return from_space_.low(); }
+  Address FromSpaceHigh() { return from_space_.high(); }
+
+  // Get the extent of the active semispace (to sweep newly copied objects
+  // during a scavenge collection).
+  Address ToSpaceLow() { return to_space_.low(); }
+  Address ToSpaceHigh() { return to_space_.high(); }
+
+  // Offsets from the beginning of the semispaces.
+  int ToSpaceOffsetForAddress(Address a) {
+    return to_space_.SpaceOffsetForAddress(a);
+  }
+  int FromSpaceOffsetForAddress(Address a) {
+    return from_space_.SpaceOffsetForAddress(a);
+  }
+
+  // True if the object is a heap object in the address range of the
+  // respective semispace (not necessarily below the allocation pointer of the
+  // semispace).
+  bool ToSpaceContains(Object* o) { return to_space_.Contains(o); }
+  bool FromSpaceContains(Object* o) { return from_space_.Contains(o); }
+
+  bool ToSpaceContains(Address a) { return to_space_.Contains(a); }
+  bool FromSpaceContains(Address a) { return from_space_.Contains(a); }
+
+#ifdef DEBUG
+  // Verify the active semispace.
+  virtual void Verify();
+  // Print the active semispace.
+  virtual void Print() { to_space_.Print(); }
+#endif
+
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  // Iterates the active semispace to collect statistics.
+  void CollectStatistics();
+  // Reports previously collected statistics of the active semispace.
+  void ReportStatistics();
+  // Clears previously collected statistics.
+  void ClearHistograms();
+
+  // Record the allocation or promotion of a heap object.  Note that we don't
+  // record every single allocation, but only those that happen in the
+  // to space during a scavenge GC.
+  void RecordAllocation(HeapObject* obj);
+  void RecordPromotion(HeapObject* obj);
+#endif
+
+ private:
+  // The current and maximum capacities of a semispace.
+  int capacity_;
+  int maximum_capacity_;
+
+  // The semispaces.
+  SemiSpace to_space_;
+  SemiSpace from_space_;
+
+  // Start address and bit mask for containment testing.
+  Address start_;
+  uint32_t address_mask_;
+  uint32_t object_mask_;
+  uint32_t object_expected_;
+
+  // Allocation pointer and limit for normal allocation and allocation during
+  // mark-compact collection.
+  AllocationInfo allocation_info_;
+  AllocationInfo mc_forwarding_info_;
+
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
+  HistogramInfo* allocated_histogram_;
+  HistogramInfo* promoted_histogram_;
+#endif
+
+  // Implementation of AllocateRaw and MCAllocateRaw.
+  inline Object* AllocateRawInternal(int size_in_bytes,
+                                     AllocationInfo* alloc_info);
+
+  friend class SemiSpaceIterator;
+
+ public:
+  TRACK_MEMORY("NewSpace")
+};
+
+
+// -----------------------------------------------------------------------------
+// Free lists for old object spaces
+//
+// Free-list nodes are free blocks in the heap.  They look like heap objects
+// (free-list node pointers have the heap object tag, and they have a map like
+// a heap object).  They have a size and a next pointer.  The next pointer is
+// the raw address of the next free list node (or NULL).
+class FreeListNode: public HeapObject {
+ public:
+  // Obtain a free-list node from a raw address.  This is not a cast because
+  // it does not check nor require that the first word at the address is a map
+  // pointer.
+  static FreeListNode* FromAddress(Address address) {
+    return reinterpret_cast<FreeListNode*>(HeapObject::FromAddress(address));
+  }
+
+  // Set the size in bytes, which can be read with HeapObject::Size().  This
+  // function also writes a map to the first word of the block so that it
+  // looks like a heap object to the garbage collector and heap iteration
+  // functions.
+  void set_size(int size_in_bytes);
+
+  // Accessors for the next field.
+  inline Address next();
+  inline void set_next(Address next);
+
+ private:
+  static const int kNextOffset = Array::kHeaderSize;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListNode);
+};
+
+
+// The free list for the old space.
+class OldSpaceFreeList BASE_EMBEDDED {
+ public:
+  explicit OldSpaceFreeList(AllocationSpace owner);
+
+  // Clear the free list.
+  void Reset();
+
+  // Return the number of bytes available on the free list.
+  int available() { return available_; }
+
+  // Place a node on the free list.  The block of size 'size_in_bytes'
+  // starting at 'start' is placed on the free list.  The return value is the
+  // number of bytes that have been lost due to internal fragmentation by
+  // freeing the block.  Bookkeeping information will be written to the block,
+  // ie, its contents will be destroyed.  The start address should be word
+  // aligned, and the size should be a non-zero multiple of the word size.
+  int Free(Address start, int size_in_bytes);
+
+  // Allocate a block of size 'size_in_bytes' from the free list.  The block
+  // is unitialized.  A failure is returned if no block is available.  The
+  // number of bytes lost to fragmentation is returned in the output parameter
+  // 'wasted_bytes'.  The size should be a non-zero multiple of the word size.
+  Object* Allocate(int size_in_bytes, int* wasted_bytes);
+
+ private:
+  // The size range of blocks, in bytes. (Smaller allocations are allowed, but
+  // will always result in waste.)
+  static const int kMinBlockSize = Array::kHeaderSize + kPointerSize;
+  static const int kMaxBlockSize = Page::kMaxHeapObjectSize;
+
+  // The identity of the owning space, for building allocation Failure
+  // objects.
+  AllocationSpace owner_;
+
+  // Total available bytes in all blocks on this free list.
+  int available_;
+
+  // Blocks are put on exact free lists in an array, indexed by size in words.
+  // The available sizes are kept in an increasingly ordered list. Entries
+  // corresponding to sizes < kMinBlockSize always have an empty free list
+  // (but index kHead is used for the head of the size list).
+  struct SizeNode {
+    // Address of the head FreeListNode of the implied block size or NULL.
+    Address head_node_;
+    // Size (words) of the next larger available size if head_node_ != NULL.
+    int next_size_;
+  };
+  static const int kFreeListsLength = kMaxBlockSize / kPointerSize + 1;
+  SizeNode free_[kFreeListsLength];
+
+  // Sentinel elements for the size list. Real elements are in ]kHead..kEnd[.
+  static const int kHead = kMinBlockSize / kPointerSize - 1;
+  static const int kEnd = kMaxInt;
+
+  // We keep a "finger" in the size list to speed up a common pattern:
+  // repeated requests for the same or increasing sizes.
+  int finger_;
+
+  // Starting from *prev, find and return the smallest size >= index (words),
+  // or kEnd. Update *prev to be the largest size < index, or kHead.
+  int FindSize(int index, int* prev) {
+    int cur = free_[*prev].next_size_;
+    while (cur < index) {
+      *prev = cur;
+      cur = free_[cur].next_size_;
+    }
+    return cur;
+  }
+
+  // Remove an existing element from the size list.
+  void RemoveSize(int index) {
+    int prev = kHead;
+    int cur = FindSize(index, &prev);
+    ASSERT(cur == index);
+    free_[prev].next_size_ = free_[cur].next_size_;
+    finger_ = prev;
+  }
+
+  // Insert a new element into the size list.
+  void InsertSize(int index) {
+    int prev = kHead;
+    int cur = FindSize(index, &prev);
+    ASSERT(cur != index);
+    free_[prev].next_size_ = index;
+    free_[index].next_size_ = cur;
+  }
+
+  // The size list is not updated during a sequence of calls to Free, but is
+  // rebuilt before the next allocation.
+  void RebuildSizeList();
+  bool needs_rebuild_;
+
+#ifdef DEBUG
+  // Does this free list contain a free block located at the address of 'node'?
+  bool Contains(FreeListNode* node);
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(OldSpaceFreeList);
+};
+
+
+// The free list for the map space.
+class MapSpaceFreeList BASE_EMBEDDED {
+ public:
+  explicit MapSpaceFreeList(AllocationSpace owner);
+
+  // Clear the free list.
+  void Reset();
+
+  // Return the number of bytes available on the free list.
+  int available() { return available_; }
+
+  // Place a node on the free list.  The block starting at 'start' (assumed to
+  // have size Map::kSize) is placed on the free list.  Bookkeeping
+  // information will be written to the block, ie, its contents will be
+  // destroyed.  The start address should be word aligned.
+  void Free(Address start);
+
+  // Allocate a map-sized block from the free list.  The block is unitialized.
+  // A failure is returned if no block is available.
+  Object* Allocate();
+
+ private:
+  // Available bytes on the free list.
+  int available_;
+
+  // The head of the free list.
+  Address head_;
+
+  // The identity of the owning space, for building allocation Failure
+  // objects.
+  AllocationSpace owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MapSpaceFreeList);
+};
+
+
+// -----------------------------------------------------------------------------
+// Old object space (excluding map objects)
+
+class OldSpace : public PagedSpace {
+ public:
+  // Creates an old space object with a given maximum capacity.
+  // The constructor does not allocate pages from OS.
+  explicit OldSpace(int max_capacity,
+                    AllocationSpace id,
+                    Executability executable)
+      : PagedSpace(max_capacity, id, executable), free_list_(id) {
+  }
+
+  // The bytes available on the free list (ie, not above the linear allocation
+  // pointer).
+  int AvailableFree() { return free_list_.available(); }
+
+  // The top of allocation in a page in this space. Undefined if page is unused.
+  virtual Address PageAllocationTop(Page* page) {
+    return page == TopPageOf(allocation_info_) ? top() : page->ObjectAreaEnd();
+  }
+
+  // Give a block of memory to the space's free list.  It might be added to
+  // the free list or accounted as waste.
+  void Free(Address start, int size_in_bytes) {
+    int wasted_bytes = free_list_.Free(start, size_in_bytes);
+    accounting_stats_.DeallocateBytes(size_in_bytes);
+    accounting_stats_.WasteBytes(wasted_bytes);
+  }
+
+  // Prepare for full garbage collection.  Resets the relocation pointer and
+  // clears the free list.
+  virtual void PrepareForMarkCompact(bool will_compact);
+
+  // Adjust the top of relocation pointer to point to the end of the object
+  // given by 'address' and 'size_in_bytes'.  Move it to the next page if
+  // necessary, ensure that it points to the address, then increment it by the
+  // size.
+  void MCAdjustRelocationEnd(Address address, int size_in_bytes);
+
+  // Updates the allocation pointer to the relocation top after a mark-compact
+  // collection.
+  virtual void MCCommitRelocationInfo();
+
+#ifdef DEBUG
+  // Verify integrity of this space.
+  virtual void Verify();
+
+  // Reports statistics for the space
+  void ReportStatistics();
+  // Dump the remembered sets in the space to stdout.
+  void PrintRSet();
+#endif
+
+ protected:
+  // Virtual function in the superclass.  Slow path of AllocateRaw.
+  HeapObject* SlowAllocateRaw(int size_in_bytes);
+
+  // Virtual function in the superclass.  Allocate linearly at the start of
+  // the page after current_page (there is assumed to be one).
+  HeapObject* AllocateInNextPage(Page* current_page, int size_in_bytes);
+
+ private:
+  // The space's free list.
+  OldSpaceFreeList free_list_;
+
+  // During relocation, we keep a pointer to the most recently relocated
+  // object in order to know when to move to the next page.
+  Address mc_end_of_relocation_;
+
+ public:
+  TRACK_MEMORY("OldSpace")
+};
+
+
+// -----------------------------------------------------------------------------
+// Old space for all map objects
+
+class MapSpace : public PagedSpace {
+ public:
+  // Creates a map space object with a maximum capacity.
+  explicit MapSpace(int max_capacity, AllocationSpace id)
+      : PagedSpace(max_capacity, id, NOT_EXECUTABLE), free_list_(id) { }
+
+  // The top of allocation in a page in this space. Undefined if page is unused.
+  virtual Address PageAllocationTop(Page* page) {
+    return page == TopPageOf(allocation_info_) ? top()
+        : page->ObjectAreaEnd() - kPageExtra;
+  }
+
+  // Give a map-sized block of memory to the space's free list.
+  void Free(Address start) {
+    free_list_.Free(start);
+    accounting_stats_.DeallocateBytes(Map::kSize);
+  }
+
+  // Given an index, returns the page address.
+  Address PageAddress(int page_index) { return page_addresses_[page_index]; }
+
+  // Prepares for a mark-compact GC.
+  virtual void PrepareForMarkCompact(bool will_compact);
+
+  // Updates the allocation pointer to the relocation top after a mark-compact
+  // collection.
+  virtual void MCCommitRelocationInfo();
+
+#ifdef DEBUG
+  // Verify integrity of this space.
+  virtual void Verify();
+
+  // Reports statistic info of the space
+  void ReportStatistics();
+  // Dump the remembered sets in the space to stdout.
+  void PrintRSet();
+#endif
+
+  // Constants.
+  static const int kMapPageIndexBits = 10;
+  static const int kMaxMapPageIndex = (1 << kMapPageIndexBits) - 1;
+
+  static const int kPageExtra = Page::kObjectAreaSize % Map::kSize;
+
+ protected:
+  // Virtual function in the superclass.  Slow path of AllocateRaw.
+  HeapObject* SlowAllocateRaw(int size_in_bytes);
+
+  // Virtual function in the superclass.  Allocate linearly at the start of
+  // the page after current_page (there is assumed to be one).
+  HeapObject* AllocateInNextPage(Page* current_page, int size_in_bytes);
+
+ private:
+  // The space's free list.
+  MapSpaceFreeList free_list_;
+
+  // An array of page start address in a map space.
+  Address page_addresses_[kMaxMapPageIndex];
+
+ public:
+  TRACK_MEMORY("MapSpace")
+};
+
+
+// -----------------------------------------------------------------------------
+// Large objects ( > Page::kMaxHeapObjectSize ) are allocated and managed by
+// the large object space. A large object is allocated from OS heap with
+// extra padding bytes (Page::kPageSize + Page::kObjectStartOffset).
+// A large object always starts at Page::kObjectStartOffset to a page.
+// Large objects do not move during garbage collections.
+
+// A LargeObjectChunk holds exactly one large object page with exactly one
+// large object.
+class LargeObjectChunk {
+ public:
+  // Allocates a new LargeObjectChunk that contains a large object page
+  // (Page::kPageSize aligned) that has at least size_in_bytes (for a large
+  // object and possibly extra remembered set words) bytes after the object
+  // area start of that page. The allocated chunk size is set in the output
+  // parameter chunk_size.
+  static LargeObjectChunk* New(int size_in_bytes,
+                               size_t* chunk_size,
+                               Executability executable);
+
+  // Interpret a raw address as a large object chunk.
+  static LargeObjectChunk* FromAddress(Address address) {
+    return reinterpret_cast<LargeObjectChunk*>(address);
+  }
+
+  // Returns the address of this chunk.
+  Address address() { return reinterpret_cast<Address>(this); }
+
+  // Accessors for the fields of the chunk.
+  LargeObjectChunk* next() { return next_; }
+  void set_next(LargeObjectChunk* chunk) { next_ = chunk; }
+
+  size_t size() { return size_; }
+  void set_size(size_t size_in_bytes) { size_ = size_in_bytes; }
+
+  // Returns the object in this chunk.
+  inline HeapObject* GetObject();
+
+  // Given a requested size (including any extra remembereed set words),
+  // returns the physical size of a chunk to be allocated.
+  static int ChunkSizeFor(int size_in_bytes);
+
+  // Given a chunk size, returns the object size it can accomodate (not
+  // including any extra remembered set words).  Used by
+  // LargeObjectSpace::Available.  Note that this can overestimate the size
+  // of object that will fit in a chunk---if the object requires extra
+  // remembered set words (eg, for large fixed arrays), the actual object
+  // size for the chunk will be smaller than reported by this function.
+  static int ObjectSizeFor(int chunk_size) {
+    if (chunk_size <= (Page::kPageSize + Page::kObjectStartOffset)) return 0;
+    return chunk_size - Page::kPageSize - Page::kObjectStartOffset;
+  }
+
+ private:
+  // A pointer to the next large object chunk in the space or NULL.
+  LargeObjectChunk* next_;
+
+  // The size of this chunk.
+  size_t size_;
+
+ public:
+  TRACK_MEMORY("LargeObjectChunk")
+};
+
+
+class LargeObjectSpace : public Space {
+  friend class LargeObjectIterator;
+ public:
+  explicit LargeObjectSpace(AllocationSpace id);
+  virtual ~LargeObjectSpace() {}
+
+  // Initializes internal data structures.
+  bool Setup();
+
+  // Releases internal resources, frees objects in this space.
+  void TearDown();
+
+  // Allocates a (non-FixedArray, non-Code) large object.
+  Object* AllocateRaw(int size_in_bytes);
+  // Allocates a large Code object.
+  Object* AllocateRawCode(int size_in_bytes);
+  // Allocates a large FixedArray.
+  Object* AllocateRawFixedArray(int size_in_bytes);
+
+  // Available bytes for objects in this space, not including any extra
+  // remembered set words.
+  int Available() {
+    return LargeObjectChunk::ObjectSizeFor(MemoryAllocator::Available());
+  }
+
+  virtual int Size() {
+    return size_;
+  }
+
+  int PageCount() {
+    return page_count_;
+  }
+
+  // Finds an object for a given address, returns Failure::Exception()
+  // if it is not found. The function iterates through all objects in this
+  // space, may be slow.
+  Object* FindObject(Address a);
+
+  // Clears remembered sets.
+  void ClearRSet();
+
+  // Iterates objects whose remembered set bits are set.
+  void IterateRSet(ObjectSlotCallback func);
+
+  // Frees unmarked objects.
+  void FreeUnmarkedObjects();
+
+  // Checks whether a heap object is in this space; O(1).
+  bool Contains(HeapObject* obj);
+
+  // Checks whether the space is empty.
+  bool IsEmpty() { return first_chunk_ == NULL; }
+
+#ifdef DEBUG
+  virtual void Verify();
+  virtual void Print();
+  void ReportStatistics();
+  void CollectCodeStatistics();
+  // Dump the remembered sets in the space to stdout.
+  void PrintRSet();
+#endif
+  // Checks whether an address is in the object area in this space.  It
+  // iterates all objects in the space. May be slow.
+  bool SlowContains(Address addr) { return !FindObject(addr)->IsFailure(); }
+
+ private:
+  // The head of the linked list of large object chunks.
+  LargeObjectChunk* first_chunk_;
+  int size_;  // allocated bytes
+  int page_count_;  // number of chunks
+
+
+  // Shared implementation of AllocateRaw, AllocateRawCode and
+  // AllocateRawFixedArray.
+  Object* AllocateRawInternal(int requested_size,
+                              int object_size,
+                              Executability executable);
+
+  // Returns the number of extra bytes (rounded up to the nearest full word)
+  // required for extra_object_bytes of extra pointers (in bytes).
+  static inline int ExtraRSetBytesFor(int extra_object_bytes);
+
+ public:
+  TRACK_MEMORY("LargeObjectSpace")
+};
+
+
+class LargeObjectIterator: public ObjectIterator {
+ public:
+  explicit LargeObjectIterator(LargeObjectSpace* space);
+  LargeObjectIterator(LargeObjectSpace* space, HeapObjectCallback size_func);
+
+  bool has_next() { return current_ != NULL; }
+  HeapObject* next();
+
+  // implementation of ObjectIterator.
+  virtual bool has_next_object() { return has_next(); }
+  virtual HeapObject* next_object() { return next(); }
+
+ private:
+  LargeObjectChunk* current_;
+  HeapObjectCallback size_func_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_SPACES_H_
diff --git a/regexp2000/src/string-stream.cc b/regexp2000/src/string-stream.cc
new file mode 100644 (file)
index 0000000..4390fa1
--- /dev/null
@@ -0,0 +1,550 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "factory.h"
+#include "string-stream.h"
+
+namespace v8 { namespace internal {
+
+static const int kMentionedObjectCacheMaxSize = 256;
+static List<HeapObject*, PreallocatedStorage>* debug_object_cache = NULL;
+static Object* current_security_token = NULL;
+
+
+char* HeapStringAllocator::allocate(unsigned bytes) {
+  space_ = NewArray<char>(bytes);
+  return space_;
+}
+
+
+NoAllocationStringAllocator::NoAllocationStringAllocator(unsigned bytes) {
+  size_ = bytes;
+  space_ = NewArray<char>(bytes);
+}
+
+
+NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory,
+                                                         unsigned size) {
+  size_ = size;
+  space_ = memory;
+}
+
+
+bool StringStream::Put(char c) {
+  if (space() == 0) return false;
+  if (length_ >= capacity_ - 1) {
+    unsigned new_capacity = capacity_;
+    char* new_buffer = allocator_->grow(&new_capacity);
+    if (new_capacity > capacity_) {
+      capacity_ = new_capacity;
+      buffer_ = new_buffer;
+    } else {
+      // Indicate truncation with dots.
+      memset(cursor(), '.', space());
+      length_ = capacity_;
+      buffer_[length_ - 2] = '\n';
+      buffer_[length_ - 1] = '\0';
+      return false;
+    }
+  }
+  buffer_[length_] = c;
+  buffer_[length_ + 1] = '\0';
+  length_++;
+  return true;
+}
+
+
+// A control character is one that configures a format element.  For
+// instance, in %.5s, .5 are control characters.
+static bool IsControlChar(char c) {
+  switch (c) {
+  case '0': case '1': case '2': case '3': case '4': case '5':
+  case '6': case '7': case '8': case '9': case '.': case '-':
+    return true;
+  default:
+    return false;
+  }
+}
+
+
+void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
+  // If we already ran out of space then return immediately.
+  if (space() == 0)
+    return;
+  int offset = 0;
+  int elm = 0;
+  while (offset < format.length()) {
+    if (format[offset] != '%' || elm == elms.length()) {
+      Put(format[offset]);
+      offset++;
+      continue;
+    }
+    // Read this formatting directive into a temporary buffer
+    EmbeddedVector<char, 24> temp;
+    int format_length = 0;
+    // Skip over the whole control character sequence until the
+    // format element type
+    temp[format_length++] = format[offset++];
+    while (offset < format.length() && IsControlChar(format[offset]))
+      temp[format_length++] = format[offset++];
+    if (offset >= format.length())
+      return;
+    char type = format[offset];
+    temp[format_length++] = type;
+    temp[format_length] = '\0';
+    offset++;
+    FmtElm current = elms[elm++];
+    switch (type) {
+    case 's': {
+      ASSERT_EQ(FmtElm::C_STR, current.type_);
+      const char* value = current.data_.u_c_str_;
+      Add(value);
+      break;
+    }
+    case 'w': {
+      ASSERT_EQ(FmtElm::LC_STR, current.type_);
+      Vector<const uc16> value = *current.data_.u_lc_str_;
+      for (int i = 0; i < value.length(); i++)
+        Put(value[i]);
+      break;
+    }
+    case 'o': {
+      ASSERT_EQ(FmtElm::OBJ, current.type_);
+      Object* obj = current.data_.u_obj_;
+      PrintObject(obj);
+      break;
+    }
+    case 'i': case 'd': case 'u': case 'x': case 'c': case 'p': {
+      int value = current.data_.u_int_;
+      EmbeddedVector<char, 24> formatted;
+      int length = OS::SNPrintF(formatted, temp.start(), value);
+      Add(Vector<const char>(formatted.start(), length));
+      break;
+    }
+    default:
+      UNREACHABLE();
+      break;
+    }
+  }
+
+  // Verify that the buffer is 0-terminated
+  ASSERT(buffer_[length_] == '\0');
+}
+
+
+void StringStream::PrintObject(Object* o) {
+  o->ShortPrint(this);
+  if (o->IsString()) {
+    if (String::cast(o)->length() <= String::kMaxMediumStringSize) {
+      return;
+    }
+  } else if (o->IsNumber() || o->IsOddball()) {
+    return;
+  }
+  if (o->IsHeapObject()) {
+    for (int i = 0; i < debug_object_cache->length(); i++) {
+      if ((*debug_object_cache)[i] == o) {
+        Add("#%d#", i);
+        return;
+      }
+    }
+    if (debug_object_cache->length() < kMentionedObjectCacheMaxSize) {
+      Add("#%d#", debug_object_cache->length());
+      debug_object_cache->Add(HeapObject::cast(o));
+    } else {
+      Add("@%p", o);
+    }
+  }
+}
+
+
+void StringStream::Add(const char* format) {
+  Add(CStrVector(format));
+}
+
+
+void StringStream::Add(Vector<const char> format) {
+  Add(format, Vector<FmtElm>::empty());
+}
+
+
+void StringStream::Add(const char* format, FmtElm arg0) {
+  const char argc = 1;
+  FmtElm argv[argc] = { arg0 };
+  Add(CStrVector(format), Vector<FmtElm>(argv, argc));
+}
+
+
+void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1) {
+  const char argc = 2;
+  FmtElm argv[argc] = { arg0, arg1 };
+  Add(CStrVector(format), Vector<FmtElm>(argv, argc));
+}
+
+
+void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
+                       FmtElm arg2) {
+  const char argc = 3;
+  FmtElm argv[argc] = { arg0, arg1, arg2 };
+  Add(CStrVector(format), Vector<FmtElm>(argv, argc));
+}
+
+
+SmartPointer<char> StringStream::ToCString() {
+  char* str = NewArray<char>(length_ + 1);
+  memcpy(str, buffer_, length_);
+  str[length_] = '\0';
+  return SmartPointer<char>(str);
+}
+
+
+void StringStream::Log() {
+  LOG(StringEvent("StackDump", buffer_));
+}
+
+
+void StringStream::OutputToStdOut() {
+  // Dump the output to stdout, but make sure to break it up into
+  // manageable chunks to avoid losing parts of the output in the OS
+  // printing code. This is a problem on Windows in particular; see
+  // the VPrint() function implementations in platform-win32.cc.
+  unsigned position = 0;
+  for (unsigned next; (next = position + 2048) < length_; position = next) {
+    char save = buffer_[next];
+    buffer_[next] = '\0';
+    internal::PrintF("%s", &buffer_[position]);
+    buffer_[next] = save;
+  }
+  internal::PrintF("%s", &buffer_[position]);
+}
+
+
+Handle<String> StringStream::ToString() {
+  return Factory::NewStringFromUtf8(Vector<const char>(buffer_, length_));
+}
+
+
+void StringStream::ClearMentionedObjectCache() {
+  current_security_token = NULL;
+  if (debug_object_cache == NULL) {
+    debug_object_cache = new List<HeapObject*, PreallocatedStorage>(0);
+  }
+  debug_object_cache->Clear();
+}
+
+
+#ifdef DEBUG
+bool StringStream::IsMentionedObjectCacheClear() {
+  return (debug_object_cache->length() == 0);
+}
+#endif
+
+
+bool StringStream::Put(String* str) {
+  return Put(str, 0, str->length());
+}
+
+
+bool StringStream::Put(String* str, int start, int end) {
+  StringInputBuffer name_buffer(str);
+  name_buffer.Seek(start);
+  for (int i = start; i < end && name_buffer.has_more(); i++) {
+    int c = name_buffer.GetNext();
+    if (c >= 127 || c < 32) {
+      c = '?';
+    }
+    if (!Put(c)) {
+      return false;  // Output was truncated.
+    }
+  }
+  return true;
+}
+
+
+void StringStream::PrintName(Object* name) {
+  if (name->IsString()) {
+    String* str = String::cast(name);
+    if (str->length() > 0) {
+      Put(str);
+    } else {
+      Add("/* anonymous */");
+    }
+  } else {
+    Add("%o", name);
+  }
+}
+
+
+void StringStream::PrintUsingMap(JSObject* js_object) {
+  Map* map = js_object->map();
+  if (!Heap::Contains(map) ||
+      !map->IsHeapObject() ||
+      !map->IsMap()) {
+    Add("<Invalid map>\n");
+    return;
+  }
+  for (DescriptorReader r(map->instance_descriptors()); !r.eos(); r.advance()) {
+    switch (r.type()) {
+      case FIELD: {
+        Object* key = r.GetKey();
+        if (key->IsString() || key->IsNumber()) {
+          int len = 3;
+          if (key->IsString()) {
+            len = String::cast(key)->length();
+          }
+          for (; len < 18; len++)
+            Put(' ');
+          if (key->IsString()) {
+            Put(String::cast(key));
+          } else {
+            key->ShortPrint();
+          }
+          Add(": ");
+          Object* value = js_object->FastPropertyAt(r.GetFieldIndex());
+          Add("%o\n", value);
+        }
+      }
+      break;
+      default:
+      break;
+    }
+  }
+}
+
+
+void StringStream::PrintFixedArray(FixedArray* array, unsigned int limit) {
+  for (unsigned int i = 0; i < 10 && i < limit; i++) {
+    Object* element = array->get(i);
+    if (element != Heap::the_hole_value()) {
+      for (int len = 1; len < 18; len++)
+        Put(' ');
+      Add("%d: %o\n", i, array->get(i));
+    }
+  }
+  if (limit >= 10) {
+    Add("                  ...\n");
+  }
+}
+
+
+void StringStream::PrintByteArray(ByteArray* byte_array) {
+  unsigned int limit = byte_array->length();
+  for (unsigned int i = 0; i < 10 && i < limit; i++) {
+    byte b = byte_array->get(i);
+    Add("             %d: %3d 0x%02x", i, b, b);
+    if (b >= ' ' && b <= '~') {
+      Add(" '%c'", b);
+    } else if (b == '\n') {
+      Add(" '\n'");
+    } else if (b == '\r') {
+      Add(" '\r'");
+    } else if (b >= 1 && b <= 26) {
+      Add(" ^%c", b + 'A' - 1);
+    }
+    Add("\n");
+  }
+  if (limit >= 10) {
+    Add("                  ...\n");
+  }
+}
+
+
+void StringStream::PrintMentionedObjectCache() {
+  Add("==== Key         ============================================\n\n");
+  for (int i = 0; i < debug_object_cache->length(); i++) {
+    HeapObject* printee = (*debug_object_cache)[i];
+    Add(" #%d# %p: ", i, printee);
+    printee->ShortPrint(this);
+    Add("\n");
+    if (printee->IsJSObject()) {
+      if (printee->IsJSValue()) {
+        Add("           value(): %o\n", JSValue::cast(printee)->value());
+      }
+      PrintUsingMap(JSObject::cast(printee));
+      if (printee->IsJSArray()) {
+        JSArray* array = JSArray::cast(printee);
+        if (array->HasFastElements()) {
+          unsigned int limit = FixedArray::cast(array->elements())->length();
+          unsigned int length =
+            static_cast<uint32_t>(JSArray::cast(array)->length()->Number());
+          if (length < limit) limit = length;
+          PrintFixedArray(FixedArray::cast(array->elements()), limit);
+        }
+      }
+    } else if (printee->IsByteArray()) {
+      PrintByteArray(ByteArray::cast(printee));
+    } else if (printee->IsFixedArray()) {
+      unsigned int limit = FixedArray::cast(printee)->length();
+      PrintFixedArray(FixedArray::cast(printee), limit);
+    }
+  }
+}
+
+
+void StringStream::PrintSecurityTokenIfChanged(Object* f) {
+  if (!f->IsHeapObject() || !Heap::Contains(HeapObject::cast(f))) {
+    return;
+  }
+  Map* map = HeapObject::cast(f)->map();
+  if (!map->IsHeapObject() ||
+      !Heap::Contains(map) ||
+      !map->IsMap() ||
+      !f->IsJSFunction()) {
+    return;
+  }
+
+  JSFunction* fun = JSFunction::cast(f);
+  Object* perhaps_context = fun->unchecked_context();
+  if (perhaps_context->IsHeapObject() &&
+      Heap::Contains(HeapObject::cast(perhaps_context)) &&
+      perhaps_context->IsContext()) {
+    Context* context = fun->context();
+    if (!Heap::Contains(context)) {
+      Add("(Function context is outside heap)\n");
+      return;
+    }
+    Object* token = context->global_context()->security_token();
+    if (token != current_security_token) {
+      Add("Security context: %o\n", token);
+      current_security_token = token;
+    }
+  } else {
+    Add("(Function context is corrupt)\n");
+  }
+}
+
+
+void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) {
+  if (f->IsHeapObject() &&
+      Heap::Contains(HeapObject::cast(f)) &&
+      Heap::Contains(HeapObject::cast(f)->map()) &&
+      HeapObject::cast(f)->map()->IsMap()) {
+    if (f->IsJSFunction()) {
+      JSFunction* fun = JSFunction::cast(f);
+      // Common case: on-stack function present and resolved.
+      PrintPrototype(fun, receiver);
+      *code = fun->code();
+    } else if (f->IsSymbol()) {
+      // Unresolved and megamorphic calls: Instead of the function
+      // we have the function name on the stack.
+      PrintName(f);
+      Add("/* unresolved */ ");
+    } else {
+      // Unless this is the frame of a built-in function, we should always have
+      // the callee function or name on the stack. If we don't, we have a
+      // problem or a change of the stack frame layout.
+      Add("%o", f);
+      Add("/* warning: no JSFunction object or function name found */ ");
+    }
+    /* } else if (is_trampoline()) {
+       Print("trampoline ");
+    */
+  } else {
+    if (!f->IsHeapObject()) {
+      Add("/* warning: 'function' was not a heap object */ ");
+      return;
+    }
+    if (!Heap::Contains(HeapObject::cast(f))) {
+      Add("/* warning: 'function' was not on the heap */ ");
+      return;
+    }
+    if (!Heap::Contains(HeapObject::cast(f)->map())) {
+      Add("/* warning: function's map was not on the heap */ ");
+      return;
+    }
+    if (!HeapObject::cast(f)->map()->IsMap()) {
+      Add("/* warning: function's map was not a valid map */ ");
+      return;
+    }
+    Add("/* warning: Invalid JSFunction object found */ ");
+  }
+}
+
+
+void StringStream::PrintPrototype(JSFunction* fun, Object* receiver) {
+  Object* name = fun->shared()->name();
+  bool print_name = false;
+  for (Object* p = receiver; p != Heap::null_value(); p = p->GetPrototype()) {
+    if (p->IsJSObject()) {
+      Object* key = JSObject::cast(p)->SlowReverseLookup(fun);
+      if (key != Heap::undefined_value()) {
+        if (!name->IsString() ||
+            !key->IsString() ||
+            !String::cast(name)->Equals(String::cast(key))) {
+          print_name = true;
+        }
+        if (name->IsString() && String::cast(name)->length() == 0) {
+          print_name = false;
+        }
+        name = key;
+      }
+    } else {
+      print_name = true;
+    }
+  }
+  PrintName(name);
+  // Also known as - if the name in the function doesn't match the name under
+  // which it was looked up.
+  if (print_name) {
+    Add("(aka ");
+    PrintName(fun->shared()->name());
+    Put(')');
+  }
+}
+
+
+char* HeapStringAllocator::grow(unsigned* bytes) {
+  unsigned new_bytes = *bytes * 2;
+  // Check for overflow.
+  if (new_bytes <= *bytes) {
+    return space_;
+  }
+  char* new_space = NewArray<char>(new_bytes);
+  if (new_space == NULL) {
+    return space_;
+  }
+  memcpy(new_space, space_, *bytes);
+  *bytes = new_bytes;
+  DeleteArray(space_);
+  space_ = new_space;
+  return new_space;
+}
+
+
+char* NoAllocationStringAllocator::grow(unsigned* bytes) {
+  unsigned new_bytes = *bytes * 2;
+  if (new_bytes > size_) {
+    new_bytes = size_;
+  }
+  *bytes = new_bytes;
+  return space_;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/string-stream.h b/regexp2000/src/string-stream.h
new file mode 100644 (file)
index 0000000..a8b9177
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_STRING_STREAM_H_
+#define V8_STRING_STREAM_H_
+
+namespace v8 { namespace internal {
+
+
+class StringAllocator {
+ public:
+  virtual ~StringAllocator() {}
+  // Allocate a number of bytes.
+  virtual char* allocate(unsigned bytes) = 0;
+  // Allocate a larger number of bytes and copy the old buffer to the new one.
+  // bytes is an input and output parameter passing the old size of the buffer
+  // and returning the new size.  If allocation fails then we return the old
+  // buffer and do not increase the size.
+  virtual char* grow(unsigned* bytes) = 0;
+};
+
+
+// Normal allocator uses new[] and delete[].
+class HeapStringAllocator: public StringAllocator {
+ public:
+  ~HeapStringAllocator() { DeleteArray(space_); }
+  char* allocate(unsigned bytes);
+  char* grow(unsigned* bytes);
+ private:
+  char* space_;
+};
+
+
+// Allocator for use when no new c++ heap allocation is allowed.
+// Allocates all space up front and does no allocation while building
+// message.
+class NoAllocationStringAllocator: public StringAllocator {
+ public:
+  explicit NoAllocationStringAllocator(unsigned bytes);
+  NoAllocationStringAllocator(char* memory, unsigned size);
+  char* allocate(unsigned bytes) { return space_; }
+  char* grow(unsigned* bytes);
+ private:
+  unsigned size_;
+  char* space_;
+};
+
+
+class FmtElm {
+ public:
+  FmtElm(int value) : type_(INT) { data_.u_int_ = value; }  // NOLINT
+  FmtElm(const char* value) : type_(C_STR) { data_.u_c_str_ = value; }  // NOLINT
+  FmtElm(const Vector<const uc16>& value) : type_(LC_STR) { data_.u_lc_str_ = &value; } // NOLINT
+  FmtElm(Object* value) : type_(OBJ) { data_.u_obj_ = value; }  // NOLINT
+  FmtElm(Handle<Object> value) : type_(HANDLE) { data_.u_handle_ = value.location(); }  // NOLINT
+  FmtElm(void* value) : type_(INT) { data_.u_int_ = reinterpret_cast<int>(value); }  // NOLINT
+ private:
+  friend class StringStream;
+  enum Type { INT, C_STR, LC_STR, OBJ, HANDLE };
+  Type type_;
+  union {
+    int u_int_;
+    const char* u_c_str_;
+    const Vector<const uc16>* u_lc_str_;
+    Object* u_obj_;
+    Object** u_handle_;
+  } data_;
+};
+
+
+class StringStream {
+ public:
+  explicit StringStream(StringAllocator* allocator):
+    allocator_(allocator),
+    capacity_(kInitialCapacity),
+    length_(0),
+    buffer_(allocator_->allocate(kInitialCapacity)) {
+    buffer_[0] = 0;
+  }
+
+  ~StringStream() {
+  }
+
+  bool Put(char c);
+  bool Put(String* str);
+  bool Put(String* str, int start, int end);
+  void Add(Vector<const char> format, Vector<FmtElm> elms);
+  void Add(const char* format);
+  void Add(Vector<const char> format);
+  void Add(const char* format, FmtElm arg0);
+  void Add(const char* format, FmtElm arg0, FmtElm arg1);
+  void Add(const char* format, FmtElm arg0, FmtElm arg1, FmtElm arg2);
+
+  // Getting the message out.
+  void OutputToStdOut();
+  void Log();
+  Handle<String> ToString();
+  SmartPointer<char> ToCString();
+
+  // Object printing support.
+  void PrintName(Object* o);
+  void PrintFixedArray(FixedArray* array, unsigned int limit);
+  void PrintByteArray(ByteArray* ba);
+  void PrintUsingMap(JSObject* js_object);
+  void PrintPrototype(JSFunction* fun, Object* receiver);
+  void PrintSecurityTokenIfChanged(Object* function);
+  // NOTE: Returns the code in the output parameter.
+  void PrintFunction(Object* function, Object* receiver, Code** code);
+
+  // Reset the stream.
+  void Reset() {
+    length_ = 0;
+    buffer_[0] = 0;
+  }
+
+  // Mentioned object cache support.
+  void PrintMentionedObjectCache();
+  static void ClearMentionedObjectCache();
+#ifdef DEBUG
+  static bool IsMentionedObjectCacheClear();
+#endif
+
+
+  static const int kInitialCapacity = 16;
+
+ private:
+  void PrintObject(Object* obj);
+
+  StringAllocator* allocator_;
+  unsigned capacity_;
+  unsigned length_;  // does not include terminating 0-character
+  char* buffer_;
+
+  int space() const { return capacity_ - length_; }
+  char* cursor() const { return buffer_ + length_; }
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringStream);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_STRING_STREAM_H_
diff --git a/regexp2000/src/string.js b/regexp2000/src/string.js
new file mode 100644 (file)
index 0000000..984d969
--- /dev/null
@@ -0,0 +1,834 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// const $String = global.String;
+// const $NaN = 0/0;
+
+
+// Set the String function and constructor.
+%SetCode($String, function(x) {
+  var value = %_ArgumentsLength() == 0 ? '' : ToString(x);
+  if (%IsConstructCall()) {
+    %_SetValueOf(this, value);
+  } else {
+    return value;
+  }
+});
+
+%FunctionSetPrototype($String, new $String());
+
+// ECMA-262 section 15.5.4.2
+function StringToString() {
+  if (!IS_STRING(this) && !%HasStringClass(this))
+    throw new $TypeError('String.prototype.toString is not generic');
+  return %_ValueOf(this);
+}
+
+
+// ECMA-262 section 15.5.4.3
+function StringValueOf() {
+  if (!IS_STRING(this) && !%HasStringClass(this))
+    throw new $TypeError('String.prototype.valueOf is not generic');
+  return %_ValueOf(this);
+}
+
+
+// ECMA-262, section 15.5.4.4
+function StringCharAt(pos) {
+  var subject = ToString(this);
+  var index = TO_INTEGER(pos);
+  if (index >= subject.length || index < 0) return "";
+  return %CharFromCode(%StringCharCodeAt(subject, index));
+}
+
+
+// ECMA-262 section 15.5.4.5
+function StringCharCodeAt(pos) {
+  var fast_answer = %_FastCharCodeAt(this, pos);
+  if (%_IsSmi(fast_answer)) {
+    return fast_answer;
+  }
+  var subject = ToString(this);
+  var index = TO_INTEGER(pos);
+  return %StringCharCodeAt(subject, index);
+}
+
+
+// ECMA-262, section 15.5.4.6
+function StringConcat() {
+  var len = %_ArgumentsLength();
+  var parts = new $Array(len + 1);
+  parts[0] = ToString(this);
+  for (var i = 0; i < len; i++)
+    parts[i + 1] = ToString(%_Arguments(i));
+  return parts.join('');
+}
+
+// Match ES3 and Safari
+%FunctionSetLength(StringConcat, 1);
+
+
+// ECMA-262 section 15.5.4.7
+function StringIndexOf(searchString /* position */) {  // length == 1
+  var subject_str = ToString(this);
+  var pattern_str = ToString(searchString);
+  var subject_str_len = subject_str.length;
+  var pattern_str_len = pattern_str.length;
+  var index = 0;
+  if (%_ArgumentsLength() > 1) {
+    var arg1 = %_Arguments(1);  // position
+    index = TO_INTEGER(arg1);
+  }
+  if (index < 0) index = 0;
+  if (index > subject_str_len) index = subject_str_len;
+  if (pattern_str_len + index > subject_str_len) return -1;
+  return %StringIndexOf(subject_str, pattern_str, index);
+}
+
+
+// ECMA-262 section 15.5.4.8
+function StringLastIndexOf(searchString /* position */) {  // length == 1
+  var sub = ToString(this);
+  var pat = ToString(searchString);
+  var index = (%_ArgumentsLength() > 1)
+      ? ToNumber(%_Arguments(1) /* position */)
+      : $NaN;
+  var firstIndex;
+  if ($isNaN(index)) {
+    firstIndex = sub.length - pat.length;
+  } else {
+    firstIndex = TO_INTEGER(index);
+    if (firstIndex + pat.length > sub.length) {
+      firstIndex = sub.length - pat.length;
+    }
+  }
+  return %StringLastIndexOf(sub, pat, firstIndex);
+}
+
+
+// ECMA-262 section 15.5.4.9
+//
+// This function is implementation specific.  For now, we do not
+// do anything locale specific.
+function StringLocaleCompare(other) {
+  if (%_ArgumentsLength() === 0) return 0;
+
+  var this_str = ToString(this);
+  var other_str = ToString(other);
+  return %StringLocaleCompare(this_str, other_str);
+}
+
+
+// ECMA-262 section 15.5.4.10
+function StringMatch(regexp) {
+  if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp);
+  var subject = ToString(this);
+
+  if (!regexp.global) return regexp.exec(subject);
+  var matches = DoRegExpExecGlobal(regexp, subject);
+
+  // If the regexp did not match, return null.
+  if (matches.length == 0) return null;
+
+  // Build the result array.
+  var result = new $Array(match_string);
+  for (var i = 0; i < matches.length; ++i) {
+    var match = matches[i];
+    var match_string = subject.slice(match[0], match[1]);
+    result[i] = match_string;
+  }
+
+  return result;
+}
+
+
+// SubString is an internal function that returns the sub string of 'string'.
+// If resulting string is of length 1, we use the one character cache
+// otherwise we call the runtime system.
+function SubString(string, start, end) {
+  // Use the one character string cache.
+  if (start + 1 == end) return %CharFromCode(%StringCharCodeAt(string, start));
+  return %StringSlice(string, start, end);
+}
+
+
+// ECMA-262, section 15.5.4.11
+function StringReplace(search, replace) {
+  var subject = ToString(this);
+
+  // Delegate to one of the regular expression variants if necessary.
+  if (IS_REGEXP(search)) {
+    if (IS_FUNCTION(replace)) {
+      return StringReplaceRegExpWithFunction(subject, search, replace);
+    } else {
+      return StringReplaceRegExp(subject, search, replace);
+    }
+  }
+
+  // Convert the search argument to a string and search for it.
+  search = ToString(search);
+  var start = %StringIndexOf(subject, search, 0);
+  if (start < 0) return subject;
+  var end = start + search.length;
+
+  var builder = new StringBuilder();
+  // prefix
+  builder.add(SubString(subject, 0, start));
+
+  // Compute the string to replace with.
+  if (IS_FUNCTION(replace)) {
+    builder.add(replace.call(null, search, start, subject));
+  } else {
+    ExpandReplacement(ToString(replace), subject, [ start, end ], builder);
+  }
+
+  // suffix
+  builder.add(SubString(subject, end, subject.length));
+
+  return builder.generate();
+}
+
+
+// Helper function for regular expressions in String.prototype.replace.
+function StringReplaceRegExp(subject, regexp, replace) {
+  // Compute an array of matches; each match is really a list of
+  // captures - pairs of (start, end) indexes into the subject string.
+  var matches;
+  if (regexp.global) {
+    matches = DoRegExpExecGlobal(regexp, subject);
+    if (matches.length == 0) return subject;
+  } else {
+    var captures = DoRegExpExec(regexp, subject, 0);
+    if (IS_NULL(captures)) return subject;
+    matches = [ captures ];
+  }
+
+  // Determine the number of matches.
+  var length = matches.length;
+
+  // Build the resulting string of subject slices and replacements.
+  var result = new StringBuilder();
+  var previous = 0;
+  // The caller of StringReplaceRegExp must ensure that replace is not a
+  // function.
+  replace = ToString(replace);
+  for (var i = 0; i < length; i++) {
+    var captures = matches[i];
+    result.add(SubString(subject, previous, captures[0]));
+    ExpandReplacement(replace, subject, captures, result);
+    previous = captures[1];  // continue after match
+  }
+  result.add(SubString(subject, previous, subject.length));
+  return result.generate();
+};
+
+
+// Expand the $-expressions in the string and return a new string with
+// the result.
+function ExpandReplacement(string, subject, captures, builder) {
+  var next = %StringIndexOf(string, '$', 0);
+  if (next < 0) {
+    builder.add(string);
+    return;
+  }
+
+  // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
+  var m = captures.length >> 1;  // includes the match
+
+  if (next > 0) builder.add(SubString(string, 0, next));
+  var length = string.length;
+
+  while (true) {
+    var expansion = '$';
+    var position = next + 1;
+    if (position < length) {
+      var peek = %StringCharCodeAt(string, position);
+      if (peek == 36) {         // $$
+        ++position;
+      } else if (peek == 38) {  // $& - match
+        ++position;
+        expansion = SubString(subject, captures[0], captures[1]);
+      } else if (peek == 96) {  // $` - prefix
+        ++position;
+        expansion = SubString(subject, 0, captures[0]);
+      } else if (peek == 39) {  // $' - suffix
+        ++position;
+        expansion = SubString(subject, captures[1], subject.length);
+      } else if (peek >= 48 && peek <= 57) {  // $n, 0 <= n <= 9
+        ++position;
+        var n = peek - 48;
+        if (position < length) {
+          peek = %StringCharCodeAt(string, position);
+          // $nn, 01 <= nn <= 99
+          if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) {
+            var nn = n * 10 + (peek - 48);
+            if (nn < m) {
+              // If the two digit capture reference is within range of
+              // the captures, we use it instead of the single digit
+              // one. Otherwise, we fall back to using the single
+              // digit reference. This matches the behavior of
+              // SpiderMonkey.
+              ++position;
+              n = nn;
+            }
+          }
+        }
+        if (0 < n && n < m) {
+          expansion = CaptureString(subject, captures, n);
+          if (IS_UNDEFINED(expansion)) expansion = "";
+        } else {
+          // Because of the captures range check in the parsing of two
+          // digit capture references, we can only enter here when a
+          // single digit capture reference is outside the range of
+          // captures.
+          --position;
+        }
+      }
+    }
+
+    // Append the $ expansion and go the the next $ in the string.
+    builder.add(expansion);
+    next = %StringIndexOf(string, '$', position);
+
+    // Return if there are no more $ characters in the string. If we
+    // haven't reached the end, we need to append the suffix.
+    if (next < 0) {
+      if (position < length) {
+        builder.add(SubString(string, position, length));
+      }
+      return;
+    }
+
+    // Append substring between the previous and the next $ character.
+    builder.add(SubString(string, position, next));
+  }
+};
+
+
+// Compute the string of a given PCRE capture.
+function CaptureString(string, captures, index) {
+  // Scale the index.
+  var scaled = index << 1;
+  // Compute start and end.
+  var start = captures[scaled];
+  var end = captures[scaled + 1];
+  // If either start or end is missing return undefined.
+  if (start < 0 || end < 0) return;
+  return SubString(string, start, end);
+};
+
+
+// Helper function for replacing regular expressions with the result of a
+// function application in String.prototype.replace.  The function application
+// must be interleaved with the regexp matching (contrary to ECMA-262
+// 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses
+// the static properties of the RegExp constructor.  Example:
+//     'abcd'.replace(/(.)/g, function() { return RegExp.$1; }
+// should be 'abcd' and not 'dddd' (or anything else).
+function StringReplaceRegExpWithFunction(subject, regexp, replace) {
+  var result = new ReplaceResultBuilder(subject);
+  // Captures is an array of pairs of (start, end) indices for the match and
+  // any captured substrings.
+  var captures = DoRegExpExec(regexp, subject, 0);
+  if (IS_NULL(captures)) return subject;
+
+  // There's at least one match.  If the regexp is global, we have to loop
+  // over all matches.  The loop is not in C++ code here like the one in
+  // RegExp.prototype.exec, because of the interleaved function application.
+  // Unfortunately, that means this code is nearly duplicated, here and in
+  // jsregexp.cc.
+  if (regexp.global) {
+    var previous = 0;
+    do {
+      result.addSpecialSlice(previous, captures[0]);
+      result.add(ApplyReplacementFunction(replace, captures, subject));
+      // Continue with the next match.
+      previous = captures[1];
+      // Increment previous if we matched an empty string, as per ECMA-262
+      // 15.5.4.10.
+      if (captures[0] == captures[1]) previous++;
+
+      // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+      // string length, there is no match
+      captures = (previous > subject.length)
+          ? null
+          : DoRegExpExec(regexp, subject, previous);
+    } while (!IS_NULL(captures));
+
+    // Tack on the final right substring after the last match, if necessary.
+    if (previous < subject.length) {
+      result.addSpecialSlice(previous, subject.length);
+    }
+  } else { // Not a global regexp, no need to loop.
+    result.addSpecialSlice(0, captures[0]);
+    result.add(ApplyReplacementFunction(replace, captures, subject));
+    result.addSpecialSlice(captures[1], subject.length);
+  }
+
+  return result.generate();
+}
+
+
+// Helper function to apply a string replacement function once.
+function ApplyReplacementFunction(replace, captures, subject) {
+  // Compute the parameter list consisting of the match, captures, index,
+  // and subject for the replace function invocation.
+  var index = captures[0];
+  // The number of captures plus one for the match.
+  var m = captures.length >> 1;
+  if (m == 1) {
+    var s = CaptureString(subject, captures, 0);
+    return ToString(replace.call(null, s, index, subject));
+  }
+  var parameters = $Array(m + 2);
+  for (var j = 0; j < m; j++) {
+    parameters[j] = CaptureString(subject, captures, j);
+  }
+  parameters[j] = index;
+  parameters[j + 1] = subject;
+  return ToString(replace.apply(null, parameters));
+}
+
+
+// ECMA-262 section 15.5.4.12
+function StringSearch(re) {
+  var regexp = new ORIGINAL_REGEXP(re);
+  var s = ToString(this);
+  var last_idx = regexp.lastIndex; // keep old lastIndex
+  regexp.lastIndex = 0;            // ignore re.global property
+  var result = regexp.exec(s);
+  regexp.lastIndex = last_idx;     // restore lastIndex
+  if (result == null)
+    return -1;
+  else
+    return result.index;
+}
+
+
+// ECMA-262 section 15.5.4.13
+function StringSlice(start, end) {
+  var s = ToString(this);
+  var s_len = s.length;
+  var start_i = TO_INTEGER(start);
+  var end_i = s_len;
+  if (end !== void 0)
+    end_i = TO_INTEGER(end);
+
+  if (start_i < 0) {
+    start_i += s_len;
+    if (start_i < 0)
+      start_i = 0;
+  } else {
+    if (start_i > s_len)
+      start_i = s_len;
+  }
+
+  if (end_i < 0) {
+    end_i += s_len;
+    if (end_i < 0)
+      end_i = 0;
+  } else {
+    if (end_i > s_len)
+      end_i = s_len;
+  }
+
+  var num_c = end_i - start_i;
+  if (num_c < 0)
+    num_c = 0;
+
+  return SubString(s, start_i, start_i + num_c);
+}
+
+
+// ECMA-262 section 15.5.4.14
+function StringSplit(separator, limit) {
+  var subject = ToString(this);
+  var result = [];
+  var lim = (limit === void 0) ? 0xffffffff : ToUint32(limit);
+
+  if (lim === 0) return result;
+
+  // ECMA-262 says that if separator is undefined, the result should
+  // be an array of size 1 containing the entire string.  SpiderMonkey
+  // and KJS have this behaviour only when no separator is given.  If
+  // undefined is explicitly given, they convert it to a string and
+  // use that.  We do as SpiderMonkey and KJS.
+  if (%_ArgumentsLength() === 0) {
+    result[result.length] = subject;
+    return result;
+  }
+
+  var length = subject.length;
+  var currentIndex = 0;
+  var startIndex = 0;
+
+  var sep = IS_REGEXP(separator) ? separator : ToString(separator);
+
+  if (length === 0) {
+    if (splitMatch(sep, subject, 0, 0) != null) return result;
+    result[result.length] = subject;
+    return result;
+  }
+
+  while (true) {
+
+    if (startIndex === length) {
+      result[result.length] = subject.slice(currentIndex, length);
+      return result;
+    }
+
+    var match = splitMatch(sep, subject, currentIndex, startIndex);
+
+    if (IS_NULL(match)) {
+      result[result.length] = subject.slice(currentIndex, length);
+      return result;
+    }
+
+    var endIndex = match[0];
+
+    // We ignore a zero-length match at the currentIndex.
+    if (startIndex === endIndex && endIndex === currentIndex) {
+      startIndex++;
+      continue;
+    }
+
+    result[result.length] = match[1];
+    if (result.length === lim) return result;
+
+    for (var i = 2; i < match.length; i++) {
+      result[result.length] = match[i];
+      if (result.length === lim) return result;
+    }
+
+    startIndex = currentIndex = endIndex;
+  }
+}
+
+
+// ECMA-262 section 15.5.4.14
+// Helper function used by split.
+function splitMatch(separator, subject, current_index, start_index) {
+  if (IS_REGEXP(separator)) {
+    var ovector = DoRegExpExec(separator, subject, start_index);
+    if (ovector == null) return null;
+    var nof_results = ovector.length >> 1;
+    var result = new $Array(nof_results + 1);
+    result[0] = ovector[1];
+    result[1] = subject.slice(current_index, ovector[0]);
+    for (var i = 1; i < nof_results; i++) {
+      var matching_start = ovector[2*i];
+      var matching_end = ovector[2*i + 1];
+      if (matching_start != -1 && matching_end != -1) {
+        result[i + 1] = subject.slice(matching_start, matching_end);
+      }
+    }
+    return result;
+  }
+
+  var separatorIndex = subject.indexOf(separator, start_index);
+  if (separatorIndex === -1) return null;
+
+  return [ separatorIndex + separator.length, subject.slice(current_index, separatorIndex) ];
+};
+
+
+// ECMA-262 section 15.5.4.15
+function StringSubstring(start, end) {
+  var s = ToString(this);
+  var s_len = s.length;
+  var start_i = TO_INTEGER(start);
+  var end_i = s_len;
+  if (!IS_UNDEFINED(end))
+    end_i = TO_INTEGER(end);
+
+  if (start_i < 0) start_i = 0;
+  if (start_i > s_len) start_i = s_len;
+  if (end_i < 0) end_i = 0;
+  if (end_i > s_len) end_i = s_len;
+
+  if (start_i > end_i) {
+    var tmp = end_i;
+    end_i = start_i;
+    start_i = tmp;
+  }
+
+  return SubString(s, start_i, end_i);
+}
+
+
+// This is not a part of ECMA-262.
+function StringSubstr(start, n) {
+  var s = ToString(this);
+  var len;
+
+  // Correct n: If not given, set to string length; if explicitly
+  // set to undefined, zero, or negative, returns empty string.
+  if (n === void 0) {
+    len = s.length;
+  } else {
+    len = TO_INTEGER(n);
+    if (len <= 0) return '';
+  }
+
+  // Correct start: If not given (or undefined), set to zero; otherwise
+  // convert to integer and handle negative case.
+  if (start === void 0) {
+    start = 0;
+  } else {
+    start = TO_INTEGER(start);
+    // If positive, and greater than or equal to the string length,
+    // return empty string.
+    if (start >= s.length) return '';
+    // If negative and absolute value is larger than the string length,
+    // use zero.
+    if (start < 0) {
+      start += s.length;
+      if (start < 0) start = 0;
+    }
+  }
+
+  var end = start + len;
+  if (end > s.length) end = s.length;
+
+  return SubString(s, start, end);
+}
+
+
+// ECMA-262, 15.5.4.16
+function StringToLowerCase() {
+  return %StringToLowerCase(ToString(this));
+}
+
+
+// ECMA-262, 15.5.4.17
+function StringToLocaleLowerCase() {
+  return %StringToLowerCase(ToString(this));
+}
+
+
+// ECMA-262, 15.5.4.18
+function StringToUpperCase() {
+  return %StringToUpperCase(ToString(this));
+}
+
+
+// ECMA-262, 15.5.4.19
+function StringToLocaleUpperCase() {
+  return %StringToUpperCase(ToString(this));
+}
+
+
+// ECMA-262, section 15.5.3.2
+function StringFromCharCode(code) {
+  var n = %_ArgumentsLength();
+  if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff)
+
+  // NOTE: This is not super-efficient, but it is necessary because we
+  // want to avoid converting to numbers from within the virtual
+  // machine. Maybe we can find another way of doing this?
+  var codes = new $Array(n);
+  for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i));
+  return %StringFromCharCodeArray(codes);
+}
+
+
+// Helper function for very basic XSS protection.
+function HtmlEscape(str) {
+  return ToString(str).replace(/</g, "&lt;")
+                      .replace(/>/g, "&gt;")
+                      .replace(/"/g, "&quot;")
+                      .replace(/'/g, "&#039;");
+};
+
+
+// Compatibility support for KJS.
+// Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js.
+function StringLink(s) {
+  return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>";
+}
+
+
+function StringAnchor(name) {
+  return "<a name=\"" + HtmlEscape(name) + "\">" + this + "</a>";
+}
+
+
+function StringFontcolor(color) {
+  return "<font color=\"" + HtmlEscape(color) + "\">" + this + "</font>";
+}
+
+
+function StringFontsize(size) {
+  return "<font size=\"" + HtmlEscape(size) + "\">" + this + "</font>";
+}
+
+
+function StringBig() {
+  return "<big>" + this + "</big>";
+}
+
+
+function StringBlink() {
+  return "<blink>" + this + "</blink>";
+}
+
+
+function StringBold() {
+  return "<b>" + this + "</b>";
+}
+
+
+function StringFixed() {
+  return "<tt>" + this + "</tt>";
+}
+
+
+function StringItalics() {
+  return "<i>" + this + "</i>";
+}
+
+
+function StringSmall() {
+  return "<small>" + this + "</small>";
+}
+
+
+function StringStrike() {
+  return "<strike>" + this + "</strike>";
+}
+
+
+function StringSub() {
+  return "<sub>" + this + "</sub>";
+}
+
+
+function StringSup() {
+  return "<sup>" + this + "</sup>";
+}
+
+
+// StringBuilder support.
+
+function StringBuilder() {
+  this.elements = new $Array();
+}
+
+
+function ReplaceResultBuilder(str) {
+  this.elements = new $Array();
+  this.special_string = str;
+}
+
+
+ReplaceResultBuilder.prototype.add =
+StringBuilder.prototype.add = function(str) {
+  if (!IS_STRING(str)) str = ToString(str);
+  if (str.length > 0) {
+    var elements = this.elements;
+    elements[elements.length] = str;
+  }
+}
+
+
+ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
+  var len = end - start;
+  if (len == 0) return;
+  var elements = this.elements;
+  if (start >= 0 && len >= 0 && start < 0x80000 && len < 0x800) {
+    elements[elements.length] = (start << 11) + len;
+  } else {
+    elements[elements.length] = SubString(this.special_string, start, end);
+  }
+}
+
+
+StringBuilder.prototype.generate = function() {
+  return %StringBuilderConcat(this.elements, "");
+}
+
+
+ReplaceResultBuilder.prototype.generate = function() {
+  return %StringBuilderConcat(this.elements, this.special_string);
+}
+
+
+// -------------------------------------------------------------------
+
+function SetupString() {
+  // Setup the constructor property on the String prototype object.
+  %SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
+
+
+  // Setup 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.
+  InstallFunctions($String.prototype, DONT_ENUM, $Array(
+    "valueOf", StringValueOf,
+    "toString", StringToString,
+    "charAt", StringCharAt,
+    "charCodeAt", StringCharCodeAt,
+    "concat", StringConcat,
+    "indexOf", StringIndexOf,
+    "lastIndexOf", StringLastIndexOf,
+    "localeCompare", StringLocaleCompare,
+    "match", StringMatch,
+    "replace", StringReplace,
+    "search", StringSearch,
+    "slice", StringSlice,
+    "split", StringSplit,
+    "substring", StringSubstring,
+    "substr", StringSubstr,
+    "toLowerCase", StringToLowerCase,
+    "toLocaleLowerCase", StringToLocaleLowerCase,
+    "toUpperCase", StringToUpperCase,
+    "toLocaleUpperCase", StringToLocaleUpperCase,
+    "link", StringLink,
+    "anchor", StringAnchor,
+    "fontcolor", StringFontcolor,
+    "fontsize", StringFontsize,
+    "big", StringBig,
+    "blink", StringBlink,
+    "bold", StringBold,
+    "fixed", StringFixed,
+    "italics", StringItalics,
+    "small", StringSmall,
+    "strike", StringStrike,
+    "sub", StringSub,
+    "sup", StringSup
+  ));
+}
+
+
+SetupString();
diff --git a/regexp2000/src/stub-cache-arm.cc b/regexp2000/src/stub-cache-arm.cc
new file mode 100644 (file)
index 0000000..0d31709
--- /dev/null
@@ -0,0 +1,841 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ic-inl.h"
+#include "codegen-inl.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+#define __ masm->
+
+
+static void ProbeTable(MacroAssembler* masm,
+                       Code::Flags flags,
+                       StubCache::Table table,
+                       Register name,
+                       Register offset) {
+  ExternalReference key_offset(SCTableReference::keyReference(table));
+  ExternalReference value_offset(SCTableReference::valueReference(table));
+
+  Label miss;
+
+  // Save the offset on the stack.
+  __ push(offset);
+
+  // Check that the key in the entry matches the name.
+  __ mov(ip, Operand(key_offset));
+  __ ldr(ip, MemOperand(ip, offset, LSL, 1));
+  __ cmp(name, Operand(ip));
+  __ b(ne, &miss);
+
+  // Get the code entry from the cache.
+  __ mov(ip, Operand(value_offset));
+  __ ldr(offset, MemOperand(ip, offset, LSL, 1));
+
+  // Check that the flags match what we're looking for.
+  __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
+  __ and_(offset, offset, Operand(~Code::kFlagsTypeMask));
+  __ cmp(offset, Operand(flags));
+  __ b(ne, &miss);
+
+  // Restore offset and re-load code entry from cache.
+  __ pop(offset);
+  __ mov(ip, Operand(value_offset));
+  __ ldr(offset, MemOperand(ip, offset, LSL, 1));
+
+  // Jump to the first instruction in the code stub.
+  __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(offset);
+
+  // Miss: Restore offset and fall through.
+  __ bind(&miss);
+  __ pop(offset);
+}
+
+
+void StubCache::GenerateProbe(MacroAssembler* masm,
+                              Code::Flags flags,
+                              Register receiver,
+                              Register name,
+                              Register scratch) {
+  Label miss;
+
+  // Make sure that code is valid. The shifting code relies on the
+  // entry size being 8.
+  ASSERT(sizeof(Entry) == 8);
+
+  // Make sure the flags does not name a specific type.
+  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
+
+  // Make sure that there are no register conflicts.
+  ASSERT(!scratch.is(receiver));
+  ASSERT(!scratch.is(name));
+
+  // Check that the receiver isn't a smi.
+  __ tst(receiver, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Get the map of the receiver and compute the hash.
+  __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
+  __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ add(scratch, scratch, Operand(ip));
+  __ eor(scratch, scratch, Operand(flags));
+  __ and_(scratch,
+          scratch,
+          Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
+
+  // Probe the primary table.
+  ProbeTable(masm, flags, kPrimary, name, scratch);
+
+  // Primary miss: Compute hash for secondary probe.
+  __ sub(scratch, scratch, Operand(name));
+  __ add(scratch, scratch, Operand(flags));
+  __ and_(scratch,
+          scratch,
+          Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
+
+  // Probe the secondary table.
+  ProbeTable(masm, flags, kSecondary, name, scratch);
+
+  // Cache miss: Fall-through and let caller handle the miss by
+  // entering the runtime system.
+  __ bind(&miss);
+}
+
+
+void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
+                                                       int index,
+                                                       Register prototype) {
+  // Load the global or builtins object from the current context.
+  __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  // Load the global context from the global or builtins object.
+  __ ldr(prototype,
+         FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
+  // Load the function from the global context.
+  __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
+  // Load the initial map.  The global functions all have initial maps.
+  __ ldr(prototype,
+         FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
+  // Load the prototype from the initial map.
+  __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
+}
+
+
+// Load a fast property out of a holder object (src). In-object properties
+// are loaded directly otherwise the property is loaded from the properties
+// fixed array.
+void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
+                                            Register dst, Register src,
+                                            JSObject* holder, int index) {
+  // Adjust for the number of properties stored in the holder.
+  index -= holder->map()->inobject_properties();
+  if (index < 0) {
+    // Get the property straight out of the holder.
+    int offset = holder->map()->instance_size() + (index * kPointerSize);
+    __ ldr(dst, FieldMemOperand(src, offset));
+  } else {
+    // Calculate the offset into the properties array.
+    int offset = index * kPointerSize + Array::kHeaderSize;
+    __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
+    __ ldr(dst, FieldMemOperand(dst, offset));
+  }
+}
+
+
+#undef __
+
+#define __ masm()->
+
+
+Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
+  // ----------- S t a t e -------------
+  //  -- r1: function
+  //  -- lr: return address
+  // -----------------------------------
+
+  HandleScope scope;
+
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Preserve the function.
+  __ push(r1);
+
+  // Push the function on the stack as the argument to the runtime function.
+  __ push(r1);
+  __ CallRuntime(Runtime::kLazyCompile, 1);
+
+  // Calculate the entry point.
+  __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // Restore saved function.
+  __ pop(r1);
+
+  // Tear down temporary frame.
+  __ LeaveInternalFrame();
+
+  // Do a tail-call of the compiled function.
+  __ Jump(r2);
+
+  return GetCodeWithFlags(flags);
+}
+
+
+Object* CallStubCompiler::CompileCallField(Object* object,
+                                           JSObject* holder,
+                                           int index) {
+  // ----------- S t a t e -------------
+  //  -- lr: return address
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  const int argc = arguments().immediate();
+
+  // Get the receiver of the function from the stack into r1.
+  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+  // Check that the receiver isn't a smi.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Do the right check and compute the holder register.
+  Register reg =
+      __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+  GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
+
+  // Check that the function really is a function.
+  __ tst(r1, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+  // Get the map.
+  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+  __ cmp(r2, Operand(JS_FUNCTION_TYPE));
+  __ b(ne, &miss);
+
+  if (object->IsGlobalObject()) {
+    // TODO(120): Patch receiver with the global proxy.
+  }
+
+  // Invoke the function.
+  __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(FIELD);
+}
+
+
+Object* CallStubCompiler::CompileCallConstant(Object* object,
+                                              JSObject* holder,
+                                              JSFunction* function,
+                                              CheckType check) {
+  // ----------- S t a t e -------------
+  //  -- lr: return address
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the receiver from the stack
+  const int argc = arguments().immediate();
+  __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  if (check != NUMBER_CHECK) {
+    __ tst(r1, Operand(kSmiTagMask));
+    __ b(eq, &miss);
+  }
+
+  switch (check) {
+    case RECEIVER_MAP_CHECK:
+      // Check that the maps haven't changed.
+      __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+      break;
+
+    case STRING_CHECK:
+      // Check that the object is a two-byte string or a symbol.
+      __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+      __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+      __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
+      __ b(hs, &miss);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::STRING_FUNCTION_INDEX,
+                                          r2);
+      __ CheckMaps(JSObject::cast(object->GetPrototype()),
+                   r2, holder, r3, r1, &miss);
+      break;
+
+    case NUMBER_CHECK: {
+      Label fast;
+      // Check that the object is a smi or a heap number.
+      __ tst(r1, Operand(kSmiTagMask));
+      __ b(eq, &fast);
+      __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+      __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+      __ cmp(r2, Operand(HEAP_NUMBER_TYPE));
+      __ b(ne, &miss);
+      __ bind(&fast);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::NUMBER_FUNCTION_INDEX,
+                                          r2);
+      __ CheckMaps(JSObject::cast(object->GetPrototype()),
+                   r2, holder, r3, r1, &miss);
+      break;
+    }
+
+    case BOOLEAN_CHECK: {
+      Label fast;
+      // Check that the object is a boolean.
+      __ cmp(r1, Operand(Factory::true_value()));
+      __ b(eq, &fast);
+      __ cmp(r1, Operand(Factory::false_value()));
+      __ b(ne, &miss);
+      __ bind(&fast);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::BOOLEAN_FUNCTION_INDEX,
+                                          r2);
+      __ CheckMaps(JSObject::cast(object->GetPrototype()),
+                   r2, holder, r3, r1, &miss);
+      break;
+    }
+
+    case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
+      __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+      // Make sure object->elements()->map() != Heap::hash_table_map()
+      // Get the elements array of the object.
+      __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
+      // Check that the object is in fast mode (not dictionary).
+      __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
+      __ cmp(r2, Operand(Factory::hash_table_map()));
+      __ b(eq, &miss);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+
+  // Get the function and setup the context.
+  __ mov(r1, Operand(Handle<JSFunction>(function)));
+  __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+
+  if (object->IsGlobalObject()) {
+    // TODO(120): Patch receiver with the global proxy.
+  }
+
+  // Jump to the cached code (tail call).
+  Handle<Code> code(function->code());
+  ParameterCount expected(function->shared()->formal_parameter_count());
+  __ InvokeCode(code, expected, arguments(),
+                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(CONSTANT_FUNCTION);
+}
+
+
+Object* CallStubCompiler::CompileCallInterceptor(Object* object,
+                                                 JSObject* holder,
+                                                 String* name) {
+  // ----------- S t a t e -------------
+  //  -- lr: return address
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // TODO(1224669): Implement.
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(INTERCEPTOR);
+}
+
+
+Object* StoreStubCompiler::CompileStoreField(JSObject* object,
+                                             int index,
+                                             Map* transition,
+                                             String* name) {
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss, exit;
+
+  // Get the receiver from the stack.
+  __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r3, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the map of the receiver hasn't changed.
+  __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ cmp(r1, Operand(Handle<Map>(object->map())));
+  __ b(ne, &miss);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(r3, r1, &miss);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  // Perform map transition for the receiver if necessary.
+  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+    // The properties must be extended before we can store the value.
+    // We jump to a runtime call that extends the propeties array.
+    __ mov(r2, Operand(Handle<Map>(transition)));
+    // Please note, if we implement keyed store for arm we need
+    // to call the Builtins::KeyedStoreIC_ExtendStorage.
+    Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
+    __ Jump(ic, RelocInfo::CODE_TARGET);
+  } else {
+    // Adjust for the number of properties stored in the object. Even in the
+    // face of a transition we can use the old map here because the size of the
+    // object and the number of in-object properties is not going to change.
+    index -= object->map()->inobject_properties();
+
+    if (index >= 0) {
+      // Get the properties array
+      __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
+    }
+
+    if (transition != NULL) {
+      // Update the map of the object; no write barrier updating is
+      // needed because the map is never in new space.
+      __ mov(ip, Operand(Handle<Map>(transition)));
+      __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
+    }
+
+    if (index < 0) {
+      // Set the property straight into the object.
+      int offset = object->map()->instance_size() + (index * kPointerSize);
+      __ str(r0, FieldMemOperand(r3, offset));
+
+      // Skip updating write barrier if storing a smi.
+      __ tst(r0, Operand(kSmiTagMask));
+      __ b(eq, &exit);
+
+      // Update the write barrier for the array address.
+      __ mov(r1, Operand(offset));
+      __ RecordWrite(r3, r1, r2);
+    } else {
+      // Write to the properties array.
+      int offset = index * kPointerSize + Array::kHeaderSize;
+      __ str(r0, FieldMemOperand(r1, offset));
+
+      // Skip updating write barrier if storing a smi.
+      __ tst(r0, Operand(kSmiTagMask));
+      __ b(eq, &exit);
+
+      // Update the write barrier for the array address.
+      __ mov(r3, Operand(offset));
+      __ RecordWrite(r1, r3, r2);  // OK to clobber r2, since we return
+    }
+
+    // Return the value (register r0).
+    __ bind(&exit);
+    __ Ret();
+  }
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ mov(r2, Operand(Handle<String>(name)));  // restore name
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
+}
+
+
+Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
+                                                AccessorInfo* callback,
+                                                String* name) {
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the object from the stack.
+  __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
+
+  // Check that the object isn't a smi.
+  __ tst(r3, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the map of the object hasn't changed.
+  __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ cmp(r1, Operand(Handle<Map>(object->map())));
+  __ b(ne, &miss);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(r3, r1, &miss);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  __ ldr(ip, MemOperand(sp));  // receiver
+  __ push(ip);
+  __ mov(ip, Operand(Handle<AccessorInfo>(callback)));  // callback info
+  __ push(ip);
+  __ push(r2);  // name
+  __ push(r0);  // value
+
+  // Do tail-call to the runtime system.
+  ExternalReference store_callback_property =
+      ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
+  __ TailCallRuntime(store_callback_property, 4);
+
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ mov(r2, Operand(Handle<String>(name)));  // restore name
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
+                                                   String* name) {
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the object from the stack.
+  __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
+
+  // Check that the object isn't a smi.
+  __ tst(r3, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the map of the object hasn't changed.
+  __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ cmp(r1, Operand(Handle<Map>(receiver->map())));
+  __ b(ne, &miss);
+
+  // Perform global security token check if needed.
+  if (receiver->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(r3, r1, &miss);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
+
+  __ ldr(ip, MemOperand(sp));  // receiver
+  __ push(ip);
+  __ push(r2);  // name
+  __ push(r0);  // value
+
+  // Do tail-call to the runtime system.
+  ExternalReference store_ic_property =
+      ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
+  __ TailCallRuntime(store_ic_property, 3);
+
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ mov(r2, Operand(Handle<String>(name)));  // restore name
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(INTERCEPTOR);
+}
+
+
+Object* LoadStubCompiler::CompileLoadField(JSObject* object,
+                                           JSObject* holder,
+                                           int index) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the maps haven't changed.
+  Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
+  GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
+  __ Ret();
+
+  // Handle load cache miss.
+  __ bind(&miss);
+  __ ldr(r0, MemOperand(sp));  // restore receiver
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(FIELD);
+}
+
+
+Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
+                                              JSObject* holder,
+                                              AccessorInfo* callback) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the maps haven't changed.
+  Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
+
+  // Push the arguments on the JS stack of the caller.
+  __ push(r0);  // receiver
+  __ mov(ip, Operand(Handle<AccessorInfo>(callback)));  // callback data
+  __ push(ip);
+  __ push(r2);  // name
+  __ push(reg);  // holder
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_callback_property =
+      ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+  __ TailCallRuntime(load_callback_property, 4);
+
+  // Handle load cache miss.
+  __ bind(&miss);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
+                                              JSObject* holder,
+                                              Object* value) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp] : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the maps haven't changed.
+  Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
+
+  // Return the constant value.
+  __ mov(r0, Operand(Handle<Object>(value)));
+  __ Ret();
+
+  // Handle load cache miss.
+  __ bind(&miss);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(CONSTANT_FUNCTION);
+}
+
+
+Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
+                                                 JSObject* holder,
+                                                 String* name) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  __ ldr(r0, MemOperand(sp, 0));
+  // Check that the receiver isn't a smi.
+  __ tst(r0, Operand(kSmiTagMask));
+  __ b(eq, &miss);
+
+  // Check that the maps haven't changed.
+  Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
+
+  // Push the arguments on the JS stack of the caller.
+  __ push(r0);  // receiver
+  __ push(reg);  // holder
+  __ push(r2);  // name
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_ic_property =
+      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+  __ TailCallRuntime(load_ic_property, 3);
+
+  // Handle load cache miss.
+  __ bind(&miss);
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(INTERCEPTOR);
+}
+
+
+// TODO(1224671): IC stubs for keyed loads have not been implemented
+// for ARM.
+Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
+                                                JSObject* receiver,
+                                                JSObject* holder,
+                                                int index) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
+                                                   JSObject* receiver,
+                                                   JSObject* holder,
+                                                   AccessorInfo* callback) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
+                                                   JSObject* receiver,
+                                                   JSObject* holder,
+                                                   Object* value) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
+                                                      JSObject* holder,
+                                                      String* name) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
+                                                  int index,
+                                                  Map* transition,
+                                                  String* name) {
+  UNIMPLEMENTED();
+  return Heap::undefined_value();
+}
+
+
+
+#undef __
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/stub-cache-ia32.cc b/regexp2000/src/stub-cache-ia32.cc
new file mode 100644 (file)
index 0000000..ef9a8bd
--- /dev/null
@@ -0,0 +1,1266 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ic-inl.h"
+#include "codegen-inl.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+#define __ masm->
+
+
+static void ProbeTable(MacroAssembler* masm,
+                       Code::Flags flags,
+                       StubCache::Table table,
+                       Register name,
+                       Register offset) {
+  ExternalReference key_offset(SCTableReference::keyReference(table));
+  ExternalReference value_offset(SCTableReference::valueReference(table));
+
+  Label miss;
+
+  // Save the offset on the stack.
+  __ push(offset);
+
+  // Check that the key in the entry matches the name.
+  __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
+  __ j(not_equal, &miss, not_taken);
+
+  // Get the code entry from the cache.
+  __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
+
+  // Check that the flags match what we're looking for.
+  __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
+  __ and_(offset, ~Code::kFlagsTypeMask);
+  __ cmp(offset, flags);
+  __ j(not_equal, &miss);
+
+  // Restore offset and re-load code entry from cache.
+  __ pop(offset);
+  __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
+
+  // Jump to the first instruction in the code stub.
+  __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
+  __ jmp(Operand(offset));
+
+  // Miss: Restore offset and fall through.
+  __ bind(&miss);
+  __ pop(offset);
+}
+
+
+void StubCache::GenerateProbe(MacroAssembler* masm,
+                              Code::Flags flags,
+                              Register receiver,
+                              Register name,
+                              Register scratch) {
+  Label miss;
+
+  // Make sure that code is valid. The shifting code relies on the
+  // entry size being 8.
+  ASSERT(sizeof(Entry) == 8);
+
+  // Make sure the flags does not name a specific type.
+  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
+
+  // Make sure that there are no register conflicts.
+  ASSERT(!scratch.is(receiver));
+  ASSERT(!scratch.is(name));
+
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Get the map of the receiver and compute the hash.
+  __ mov(scratch, FieldOperand(name, String::kLengthOffset));
+  __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ xor_(scratch, flags);
+  __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
+
+  // Probe the primary table.
+  ProbeTable(masm, flags, kPrimary, name, scratch);
+
+  // Primary miss: Compute hash for secondary probe.
+  __ sub(scratch, Operand(name));
+  __ add(Operand(scratch), Immediate(flags));
+  __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
+
+  // Probe the secondary table.
+  ProbeTable(masm, flags, kSecondary, name, scratch);
+
+  // Cache miss: Fall-through and let caller handle the miss by
+  // entering the runtime system.
+  __ bind(&miss);
+}
+
+
+void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
+                                                       int index,
+                                                       Register prototype) {
+  // Load the global or builtins object from the current context.
+  __ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  // Load the global context from the global or builtins object.
+  __ mov(prototype,
+         FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
+  // Load the function from the global context.
+  __ mov(prototype, Operand(prototype, Context::SlotOffset(index)));
+  // Load the initial map.  The global functions all have initial maps.
+  __ mov(prototype,
+         FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
+  // Load the prototype from the initial map.
+  __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
+}
+
+
+void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
+                                           Register receiver,
+                                           Register scratch,
+                                           Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the object is a JS array.
+  __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+  __ cmp(scratch, JS_ARRAY_TYPE);
+  __ j(not_equal, miss_label, not_taken);
+
+  // Load length directly from the JS array.
+  __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadShortStringLength(MacroAssembler* masm,
+                                                 Register receiver,
+                                                 Register scratch,
+                                                 Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the object is a short string.
+  __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+  __ and_(scratch, kIsNotStringMask | kStringSizeMask);
+  __ cmp(scratch, kStringTag | kShortStringTag);
+  __ j(not_equal, miss_label, not_taken);
+
+  // Load length directly from the string.
+  __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
+  __ shr(eax, String::kShortLengthShift);
+  __ shl(eax, kSmiTagSize);
+  __ ret(0);
+}
+
+void StubCompiler::GenerateLoadMediumStringLength(MacroAssembler* masm,
+                                                  Register receiver,
+                                                  Register scratch,
+                                                  Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the object is a short string.
+  __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+  __ and_(scratch, kIsNotStringMask | kStringSizeMask);
+  __ cmp(scratch, kStringTag | kMediumStringTag);
+  __ j(not_equal, miss_label, not_taken);
+
+  // Load length directly from the string.
+  __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
+  __ shr(eax, String::kMediumLengthShift);
+  __ shl(eax, kSmiTagSize);
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadLongStringLength(MacroAssembler* masm,
+                                                Register receiver,
+                                                Register scratch,
+                                                Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the object is a short string.
+  __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+  __ and_(scratch, kIsNotStringMask | kStringSizeMask);
+  __ cmp(scratch, kStringTag | kLongStringTag);
+  __ j(not_equal, miss_label, not_taken);
+
+  // Load length directly from the string.
+  __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
+  __ shr(eax, String::kLongLengthShift);
+  __ shl(eax, kSmiTagSize);
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
+                                                 Register receiver,
+                                                 Register scratch1,
+                                                 Register scratch2,
+                                                 Label* miss_label) {
+  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
+  __ mov(eax, Operand(scratch1));
+  __ ret(0);
+}
+
+
+// Load a fast property out of a holder object (src). In-object properties
+// are loaded directly otherwise the property is loaded from the properties
+// fixed array.
+void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
+                              Register dst, Register src,
+                              JSObject* holder, int index) {
+  // Adjust for the number of properties stored in the holder.
+  index -= holder->map()->inobject_properties();
+  if (index < 0) {
+    // Get the property straight out of the holder.
+    int offset = holder->map()->instance_size() + (index * kPointerSize);
+    __ mov(dst, FieldOperand(src, offset));
+  } else {
+    // Calculate the offset into the properties array.
+    int offset = index * kPointerSize + Array::kHeaderSize;
+    __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+    __ mov(dst, FieldOperand(dst, offset));
+  }
+}
+
+
+void StubCompiler::GenerateLoadField(MacroAssembler* masm,
+                                     JSObject* object,
+                                     JSObject* holder,
+                                     Register receiver,
+                                     Register scratch1,
+                                     Register scratch2,
+                                     int index,
+                                     Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+
+  // Get the value from the properties.
+  GenerateFastPropertyLoad(masm, eax, reg, holder, index);
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
+                                        JSObject* object,
+                                        JSObject* holder,
+                                        Register receiver,
+                                        Register name,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        AccessorInfo* callback,
+                                        Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+
+  // Push the arguments on the JS stack of the caller.
+  __ pop(scratch2);  // remove return address
+  __ push(receiver);  // receiver
+  __ push(Immediate(Handle<AccessorInfo>(callback)));  // callback data
+  __ push(name);  // name
+  __ push(reg);  // holder
+  __ push(scratch2);  // restore return address
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_callback_property =
+      ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+  __ TailCallRuntime(load_callback_property, 4);
+}
+
+
+void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
+                                        JSObject* object,
+                                        JSObject* holder,
+                                        Register receiver,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        Object* value,
+                                        Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+
+  // Return the constant value.
+  __ mov(eax, Handle<Object>(value));
+  __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
+                                           JSObject* object,
+                                           JSObject* holder,
+                                           Register receiver,
+                                           Register name,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Label* miss_label) {
+  // Check that the receiver isn't a smi.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the maps haven't changed.
+  Register reg =
+      __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
+
+  // Push the arguments on the JS stack of the caller.
+  __ pop(scratch2);  // remove return address
+  __ push(receiver);  // receiver
+  __ push(reg);  // holder
+  __ push(name);  // name
+  __ push(scratch2);  // restore return address
+
+  // Do tail-call to the runtime system.
+  ExternalReference load_ic_property =
+      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+  __ TailCallRuntime(load_ic_property, 3);
+}
+
+
+void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
+  ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
+  Code* code = NULL;
+  if (kind == Code::LOAD_IC) {
+    code = Builtins::builtin(Builtins::LoadIC_Miss);
+  } else {
+    code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+  }
+
+  Handle<Code> ic(code);
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+                                      Builtins::Name storage_extend,
+                                      JSObject* object,
+                                      int index,
+                                      Map* transition,
+                                      Register receiver_reg,
+                                      Register name_reg,
+                                      Register scratch,
+                                      Label* miss_label) {
+  // Check that the object isn't a smi.
+  __ test(receiver_reg, Immediate(kSmiTagMask));
+  __ j(zero, miss_label, not_taken);
+
+  // Check that the map of the object hasn't changed.
+  __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+         Immediate(Handle<Map>(object->map())));
+  __ j(not_equal, miss_label, not_taken);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  // Perform map transition for the receiver if necessary.
+  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+    // The properties must be extended before we can store the value.
+    // We jump to a runtime call that extends the propeties array.
+    __ mov(Operand(ecx), Immediate(Handle<Map>(transition)));
+    Handle<Code> ic(Builtins::builtin(storage_extend));
+    __ jmp(ic, RelocInfo::CODE_TARGET);
+    return;
+  }
+
+  // Adjust for the number of properties stored in the object. Even in the
+  // face of a transition we can use the old map here because the size of the
+  // object and the number of in-object properties is not going to change.
+  index -= object->map()->inobject_properties();
+
+  if (index >= 0) {
+    // Get the properties array (optimistically).
+    __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+  }
+
+  if (transition != NULL) {
+    // Update the map of the object; no write barrier updating is
+    // needed because the map is never in new space.
+    __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+           Immediate(Handle<Map>(transition)));
+  }
+
+  if (index < 0) {
+    // Set the property straight into the object.
+    int offset = object->map()->instance_size() + (index * kPointerSize);
+    __ mov(FieldOperand(receiver_reg, offset), eax);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ mov(name_reg, Operand(eax));
+    __ RecordWrite(receiver_reg, offset, name_reg, scratch);
+  } else {
+    // Write to the properties array.
+    int offset = index * kPointerSize + Array::kHeaderSize;
+    __ mov(FieldOperand(scratch, offset), eax);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ mov(name_reg, Operand(eax));
+    __ RecordWrite(scratch, offset, name_reg, receiver_reg);
+  }
+
+  // Return the value (register eax).
+  __ ret(0);
+}
+
+
+#undef __
+
+#define __ masm()->
+
+
+// TODO(1241006): Avoid having lazy compile stubs specialized by the
+// number of arguments. It is not needed anymore.
+Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
+  HandleScope scope;
+
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Push a copy of the function onto the stack.
+  __ push(edi);
+
+  __ push(edi);  // function is also the parameter to the runtime call
+  __ CallRuntime(Runtime::kLazyCompile, 1);
+  __ pop(edi);
+
+  // Tear down temporary frame.
+  __ LeaveInternalFrame();
+
+  // Do a tail-call of the compiled function.
+  __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
+  __ jmp(Operand(ecx));
+
+  return GetCodeWithFlags(flags);
+}
+
+
+Object* CallStubCompiler::CompileCallField(Object* object,
+                                           JSObject* holder,
+                                           int index) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Do the right check and compute the holder register.
+  Register reg =
+      __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+
+  GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
+
+  // Check that the function really is a function.
+  __ test(edi, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+  __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));  // get the map
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ cmp(ebx, JS_FUNCTION_TYPE);
+  __ j(not_equal, &miss, not_taken);
+
+  if (object->IsGlobalObject()) {
+    // TODO(120): Patch receiver with the global proxy.
+  }
+
+  // Invoke the function.
+  __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(FIELD);
+}
+
+
+Object* CallStubCompiler::CompileCallConstant(Object* object,
+                                              JSObject* holder,
+                                              JSFunction* function,
+                                              CheckType check) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the receiver from the stack.
+  const int argc = arguments().immediate();
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+
+  // Check that the receiver isn't a smi.
+  if (check != NUMBER_CHECK) {
+    __ test(edx, Immediate(kSmiTagMask));
+    __ j(zero, &miss, not_taken);
+  }
+
+  switch (check) {
+    case RECEIVER_MAP_CHECK:
+      // Check that the maps haven't changed.
+      __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+      break;
+
+    case STRING_CHECK:
+      // Check that the object is a two-byte string or a symbol.
+      __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+      __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+      __ cmp(ecx, FIRST_NONSTRING_TYPE);
+      __ j(above_equal, &miss, not_taken);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::STRING_FUNCTION_INDEX,
+                                          ecx);
+      __ CheckMaps(JSObject::cast(object->GetPrototype()),
+                   ecx, holder, ebx, edx, &miss);
+      break;
+
+    case NUMBER_CHECK: {
+      Label fast;
+      // Check that the object is a smi or a heap number.
+      __ test(edx, Immediate(kSmiTagMask));
+      __ j(zero, &fast, taken);
+      __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+      __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+      __ cmp(ecx, HEAP_NUMBER_TYPE);
+      __ j(not_equal, &miss, not_taken);
+      __ bind(&fast);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::NUMBER_FUNCTION_INDEX,
+                                          ecx);
+      __ CheckMaps(JSObject::cast(object->GetPrototype()),
+                   ecx, holder, ebx, edx, &miss);
+      break;
+    }
+
+    case BOOLEAN_CHECK: {
+      Label fast;
+      // Check that the object is a boolean.
+      __ cmp(edx, Factory::true_value());
+      __ j(equal, &fast, taken);
+      __ cmp(edx, Factory::false_value());
+      __ j(not_equal, &miss, not_taken);
+      __ bind(&fast);
+      // Check that the maps starting from the prototype haven't changed.
+      GenerateLoadGlobalFunctionPrototype(masm(),
+                                          Context::BOOLEAN_FUNCTION_INDEX,
+                                          ecx);
+      __ CheckMaps(JSObject::cast(object->GetPrototype()),
+                   ecx, holder, ebx, edx, &miss);
+      break;
+    }
+
+    case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
+      __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+      // Make sure object->elements()->map() != Heap::dictionary_array_map()
+      // Get the elements array of the object.
+      __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+      // Check that the object is in fast mode (not dictionary).
+      __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
+             Immediate(Factory::hash_table_map()));
+      __ j(equal, &miss, not_taken);
+      break;
+
+    default:
+      UNREACHABLE();
+  }
+
+  // Get the function and setup the context.
+  __ mov(Operand(edi), Immediate(Handle<JSFunction>(function)));
+  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+
+  if (object->IsGlobalObject()) {
+    // TODO(120): Patch receiver with the global proxy.
+  }
+
+  // Jump to the cached code (tail call).
+  Handle<Code> code(function->code());
+  ParameterCount expected(function->shared()->formal_parameter_count());
+  __ InvokeCode(code, expected, arguments(),
+                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+
+  // Handle call cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(CONSTANT_FUNCTION);
+}
+
+
+Object* CallStubCompiler::CompileCallInterceptor(Object* object,
+                                                 JSObject* holder,
+                                                 String* name) {
+  // ----------- S t a t e -------------
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the number of arguments.
+  const int argc = arguments().immediate();
+
+  // Get the receiver from the stack.
+  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+  // Check that the receiver isn't a smi.
+  __ test(edx, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Check that maps have not changed and compute the holder register.
+  Register reg =
+      __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Push arguments on the expression stack.
+  __ push(edx);  // receiver
+  __ push(reg);  // holder
+  __ push(Operand(ebp, (argc + 3) * kPointerSize));  // name
+
+  // Perform call.
+  ExternalReference load_interceptor =
+      ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+  __ mov(Operand(eax), Immediate(3));
+  __ mov(Operand(ebx), Immediate(load_interceptor));
+
+  CEntryStub stub;
+  __ CallStub(&stub);
+
+  // Move result to edi and restore receiver.
+  __ mov(Operand(edi), eax);
+  __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize));  // receiver
+
+  // Exit frame.
+  __ LeaveInternalFrame();
+
+  // Check that the function really is a function.
+  __ test(edi, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+  __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ cmp(ebx, JS_FUNCTION_TYPE);
+  __ j(not_equal, &miss, not_taken);
+
+  if (object->IsGlobalObject()) {
+    // TODO(120): Patch receiver with the global proxy.
+  }
+
+  // Invoke the function.
+  __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
+
+  // Handle load cache miss.
+  __ bind(&miss);
+  Handle<Code> ic = ComputeCallMiss(argc);
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(INTERCEPTOR);
+}
+
+
+Object* StoreStubCompiler::CompileStoreField(JSObject* object,
+                                             int index,
+                                             Map* transition,
+                                             String* name) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the object from the stack.
+  __ mov(ebx, Operand(esp, 1 * kPointerSize));
+
+  // Generate store field code.  Trashes the name register.
+  GenerateStoreField(masm(),
+                     Builtins::StoreIC_ExtendStorage,
+                     object,
+                     index,
+                     transition,
+                     ebx, ecx, edx,
+                     &miss);
+
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ mov(Operand(ecx), Immediate(Handle<String>(name)));  // restore name
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
+}
+
+
+Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
+                                                AccessorInfo* callback,
+                                                String* name) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the object from the stack.
+  __ mov(ebx, Operand(esp, 1 * kPointerSize));
+
+  // Check that the object isn't a smi.
+  __ test(ebx, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Check that the map of the object hasn't changed.
+  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
+         Immediate(Handle<Map>(object->map())));
+  __ j(not_equal, &miss, not_taken);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(ebx, edx, &miss);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  __ pop(ebx);  // remove the return address
+  __ push(Operand(esp, 0));  // receiver
+  __ push(Immediate(Handle<AccessorInfo>(callback)));  // callback info
+  __ push(ecx);  // name
+  __ push(eax);  // value
+  __ push(ebx);  // restore return address
+
+  // Do tail-call to the runtime system.
+  ExternalReference store_callback_property =
+      ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
+  __ TailCallRuntime(store_callback_property, 4);
+
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ mov(Operand(ecx), Immediate(Handle<String>(name)));  // restore name
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
+                                                   String* name) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  // Get the object from the stack.
+  __ mov(ebx, Operand(esp, 1 * kPointerSize));
+
+  // Check that the object isn't a smi.
+  __ test(ebx, Immediate(kSmiTagMask));
+  __ j(zero, &miss, not_taken);
+
+  // Check that the map of the object hasn't changed.
+  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
+         Immediate(Handle<Map>(receiver->map())));
+  __ j(not_equal, &miss, not_taken);
+
+  // Perform global security token check if needed.
+  if (receiver->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(ebx, edx, &miss);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
+
+  __ pop(ebx);  // remove the return address
+  __ push(Operand(esp, 0));  // receiver
+  __ push(ecx);  // name
+  __ push(eax);  // value
+  __ push(ebx);  // restore return address
+
+  // Do tail-call to the runtime system.
+  ExternalReference store_ic_property =
+      ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
+  __ TailCallRuntime(store_ic_property, 3);
+
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ mov(Operand(ecx), Immediate(Handle<String>(name)));  // restore name
+  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(INTERCEPTOR);
+}
+
+
+Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
+                                                  int index,
+                                                  Map* transition,
+                                                  String* name) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- esp[0] : return address
+  //  -- esp[4] : key
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ IncrementCounter(&Counters::keyed_store_field, 1);
+
+  // Get the name from the stack.
+  __ mov(ecx, Operand(esp, 1 * kPointerSize));
+  // Check that the name has not changed.
+  __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  // Get the object from the stack.
+  __ mov(ebx, Operand(esp, 2 * kPointerSize));
+
+  // Generate store field code.  Trashes the name register.
+  GenerateStoreField(masm(),
+                     Builtins::KeyedStoreIC_ExtendStorage,
+                     object,
+                     index,
+                     transition,
+                     ebx, ecx, edx,
+                     &miss);
+
+  // Handle store cache miss.
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_store_field, 1);
+  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+
+  // Return the generated code.
+  return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
+}
+
+
+Object* LoadStubCompiler::CompileLoadField(JSObject* object,
+                                           JSObject* holder,
+                                           int index) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(FIELD);
+}
+
+
+Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
+                                              JSObject* holder,
+                                              AccessorInfo* callback) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
+                       edx, callback, &miss);
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
+                                              JSObject* holder,
+                                              Object* value) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CONSTANT_FUNCTION);
+}
+
+
+Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
+                                                 JSObject* holder,
+                                                 String* name) {
+  // ----------- S t a t e -------------
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  //  -- esp[4] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(INTERCEPTOR);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
+                                                JSObject* receiver,
+                                                JSObject* holder,
+                                                int index) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_field, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_field, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(FIELD);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
+                                                   JSObject* receiver,
+                                                   JSObject* holder,
+                                                   AccessorInfo* callback) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_callback, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
+                       callback, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_callback, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
+                                                   JSObject* receiver,
+                                                   JSObject* holder,
+                                                   Object* value) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CONSTANT_FUNCTION);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
+                                                      JSObject* holder,
+                                                      String* name) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(INTERCEPTOR);
+}
+
+
+
+
+Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_array_length, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadArrayLength(masm(), ecx, edx, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_array_length, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_string_length, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadShortStringLength(masm(), ecx, edx, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_string_length, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_string_length, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadMediumStringLength(masm(), ecx, edx, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_string_length, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_string_length, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadLongStringLength(masm(), ecx, edx, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_string_length, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
+  // ----------- S t a t e -------------
+  //  -- esp[0] : return address
+  //  -- esp[4] : name
+  //  -- esp[8] : receiver
+  // -----------------------------------
+  HandleScope scope;
+  Label miss;
+
+  __ mov(eax, (Operand(esp, kPointerSize)));
+  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
+  __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
+
+  // Check that the name has not changed.
+  __ cmp(Operand(eax), Immediate(Handle<String>(name)));
+  __ j(not_equal, &miss, not_taken);
+
+  GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
+  __ bind(&miss);
+  __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
+  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(CALLBACKS);
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/stub-cache.cc b/regexp2000/src/stub-cache.cc
new file mode 100644 (file)
index 0000000..8d7c395
--- /dev/null
@@ -0,0 +1,957 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "arguments.h"
+#include "ic-inl.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+// -----------------------------------------------------------------------
+// StubCache implementation.
+
+
+StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
+StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
+
+void StubCache::Initialize(bool create_heap_objects) {
+  ASSERT(IsPowerOf2(kPrimaryTableSize));
+  ASSERT(IsPowerOf2(kSecondaryTableSize));
+  if (create_heap_objects) {
+    HandleScope scope;
+    Clear();
+  }
+}
+
+
+Code* StubCache::Set(String* name, Map* map, Code* code) {
+  // Get the flags from the code.
+  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
+
+  // Validate that the name does not move on scavenge, and that we
+  // can use identity checks instead of string equality checks.
+  ASSERT(!Heap::InNewSpace(name));
+  ASSERT(name->IsSymbol());
+
+  // The state bits are not important to the hash function because
+  // the stub cache only contains monomorphic stubs. Make sure that
+  // the bits are the least significant so they will be the ones
+  // masked out.
+  ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
+  ASSERT(Code::kFlagsICStateShift == 0);
+
+  // Make sure that the code type is not included in the hash.
+  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
+
+  // Compute the primary entry.
+  int primary_offset = PrimaryOffset(name, flags, map);
+  Entry* primary = entry(primary_, primary_offset);
+  Code* hit = primary->value;
+
+  // If the primary entry has useful data in it, we retire it to the
+  // secondary cache before overwriting it.
+  if (hit != Builtins::builtin(Builtins::Illegal)) {
+    Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
+    int secondary_offset =
+        SecondaryOffset(primary->key, primary_flags, primary_offset);
+    Entry* secondary = entry(secondary_, secondary_offset);
+    *secondary = *primary;
+  }
+
+  // Update primary cache.
+  primary->key = name;
+  primary->value = code;
+  return code;
+}
+
+
+Object* StubCache::ComputeLoadField(String* name,
+                                    JSObject* receiver,
+                                    JSObject* holder,
+                                    int field_index) {
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    LoadStubCompiler compiler;
+    code = compiler.CompileLoadField(receiver, holder, field_index);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return code;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+Object* StubCache::ComputeLoadCallback(String* name,
+                                       JSObject* receiver,
+                                       JSObject* holder,
+                                       AccessorInfo* callback) {
+  ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    LoadStubCompiler compiler;
+    code = compiler.CompileLoadCallback(receiver, holder, callback);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return code;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+Object* StubCache::ComputeLoadConstant(String* name,
+                                       JSObject* receiver,
+                                       JSObject* holder,
+                                       Object* value) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    LoadStubCompiler compiler;
+    code = compiler.CompileLoadConstant(receiver, holder, value);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return code;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+Object* StubCache::ComputeLoadInterceptor(String* name,
+                                          JSObject* receiver,
+                                          JSObject* holder) {
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    LoadStubCompiler compiler;
+    code = compiler.CompileLoadInterceptor(receiver, holder, name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return code;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
+  Code* code = Builtins::builtin(Builtins::LoadIC_Normal);
+  return Set(name, receiver->map(), code);
+}
+
+
+Object* StubCache::ComputeKeyedLoadField(String* name,
+                                         JSObject* receiver,
+                                         JSObject* holder,
+                                         int field_index) {
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadField(name, receiver, holder, field_index);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeKeyedLoadConstant(String* name,
+                                            JSObject* receiver,
+                                            JSObject* holder,
+                                            Object* value) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadConstant(name, receiver, holder, value);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeKeyedLoadInterceptor(String* name,
+                                               JSObject* receiver,
+                                               JSObject* holder) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadInterceptor(receiver, holder, name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeKeyedLoadCallback(String* name,
+                                            JSObject* receiver,
+                                            JSObject* holder,
+                                            AccessorInfo* callback) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadCallback(name, receiver, holder, callback);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+
+Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
+                                               JSArray* receiver) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadArrayLength(name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeKeyedLoadShortStringLength(String* name,
+                                                     String* receiver) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadShortStringLength(name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeKeyedLoadMediumStringLength(String* name,
+                                                      String* receiver) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadMediumStringLength(name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeKeyedLoadLongStringLength(String* name,
+                                                    String* receiver) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadLongStringLength(name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeKeyedLoadFunctionPrototype(String* name,
+                                                     JSFunction* receiver) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedLoadStubCompiler compiler;
+    code = compiler.CompileLoadFunctionPrototype(name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeStoreField(String* name,
+                                     JSObject* receiver,
+                                     int field_index,
+                                     Map* transition) {
+  PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    StoreStubCompiler compiler;
+    code = compiler.CompileStoreField(receiver, field_index, transition, name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+Object* StubCache::ComputeStoreCallback(String* name,
+                                        JSObject* receiver,
+                                        AccessorInfo* callback) {
+  ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    StoreStubCompiler compiler;
+    code = compiler.CompileStoreCallback(receiver, callback, name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+Object* StubCache::ComputeStoreInterceptor(String* name,
+                                           JSObject* receiver) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    StoreStubCompiler compiler;
+    code = compiler.CompileStoreInterceptor(receiver, name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+Object* StubCache::ComputeKeyedStoreField(String* name, JSObject* receiver,
+                                          int field_index, Map* transition) {
+  PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
+  Object* code = receiver->map()->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    KeyedStoreStubCompiler compiler;
+    code = compiler.CompileStoreField(receiver, field_index, transition, name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("KeyedStoreIC", Code::cast(code), name));
+    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return code;
+}
+
+
+Object* StubCache::ComputeCallConstant(int argc,
+                                       String* name,
+                                       Object* object,
+                                       JSObject* holder,
+                                       JSFunction* function) {
+  // Compute the check type and the map.
+  Map* map = IC::GetCodeCacheMapForObject(object);
+
+  // Compute check type based on receiver/holder.
+  StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK;
+  if (object->IsString()) {
+    check = StubCompiler::STRING_CHECK;
+  } else if (object->IsNumber()) {
+    check = StubCompiler::NUMBER_CHECK;
+  } else if (object->IsBoolean()) {
+    check = StubCompiler::BOOLEAN_CHECK;
+  }
+
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::CALL_IC, CONSTANT_FUNCTION, argc);
+  Object* code = map->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    if (object->IsJSObject()) {
+      Object* opt =
+          Top::LookupSpecialFunction(JSObject::cast(object), holder, function);
+      if (opt->IsJSFunction()) {
+        check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK;
+        function = JSFunction::cast(opt);
+      }
+    }
+    // If the function hasn't been compiled yet, we cannot do it now
+    // because it may cause GC. To avoid this issue, we return an
+    // internal error which will make sure we do not update any
+    // caches.
+    if (!function->is_compiled()) return Failure::InternalError();
+    // Compile the stub - only create stubs for fully compiled functions.
+    CallStubCompiler compiler(argc);
+    code = compiler.CompileCallConstant(object, holder, function, check);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
+    Object* result = map->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return Set(name, map, Code::cast(code));
+}
+
+
+Object* StubCache::ComputeCallField(int argc,
+                                    String* name,
+                                    Object* object,
+                                    JSObject* holder,
+                                    int index) {
+  // Compute the check type and the map.
+  Map* map = IC::GetCodeCacheMapForObject(object);
+
+  // TODO(1233596): We cannot do receiver map check for non-JS objects
+  // because they may be represented as immediates without a
+  // map. Instead, we check against the map in the holder.
+  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
+    object = holder;
+  }
+
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, FIELD, argc);
+  Object* code = map->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    CallStubCompiler compiler(argc);
+    code = compiler.CompileCallField(object, holder, index);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
+    Object* result = map->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return Set(name, map, Code::cast(code));
+}
+
+
+Object* StubCache::ComputeCallInterceptor(int argc,
+                                          String* name,
+                                          Object* object,
+                                          JSObject* holder) {
+  // Compute the check type and the map.
+  // If the object is a value, we use the prototype map for the cache.
+  Map* map = IC::GetCodeCacheMapForObject(object);
+
+  // TODO(1233596): We cannot do receiver map check for non-JS objects
+  // because they may be represented as immediates without a
+  // map. Instead, we check against the map in the holder.
+  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
+    object = holder;
+  }
+
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::CALL_IC, INTERCEPTOR, argc);
+  Object* code = map->FindInCodeCache(name, flags);
+  if (code->IsUndefined()) {
+    CallStubCompiler compiler(argc);
+    code = compiler.CompileCallInterceptor(object, holder, name);
+    if (code->IsFailure()) return code;
+    LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
+    Object* result = map->UpdateCodeCache(name, Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return Set(name, map, Code::cast(code));
+}
+
+
+Object* StubCache::ComputeCallNormal(int argc,
+                                     String* name,
+                                     JSObject* receiver) {
+  Object* code = ComputeCallNormal(argc);
+  if (code->IsFailure()) return code;
+  return Set(name, receiver->map(), Code::cast(code));
+}
+
+
+static Object* GetProbeValue(Code::Flags flags) {
+  Dictionary* dictionary = Heap::non_monomorphic_cache();
+  int entry = dictionary->FindNumberEntry(flags);
+  if (entry != -1) return dictionary->ValueAt(entry);
+  return Heap::undefined_value();
+}
+
+
+static Object* ProbeCache(Code::Flags flags) {
+  Object* probe = GetProbeValue(flags);
+  if (probe != Heap::undefined_value()) return probe;
+  // Seed the cache with an undefined value to make sure that any
+  // generated code object can always be inserted into the cache
+  // without causing  allocation failures.
+  Object* result =
+      Heap::non_monomorphic_cache()->AtNumberPut(flags,
+                                                 Heap::undefined_value());
+  if (result->IsFailure()) return result;
+  Heap::set_non_monomorphic_cache(Dictionary::cast(result));
+  return probe;
+}
+
+
+static Object* FillCache(Object* code) {
+  if (code->IsCode()) {
+    int entry =
+        Heap::non_monomorphic_cache()->FindNumberEntry(
+            Code::cast(code)->flags());
+    // The entry must be present see comment in ProbeCache.
+    ASSERT(entry != -1);
+    ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
+           Heap::undefined_value());
+    Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
+    CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
+  }
+  return code;
+}
+
+
+Code* StubCache::FindCallInitialize(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc);
+  Object* result = ProbeCache(flags);
+  ASSERT(!result->IsUndefined());
+  // This might be called during the marking phase of the collector
+  // hence the unchecked cast.
+  return reinterpret_cast<Code*>(result);
+}
+
+
+Object* StubCache::ComputeCallInitialize(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  return FillCache(compiler.CompileCallInitialize(flags));
+}
+
+
+Object* StubCache::ComputeCallPreMonomorphic(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, PREMONOMORPHIC, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  return FillCache(compiler.CompileCallPreMonomorphic(flags));
+}
+
+
+Object* StubCache::ComputeCallNormal(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  return FillCache(compiler.CompileCallNormal(flags));
+}
+
+
+Object* StubCache::ComputeCallMegamorphic(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, MEGAMORPHIC, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  return FillCache(compiler.CompileCallMegamorphic(flags));
+}
+
+
+Object* StubCache::ComputeCallMiss(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::STUB, MEGAMORPHIC, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  return FillCache(compiler.CompileCallMiss(flags));
+}
+
+
+Object* StubCache::ComputeCallDebugBreak(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, DEBUG_BREAK, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  return FillCache(compiler.CompileCallDebugBreak(flags));
+}
+
+
+Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::CALL_IC, DEBUG_PREPARE_STEP_IN, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
+}
+
+
+Object* StubCache::ComputeLazyCompile(int argc) {
+  Code::Flags flags =
+      Code::ComputeFlags(Code::STUB, UNINITIALIZED, NORMAL, argc);
+  Object* probe = ProbeCache(flags);
+  if (!probe->IsUndefined()) return probe;
+  StubCompiler compiler;
+  Object* result = FillCache(compiler.CompileLazyCompile(flags));
+  if (result->IsCode()) {
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("LazyCompile", code, code->arguments_count()));
+  }
+  return result;
+}
+
+
+void StubCache::Clear() {
+  for (int i = 0; i < kPrimaryTableSize; i++) {
+    primary_[i].key = Heap::empty_string();
+    primary_[i].value = Builtins::builtin(Builtins::Illegal);
+  }
+  for (int j = 0; j < kSecondaryTableSize; j++) {
+    secondary_[j].key = Heap::empty_string();
+    secondary_[j].value = Builtins::builtin(Builtins::Illegal);
+  }
+}
+
+
+// ------------------------------------------------------------------------
+// StubCompiler implementation.
+
+
+// Support function for computing call IC miss stubs.
+Handle<Code> ComputeCallMiss(int argc) {
+  CALL_HEAP_FUNCTION(StubCache::ComputeCallMiss(argc), Code);
+}
+
+
+
+Object* LoadCallbackProperty(Arguments args) {
+  Handle<JSObject> recv = args.at<JSObject>(0);
+  AccessorInfo* callback = AccessorInfo::cast(args[1]);
+  v8::AccessorGetter fun =
+      FUNCTION_CAST<v8::AccessorGetter>(
+          v8::ToCData<Address>(callback->getter()));
+  ASSERT(fun != NULL);
+  Handle<String> name = args.at<String>(2);
+  Handle<JSObject> holder = args.at<JSObject>(3);
+  HandleScope scope;
+  Handle<Object> data(callback->data());
+  LOG(ApiNamedPropertyAccess("load", *recv, *name));
+  // NOTE: If we can align the structure of an AccessorInfo with the
+  // locations of the arguments to this function maybe we don't have
+  // to explicitly create the structure but can just pass a pointer
+  // into the stack.
+  v8::AccessorInfo info(
+    v8::Utils::ToLocal(recv),
+    v8::Utils::ToLocal(data),
+    v8::Utils::ToLocal(holder));
+  v8::Handle<v8::Value> result;
+  {
+    // Leaving JavaScript.
+    VMState state(OTHER);
+    result = fun(v8::Utils::ToLocal(name), info);
+  }
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  if (result.IsEmpty()) {
+    return Heap::undefined_value();
+  } else {
+    return *v8::Utils::OpenHandle(*result);
+  }
+}
+
+
+Object* StoreCallbackProperty(Arguments args) {
+  Handle<JSObject> recv = args.at<JSObject>(0);
+  AccessorInfo* callback = AccessorInfo::cast(args[1]);
+  v8::AccessorSetter fun =
+      FUNCTION_CAST<v8::AccessorSetter>(
+          v8::ToCData<Address>(callback->setter()));
+  ASSERT(fun != NULL);
+  Handle<String> name = args.at<String>(2);
+  Handle<Object> value = args.at<Object>(3);
+  HandleScope scope;
+  Handle<Object> data(callback->data());
+  LOG(ApiNamedPropertyAccess("store", *recv, *name));
+  v8::AccessorInfo info(
+    v8::Utils::ToLocal(recv),
+    v8::Utils::ToLocal(data),
+    v8::Utils::ToLocal(recv));
+  {
+    // Leaving JavaScript.
+    VMState state(OTHER);
+    fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
+  }
+  RETURN_IF_SCHEDULED_EXCEPTION();
+  return *value;
+}
+
+
+Object* LoadInterceptorProperty(Arguments args) {
+  HandleScope scope;
+  Handle<JSObject> recv = args.at<JSObject>(0);
+  Handle<JSObject> holder = args.at<JSObject>(1);
+  Handle<String> name = args.at<String>(2);
+  ASSERT(holder->HasNamedInterceptor());
+  PropertyAttributes attr = NONE;
+  Handle<Object> result = GetPropertyWithInterceptor(recv, holder, name, &attr);
+
+  // GetPropertyWithInterceptor already converts a scheduled exception
+  // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION() here.
+
+  // Make sure to propagate exceptions.
+  if (result.is_null())  {
+    // Failure::Exception is converted to a null handle in the
+    // handle-based methods such as SetProperty.  We therefore need
+    // to convert null handles back to exceptions.
+    ASSERT(Top::has_pending_exception());
+    return Failure::Exception();
+  }
+
+  // If the property is present, return it.
+  if (attr != ABSENT) return *result;
+
+  // If the top frame is an internal frame, this is really a call
+  // IC. In this case, we simply return the undefined result which
+  // will lead to an exception when trying to invoke the result as a
+  // function.
+  StackFrameIterator it;
+  it.Advance();  // skip exit frame
+  if (it.frame()->is_internal()) return *result;
+
+  // If the load is non-contextual, just return the undefined result.
+  // Note that both keyed and non-keyed loads may end up here, so we
+  // can't use either LoadIC or KeyedLoadIC constructors.
+  IC ic(IC::NO_EXTRA_FRAME);
+  ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
+  if (!ic.is_contextual()) return *result;
+
+  // Throw a reference error.
+  Handle<Object> error =
+      Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
+  return Top::Throw(*error);
+}
+
+
+Object* StoreInterceptorProperty(Arguments args) {
+  HandleScope scope;
+  Handle<JSObject> recv = args.at<JSObject>(0);
+  Handle<String> name = args.at<String>(1);
+  Handle<Object> value = args.at<Object>(2);
+  ASSERT(recv->HasNamedInterceptor());
+  PropertyAttributes attr = NONE;
+  Handle<Object> result = SetPropertyWithInterceptor(recv, name, value, attr);
+
+  // SetPropertyWithInterceptor already converts a scheduled exception
+  // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION() here.
+
+  // Make sure to propagate exceptions.
+  if (result.is_null()) {
+    // Failure::Exception is converted to a null handle in the
+    // handle-based methods such as SetProperty.  We therefore need
+    // to convert null handles back to exceptions.
+    ASSERT(Top::has_pending_exception());
+    return Failure::Exception();
+  }
+  return *result;
+}
+
+
+Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
+  HandleScope scope;
+  int argc = Code::ExtractArgumentsCountFromFlags(flags);
+  CallIC::GenerateInitialize(masm(), argc);
+  Object* result = GetCodeWithFlags(flags);
+  if (!result->IsFailure()) {
+    Counters::call_initialize_stubs.Increment();
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("CallInitialize", code, code->arguments_count()));
+  }
+  return result;
+}
+
+
+Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
+  HandleScope scope;
+  int argc = Code::ExtractArgumentsCountFromFlags(flags);
+  CallIC::GenerateInitialize(masm(), argc);
+  Object* result = GetCodeWithFlags(flags);
+  if (!result->IsFailure()) {
+    Counters::call_premonomorphic_stubs.Increment();
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("CallPreMonomorphic", code, code->arguments_count()));
+  }
+  return result;
+}
+
+
+Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
+  HandleScope scope;
+  int argc = Code::ExtractArgumentsCountFromFlags(flags);
+  CallIC::GenerateNormal(masm(), argc);
+  Object* result = GetCodeWithFlags(flags);
+  if (!result->IsFailure()) {
+    Counters::call_normal_stubs.Increment();
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("CallNormal", code, code->arguments_count()));
+  }
+  return result;
+}
+
+
+Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
+  HandleScope scope;
+  int argc = Code::ExtractArgumentsCountFromFlags(flags);
+  CallIC::GenerateMegamorphic(masm(), argc);
+  Object* result = GetCodeWithFlags(flags);
+  if (!result->IsFailure()) {
+    Counters::call_megamorphic_stubs.Increment();
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("CallMegamorphic", code, code->arguments_count()));
+  }
+  return result;
+}
+
+
+Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
+  HandleScope scope;
+  int argc = Code::ExtractArgumentsCountFromFlags(flags);
+  CallIC::GenerateMiss(masm(), argc);
+  Object* result = GetCodeWithFlags(flags);
+  if (!result->IsFailure()) {
+    Counters::call_megamorphic_stubs.Increment();
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("CallMiss", code, code->arguments_count()));
+  }
+  return result;
+}
+
+
+Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
+  HandleScope scope;
+  Builtins::Generate_CallIC_DebugBreak(masm());
+  Object* result = GetCodeWithFlags(flags);
+  if (!result->IsFailure()) {
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("CallDebugBreak", code, code->arguments_count()));
+  }
+  return result;
+}
+
+
+Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
+  HandleScope scope;
+  // Use the same code for the the step in preparations as we do for
+  // the miss case.
+  int argc = Code::ExtractArgumentsCountFromFlags(flags);
+  CallIC::GenerateMiss(masm(), argc);
+  Object* result = GetCodeWithFlags(flags);
+  if (!result->IsFailure()) {
+    Code* code = Code::cast(result);
+    USE(code);
+    LOG(CodeCreateEvent("CallDebugPrepareStepIn", code,
+                        code->arguments_count()));
+  }
+  return result;
+}
+
+
+Object* StubCompiler::GetCodeWithFlags(Code::Flags flags) {
+  CodeDesc desc;
+  masm_.GetCode(&desc);
+  Object* result = Heap::CreateCode(desc, NULL, flags);
+#ifdef DEBUG
+  if (FLAG_print_code_stubs && !result->IsFailure()) {
+    Code::cast(result)->Print();
+  }
+#endif
+  return result;
+}
+
+
+Object* LoadStubCompiler::GetCode(PropertyType type) {
+  return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::LOAD_IC, type));
+}
+
+
+Object* KeyedLoadStubCompiler::GetCode(PropertyType type) {
+  return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC,
+                                                        type));
+}
+
+
+Object* StoreStubCompiler::GetCode(PropertyType type) {
+  return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::STORE_IC, type));
+}
+
+
+Object* KeyedStoreStubCompiler::GetCode(PropertyType type) {
+  return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC,
+                                                        type));
+}
+
+
+Object* CallStubCompiler::GetCode(PropertyType type) {
+  int argc = arguments_.immediate();
+  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, type, argc);
+  return GetCodeWithFlags(flags);
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/stub-cache.h b/regexp2000/src/stub-cache.h
new file mode 100644 (file)
index 0000000..4fb78da
--- /dev/null
@@ -0,0 +1,480 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_STUB_CACHE_H_
+#define V8_STUB_CACHE_H_
+
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+
+// The stub cache is used for megamorphic calls and property accesses.
+// It maps (map, name, type)->Code*
+
+// The design of the table uses the inline cache stubs used for
+// mono-morphic calls. The beauty of this, we do not have to
+// invalidate the cache whenever a prototype map is changed.  The stub
+// validates the map chain as in the mono-morphic case.
+
+class SCTableReference;
+
+class StubCache : public AllStatic {
+ public:
+  struct Entry {
+    String* key;
+    Code* value;
+  };
+
+
+  static void Initialize(bool create_heap_objects);
+
+  // Computes the right stub matching. Inserts the result in the
+  // cache before returning.  This might compile a stub if needed.
+  static Object* ComputeLoadField(String* name,
+                                  JSObject* receiver,
+                                  JSObject* holder,
+                                  int field_index);
+
+  static Object* ComputeLoadCallback(String* name,
+                                     JSObject* receiver,
+                                     JSObject* holder,
+                                     AccessorInfo* callback);
+
+  static Object* ComputeLoadConstant(String* name,
+                                     JSObject* receiver,
+                                     JSObject* holder,
+                                     Object* value);
+
+  static Object* ComputeLoadInterceptor(String* name,
+                                        JSObject* receiver,
+                                        JSObject* holder);
+
+  static Object* ComputeLoadNormal(String* name, JSObject* receiver);
+
+
+  // ---
+
+  static Object* ComputeKeyedLoadField(String* name,
+                                       JSObject* receiver,
+                                       JSObject* holder,
+                                       int field_index);
+
+  static Object* ComputeKeyedLoadCallback(String* name,
+                                          JSObject* receiver,
+                                          JSObject* holder,
+                                          AccessorInfo* callback);
+
+  static Object* ComputeKeyedLoadConstant(String* name, JSObject* receiver,
+                                          JSObject* holder, Object* value);
+
+  static Object* ComputeKeyedLoadInterceptor(String* name,
+                                             JSObject* receiver,
+                                             JSObject* holder);
+
+  static Object* ComputeKeyedLoadArrayLength(String* name, JSArray* receiver);
+
+  static Object* ComputeKeyedLoadShortStringLength(String* name,
+                                                   String* receiver);
+
+  static Object* ComputeKeyedLoadMediumStringLength(String* name,
+                                                    String* receiver);
+
+  static Object* ComputeKeyedLoadLongStringLength(String* name,
+                                                  String* receiver);
+
+  static Object* ComputeKeyedLoadFunctionPrototype(String* name,
+                                                   JSFunction* receiver);
+
+  // ---
+
+  static Object* ComputeStoreField(String* name,
+                                   JSObject* receiver,
+                                   int field_index,
+                                   Map* transition = NULL);
+
+  static Object* ComputeStoreCallback(String* name,
+                                      JSObject* receiver,
+                                      AccessorInfo* callback);
+
+  static Object* ComputeStoreInterceptor(String* name, JSObject* receiver);
+
+  // ---
+
+  static Object* ComputeKeyedStoreField(String* name,
+                                        JSObject* receiver,
+                                        int field_index,
+                                        Map* transition = NULL);
+
+  // ---
+
+  static Object* ComputeCallField(int argc,
+                                  String* name,
+                                  Object* object,
+                                  JSObject* holder,
+                                  int index);
+
+  static Object* ComputeCallConstant(int argc,
+                                     String* name,
+                                     Object* object,
+                                     JSObject* holder,
+                                     JSFunction* function);
+
+  static Object* ComputeCallNormal(int argc, String* name, JSObject* receiver);
+
+  static Object* ComputeCallInterceptor(int argc,
+                                        String* name,
+                                        Object* object,
+                                        JSObject* holder);
+
+  // ---
+
+  static Object* ComputeCallInitialize(int argc);
+  static Object* ComputeCallPreMonomorphic(int argc);
+  static Object* ComputeCallNormal(int argc);
+  static Object* ComputeCallMegamorphic(int argc);
+  static Object* ComputeCallMiss(int argc);
+
+  // Finds the Code object stored in the Heap::non_monomorphic_cache().
+  static Code* FindCallInitialize(int argc);
+
+  static Object* ComputeCallDebugBreak(int argc);
+  static Object* ComputeCallDebugPrepareStepIn(int argc);
+
+  static Object* ComputeLazyCompile(int argc);
+
+
+  // Update cache for entry hash(name, map).
+  static Code* Set(String* name, Map* map, Code* code);
+
+  // Clear the lookup table (@ mark compact collection).
+  static void Clear();
+
+  // Functions for generating stubs at startup.
+  static void GenerateMiss(MacroAssembler* masm);
+
+  // Generate code for probing the stub cache table.
+  static void GenerateProbe(MacroAssembler* masm,
+                            Code::Flags flags,
+                            Register receiver,
+                            Register name,
+                            Register scratch);
+
+  enum Table {
+    kPrimary,
+    kSecondary
+  };
+
+ private:
+  friend class SCTableReference;
+  static const int kPrimaryTableSize = 2048;
+  static const int kSecondaryTableSize = 512;
+  static Entry primary_[];
+  static Entry secondary_[];
+
+  // Computes the hashed offsets for primary and secondary caches.
+  static int PrimaryOffset(String* name, Code::Flags flags, Map* map) {
+    // This works well because the heap object tag size and the hash
+    // shift are equal.  Shifting down the length field to get the
+    // hash code would effectively throw away two bits of the hash
+    // code.
+    ASSERT(kHeapObjectTagSize == String::kHashShift);
+    // Compute the hash of the name (use entire length field).
+    ASSERT(name->HasHashCode());
+    uint32_t field = name->length_field();
+    // Base the offset on a simple combination of name, flags, and map.
+    uint32_t key = (reinterpret_cast<uint32_t>(map) + field) ^ flags;
+    return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
+  }
+
+  static int SecondaryOffset(String* name, Code::Flags flags, int seed) {
+    // Use the seed from the primary cache in the secondary cache.
+    uint32_t key = seed - reinterpret_cast<uint32_t>(name) + flags;
+    return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
+  }
+
+  // Compute the entry for a given offset in exactly the same way as
+  // we done in generated code. This makes it a lot easier to avoid
+  // making mistakes in the hashed offset computations.
+  static Entry* entry(Entry* table, int offset) {
+    return reinterpret_cast<Entry*>(
+        reinterpret_cast<Address>(table) + (offset << 1));
+  }
+};
+
+
+class SCTableReference {
+ public:
+  static SCTableReference keyReference(StubCache::Table table) {
+    return SCTableReference(
+        reinterpret_cast<Address>(&first_entry(table)->key));
+  }
+
+
+  static SCTableReference valueReference(StubCache::Table table) {
+    return SCTableReference(
+        reinterpret_cast<Address>(&first_entry(table)->value));
+  }
+
+  Address address() const { return address_; }
+
+ private:
+  explicit SCTableReference(Address address) : address_(address) {}
+
+  static StubCache::Entry* first_entry(StubCache::Table table) {
+    switch (table) {
+      case StubCache::kPrimary: return StubCache::primary_;
+      case StubCache::kSecondary: return StubCache::secondary_;
+    }
+    UNREACHABLE();
+    return NULL;
+  }
+
+  Address address_;
+};
+
+// ------------------------------------------------------------------------
+
+
+// Support functions for IC stubs for callbacks.
+Object* LoadCallbackProperty(Arguments args);
+Object* StoreCallbackProperty(Arguments args);
+
+
+// Support functions for IC stubs for interceptors.
+Object* LoadInterceptorProperty(Arguments args);
+Object* StoreInterceptorProperty(Arguments args);
+Object* CallInterceptorProperty(Arguments args);
+
+
+// Support function for computing call IC miss stubs.
+Handle<Code> ComputeCallMiss(int argc);
+
+
+// The stub compiler compiles stubs for the stub cache.
+class StubCompiler BASE_EMBEDDED {
+ public:
+  enum CheckType {
+    RECEIVER_MAP_CHECK,
+    STRING_CHECK,
+    NUMBER_CHECK,
+    BOOLEAN_CHECK,
+    JSARRAY_HAS_FAST_ELEMENTS_CHECK
+  };
+
+  StubCompiler() : masm_(NULL, 256) { }
+
+  Object* CompileCallInitialize(Code::Flags flags);
+  Object* CompileCallPreMonomorphic(Code::Flags flags);
+  Object* CompileCallNormal(Code::Flags flags);
+  Object* CompileCallMegamorphic(Code::Flags flags);
+  Object* CompileCallMiss(Code::Flags flags);
+  Object* CompileCallDebugBreak(Code::Flags flags);
+  Object* CompileCallDebugPrepareStepIn(Code::Flags flags);
+  Object* CompileLazyCompile(Code::Flags flags);
+
+  // Static functions for generating parts of stubs.
+  static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
+                                                  int index,
+                                                  Register prototype);
+  static void GenerateFastPropertyLoad(MacroAssembler* masm,
+                                       Register dst, Register src,
+                                       JSObject* holder, int index);
+  static void GenerateLoadField(MacroAssembler* masm,
+                                JSObject* object,
+                                JSObject* holder,
+                                Register receiver,
+                                Register scratch1,
+                                Register scratch2,
+                                int index,
+                                Label* miss_label);
+  static void GenerateLoadCallback(MacroAssembler* masm,
+                                   JSObject* object,
+                                   JSObject* holder,
+                                   Register receiver,
+                                   Register name,
+                                   Register scratch1,
+                                   Register scratch2,
+                                   AccessorInfo* callback,
+                                   Label* miss_label);
+  static void GenerateLoadConstant(MacroAssembler* masm,
+                                   JSObject* object,
+                                   JSObject* holder,
+                                   Register receiver,
+                                   Register scratch1,
+                                   Register scratch2,
+                                   Object* value,
+                                   Label* miss_label);
+  static void GenerateLoadInterceptor(MacroAssembler* masm,
+                                      JSObject* object,
+                                      JSObject* holder,
+                                      Register receiver,
+                                      Register name,
+                                      Register scratch1,
+                                      Register scratch2,
+                                      Label* miss_label);
+  static void GenerateLoadArrayLength(MacroAssembler* masm,
+                                      Register receiver,
+                                      Register scratch,
+                                      Label* miss_label);
+  static void GenerateLoadShortStringLength(MacroAssembler* masm,
+                                            Register receiver,
+                                            Register scratch,
+                                            Label* miss_label);
+  static void GenerateLoadMediumStringLength(MacroAssembler* masm,
+                                             Register receiver,
+                                             Register scratch,
+                                             Label* miss_label);
+  static void GenerateLoadLongStringLength(MacroAssembler* masm,
+                                           Register receiver,
+                                           Register scratch,
+                                           Label* miss_label);
+  static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
+                                            Register receiver,
+                                            Register scratch1,
+                                            Register scratch2,
+                                            Label* miss_label);
+  static void GenerateStoreField(MacroAssembler* masm,
+                                 Builtins::Name storage_extend,
+                                 JSObject* object,
+                                 int index,
+                                 Map* transition,
+                                 Register receiver_reg,
+                                 Register name_reg,
+                                 Register scratch,
+                                 Label* miss_label);
+  static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind);
+
+ protected:
+  Object* GetCodeWithFlags(Code::Flags flags);
+
+  MacroAssembler* masm() { return &masm_; }
+
+ private:
+  MacroAssembler masm_;
+};
+
+
+class LoadStubCompiler: public StubCompiler {
+ public:
+  Object* CompileLoadField(JSObject* object, JSObject* holder, int index);
+  Object* CompileLoadCallback(JSObject* object,
+                              JSObject* holder,
+                              AccessorInfo* callback);
+  Object* CompileLoadConstant(JSObject* object,
+                              JSObject* holder,
+                              Object* value);
+  Object* CompileLoadInterceptor(JSObject* object,
+                                 JSObject* holder,
+                                 String* name);
+
+ private:
+  Object* GetCode(PropertyType);
+};
+
+
+class KeyedLoadStubCompiler: public StubCompiler {
+ public:
+  Object* CompileLoadField(String* name,
+                           JSObject* object,
+                           JSObject* holder,
+                           int index);
+  Object* CompileLoadCallback(String* name,
+                              JSObject* object,
+                              JSObject* holder,
+                              AccessorInfo* callback);
+  Object* CompileLoadConstant(String* name,
+                              JSObject* object,
+                              JSObject* holder,
+                              Object* value);
+  Object* CompileLoadInterceptor(JSObject* object,
+                                 JSObject* holder,
+                                 String* name);
+  Object* CompileLoadArrayLength(String* name);
+  Object* CompileLoadShortStringLength(String* name);
+  Object* CompileLoadMediumStringLength(String* name);
+  Object* CompileLoadLongStringLength(String* name);
+  Object* CompileLoadFunctionPrototype(String* name);
+
+ private:
+  Object* GetCode(PropertyType);
+};
+
+
+class StoreStubCompiler: public StubCompiler {
+ public:
+  Object* CompileStoreField(JSObject* object,
+                            int index,
+                            Map* transition,
+                            String* name);
+  Object* CompileStoreCallback(JSObject* object,
+                               AccessorInfo* callbacks,
+                               String* name);
+  Object* CompileStoreInterceptor(JSObject* object, String* name);
+
+ private:
+  Object* GetCode(PropertyType type);
+};
+
+
+class KeyedStoreStubCompiler: public StubCompiler {
+ public:
+  Object* CompileStoreField(JSObject* object,
+                            int index,
+                            Map* transition,
+                            String* name);
+
+ private:
+  Object* GetCode(PropertyType type);
+};
+
+
+class CallStubCompiler: public StubCompiler {
+ public:
+  explicit CallStubCompiler(int argc) : arguments_(argc) { }
+
+  Object* CompileCallField(Object* object, JSObject* holder, int index);
+  Object* CompileCallConstant(Object* object,
+                              JSObject* holder,
+                              JSFunction* function,
+                              CheckType check);
+  Object* CompileCallInterceptor(Object* object,
+                                 JSObject* holder,
+                                 String* name);
+
+ private:
+  const ParameterCount arguments_;
+
+  const ParameterCount& arguments() { return arguments_; }
+
+  Object* GetCode(PropertyType type);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_STUB_CACHE_H_
diff --git a/regexp2000/src/third_party/dtoa/COPYING b/regexp2000/src/third_party/dtoa/COPYING
new file mode 100644 (file)
index 0000000..c991754
--- /dev/null
@@ -0,0 +1,15 @@
+The author of this software is David M. Gay.
+
+Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose without fee is hereby granted, provided that this entire
+notice is included in all copies of any software which is or includes
+a copy or modification of this software and in all copies of the
+supporting documentation for such software.
+
+THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES
+ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+PURPOSE.
diff --git a/regexp2000/src/third_party/dtoa/dtoa.c b/regexp2000/src/third_party/dtoa/dtoa.c
new file mode 100644 (file)
index 0000000..5caa96d
--- /dev/null
@@ -0,0 +1,3324 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").     */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *     _control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ *     1. We only require IEEE, IBM, or VAX double-precision
+ *             arithmetic (not IEEE double-extended).
+ *     2. We get by with floating-point arithmetic in a case that
+ *             Clinger missed -- when we're computing d * 10^n
+ *             for a small integer d and the integer n is not too
+ *             much larger than 22 (the maximum integer k for which
+ *             we can represent 10^k exactly), we may be able to
+ *             compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *     3. Rather than a bit-at-a-time adjustment of the binary
+ *             result in the hard case, we use floating-point
+ *             arithmetic to determine the adjustment to within
+ *             one bit; only in really hard cases do we need to
+ *             compute a second residual.
+ *     4. Because of 3., we don't need a large table of powers of 10
+ *             for ten-to-e (just some small tables, e.g. of 10^k
+ *             for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *     significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *     significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *     computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *     and strtod and dtoa should round accordingly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *     and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *     that use extended-precision instructions to compute rounded
+ *     products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *     products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *     integer type (of >= 64 bits).  On such machines, you can
+ *     #define Just_16 to store 16 bits per 32-bit Long when doing
+ *     high-precision integer arithmetic.  Whether this speeds things
+ *     up or slows things down depends on the machine and the number
+ *     being converted.  If long long is available and the name is
+ *     something other than "long long", #define Llong to be the name,
+ *     and if "unsigned Llong" does not work as an unsigned version of
+ *     Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *     define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *     FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *     if memory is available and otherwise does something you deem
+ *     appropriate.  If MALLOC is undefined, malloc will be invoked
+ *     directly -- and assumed always to succeed.
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *     memory allocations from a private pool of memory when possible.
+ *     When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *     unless #defined to be a different length.  This default length
+ *     suffices to get rid of MALLOC calls except for unusual cases,
+ *     such as decimal-to-binary conversion of a very long string of
+ *     digits.  The longest string dtoa can return is about 751 bytes
+ *     long.  For conversions by strtod of strings of 800 digits and
+ *     all dtoa conversions in single-threaded executions with 8-byte
+ *     pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ *     pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
+ *     Infinity and NaN (case insensitively).  On some systems (e.g.,
+ *     some HP systems), it may be necessary to #define NAN_WORD0
+ *     appropriately -- to the most significant word of a quiet NaN.
+ *     (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ *     When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *     strtod also accepts (case insensitively) strings of the form
+ *     NaN(x), where x is a string of hexadecimal digits and spaces;
+ *     if there is only one string of hexadecimal digits, it is taken
+ *     for the 52 fraction bits of the resulting NaN; if there are two
+ *     or more strings of hex digits, the first is for the high 20 bits,
+ *     the second and subsequent for the low 32 bits, with intervening
+ *     white space ignored; but if this results in none of the 52
+ *     fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ *     and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *     multiple threads.  In this case, you must provide (or suitably
+ *     #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *     by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *     in pow5mult, ensures lazy evaluation of only one copy of high
+ *     powers of 5; omitting this lock would introduce a small
+ *     probability of wasting memory, but would otherwise be harmless.)
+ *     You must also invoke freedtoa(s) to free the value s returned by
+ *     dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ *     avoids underflows on inputs whose result does not underflow.
+ *     If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ *     floating-point numbers and flushes underflows to zero rather
+ *     than implementing gradual underflow, then you must also #define
+ *     Sudden_Underflow.
+ * #define YES_ALIAS to permit aliasing certain double values with
+ *     arrays of ULongs.  This leads to slightly better code with
+ *     some compilers and was always used prior to 19990916, but it
+ *     is not strictly legal and can cause trouble with aggressively
+ *     optimizing compilers (e.g., gcc 2.95.1 under -O2).
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ *     computation should be done to set the inexact flag when the
+ *     result is inexact and avoid setting inexact when the result
+ *     is exact.  In this case, dtoa.c must be compiled in
+ *     an environment, perhaps provided by #include "dtoa.c" in a
+ *     suitable wrapper, that defines two functions,
+ *             int get_inexact(void);
+ *             void clear_inexact(void);
+ *     such that get_inexact() returns a nonzero value if the
+ *     inexact bit is already set, and clear_inexact() sets the
+ *     inexact bit to 0.  When SET_INEXACT is #defined, strtod
+ *     also does extra computations to set the underflow and overflow
+ *     flags when appropriate (i.e., when the result is tiny and
+ *     inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ *     the result overflows to +-Infinity or underflows to 0.
+ */
+
+#ifndef Long
+#define Long long
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+#ifdef MALLOC
+#ifdef KR_headers
+extern char *MALLOC();
+#else
+extern void *MALLOC(size_t);
+#endif
+#else
+#define MALLOC malloc
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#include "errno.h"
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef YES_ALIAS
+#define dval(x) x
+#ifdef IEEE_8087
+#define word0(x) ((ULong *)&x)[1]
+#define word1(x) ((ULong *)&x)[0]
+#else
+#define word0(x) ((ULong *)&x)[0]
+#define word1(x) ((ULong *)&x)[1]
+#endif
+#else
+#ifdef IEEE_8087
+#define word0(x) ((U*)&x)->L[1]
+#define word1(x) ((U*)&x)->L[0]
+#else
+#define word0(x) ((U*)&x)->L[0]
+#define word1(x) ((U*)&x)->L[1]
+#endif
+#define dval(x) ((U*)&x)->d
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm    /* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#define Rounding rounding
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8        /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Bias 129
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef KR_headers
+#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)
+#else
+#define FFFFFFFF 0xffffffffUL
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else  /* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)   /*nothing*/
+#define FREE_DTOA_LOCK(n)      /*nothing*/
+#endif
+
+#define Kmax 15
+
+#ifdef __cplusplus
+extern "C" double strtod(const char *s00, char **se);
+extern "C" char *dtoa(double d, int mode, int ndigits,
+                       int *decpt, int *sign, char **rve);
+#endif
+
+ struct
+Bigint {
+       struct Bigint *next;
+       int k, maxwds, sign, wds;
+       ULong x[1];
+       };
+
+ typedef struct Bigint Bigint;
+
+ static Bigint *freelist[Kmax+1];
+
+ static Bigint *
+Balloc
+#ifdef KR_headers
+       (k) int k;
+#else
+       (int k)
+#endif
+{
+       int x;
+       Bigint *rv;
+#ifndef Omit_Private_Memory
+       unsigned int len;
+#endif
+
+       ACQUIRE_DTOA_LOCK(0);
+       if ((rv = freelist[k])) {
+               freelist[k] = rv->next;
+               }
+       else {
+               x = 1 << k;
+#ifdef Omit_Private_Memory
+               rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+               len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+                       /sizeof(double);
+               if (pmem_next - private_mem + len <= PRIVATE_mem) {
+                       rv = (Bigint*)pmem_next;
+                       pmem_next += len;
+                       }
+               else
+                       rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+               rv->k = k;
+               rv->maxwds = x;
+               }
+       FREE_DTOA_LOCK(0);
+       rv->sign = rv->wds = 0;
+       return rv;
+       }
+
+ static void
+Bfree
+#ifdef KR_headers
+       (v) Bigint *v;
+#else
+       (Bigint *v)
+#endif
+{
+       if (v) {
+               ACQUIRE_DTOA_LOCK(0);
+               v->next = freelist[v->k];
+               freelist[v->k] = v;
+               FREE_DTOA_LOCK(0);
+               }
+       }
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(Long) + 2*sizeof(int))
+
+ static Bigint *
+multadd
+#ifdef KR_headers
+       (b, m, a) Bigint *b; int m, a;
+#else
+       (Bigint *b, int m, int a)       /* multiply by m and add a */
+#endif
+{
+       int i, wds;
+#ifdef ULLong
+       ULong *x;
+       ULLong carry, y;
+#else
+       ULong carry, *x, y;
+#ifdef Pack_32
+       ULong xi, z;
+#endif
+#endif
+       Bigint *b1;
+
+       wds = b->wds;
+       x = b->x;
+       i = 0;
+       carry = a;
+       do {
+#ifdef ULLong
+               y = *x * (ULLong)m + carry;
+               carry = y >> 32;
+               *x++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+               xi = *x;
+               y = (xi & 0xffff) * m + carry;
+               z = (xi >> 16) * m + (y >> 16);
+               carry = z >> 16;
+               *x++ = (z << 16) + (y & 0xffff);
+#else
+               y = *x * m + carry;
+               carry = y >> 16;
+               *x++ = y & 0xffff;
+#endif
+#endif
+               }
+               while(++i < wds);
+       if (carry) {
+               if (wds >= b->maxwds) {
+                       b1 = Balloc(b->k+1);
+                       Bcopy(b1, b);
+                       Bfree(b);
+                       b = b1;
+                       }
+               b->x[wds++] = carry;
+               b->wds = wds;
+               }
+       return b;
+       }
+
+ static Bigint *
+s2b
+#ifdef KR_headers
+       (s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9;
+#else
+       (CONST char *s, int nd0, int nd, ULong y9)
+#endif
+{
+       Bigint *b;
+       int i, k;
+       Long x, y;
+
+       x = (nd + 8) / 9;
+       for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+       b = Balloc(k);
+       b->x[0] = y9;
+       b->wds = 1;
+#else
+       b = Balloc(k+1);
+       b->x[0] = y9 & 0xffff;
+       b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+       i = 9;
+       if (9 < nd0) {
+               s += 9;
+               do b = multadd(b, 10, *s++ - '0');
+                       while(++i < nd0);
+               s++;
+               }
+       else
+               s += 10;
+       for(; i < nd; i++)
+               b = multadd(b, 10, *s++ - '0');
+       return b;
+       }
+
+ static int
+hi0bits
+#ifdef KR_headers
+       (x) register ULong x;
+#else
+       (register ULong x)
+#endif
+{
+       register int k = 0;
+
+       if (!(x & 0xffff0000)) {
+               k = 16;
+               x <<= 16;
+               }
+       if (!(x & 0xff000000)) {
+               k += 8;
+               x <<= 8;
+               }
+       if (!(x & 0xf0000000)) {
+               k += 4;
+               x <<= 4;
+               }
+       if (!(x & 0xc0000000)) {
+               k += 2;
+               x <<= 2;
+               }
+       if (!(x & 0x80000000)) {
+               k++;
+               if (!(x & 0x40000000))
+                       return 32;
+               }
+       return k;
+       }
+
+ static int
+lo0bits
+#ifdef KR_headers
+       (y) ULong *y;
+#else
+       (ULong *y)
+#endif
+{
+       register int k;
+       register ULong x = *y;
+
+       if (x & 7) {
+               if (x & 1)
+                       return 0;
+               if (x & 2) {
+                       *y = x >> 1;
+                       return 1;
+                       }
+               *y = x >> 2;
+               return 2;
+               }
+       k = 0;
+       if (!(x & 0xffff)) {
+               k = 16;
+               x >>= 16;
+               }
+       if (!(x & 0xff)) {
+               k += 8;
+               x >>= 8;
+               }
+       if (!(x & 0xf)) {
+               k += 4;
+               x >>= 4;
+               }
+       if (!(x & 0x3)) {
+               k += 2;
+               x >>= 2;
+               }
+       if (!(x & 1)) {
+               k++;
+               x >>= 1;
+               if (!x)
+                       return 32;
+               }
+       *y = x;
+       return k;
+       }
+
+ static Bigint *
+i2b
+#ifdef KR_headers
+       (i) int i;
+#else
+       (int i)
+#endif
+{
+       Bigint *b;
+
+       b = Balloc(1);
+       b->x[0] = i;
+       b->wds = 1;
+       return b;
+       }
+
+ static Bigint *
+mult
+#ifdef KR_headers
+       (a, b) Bigint *a, *b;
+#else
+       (Bigint *a, Bigint *b)
+#endif
+{
+       Bigint *c;
+       int k, wa, wb, wc;
+       ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+       ULong y;
+#ifdef ULLong
+       ULLong carry, z;
+#else
+       ULong carry, z;
+#ifdef Pack_32
+       ULong z2;
+#endif
+#endif
+
+       if (a->wds < b->wds) {
+               c = a;
+               a = b;
+               b = c;
+               }
+       k = a->k;
+       wa = a->wds;
+       wb = b->wds;
+       wc = wa + wb;
+       if (wc > a->maxwds)
+               k++;
+       c = Balloc(k);
+       for(x = c->x, xa = x + wc; x < xa; x++)
+               *x = 0;
+       xa = a->x;
+       xae = xa + wa;
+       xb = b->x;
+       xbe = xb + wb;
+       xc0 = c->x;
+#ifdef ULLong
+       for(; xb < xbe; xc0++) {
+               if ((y = *xb++)) {
+                       x = xa;
+                       xc = xc0;
+                       carry = 0;
+                       do {
+                               z = *x++ * (ULLong)y + *xc + carry;
+                               carry = z >> 32;
+                               *xc++ = z & FFFFFFFF;
+                               }
+                               while(x < xae);
+                       *xc = carry;
+                       }
+               }
+#else
+#ifdef Pack_32
+       for(; xb < xbe; xb++, xc0++) {
+               if (y = *xb & 0xffff) {
+                       x = xa;
+                       xc = xc0;
+                       carry = 0;
+                       do {
+                               z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+                               carry = z >> 16;
+                               z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+                               carry = z2 >> 16;
+                               Storeinc(xc, z2, z);
+                               }
+                               while(x < xae);
+                       *xc = carry;
+                       }
+               if (y = *xb >> 16) {
+                       x = xa;
+                       xc = xc0;
+                       carry = 0;
+                       z2 = *xc;
+                       do {
+                               z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+                               carry = z >> 16;
+                               Storeinc(xc, z, z2);
+                               z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+                               carry = z2 >> 16;
+                               }
+                               while(x < xae);
+                       *xc = z2;
+                       }
+               }
+#else
+       for(; xb < xbe; xc0++) {
+               if (y = *xb++) {
+                       x = xa;
+                       xc = xc0;
+                       carry = 0;
+                       do {
+                               z = *x++ * y + *xc + carry;
+                               carry = z >> 16;
+                               *xc++ = z & 0xffff;
+                               }
+                               while(x < xae);
+                       *xc = carry;
+                       }
+               }
+#endif
+#endif
+       for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+       c->wds = wc;
+       return c;
+       }
+
+ static Bigint *p5s;
+
+ static Bigint *
+pow5mult
+#ifdef KR_headers
+       (b, k) Bigint *b; int k;
+#else
+       (Bigint *b, int k)
+#endif
+{
+       Bigint *b1, *p5, *p51;
+       int i;
+       static int p05[3] = { 5, 25, 125 };
+
+       if ((i = k & 3))
+               b = multadd(b, p05[i-1], 0);
+
+       if (!(k >>= 2))
+               return b;
+       if (!(p5 = p5s)) {
+               /* first time */
+#ifdef MULTIPLE_THREADS
+               ACQUIRE_DTOA_LOCK(1);
+               if (!(p5 = p5s)) {
+                       p5 = p5s = i2b(625);
+                       p5->next = 0;
+                       }
+               FREE_DTOA_LOCK(1);
+#else
+               p5 = p5s = i2b(625);
+               p5->next = 0;
+#endif
+               }
+       for(;;) {
+               if (k & 1) {
+                       b1 = mult(b, p5);
+                       Bfree(b);
+                       b = b1;
+                       }
+               if (!(k >>= 1))
+                       break;
+               if (!(p51 = p5->next)) {
+#ifdef MULTIPLE_THREADS
+                       ACQUIRE_DTOA_LOCK(1);
+                       if (!(p51 = p5->next)) {
+                               p51 = p5->next = mult(p5,p5);
+                               p51->next = 0;
+                               }
+                       FREE_DTOA_LOCK(1);
+#else
+                       p51 = p5->next = mult(p5,p5);
+                       p51->next = 0;
+#endif
+                       }
+               p5 = p51;
+               }
+       return b;
+       }
+
+ static Bigint *
+lshift
+#ifdef KR_headers
+       (b, k) Bigint *b; int k;
+#else
+       (Bigint *b, int k)
+#endif
+{
+       int i, k1, n, n1;
+       Bigint *b1;
+       ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+       n = k >> 5;
+#else
+       n = k >> 4;
+#endif
+       k1 = b->k;
+       n1 = n + b->wds + 1;
+       for(i = b->maxwds; n1 > i; i <<= 1)
+               k1++;
+       b1 = Balloc(k1);
+       x1 = b1->x;
+       for(i = 0; i < n; i++)
+               *x1++ = 0;
+       x = b->x;
+       xe = x + b->wds;
+#ifdef Pack_32
+       if (k &= 0x1f) {
+               k1 = 32 - k;
+               z = 0;
+               do {
+                       *x1++ = *x << k | z;
+                       z = *x++ >> k1;
+                       }
+                       while(x < xe);
+               if ((*x1 = z))
+                       ++n1;
+               }
+#else
+       if (k &= 0xf) {
+               k1 = 16 - k;
+               z = 0;
+               do {
+                       *x1++ = *x << k  & 0xffff | z;
+                       z = *x++ >> k1;
+                       }
+                       while(x < xe);
+               if (*x1 = z)
+                       ++n1;
+               }
+#endif
+       else do
+               *x1++ = *x++;
+               while(x < xe);
+       b1->wds = n1 - 1;
+       Bfree(b);
+       return b1;
+       }
+
+ static int
+cmp
+#ifdef KR_headers
+       (a, b) Bigint *a, *b;
+#else
+       (Bigint *a, Bigint *b)
+#endif
+{
+       ULong *xa, *xa0, *xb, *xb0;
+       int i, j;
+
+       i = a->wds;
+       j = b->wds;
+#ifdef DEBUG
+       if (i > 1 && !a->x[i-1])
+               Bug("cmp called with a->x[a->wds-1] == 0");
+       if (j > 1 && !b->x[j-1])
+               Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+       if (i -= j)
+               return i;
+       xa0 = a->x;
+       xa = xa0 + j;
+       xb0 = b->x;
+       xb = xb0 + j;
+       for(;;) {
+               if (*--xa != *--xb)
+                       return *xa < *xb ? -1 : 1;
+               if (xa <= xa0)
+                       break;
+               }
+       return 0;
+       }
+
+ static Bigint *
+diff
+#ifdef KR_headers
+       (a, b) Bigint *a, *b;
+#else
+       (Bigint *a, Bigint *b)
+#endif
+{
+       Bigint *c;
+       int i, wa, wb;
+       ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+       ULLong borrow, y;
+#else
+       ULong borrow, y;
+#ifdef Pack_32
+       ULong z;
+#endif
+#endif
+
+       i = cmp(a,b);
+       if (!i) {
+               c = Balloc(0);
+               c->wds = 1;
+               c->x[0] = 0;
+               return c;
+               }
+       if (i < 0) {
+               c = a;
+               a = b;
+               b = c;
+               i = 1;
+               }
+       else
+               i = 0;
+       c = Balloc(a->k);
+       c->sign = i;
+       wa = a->wds;
+       xa = a->x;
+       xae = xa + wa;
+       wb = b->wds;
+       xb = b->x;
+       xbe = xb + wb;
+       xc = c->x;
+       borrow = 0;
+#ifdef ULLong
+       do {
+               y = (ULLong)*xa++ - *xb++ - borrow;
+               borrow = y >> 32 & (ULong)1;
+               *xc++ = y & FFFFFFFF;
+               }
+               while(xb < xbe);
+       while(xa < xae) {
+               y = *xa++ - borrow;
+               borrow = y >> 32 & (ULong)1;
+               *xc++ = y & FFFFFFFF;
+               }
+#else
+#ifdef Pack_32
+       do {
+               y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+               borrow = (y & 0x10000) >> 16;
+               z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+               borrow = (z & 0x10000) >> 16;
+               Storeinc(xc, z, y);
+               }
+               while(xb < xbe);
+       while(xa < xae) {
+               y = (*xa & 0xffff) - borrow;
+               borrow = (y & 0x10000) >> 16;
+               z = (*xa++ >> 16) - borrow;
+               borrow = (z & 0x10000) >> 16;
+               Storeinc(xc, z, y);
+               }
+#else
+       do {
+               y = *xa++ - *xb++ - borrow;
+               borrow = (y & 0x10000) >> 16;
+               *xc++ = y & 0xffff;
+               }
+               while(xb < xbe);
+       while(xa < xae) {
+               y = *xa++ - borrow;
+               borrow = (y & 0x10000) >> 16;
+               *xc++ = y & 0xffff;
+               }
+#endif
+#endif
+       while(!*--xc)
+               wa--;
+       c->wds = wa;
+       return c;
+       }
+
+ static double
+ulp
+#ifdef KR_headers
+       (x) double x;
+#else
+       (double x)
+#endif
+{
+       register Long L;
+       double a;
+
+       L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+       if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+               L |= Exp_msk1 >> 4;
+#endif
+               word0(a) = L;
+               word1(a) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+               }
+       else {
+               L = -L >> Exp_shift;
+               if (L < Exp_shift) {
+                       word0(a) = 0x80000 >> L;
+                       word1(a) = 0;
+                       }
+               else {
+                       word0(a) = 0;
+                       L -= Exp_shift;
+                       word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+                       }
+               }
+#endif
+#endif
+       return dval(a);
+       }
+
+ static double
+b2d
+#ifdef KR_headers
+       (a, e) Bigint *a; int *e;
+#else
+       (Bigint *a, int *e)
+#endif
+{
+       ULong *xa, *xa0, w, y, z;
+       int k;
+       double d;
+#ifdef VAX
+       ULong d0, d1;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+       xa0 = a->x;
+       xa = xa0 + a->wds;
+       y = *--xa;
+#ifdef DEBUG
+       if (!y) Bug("zero y in b2d");
+#endif
+       k = hi0bits(y);
+       *e = 32 - k;
+#ifdef Pack_32
+       if (k < Ebits) {
+               d0 = Exp_1 | (y >> (Ebits - k));
+               w = xa > xa0 ? *--xa : 0;
+               d1 = (y << ((32-Ebits) + k)) | (w >> (Ebits - k));
+               goto ret_d;
+               }
+       z = xa > xa0 ? *--xa : 0;
+       if (k -= Ebits) {
+               d0 = Exp_1 | (y << k) | (z >> (32 - k));
+               y = xa > xa0 ? *--xa : 0;
+               d1 = (z << k) | (y >> (32 - k));
+               }
+       else {
+               d0 = Exp_1 | y;
+               d1 = z;
+               }
+#else
+       if (k < Ebits + 16) {
+               z = xa > xa0 ? *--xa : 0;
+               d0 = Exp_1 | (y << (k - Ebits)) | (z >> (Ebits + 16 - k));
+               w = xa > xa0 ? *--xa : 0;
+               y = xa > xa0 ? *--xa : 0;
+               d1 = (z << (k + 16 - Ebits)) | (w << (k - Ebits)) | (y >> (16 + Ebits - k));
+               goto ret_d;
+               }
+       z = xa > xa0 ? *--xa : 0;
+       w = xa > xa0 ? *--xa : 0;
+       k -= Ebits + 16;
+       d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+       y = xa > xa0 ? *--xa : 0;
+       d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+       word0(d) = d0 >> 16 | d0 << 16;
+       word1(d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+       return dval(d);
+       }
+
+ static Bigint *
+d2b
+#ifdef KR_headers
+       (d, e, bits) double d; int *e, *bits;
+#else
+       (double d, int *e, int *bits)
+#endif
+{
+       Bigint *b;
+       int de, k;
+       ULong *x, y, z;
+#ifndef Sudden_Underflow
+       int i;
+#endif
+#ifdef VAX
+       ULong d0, d1;
+       d0 = word0(d) >> 16 | word0(d) << 16;
+       d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+       b = Balloc(1);
+#else
+       b = Balloc(2);
+#endif
+       x = b->x;
+
+       z = d0 & Frac_mask;
+       d0 &= 0x7fffffff;       /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+       de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+       z |= Exp_msk11;
+#endif
+#else
+       if ((de = (int)(d0 >> Exp_shift)))
+               z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+       if ((y = d1)) {
+               if ((k = lo0bits(&y))) {
+                       x[0] = y | (z << (32 - k));
+                       z >>= k;
+                       }
+               else
+                       x[0] = y;
+#ifndef Sudden_Underflow
+               i =
+#endif
+                   b->wds = (x[1] = z) ? 2 : 1;
+               }
+       else {
+               /* This assertion fails for "1e-500" and other very 
+                * small numbers.  It provides the right result (0) 
+                * though. This assert has also been removed from KJS's
+                * version of dtoa.c.
+                *
+                * #ifdef DEBUG
+                *     if (!z) Bug("zero z in b2d");
+                * #endif
+                */
+               k = lo0bits(&z);
+               x[0] = z;
+#ifndef Sudden_Underflow
+               i =
+#endif
+                   b->wds = 1;
+               k += 32;
+               }
+#else
+       if (y = d1) {
+               if (k = lo0bits(&y))
+                       if (k >= 16) {
+                               x[0] = y | z << 32 - k & 0xffff;
+                               x[1] = z >> k - 16 & 0xffff;
+                               x[2] = z >> k;
+                               i = 2;
+                               }
+                       else {
+                               x[0] = y & 0xffff;
+                               x[1] = y >> 16 | z << 16 - k & 0xffff;
+                               x[2] = z >> k & 0xffff;
+                               x[3] = z >> k+16;
+                               i = 3;
+                               }
+               else {
+                       x[0] = y & 0xffff;
+                       x[1] = y >> 16;
+                       x[2] = z & 0xffff;
+                       x[3] = z >> 16;
+                       i = 3;
+                       }
+               }
+       else {
+#ifdef DEBUG
+               if (!z)
+                       Bug("Zero passed to d2b");
+#endif
+               k = lo0bits(&z);
+               if (k >= 16) {
+                       x[0] = z;
+                       i = 0;
+                       }
+               else {
+                       x[0] = z & 0xffff;
+                       x[1] = z >> 16;
+                       i = 1;
+                       }
+               k += 32;
+               }
+       while(!x[i])
+               --i;
+       b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+       if (de) {
+#endif
+#ifdef IBM
+               *e = (de - Bias - (P-1) << 2) + k;
+               *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+               *e = de - Bias - (P-1) + k;
+               *bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+               }
+       else {
+               *e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+               *bits = 32*i - hi0bits(x[i-1]);
+#else
+               *bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+               }
+#endif
+       return b;
+       }
+#undef d0
+#undef d1
+
+ static double
+ratio
+#ifdef KR_headers
+       (a, b) Bigint *a, *b;
+#else
+       (Bigint *a, Bigint *b)
+#endif
+{
+       double da, db;
+       int k, ka, kb;
+
+       dval(da) = b2d(a, &ka);
+       dval(db) = b2d(b, &kb);
+#ifdef Pack_32
+       k = ka - kb + 32*(a->wds - b->wds);
+#else
+       k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+       if (k > 0) {
+               word0(da) += (k >> 2)*Exp_msk1;
+               if (k &= 3)
+                       dval(da) *= 1 << k;
+               }
+       else {
+               k = -k;
+               word0(db) += (k >> 2)*Exp_msk1;
+               if (k &= 3)
+                       dval(db) *= 1 << k;
+               }
+#else
+       if (k > 0)
+               word0(da) += k*Exp_msk1;
+       else {
+               k = -k;
+               word0(db) += k*Exp_msk1;
+               }
+#endif
+       return dval(da) / dval(db);
+       }
+
+ static CONST double
+tens[] = {
+               1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+               1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+               1e20, 1e21, 1e22
+#ifdef VAX
+               , 1e23, 1e24
+#endif
+               };
+
+ static CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+               9007199254740992.*9007199254740992.e-256
+               /* = 2^106 * 1e-53 */
+#else
+               1e-256
+#endif
+               };
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static CONST double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#ifndef IEEE_Arith
+#undef INFNAN_CHECK
+#endif
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+ static int
+match
+#ifdef KR_headers
+       (sp, t) char **sp, *t;
+#else
+       (CONST char **sp, char *t)
+#endif
+{
+       int c, d;
+       CONST char *s = *sp;
+
+       while(d = *t++) {
+               if ((c = *++s) >= 'A' && c <= 'Z')
+                       c += 'a' - 'A';
+               if (c != d)
+                       return 0;
+               }
+       *sp = s + 1;
+       return 1;
+       }
+
+#ifndef No_Hex_NaN
+ static void
+hexnan
+#ifdef KR_headers
+       (rvp, sp) double *rvp; CONST char **sp;
+#else
+       (double *rvp, CONST char **sp)
+#endif
+{
+       ULong c, x[2];
+       CONST char *s;
+       int havedig, udx0, xshift;
+
+       x[0] = x[1] = 0;
+       havedig = xshift = 0;
+       udx0 = 1;
+       s = *sp;
+       while(c = *(CONST unsigned char*)++s) {
+               if (c >= '0' && c <= '9')
+                       c -= '0';
+               else if (c >= 'a' && c <= 'f')
+                       c += 10 - 'a';
+               else if (c >= 'A' && c <= 'F')
+                       c += 10 - 'A';
+               else if (c <= ' ') {
+                       if (udx0 && havedig) {
+                               udx0 = 0;
+                               xshift = 1;
+                               }
+                       continue;
+                       }
+               else if (/*(*/ c == ')' && havedig) {
+                       *sp = s + 1;
+                       break;
+                       }
+               else
+                       return; /* invalid form: don't change *sp */
+               havedig = 1;
+               if (xshift) {
+                       xshift = 0;
+                       x[0] = x[1];
+                       x[1] = 0;
+                       }
+               if (udx0)
+                       x[0] = (x[0] << 4) | (x[1] >> 28);
+               x[1] = (x[1] << 4) | c;
+               }
+       if ((x[0] &= 0xfffff) || x[1]) {
+               word0(*rvp) = Exp_mask | x[0];
+               word1(*rvp) = x[1];
+               }
+       }
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+ double
+strtod
+#ifdef KR_headers
+       (s00, se) CONST char *s00; char **se;
+#else
+       (CONST char *s00, char **se)
+#endif
+{
+#ifdef Avoid_Underflow
+       int scale;
+#endif
+       int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+                e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+       CONST char *s, *s0, *s1;
+       double aadj, aadj1, adj, rv, rv0;
+       Long L;
+       ULong y, z;
+       Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef SET_INEXACT
+       int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS
+       int rounding;
+#endif
+#ifdef USE_LOCALE
+       CONST char *s2;
+#endif
+
+       sign = nz0 = nz = 0;
+       dval(rv) = 0.;
+       for(s = s00;;s++) switch(*s) {
+               case '-':
+                       sign = 1;
+                       /* no break */
+               case '+':
+                       if (*++s)
+                               goto break2;
+                       /* no break */
+               case 0:
+                       goto ret0;
+               case '\t':
+               case '\n':
+               case '\v':
+               case '\f':
+               case '\r':
+               case ' ':
+                       continue;
+               default:
+                       goto break2;
+               }
+ break2:
+       if (*s == '0') {
+               nz0 = 1;
+               while(*++s == '0') ;
+               if (!*s)
+                       goto ret;
+               }
+       s0 = s;
+       y = z = 0;
+       for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+               if (nd < 9)
+                       y = 10*y + c - '0';
+               else if (nd < 16)
+                       z = 10*z + c - '0';
+       nd0 = nd;
+#ifdef USE_LOCALE
+       s1 = localeconv()->decimal_point;
+       if (c == *s1) {
+               c = '.';
+               if (*++s1) {
+                       s2 = s;
+                       for(;;) {
+                               if (*++s2 != *s1) {
+                                       c = 0;
+                                       break;
+                                       }
+                               if (!*++s1) {
+                                       s = s2;
+                                       break;
+                                       }
+                               }
+                       }
+               }
+#endif
+       if (c == '.') {
+               c = *++s;
+               if (!nd) {
+                       for(; c == '0'; c = *++s)
+                               nz++;
+                       if (c > '0' && c <= '9') {
+                               s0 = s;
+                               nf += nz;
+                               nz = 0;
+                               goto have_dig;
+                               }
+                       goto dig_done;
+                       }
+               for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+                       nz++;
+                       if (c -= '0') {
+                               nf += nz;
+                               for(i = 1; i < nz; i++)
+                                       if (nd++ < 9)
+                                               y *= 10;
+                                       else if (nd <= DBL_DIG + 1)
+                                               z *= 10;
+                               if (nd++ < 9)
+                                       y = 10*y + c;
+                               else if (nd <= DBL_DIG + 1)
+                                       z = 10*z + c;
+                               nz = 0;
+                               }
+                       }
+               }
+ dig_done:
+       e = 0;
+       if (c == 'e' || c == 'E') {
+               if (!nd && !nz && !nz0) {
+                       goto ret0;
+                       }
+               s00 = s;
+               esign = 0;
+               switch(c = *++s) {
+                       case '-':
+                               esign = 1;
+                       case '+':
+                               c = *++s;
+                       }
+               if (c >= '0' && c <= '9') {
+                       while(c == '0')
+                               c = *++s;
+                       if (c > '0' && c <= '9') {
+                               L = c - '0';
+                               s1 = s;
+                               while((c = *++s) >= '0' && c <= '9')
+                                       L = 10*L + c - '0';
+                               if (s - s1 > 8 || L > 19999)
+                                       /* Avoid confusion from exponents
+                                        * so large that e might overflow.
+                                        */
+                                       e = 19999; /* safe for 16 bit ints */
+                               else
+                                       e = (int)L;
+                               if (esign)
+                                       e = -e;
+                               }
+                       else
+                               e = 0;
+                       }
+               else
+                       s = s00;
+               }
+       if (!nd) {
+               if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+                       /* Check for Nan and Infinity */
+                       switch(c) {
+                         case 'i':
+                         case 'I':
+                               if (match(&s,"nf")) {
+                                       --s;
+                                       if (!match(&s,"inity"))
+                                               ++s;
+                                       word0(rv) = 0x7ff00000;
+                                       word1(rv) = 0;
+                                       goto ret;
+                                       }
+                               break;
+                         case 'n':
+                         case 'N':
+                               if (match(&s, "an")) {
+                                       word0(rv) = NAN_WORD0;
+                                       word1(rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+                                       if (*s == '(') /*)*/
+                                               hexnan(&rv, &s);
+#endif
+                                       goto ret;
+                                       }
+                         }
+#endif /* INFNAN_CHECK */
+ ret0:
+                       s = s00;
+                       sign = 0;
+                       }
+               goto ret;
+               }
+       e1 = e -= nf;
+
+       /* Now we have nd0 digits, starting at s0, followed by a
+        * decimal point, followed by nd-nd0 digits.  The number we're
+        * after is the integer represented by those digits times
+        * 10**e */
+
+       if (!nd0)
+               nd0 = nd;
+       k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+       dval(rv) = y;
+       if (k > 9) {
+#ifdef SET_INEXACT
+               if (k > DBL_DIG)
+                       oldinexact = get_inexact();
+#endif
+               dval(rv) = tens[k - 9] * dval(rv) + z;
+               }
+       bd0 = 0;
+       if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+               && Flt_Rounds == 1
+#endif
+#endif
+                       ) {
+               if (!e)
+                       goto ret;
+               if (e > 0) {
+                       if (e <= Ten_pmax) {
+#ifdef VAX
+                               goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+                               /* round correctly FLT_ROUNDS = 2 or 3 */
+                               if (sign) {
+                                       rv = -rv;
+                                       sign = 0;
+                                       }
+#endif
+                               /* rv = */ rounded_product(dval(rv), tens[e]);
+                               goto ret;
+#endif
+                               }
+                       i = DBL_DIG - nd;
+                       if (e <= Ten_pmax + i) {
+                               /* A fancier test would sometimes let us do
+                                * this for larger i values.
+                                */
+#ifdef Honor_FLT_ROUNDS
+                               /* round correctly FLT_ROUNDS = 2 or 3 */
+                               if (sign) {
+                                       rv = -rv;
+                                       sign = 0;
+                                       }
+#endif
+                               e -= i;
+                               dval(rv) *= tens[i];
+#ifdef VAX
+                               /* VAX exponent range is so narrow we must
+                                * worry about overflow here...
+                                */
+ vax_ovfl_check:
+                               word0(rv) -= P*Exp_msk1;
+                               /* rv = */ rounded_product(dval(rv), tens[e]);
+                               if ((word0(rv) & Exp_mask)
+                                > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+                                       goto ovfl;
+                               word0(rv) += P*Exp_msk1;
+#else
+                               /* rv = */ rounded_product(dval(rv), tens[e]);
+#endif
+                               goto ret;
+                               }
+                       }
+#ifndef Inaccurate_Divide
+               else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+                       /* round correctly FLT_ROUNDS = 2 or 3 */
+                       if (sign) {
+                               rv = -rv;
+                               sign = 0;
+                               }
+#endif
+                       /* rv = */ rounded_quotient(dval(rv), tens[-e]);
+                       goto ret;
+                       }
+#endif
+               }
+       e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+       inexact = 1;
+       if (k <= DBL_DIG)
+               oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+       scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+       if ((rounding = Flt_Rounds) >= 2) {
+               if (sign)
+                       rounding = rounding == 2 ? 0 : 2;
+               else
+                       if (rounding != 2)
+                               rounding = 0;
+               }
+#endif
+#endif /*IEEE_Arith*/
+
+       /* Get starting approximation = rv * 10**e1 */
+
+       if (e1 > 0) {
+               if ((i = e1 & 15))
+                       dval(rv) *= tens[i];
+               if (e1 &= ~15) {
+                       if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+#ifndef NO_ERRNO
+                               errno = ERANGE;
+#endif
+                               /* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+                               switch(rounding) {
+                                 case 0: /* toward 0 */
+                                 case 3: /* toward -infinity */
+                                       word0(rv) = Big0;
+                                       word1(rv) = Big1;
+                                       break;
+                                 default:
+                                       word0(rv) = Exp_mask;
+                                       word1(rv) = 0;
+                                 }
+#else /*Honor_FLT_ROUNDS*/
+                               word0(rv) = Exp_mask;
+                               word1(rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+                               /* set overflow bit */
+                               dval(rv0) = 1e300;
+                               dval(rv0) *= dval(rv0);
+#endif
+#else /*IEEE_Arith*/
+                               word0(rv) = Big0;
+                               word1(rv) = Big1;
+#endif /*IEEE_Arith*/
+                               if (bd0)
+                                       goto retfree;
+                               goto ret;
+                               }
+                       e1 >>= 4;
+                       for(j = 0; e1 > 1; j++, e1 >>= 1)
+                               if (e1 & 1)
+                                       dval(rv) *= bigtens[j];
+               /* The last multiplication could overflow. */
+                       word0(rv) -= P*Exp_msk1;
+                       dval(rv) *= bigtens[j];
+                       if ((z = word0(rv) & Exp_mask)
+                        > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+                               goto ovfl;
+                       if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+                               /* set to largest number */
+                               /* (Can't trust DBL_MAX) */
+                               word0(rv) = Big0;
+                               word1(rv) = Big1;
+                               }
+                       else
+                               word0(rv) += P*Exp_msk1;
+                       }
+               }
+       else if (e1 < 0) {
+               e1 = -e1;
+               if ((i = e1 & 15))
+                       dval(rv) /= tens[i];
+               if (e1 >>= 4) {
+                       if (e1 >= 1 << n_bigtens)
+                               goto undfl;
+#ifdef Avoid_Underflow
+                       if (e1 & Scale_Bit)
+                               scale = 2*P;
+                       for(j = 0; e1 > 0; j++, e1 >>= 1)
+                               if (e1 & 1)
+                                       dval(rv) *= tinytens[j];
+                       if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask)
+                                               >> Exp_shift)) > 0) {
+                               /* scaled rv is denormal; zap j low bits */
+                               if (j >= 32) {
+                                       word1(rv) = 0;
+                                       if (j >= 53)
+                                        word0(rv) = (P+2)*Exp_msk1;
+                                       else
+                                        word0(rv) &= 0xffffffff << (j-32);
+                                       }
+                               else
+                                       word1(rv) &= 0xffffffff << j;
+                               }
+#else
+                       for(j = 0; e1 > 1; j++, e1 >>= 1)
+                               if (e1 & 1)
+                                       dval(rv) *= tinytens[j];
+                       /* The last multiplication could underflow. */
+                       dval(rv0) = dval(rv);
+                       dval(rv) *= tinytens[j];
+                       if (!dval(rv)) {
+                               dval(rv) = 2.*dval(rv0);
+                               dval(rv) *= tinytens[j];
+#endif
+                               if (!dval(rv)) {
+ undfl:
+                                       dval(rv) = 0.;
+#ifndef NO_ERRNO
+                                       errno = ERANGE;
+#endif
+                                       if (bd0)
+                                               goto retfree;
+                                       goto ret;
+                                       }
+#ifndef Avoid_Underflow
+                               word0(rv) = Tiny0;
+                               word1(rv) = Tiny1;
+                               /* The refinement below will clean
+                                * this approximation up.
+                                */
+                               }
+#endif
+                       }
+               }
+
+       /* Now the hard part -- adjusting rv to the correct value.*/
+
+       /* Put digits into bd: true value = bd * 10^e */
+
+       bd0 = s2b(s0, nd0, nd, y);
+
+       for(;;) {
+               bd = Balloc(bd0->k);
+               Bcopy(bd, bd0);
+               bb = d2b(dval(rv), &bbe, &bbbits);      /* rv = bb * 2^bbe */
+               bs = i2b(1);
+
+               if (e >= 0) {
+                       bb2 = bb5 = 0;
+                       bd2 = bd5 = e;
+                       }
+               else {
+                       bb2 = bb5 = -e;
+                       bd2 = bd5 = 0;
+                       }
+               if (bbe >= 0)
+                       bb2 += bbe;
+               else
+                       bd2 -= bbe;
+               bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+               if (rounding != 1)
+                       bs2++;
+#endif
+#ifdef Avoid_Underflow
+               j = bbe - scale;
+               i = j + bbbits - 1;     /* logb(rv) */
+               if (i < Emin)   /* denormal */
+                       j += P - Emin;
+               else
+                       j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+               j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+               j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+               j = bbe;
+               i = j + bbbits - 1;     /* logb(rv) */
+               if (i < Emin)   /* denormal */
+                       j += P - Emin;
+               else
+                       j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+               bb2 += j;
+               bd2 += j;
+#ifdef Avoid_Underflow
+               bd2 += scale;
+#endif
+               i = bb2 < bd2 ? bb2 : bd2;
+               if (i > bs2)
+                       i = bs2;
+               if (i > 0) {
+                       bb2 -= i;
+                       bd2 -= i;
+                       bs2 -= i;
+                       }
+               if (bb5 > 0) {
+                       bs = pow5mult(bs, bb5);
+                       bb1 = mult(bs, bb);
+                       Bfree(bb);
+                       bb = bb1;
+                       }
+               if (bb2 > 0)
+                       bb = lshift(bb, bb2);
+               if (bd5 > 0)
+                       bd = pow5mult(bd, bd5);
+               if (bd2 > 0)
+                       bd = lshift(bd, bd2);
+               if (bs2 > 0)
+                       bs = lshift(bs, bs2);
+               delta = diff(bb, bd);
+               dsign = delta->sign;
+               delta->sign = 0;
+               i = cmp(delta, bs);
+#ifdef Honor_FLT_ROUNDS
+               if (rounding != 1) {
+                       if (i < 0) {
+                               /* Error is less than an ulp */
+                               if (!delta->x[0] && delta->wds <= 1) {
+                                       /* exact */
+#ifdef SET_INEXACT
+                                       inexact = 0;
+#endif
+                                       break;
+                                       }
+                               if (rounding) {
+                                       if (dsign) {
+                                               adj = 1.;
+                                               goto apply_adj;
+                                               }
+                                       }
+                               else if (!dsign) {
+                                       adj = -1.;
+                                       if (!word1(rv)
+                                        && !(word0(rv) & Frac_mask)) {
+                                               y = word0(rv) & Exp_mask;
+#ifdef Avoid_Underflow
+                                               if (!scale || y > 2*P*Exp_msk1)
+#else
+                                               if (y)
+#endif
+                                                 {
+                                                 delta = lshift(delta,Log2P);
+                                                 if (cmp(delta, bs) <= 0)
+                                                       adj = -0.5;
+                                                 }
+                                               }
+ apply_adj:
+#ifdef Avoid_Underflow
+                                       if (scale && (y = word0(rv) & Exp_mask)
+                                               <= 2*P*Exp_msk1)
+                                         word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+                                       if ((word0(rv) & Exp_mask) <=
+                                                       P*Exp_msk1) {
+                                               word0(rv) += P*Exp_msk1;
+                                               dval(rv) += adj*ulp(dval(rv));
+                                               word0(rv) -= P*Exp_msk1;
+                                               }
+                                       else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+                                       dval(rv) += adj*ulp(dval(rv));
+                                       }
+                               break;
+                               }
+                       adj = ratio(delta, bs);
+                       if (adj < 1.)
+                               adj = 1.;
+                       if (adj <= 0x7ffffffe) {
+                               /* adj = rounding ? ceil(adj) : floor(adj); */
+                               y = adj;
+                               if (y != adj) {
+                                       if (!((rounding>>1) ^ dsign))
+                                               y++;
+                                       adj = y;
+                                       }
+                               }
+#ifdef Avoid_Underflow
+                       if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+                               word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+                       if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+                               word0(rv) += P*Exp_msk1;
+                               adj *= ulp(dval(rv));
+                               if (dsign)
+                                       dval(rv) += adj;
+                               else
+                                       dval(rv) -= adj;
+                               word0(rv) -= P*Exp_msk1;
+                               goto cont;
+                               }
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+                       adj *= ulp(dval(rv));
+                       if (dsign)
+                               dval(rv) += adj;
+                       else
+                               dval(rv) -= adj;
+                       goto cont;
+                       }
+#endif /*Honor_FLT_ROUNDS*/
+
+               if (i < 0) {
+                       /* Error is less than half an ulp -- check for
+                        * special case of mantissa a power of two.
+                        */
+                       if (dsign || word1(rv) || word0(rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+                        || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+                        || (word0(rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+                               ) {
+#ifdef SET_INEXACT
+                               if (!delta->x[0] && delta->wds <= 1)
+                                       inexact = 0;
+#endif
+                               break;
+                               }
+                       if (!delta->x[0] && delta->wds <= 1) {
+                               /* exact result */
+#ifdef SET_INEXACT
+                               inexact = 0;
+#endif
+                               break;
+                               }
+                       delta = lshift(delta,Log2P);
+                       if (cmp(delta, bs) > 0)
+                               goto drop_down;
+                       break;
+                       }
+               if (i == 0) {
+                       /* exactly half-way between */
+                       if (dsign) {
+                               if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+                                &&  word1(rv) == (
+#ifdef Avoid_Underflow
+                       (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+               ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+                                                  0xffffffff)) {
+                                       /*boundary case -- increment exponent*/
+                                       word0(rv) = (word0(rv) & Exp_mask)
+                                               + Exp_msk1
+#ifdef IBM
+                                               | Exp_msk1 >> 4
+#endif
+                                               ;
+                                       word1(rv) = 0;
+#ifdef Avoid_Underflow
+                                       dsign = 0;
+#endif
+                                       break;
+                                       }
+                               }
+                       else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+ drop_down:
+                               /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+                               L = word0(rv) & Exp_mask;
+#ifdef IBM
+                               if (L <  Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+                               if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+                               if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+                                       goto undfl;
+                               L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+                               if (scale) {
+                                       L = word0(rv) & Exp_mask;
+                                       if (L <= (2*P+1)*Exp_msk1) {
+                                               if (L > (P+2)*Exp_msk1)
+                                                       /* round even ==> */
+                                                       /* accept rv */
+                                                       break;
+                                               /* rv = smallest denormal */
+                                               goto undfl;
+                                               }
+                                       }
+#endif /*Avoid_Underflow*/
+                               L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+                               word0(rv) = L | Bndry_mask1;
+                               word1(rv) = 0xffffffff;
+#ifdef IBM
+                               goto cont;
+#else
+                               break;
+#endif
+                               }
+#ifndef ROUND_BIASED
+                       if (!(word1(rv) & LSB))
+                               break;
+#endif
+                       if (dsign)
+                               dval(rv) += ulp(dval(rv));
+#ifndef ROUND_BIASED
+                       else {
+                               dval(rv) -= ulp(dval(rv));
+#ifndef Sudden_Underflow
+                               if (!dval(rv))
+                                       goto undfl;
+#endif
+                               }
+#ifdef Avoid_Underflow
+                       dsign = 1 - dsign;
+#endif
+#endif
+                       break;
+                       }
+               if ((aadj = ratio(delta, bs)) <= 2.) {
+                       if (dsign)
+                               aadj = aadj1 = 1.;
+                       else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+                               if (word1(rv) == Tiny1 && !word0(rv))
+                                       goto undfl;
+#endif
+                               aadj = 1.;
+                               aadj1 = -1.;
+                               }
+                       else {
+                               /* special case -- power of FLT_RADIX to be */
+                               /* rounded down... */
+
+                               if (aadj < 2./FLT_RADIX)
+                                       aadj = 1./FLT_RADIX;
+                               else
+                                       aadj *= 0.5;
+                               aadj1 = -aadj;
+                               }
+                       }
+               else {
+                       aadj *= 0.5;
+                       aadj1 = dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+                       switch(Rounding) {
+                               case 2: /* towards +infinity */
+                                       aadj1 -= 0.5;
+                                       break;
+                               case 0: /* towards 0 */
+                               case 3: /* towards -infinity */
+                                       aadj1 += 0.5;
+                               }
+#else
+                       if (Flt_Rounds == 0)
+                               aadj1 += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+                       }
+               y = word0(rv) & Exp_mask;
+
+               /* Check for overflow */
+
+               if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+                       dval(rv0) = dval(rv);
+                       word0(rv) -= P*Exp_msk1;
+                       adj = aadj1 * ulp(dval(rv));
+                       dval(rv) += adj;
+                       if ((word0(rv) & Exp_mask) >=
+                                       Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+                               if (word0(rv0) == Big0 && word1(rv0) == Big1)
+                                       goto ovfl;
+                               word0(rv) = Big0;
+                               word1(rv) = Big1;
+                               goto cont;
+                               }
+                       else
+                               word0(rv) += P*Exp_msk1;
+                       }
+               else {
+#ifdef Avoid_Underflow
+                       if (scale && y <= 2*P*Exp_msk1) {
+                               if (aadj <= 0x7fffffff) {
+                                       if ((z = aadj) <= 0)
+                                               z = 1;
+                                       aadj = z;
+                                       aadj1 = dsign ? aadj : -aadj;
+                                       }
+                               word0(aadj1) += (2*P+1)*Exp_msk1 - y;
+                               }
+                       adj = aadj1 * ulp(dval(rv));
+                       dval(rv) += adj;
+#else
+#ifdef Sudden_Underflow
+                       if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+                               dval(rv0) = dval(rv);
+                               word0(rv) += P*Exp_msk1;
+                               adj = aadj1 * ulp(dval(rv));
+                               dval(rv) += adj;
+#ifdef IBM
+                               if ((word0(rv) & Exp_mask) <  P*Exp_msk1)
+#else
+                               if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+                                       {
+                                       if (word0(rv0) == Tiny0
+                                        && word1(rv0) == Tiny1)
+                                               goto undfl;
+                                       word0(rv) = Tiny0;
+                                       word1(rv) = Tiny1;
+                                       goto cont;
+                                       }
+                               else
+                                       word0(rv) -= P*Exp_msk1;
+                               }
+                       else {
+                               adj = aadj1 * ulp(dval(rv));
+                               dval(rv) += adj;
+                               }
+#else /*Sudden_Underflow*/
+                       /* Compute adj so that the IEEE rounding rules will
+                        * correctly round rv + adj in some half-way cases.
+                        * If rv * ulp(rv) is denormalized (i.e.,
+                        * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+                        * trouble from bits lost to denormalization;
+                        * example: 1.2e-307 .
+                        */
+                       if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+                               aadj1 = (double)(int)(aadj + 0.5);
+                               if (!dsign)
+                                       aadj1 = -aadj1;
+                               }
+                       adj = aadj1 * ulp(dval(rv));
+                       dval(rv) += adj;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+                       }
+               z = word0(rv) & Exp_mask;
+#ifndef SET_INEXACT
+#ifdef Avoid_Underflow
+               if (!scale)
+#endif
+               if (y == z) {
+                       /* Can we stop now? */
+                       L = (Long)aadj;
+                       aadj -= L;
+                       /* The tolerances below are conservative. */
+                       if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+                               if (aadj < .4999999 || aadj > .5000001)
+                                       break;
+                               }
+                       else if (aadj < .4999999/FLT_RADIX)
+                               break;
+                       }
+#endif
+ cont:
+               Bfree(bb);
+               Bfree(bd);
+               Bfree(bs);
+               Bfree(delta);
+               }
+#ifdef SET_INEXACT
+       if (inexact) {
+               if (!oldinexact) {
+                       word0(rv0) = Exp_1 + (70 << Exp_shift);
+                       word1(rv0) = 0;
+                       dval(rv0) += 1.;
+                       }
+               }
+       else if (!oldinexact)
+               clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+       if (scale) {
+               word0(rv0) = Exp_1 - 2*P*Exp_msk1;
+               word1(rv0) = 0;
+               dval(rv) *= dval(rv0);
+#ifndef NO_ERRNO
+               /* try to avoid the bug of testing an 8087 register value */
+               if (word0(rv) == 0 && word1(rv) == 0)
+                       errno = ERANGE;
+#endif
+               }
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+       if (inexact && !(word0(rv) & Exp_mask)) {
+               /* set underflow bit */
+               dval(rv0) = 1e-300;
+               dval(rv0) *= dval(rv0);
+               }
+#endif
+ retfree:
+       Bfree(bb);
+       Bfree(bd);
+       Bfree(bs);
+       Bfree(bd0);
+       Bfree(delta);
+ ret:
+       if (se)
+               *se = (char *)s;
+       return sign ? -dval(rv) : dval(rv);
+       }
+
+ static int
+quorem
+#ifdef KR_headers
+       (b, S) Bigint *b, *S;
+#else
+       (Bigint *b, Bigint *S)
+#endif
+{
+       int n;
+       ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+       ULLong borrow, carry, y, ys;
+#else
+       ULong borrow, carry, y, ys;
+#ifdef Pack_32
+       ULong si, z, zs;
+#endif
+#endif
+
+       n = S->wds;
+#ifdef DEBUG
+       /*debug*/ if (b->wds > n)
+       /*debug*/       Bug("oversize b in quorem");
+#endif
+       if (b->wds < n)
+               return 0;
+       sx = S->x;
+       sxe = sx + --n;
+       bx = b->x;
+       bxe = bx + n;
+       q = *bxe / (*sxe + 1);  /* ensure q <= true quotient */
+#ifdef DEBUG
+       /*debug*/ if (q > 9)
+       /*debug*/       Bug("oversized quotient in quorem");
+#endif
+       if (q) {
+               borrow = 0;
+               carry = 0;
+               do {
+#ifdef ULLong
+                       ys = *sx++ * (ULLong)q + carry;
+                       carry = ys >> 32;
+                       y = *bx - (ys & FFFFFFFF) - borrow;
+                       borrow = y >> 32 & (ULong)1;
+                       *bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+                       si = *sx++;
+                       ys = (si & 0xffff) * q + carry;
+                       zs = (si >> 16) * q + (ys >> 16);
+                       carry = zs >> 16;
+                       y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+                       borrow = (y & 0x10000) >> 16;
+                       z = (*bx >> 16) - (zs & 0xffff) - borrow;
+                       borrow = (z & 0x10000) >> 16;
+                       Storeinc(bx, z, y);
+#else
+                       ys = *sx++ * q + carry;
+                       carry = ys >> 16;
+                       y = *bx - (ys & 0xffff) - borrow;
+                       borrow = (y & 0x10000) >> 16;
+                       *bx++ = y & 0xffff;
+#endif
+#endif
+                       }
+                       while(sx <= sxe);
+               if (!*bxe) {
+                       bx = b->x;
+                       while(--bxe > bx && !*bxe)
+                               --n;
+                       b->wds = n;
+                       }
+               }
+       if (cmp(b, S) >= 0) {
+               q++;
+               borrow = 0;
+               carry = 0;
+               bx = b->x;
+               sx = S->x;
+               do {
+#ifdef ULLong
+                       ys = *sx++ + carry;
+                       carry = ys >> 32;
+                       y = *bx - (ys & FFFFFFFF) - borrow;
+                       borrow = y >> 32 & (ULong)1;
+                       *bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+                       si = *sx++;
+                       ys = (si & 0xffff) + carry;
+                       zs = (si >> 16) + (ys >> 16);
+                       carry = zs >> 16;
+                       y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+                       borrow = (y & 0x10000) >> 16;
+                       z = (*bx >> 16) - (zs & 0xffff) - borrow;
+                       borrow = (z & 0x10000) >> 16;
+                       Storeinc(bx, z, y);
+#else
+                       ys = *sx++ + carry;
+                       carry = ys >> 16;
+                       y = *bx - (ys & 0xffff) - borrow;
+                       borrow = (y & 0x10000) >> 16;
+                       *bx++ = y & 0xffff;
+#endif
+#endif
+                       }
+                       while(sx <= sxe);
+               bx = b->x;
+               bxe = bx + n;
+               if (!*bxe) {
+                       while(--bxe > bx && !*bxe)
+                               --n;
+                       b->wds = n;
+                       }
+               }
+       return q;
+       }
+
+#ifndef MULTIPLE_THREADS
+ static char *dtoa_result;
+#endif
+
+ static char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+       int j, k, *r;
+
+       j = sizeof(ULong);
+       for(k = 0;
+               sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+               j <<= 1)
+                       k++;
+       r = (int*)Balloc(k);
+       *r = k;
+       return
+#ifndef MULTIPLE_THREADS
+       dtoa_result =
+#endif
+               (char *)(r+1);
+       }
+
+ static char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(const char *s, char **rve, int n)
+#endif
+{
+       char *rv, *t;
+
+       t = rv = rv_alloc(n);
+       while ((*t = *s++)) t++;
+       if (rve)
+               *rve = t;
+       return rv;
+       }
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+       Bigint *b = (Bigint *)((int *)s - 1);
+       b->maxwds = 1 << (b->k = *(int*)b);
+       Bfree(b);
+#ifndef MULTIPLE_THREADS
+       if (s == dtoa_result)
+               dtoa_result = 0;
+#endif
+       }
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *     1. Rather than iterating, we use a simple numeric overestimate
+ *        to determine k = floor(log10(d)).  We scale relevant
+ *        quantities using O(log2(k)) rather than O(k) multiplications.
+ *     2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *        try to generate digits strictly left to right.  Instead, we
+ *        compute with fewer bits and propagate the carry if necessary
+ *        when rounding the final digit up.  This is often faster.
+ *     3. Under the assumption that input will be rounded nearest,
+ *        mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *        That is, we allow equality in stopping tests when the
+ *        round-nearest rule will give the same floating-point value
+ *        as would satisfaction of the stopping test with strict
+ *        inequality.
+ *     4. We remove common factors of powers of 2 from relevant
+ *        quantities.
+ *     5. When converting floating-point integers less than 1e16,
+ *        we use floating-point arithmetic rather than resorting
+ *        to multiple-precision integers.
+ *     6. When asked to produce fewer than 15 digits, we first try
+ *        to get by with floating-point arithmetic; we resort to
+ *        multiple-precision integer arithmetic only if we cannot
+ *        guarantee that the floating-point calculation has given
+ *        the correctly rounded result.  For k requested digits and
+ *        "uniformly" distributed input, the probability is
+ *        something like 10^(k-15) that we must resort to the Long
+ *        calculation.
+ */
+
+ char *
+dtoa
+#ifdef KR_headers
+       (d, mode, ndigits, decpt, sign, rve)
+       double d; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+       (double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*    Arguments ndigits, decpt, sign are similar to those
+       of ecvt and fcvt; trailing zeros are suppressed from
+       the returned string.  If not null, *rve is set to point
+       to the end of the return value.  If d is +-Infinity or NaN,
+       then *decpt is set to 9999.
+
+       mode:
+               0 ==> shortest string that yields d when read in
+                       and rounded to nearest.
+               1 ==> like 0, but with Steele & White stopping rule;
+                       e.g. with IEEE P754 arithmetic , mode 0 gives
+                       1e23 whereas mode 1 gives 9.999999999999999e22.
+               2 ==> max(1,ndigits) significant digits.  This gives a
+                       return value similar to that of ecvt, except
+                       that trailing zeros are suppressed.
+               3 ==> through ndigits past the decimal point.  This
+                       gives a return value similar to that from fcvt,
+                       except that trailing zeros are suppressed, and
+                       ndigits can be negative.
+               4,5 ==> similar to 2 and 3, respectively, but (in
+                       round-nearest mode) with the tests of mode 0 to
+                       possibly return a shorter string that rounds to d.
+                       With IEEE arithmetic and compilation with
+                       -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+                       as modes 2 and 3 when FLT_ROUNDS != 1.
+               6-9 ==> Debugging modes similar to mode - 4:  don't try
+                       fast floating-point estimate (if applicable).
+
+               Values of mode other than 0-9 are treated as mode 0.
+
+               Sufficient space is allocated to the return value
+               to hold the suppressed trailing zeros.
+       */
+
+       int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+               j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+               spec_case, try_quick, bias_round_up;
+       Long L;
+#ifndef Sudden_Underflow
+       int denorm;
+       ULong x;
+#endif
+       Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+       double d2, ds, eps;
+       char *s, *s0;
+#ifdef Honor_FLT_ROUNDS
+       int rounding;
+#endif
+#ifdef SET_INEXACT
+       int inexact, oldinexact;
+#endif
+
+        /* In mode 2 and 3 we bias rounding up when there are ties. */
+        bias_round_up = mode == 2 || mode == 3;
+
+        ilim = ilim1 = 0; /* to avoid Google3 compiler warnings */
+
+#ifndef MULTIPLE_THREADS
+       if (dtoa_result) {
+               freedtoa(dtoa_result);
+               dtoa_result = 0;
+               }
+#endif
+
+       if (word0(d) & Sign_bit) {
+               /* set sign for everything, including 0's and NaNs */
+               *sign = 1;
+               word0(d) &= ~Sign_bit;  /* clear sign bit */
+               }
+       else
+               *sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+       if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+       if (word0(d)  == 0x8000)
+#endif
+               {
+               /* Infinity or NaN */
+               *decpt = 9999;
+#ifdef IEEE_Arith
+               if (!word1(d) && !(word0(d) & 0xfffff))
+                       return nrv_alloc("Infinity", rve, 8);
+#endif
+               return nrv_alloc("NaN", rve, 3);
+               }
+#endif
+#ifdef IBM
+       dval(d) += 0; /* normalize */
+#endif
+       if (!dval(d)) {
+               *decpt = 1;
+               return nrv_alloc("0", rve, 1);
+               }
+
+#ifdef SET_INEXACT
+       try_quick = oldinexact = get_inexact();
+       inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+       if ((rounding = Flt_Rounds) >= 2) {
+               if (*sign)
+                       rounding = rounding == 2 ? 0 : 2;
+               else
+                       if (rounding != 2)
+                               rounding = 0;
+               }
+#endif
+
+       b = d2b(dval(d), &be, &bbits);
+#ifdef Sudden_Underflow
+       i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+       if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
+#endif
+               dval(d2) = dval(d);
+               word0(d2) &= Frac_mask1;
+               word0(d2) |= Exp_11;
+#ifdef IBM
+               if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+                       dval(d2) /= 1 << j;
+#endif
+
+               /* log(x)       ~=~ log(1.5) + (x-1.5)/1.5
+                * log10(x)      =  log(x) / log(10)
+                *              ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+                * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+                *
+                * This suggests computing an approximation k to log10(d) by
+                *
+                * k = (i - Bias)*0.301029995663981
+                *      + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+                *
+                * We want k to be too large rather than too small.
+                * The error in the first-order Taylor series approximation
+                * is in our favor, so we just round up the constant enough
+                * to compensate for any error in the multiplication of
+                * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+                * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+                * adding 1e-13 to the constant term more than suffices.
+                * Hence we adjust the constant term to 0.1760912590558.
+                * (We could get a more accurate k by invoking log10,
+                *  but this is probably not worthwhile.)
+                */
+
+               i -= Bias;
+#ifdef IBM
+               i <<= 2;
+               i += j;
+#endif
+#ifndef Sudden_Underflow
+               denorm = 0;
+               }
+       else {
+               /* d is denormalized */
+
+               i = bbits + be + (Bias + (P-1) - 1);
+               x = i > 32  ? (word0(d) << (64 - i)) | (word1(d) >> (i - 32))
+                           : word1(d) << (32 - i);
+               dval(d2) = x;
+               word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+               i -= (Bias + (P-1) - 1) + 1;
+               denorm = 1;
+               }
+#endif
+       ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+       k = (int)ds;
+       if (ds < 0. && ds != k)
+               k--;    /* want k = floor(ds) */
+       k_check = 1;
+       if (k >= 0 && k <= Ten_pmax) {
+               if (dval(d) < tens[k])
+                       k--;
+               k_check = 0;
+               }
+       j = bbits - i - 1;
+       if (j >= 0) {
+               b2 = 0;
+               s2 = j;
+               }
+       else {
+               b2 = -j;
+               s2 = 0;
+               }
+       if (k >= 0) {
+               b5 = 0;
+               s5 = k;
+               s2 += k;
+               }
+       else {
+               b2 -= k;
+               b5 = -k;
+               s5 = 0;
+               }
+       if (mode < 0 || mode > 9)
+               mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+       try_quick = Rounding == 1;
+#else
+       try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+       if (mode > 5) {
+               mode -= 4;
+               try_quick = 0;
+               }
+       leftright = 1;
+       switch(mode) {
+               case 0:
+               case 1:
+                       ilim = ilim1 = -1;
+                       i = 18;
+                       ndigits = 0;
+                       break;
+               case 2:
+                       leftright = 0;
+                       /* no break */
+               case 4:
+                       if (ndigits <= 0)
+                               ndigits = 1;
+                       ilim = ilim1 = i = ndigits;
+                       break;
+               case 3:
+                       leftright = 0;
+                       /* no break */
+               case 5:
+                       i = ndigits + k + 1;
+                       ilim = i;
+                       ilim1 = i - 1;
+                       if (i <= 0)
+                               i = 1;
+               }
+       s = s0 = rv_alloc(i);
+
+#ifdef Honor_FLT_ROUNDS
+       if (mode > 1 && rounding != 1)
+               leftright = 0;
+#endif
+
+       if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+               /* Try to get by with floating-point arithmetic. */
+
+               i = 0;
+               dval(d2) = dval(d);
+               k0 = k;
+               ilim0 = ilim;
+               ieps = 2; /* conservative */
+               if (k > 0) {
+                       ds = tens[k&0xf];
+                       j = k >> 4;
+                       if (j & Bletch) {
+                               /* prevent overflows */
+                               j &= Bletch - 1;
+                               dval(d) /= bigtens[n_bigtens-1];
+                               ieps++;
+                               }
+                       for(; j; j >>= 1, i++)
+                               if (j & 1) {
+                                       ieps++;
+                                       ds *= bigtens[i];
+                                       }
+                       dval(d) /= ds;
+                       }
+               else if ((j1 = -k)) {
+                       dval(d) *= tens[j1 & 0xf];
+                       for(j = j1 >> 4; j; j >>= 1, i++)
+                               if (j & 1) {
+                                       ieps++;
+                                       dval(d) *= bigtens[i];
+                                       }
+                       }
+               if (k_check && dval(d) < 1. && ilim > 0) {
+                       if (ilim1 <= 0)
+                               goto fast_failed;
+                       ilim = ilim1;
+                       k--;
+                       dval(d) *= 10.;
+                       ieps++;
+                       }
+               dval(eps) = ieps*dval(d) + 7.;
+               word0(eps) -= (P-1)*Exp_msk1;
+               if (ilim == 0) {
+                       S = mhi = 0;
+                       dval(d) -= 5.;
+                       if (dval(d) > dval(eps))
+                               goto one_digit;
+                       if (dval(d) < -dval(eps))
+                               goto no_digits;
+                       goto fast_failed;
+                       }
+#ifndef No_leftright
+               if (leftright) {
+                       /* Use Steele & White method of only
+                        * generating digits needed.
+                        */
+                       dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+                       for(i = 0;;) {
+                               L = dval(d);
+                               dval(d) -= L;
+                               *s++ = '0' + (int)L;
+                               if (dval(d) < dval(eps))
+                                       goto ret1;
+                               if (1. - dval(d) < dval(eps))
+                                       goto bump_up;
+                               if (++i >= ilim)
+                                       break;
+                               dval(eps) *= 10.;
+                               dval(d) *= 10.;
+                               }
+                       }
+               else {
+#endif
+                       /* Generate ilim digits, then fix them up. */
+                       dval(eps) *= tens[ilim-1];
+                       for(i = 1;; i++, dval(d) *= 10.) {
+                               L = (Long)(dval(d));
+                               if (!(dval(d) -= L))
+                                       ilim = i;
+                               *s++ = '0' + (int)L;
+                               if (i == ilim) {
+                                       if (dval(d) > 0.5 + dval(eps))
+                                               goto bump_up;
+                                       else if (dval(d) < 0.5 - dval(eps)) {
+                                               while(*--s == '0');
+                                               s++;
+                                               goto ret1;
+                                               }
+                                       break;
+                                       }
+                               }
+#ifndef No_leftright
+                       }
+#endif
+ fast_failed:
+               s = s0;
+               dval(d) = dval(d2);
+               k = k0;
+               ilim = ilim0;
+               }
+
+       /* Do we have a "small" integer? */
+
+       if (be >= 0 && k <= Int_max) {
+               /* Yes. */
+               ds = tens[k];
+               if (ndigits < 0 && ilim <= 0) {
+                       S = mhi = 0;
+                       if (ilim < 0 || dval(d) < 5*ds || ((dval(d) == 5*ds) && !bias_round_up))
+                               goto no_digits;
+                       goto one_digit;
+                       }
+
+                /* Limit looping by the number of digits to produce.
+                 * Firefox had a crash bug because some plugins reduce
+                 * the precision of double arithmetic.  With reduced
+                 * precision "dval(d) -= L*ds" might be imprecise and
+                 * d might not become zero and the loop might not
+                 * terminate.
+                 *
+                 * See https://bugzilla.mozilla.org/show_bug.cgi?id=358569
+                 */
+               for(i = 1; i <= k+1; i++, dval(d) *= 10.) {
+                       L = (Long)(dval(d) / ds);
+                       dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+                       /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+                       if (dval(d) < 0) {
+                               L--;
+                               dval(d) += ds;
+                               }
+#endif
+                       *s++ = '0' + (int)L;
+                       if (!dval(d)) {
+#ifdef SET_INEXACT
+                               inexact = 0;
+#endif
+                               break;
+                               }
+                       if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+                               if (mode > 1)
+                               switch(rounding) {
+                                 case 0: goto ret1;
+                                 case 2: goto bump_up;
+                                 }
+#endif
+                               dval(d) += dval(d);
+                               if (dval(d) > ds || (dval(d) == ds && ((L & 1) || bias_round_up))) {
+ bump_up:
+                                       while(*--s == '9')
+                                               if (s == s0) {
+                                                       k++;
+                                                       *s = '0';
+                                                       break;
+                                                       }
+                                       ++*s++;
+                                       }
+                               break;
+                               }
+                       }
+               goto ret1;
+               }
+
+       m2 = b2;
+       m5 = b5;
+       mhi = mlo = 0;
+       if (leftright) {
+               i =
+#ifndef Sudden_Underflow
+                       denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+                       1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+                       1 + P - bbits;
+#endif
+               b2 += i;
+               s2 += i;
+               mhi = i2b(1);
+               }
+       if (m2 > 0 && s2 > 0) {
+               i = m2 < s2 ? m2 : s2;
+               b2 -= i;
+               m2 -= i;
+               s2 -= i;
+               }
+       if (b5 > 0) {
+               if (leftright) {
+                       if (m5 > 0) {
+                               mhi = pow5mult(mhi, m5);
+                               b1 = mult(mhi, b);
+                               Bfree(b);
+                               b = b1;
+                               }
+                       if ((j = b5 - m5))
+                               b = pow5mult(b, j);
+                       }
+               else
+                       b = pow5mult(b, b5);
+               }
+       S = i2b(1);
+       if (s5 > 0)
+               S = pow5mult(S, s5);
+
+       /* Check for special case that d is a normalized power of 2. */
+
+       spec_case = 0;
+       if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+                       && rounding == 1
+#endif
+                               ) {
+               if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+                && word0(d) & (Exp_mask & ~Exp_msk1)
+#endif
+                               ) {
+                       /* The special case */
+                       b2 += Log2P;
+                       s2 += Log2P;
+                       spec_case = 1;
+                       }
+               }
+
+       /* Arrange for convenient computation of quotients:
+        * shift left if necessary so divisor has 4 leading 0 bits.
+        *
+        * Perhaps we should just compute leading 28 bits of S once
+        * and for all and pass them and a shift to quorem, so it
+        * can do shifts and ors to compute the numerator for q.
+        */
+#ifdef Pack_32
+       if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f))
+               i = 32 - i;
+#else
+       if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf))
+               i = 16 - i;
+#endif
+       if (i > 4) {
+               i -= 4;
+               b2 += i;
+               m2 += i;
+               s2 += i;
+               }
+       else if (i < 4) {
+               i += 28;
+               b2 += i;
+               m2 += i;
+               s2 += i;
+               }
+       if (b2 > 0)
+               b = lshift(b, b2);
+       if (s2 > 0)
+               S = lshift(S, s2);
+       if (k_check) {
+               if (cmp(b,S) < 0) {
+                       k--;
+                       b = multadd(b, 10, 0);  /* we botched the k estimate */
+                       if (leftright)
+                               mhi = multadd(mhi, 10, 0);
+                       ilim = ilim1;
+                       }
+               }
+       if (ilim <= 0 && (mode == 3 || mode == 5)) {
+                S = multadd(S, 5, 0);
+               if (ilim < 0 || cmp(b, S) < 0 || ((cmp(b, S) == 0) && !bias_round_up)) {
+                       /* no digits, fcvt style */
+ no_digits:
+                       k = -1 - ndigits;
+                       goto ret;
+                       }
+ one_digit:
+               *s++ = '1';
+               k++;
+               goto ret;
+               }
+       if (leftright) {
+               if (m2 > 0)
+                       mhi = lshift(mhi, m2);
+
+               /* Compute mlo -- check for special case
+                * that d is a normalized power of 2.
+                */
+
+               mlo = mhi;
+               if (spec_case) {
+                       mhi = Balloc(mhi->k);
+                       Bcopy(mhi, mlo);
+                       mhi = lshift(mhi, Log2P);
+                       }
+
+               for(i = 1;;i++) {
+                       dig = quorem(b,S) + '0';
+                       /* Do we yet have the shortest decimal string
+                        * that will round to d?
+                        */
+                       j = cmp(b, mlo);
+                       delta = diff(S, mhi);
+                       j1 = delta->sign ? 1 : cmp(b, delta);
+                       Bfree(delta);
+#ifndef ROUND_BIASED
+                       if (j1 == 0 && mode != 1 && !(word1(d) & 1)
+#ifdef Honor_FLT_ROUNDS
+                               && rounding >= 1
+#endif
+                                                                  ) {
+                               if (dig == '9')
+                                       goto round_9_up;
+                               if (j > 0)
+                                       dig++;
+#ifdef SET_INEXACT
+                               else if (!b->x[0] && b->wds <= 1)
+                                       inexact = 0;
+#endif
+                               *s++ = dig;
+                               goto ret;
+                               }
+#endif
+                       if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+                                                       && !(word1(d) & 1)
+#endif
+                                       )) {
+                               if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+                                       inexact = 0;
+#endif
+                                       goto accept_dig;
+                                       }
+#ifdef Honor_FLT_ROUNDS
+                               if (mode > 1)
+                                switch(rounding) {
+                                 case 0: goto accept_dig;
+                                 case 2: goto keep_dig;
+                                 }
+#endif /*Honor_FLT_ROUNDS*/
+                               if (j1 > 0) {
+                                       b = lshift(b, 1);
+                                       j1 = cmp(b, S);
+                                       if ((j1 > 0 || (j1 == 0 && ((dig & 1) || bias_round_up)))
+                                            && dig++ == '9')
+                                               goto round_9_up;
+                                       }
+ accept_dig:
+                               *s++ = dig;
+                               goto ret;
+                               }
+                       if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+                               if (!rounding)
+                                       goto accept_dig;
+#endif
+                               if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+                                       *s++ = '9';
+                                       goto roundoff;
+                                       }
+                               *s++ = dig + 1;
+                               goto ret;
+                               }
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+                       *s++ = dig;
+                       if (i == ilim)
+                               break;
+                       b = multadd(b, 10, 0);
+                       if (mlo == mhi)
+                               mlo = mhi = multadd(mhi, 10, 0);
+                       else {
+                               mlo = multadd(mlo, 10, 0);
+                               mhi = multadd(mhi, 10, 0);
+                               }
+                       }
+               }
+       else
+               for(i = 1;; i++) {
+                       *s++ = dig = quorem(b,S) + '0';
+                       if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+                               inexact = 0;
+#endif
+                               goto ret;
+                               }
+                       if (i >= ilim)
+                               break;
+                       b = multadd(b, 10, 0);
+                       }
+
+       /* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+       switch(rounding) {
+         case 0: goto trimzeros;
+         case 2: goto roundoff;
+         }
+#endif
+       b = lshift(b, 1);
+       j = cmp(b, S);
+       if (j > 0 || (j == 0 && ((dig & 1) || bias_round_up))) {
+ roundoff:
+               while(*--s == '9')
+                       if (s == s0) {
+                               k++;
+                               *s++ = '1';
+                               goto ret;
+                               }
+               ++*s++;
+               }
+       else {
+/* trimzeros:  (never used) */
+               while(*--s == '0');
+               s++;
+               }
+ ret:
+       Bfree(S);
+       if (mhi) {
+               if (mlo && mlo != mhi)
+                       Bfree(mlo);
+               Bfree(mhi);
+               }
+ ret1:
+#ifdef SET_INEXACT
+       if (inexact) {
+               if (!oldinexact) {
+                       word0(d) = Exp_1 + (70 << Exp_shift);
+                       word1(d) = 0;
+                       dval(d) += 1.;
+                       }
+               }
+       else if (!oldinexact)
+               clear_inexact();
+#endif
+       Bfree(b);
+       *s = 0;
+       *decpt = k + 1;
+       if (rve)
+               *rve = s;
+       return s0;
+       }
+#ifdef __cplusplus
+}
+#endif
diff --git a/regexp2000/src/third_party/jscre/ASCIICType.h b/regexp2000/src/third_party/jscre/ASCIICType.h
new file mode 100644 (file)
index 0000000..40547d2
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  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. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 WTF_ASCIICType_h
+#define WTF_ASCIICType_h
+
+// The behavior of many of the functions in the <ctype.h> header is dependent
+// on the current locale. But in the WebKit project, all uses of those functions
+// are in code processing something that's not locale-specific. These equivalents
+// for some of the <ctype.h> functions are named more explicitly, not dependent
+// on the C library locale, and we should also optimize them as needed.
+
+// All functions return false or leave the character unchanged if passed a character
+// that is outside the range 0-7F. So they can be used on Unicode strings or
+// characters if the intent is to do processing only if the character is ASCII.
+
+    inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+    inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+    inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+
+    inline bool isASCIIAlphanumeric(char c) { return c >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+    inline bool isASCIIAlphanumeric(unsigned short c) { return c >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+    inline bool isASCIIAlphanumeric(int c) { return c >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+
+    inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); }
+    inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); }
+    inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); }
+
+    inline bool isASCIIHexDigit(char c) { return c >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'f'; }
+    inline bool isASCIIHexDigit(unsigned short c) { return c >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'f'; }
+    inline bool isASCIIHexDigit(int c) { return c >= '0' && c <= '9' || (c | 0x20) >= 'a' && (c | 0x20) <= 'f'; }
+
+    inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; }
+    inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; }
+    inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; }
+
+    inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; }
+    inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; }
+    inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; }
+
+    /*
+        Statistics from a run of Apple's page load test for callers of isASCIISpace:
+
+            character          count
+            ---------          -----
+            non-spaces         689383
+        20  space              294720
+        0A  \n                 89059
+        09  \t                 28320
+        0D  \r                 0
+        0C  \f                 0
+        0B  \v                 0
+    */
+    inline bool isASCIISpace(char c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
+    inline bool isASCIISpace(unsigned short c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
+    inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
+
+    inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
+    inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
+    inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
+
+    inline char toASCIIUpper(char c) { return static_cast<char>(c & ~((c >= 'a' && c <= 'z') << 5)); }
+    inline unsigned short toASCIIUpper(unsigned short c) { return static_cast<unsigned short>(c & ~((c >= 'a' && c <= 'z') << 5)); }
+    inline int toASCIIUpper(int c) { return static_cast<int>(c & ~((c >= 'a' && c <= 'z') << 5)); }
+
+    inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+
+#endif
diff --git a/regexp2000/src/third_party/jscre/AUTHORS b/regexp2000/src/third_party/jscre/AUTHORS
new file mode 100644 (file)
index 0000000..dbac2a5
--- /dev/null
@@ -0,0 +1,12 @@
+Originally written by:  Philip Hazel
+Email local part:       ph10
+Email domain:           cam.ac.uk
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+
+Adapted for JavaScriptCore and WebKit by Apple Inc.
+
+Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/regexp2000/src/third_party/jscre/COPYING b/regexp2000/src/third_party/jscre/COPYING
new file mode 100644 (file)
index 0000000..6ffdc24
--- /dev/null
@@ -0,0 +1,35 @@
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed.
+
+Copyright (c) 1997-2005 University of Cambridge. 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 the University of Cambridge nor the name of Apple
+      Inc. nor the names of their 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.
diff --git a/regexp2000/src/third_party/jscre/LICENSE b/regexp2000/src/third_party/jscre/LICENSE
new file mode 100644 (file)
index 0000000..020c45f
--- /dev/null
@@ -0,0 +1,85 @@
+-----------------------------------------------------------------------------
+The following license text is extracted from the header of the file
+ASCIICType.h and applies only to that file.
+-----------------------------------------------------------------------------
+
+Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1.  Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer. 
+2.  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. 
+3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+
+-----------------------------------------------------------------------------
+The following license text is from the file COPYING and applies to the other
+source files in this directory.
+-----------------------------------------------------------------------------
+
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed.
+
+Copyright (c) 1997-2005 University of Cambridge. 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 the University of Cambridge nor the name of Apple
+      Inc. nor the names of their 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.
+
+-----------------------------------------------------------------------------
+The following copyright lines are found in individual files other than
+ASCIICType.h
+-----------------------------------------------------------------------------
+
+
+Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
+Copyright (C) 2002, 2004, 2006, 2007, 2008 Apple Inc.  All rights reserved.
+Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+Copyright (c) 1997-2005 University of Cambridge
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+Copyright (c) 1997-2006 University of Cambridge
+Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/regexp2000/src/third_party/jscre/config.h b/regexp2000/src/third_party/jscre/config.h
new file mode 100644 (file)
index 0000000..05914ad
--- /dev/null
@@ -0,0 +1,143 @@
+
+/* On Unix-like systems config.in is converted by "configure" into config.h.
+Some other environments also support the use of "configure". PCRE is written in
+Standard C, but there are a few non-standard things it can cope with, allowing
+it to run on SunOS4 and other "close to standard" systems.
+
+On a non-Unix-like system you should just copy this file into config.h, and set
+up the macros the way you need them. You should normally change the definitions
+of HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way
+autoconf works, these cannot be made the defaults. If your system has bcopy()
+and not memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE.
+If your system has neither bcopy() nor memmove(), leave them both as 0; an
+emulation function will be used. */
+
+/* If you are compiling for a system that uses EBCDIC instead of ASCII
+character codes, define this macro as 1. On systems that can use "configure",
+this can be done via --enable-ebcdic. */
+
+#ifndef EBCDIC
+#define EBCDIC 0
+#endif
+
+/* If you are compiling for a system other than a Unix-like system or Win32,
+and it needs some magic to be inserted before the definition of a function that
+is exported by the library, define this macro to contain the relevant magic. If
+you do not define this macro, it defaults to "extern" for a C compiler and
+"extern C" for a C++ compiler on non-Win32 systems. This macro apears at the
+start of every exported function that is part of the external API. It does not
+appear on functions that are "external" in the C sense, but which are internal
+to the library. */
+
+/* #define PCRE_DATA_SCOPE */
+
+/* Define the following macro to empty if the "const" keyword does not work. */
+
+#undef const
+
+/* Define the following macro to "unsigned" if <stddef.h> does not define
+size_t. */
+
+#undef size_t
+
+/* The following two definitions are mainly for the benefit of SunOS4, which
+does not have the strerror() or memmove() functions that should be present in
+all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should
+normally be defined with the value 1 for other systems, but unfortunately we
+cannot make this the default because "configure" files generated by autoconf
+will only change 0 to 1; they won't change 1 to 0 if the functions are not
+found. */
+
+#define HAVE_STRERROR 1
+#define HAVE_MEMMOVE  1
+
+/* There are some non-Unix-like systems that don't even have bcopy(). If this
+macro is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of
+HAVE_BCOPY is not relevant. */
+
+#define HAVE_BCOPY    0
+
+/* The value of NEWLINE determines the newline character. The default is to
+leave it up to the compiler, but some sites want to force a particular value.
+On Unix-like systems, "configure" can be used to override this default. */
+
+#ifndef NEWLINE
+#define NEWLINE '\n'
+#endif
+
+/* The value of LINK_SIZE determines the number of bytes used to store links as
+offsets within the compiled regex. The default is 2, which allows for compiled
+patterns up to 64K long. This covers the vast majority of cases. However, PCRE
+can also be compiled to use 3 or 4 bytes instead. This allows for longer
+patterns in extreme cases. On systems that support it, "configure" can be used
+to override this default. */
+
+#ifndef LINK_SIZE
+#define LINK_SIZE   2
+#endif
+
+/* When calling PCRE via the POSIX interface, additional working storage is
+required for holding the pointers to capturing substrings because PCRE requires
+three integers per substring, whereas the POSIX interface provides only two. If
+the number of expected substrings is small, the wrapper function uses space on
+the stack, because this is faster than using malloc() for each call. The
+threshold above which the stack is no longer used is defined by POSIX_MALLOC_
+THRESHOLD. On systems that support it, "configure" can be used to override this
+default. */
+
+#ifndef POSIX_MALLOC_THRESHOLD
+#define POSIX_MALLOC_THRESHOLD 10
+#endif
+
+/* PCRE uses recursive function calls to handle backtracking while matching.
+This can sometimes be a problem on systems that have stacks of limited size.
+Define NO_RECURSE to get a version that doesn't use recursion in the match()
+function; instead it creates its own stack by steam using pcre_recurse_malloc()
+to obtain memory from the heap. For more detail, see the comments and other
+stuff just above the match() function. On systems that support it, "configure"
+can be used to set this in the Makefile (use --disable-stack-for-recursion). */
+
+/* #define NO_RECURSE */
+
+/* The value of MATCH_LIMIT determines the default number of times the internal
+match() function can be called during a single execution of pcre_exec(). There
+is a runtime interface for setting a different limit. The limit exists in order
+to catch runaway regular expressions that take for ever to determine that they
+do not match. The default is set very large so that it does not accidentally
+catch legitimate cases. On systems that support it, "configure" can be used to
+override this default default. */
+
+#ifndef MATCH_LIMIT
+#define MATCH_LIMIT 10000000
+#endif
+
+/* The above limit applies to all calls of match(), whether or not they
+increase the recursion depth. In some environments it is desirable to limit the
+depth of recursive calls of match() more strictly, in order to restrict the
+maximum amount of stack (or heap, if NO_RECURSE is defined) that is used. The
+value of MATCH_LIMIT_RECURSION applies only to recursive calls of match(). To
+have any useful effect, it must be less than the value of MATCH_LIMIT. There is
+a runtime method for setting a different limit. On systems that support it,
+"configure" can be used to override this default default. */
+
+#ifndef MATCH_LIMIT_RECURSION
+#define MATCH_LIMIT_RECURSION MATCH_LIMIT
+#endif
+
+/* These three limits are parameterized just in case anybody ever wants to
+change them. Care must be taken if they are increased, because they guard
+against integer overflow caused by enormously large patterns. */
+
+#ifndef MAX_NAME_SIZE
+#define MAX_NAME_SIZE 32
+#endif
+
+#ifndef MAX_NAME_COUNT
+#define MAX_NAME_COUNT 10000
+#endif
+
+#ifndef MAX_DUPLENGTH
+#define MAX_DUPLENGTH 30000
+#endif
+
+/* End */
diff --git a/regexp2000/src/third_party/jscre/pcre.h b/regexp2000/src/third_party/jscre/pcre.h
new file mode 100644 (file)
index 0000000..e11f2ed
--- /dev/null
@@ -0,0 +1,80 @@
+/* This is the public header file for JavaScriptCore's variant of the PCRE
+library. While this library started out as a copy of PCRE, many of the
+features of PCRE have been removed. This library now supports only the
+regular expression features required by the JavaScript language
+specification, and has only the functions needed by JavaScriptCore and the
+rest of WebKit.
+
+           Copyright (c) 1997-2005 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. 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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE.
+
+#ifndef JSRegExp_h
+#define JSRegExp_h
+
+#include "../../../include/v8.h"
+
+// JSCRE is very chatty in debug mode, so in order to keep it slient
+// while still importing v8.h correctly (it contains #ifdef DEBUGs)
+// we allow DEBUG to be set and undef it manually.
+#undef DEBUG
+
+typedef uint16_t UChar;
+
+struct JSRegExp;
+typedef struct JSRegExp JscreRegExp;
+
+enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase };
+enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline };
+
+/* jsRegExpExecute error codes */
+const int JSRegExpErrorNoMatch = -1;
+const int JSRegExpErrorHitLimit = -2;
+const int JSRegExpErrorNoMemory = -3;
+const int JSRegExpErrorInternal = -4;
+
+typedef void* malloc_t(size_t size);
+typedef void free_t(void* address);
+
+JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
+    JSRegExpIgnoreCaseOption, JSRegExpMultilineOption,
+    unsigned* numSubpatterns, const char** errorMessage,
+    malloc_t* allocate_function, free_t* free_function);
+
+int jsRegExpExecute(const JSRegExp*,
+    const UChar* subject, int subjectLength, int startOffset,
+    int* offsetsVector, int offsetsVectorLength);
+
+void jsRegExpFree(JSRegExp*);
+
+#endif
diff --git a/regexp2000/src/third_party/jscre/pcre_chartables.c b/regexp2000/src/third_party/jscre/pcre_chartables.c
new file mode 100644 (file)
index 0000000..c5fe2c5
--- /dev/null
@@ -0,0 +1,96 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* This file is automatically written by the dftables auxiliary 
+program. If you edit it by hand, you might like to edit the Makefile to 
+prevent its ever being regenerated.
+
+This file contains the default tables for characters with codes less than
+128 (ASCII characters). These tables are used when no external tables are
+passed to PCRE. */
+
+const unsigned char kjs_pcre_default_tables[480] = {
+
+/* This table is a lower casing table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table is a case flipping table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
+  0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 
+  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
+  0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table contains bit maps for various character classes.
+Each map is 32 bytes long and the bits run from the least
+significant end of each byte. The classes are: space, digit, word. */
+
+  0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* This table identifies various classes of character by individual bits:
+  0x01   white space character
+  0x08   hexadecimal digit
+  0x10   alphanumeric or '_'
+*/
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*   0-  7 */
+  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /*   8- 15 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  16- 23 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  24- 31 */
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*    - '  */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  ( - /  */
+  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,  /*  0 - 7  */
+  0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  8 - ?  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  @ - G  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  H - O  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  P - W  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,  /*  X - _  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  ` - g  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  h - o  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  p - w  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /*  x -127 */
+
+
+/* End of chartables.c */
diff --git a/regexp2000/src/third_party/jscre/pcre_compile.cpp b/regexp2000/src/third_party/jscre/pcre_compile.cpp
new file mode 100644 (file)
index 0000000..e0238f4
--- /dev/null
@@ -0,0 +1,2673 @@
+/* This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed. This library now supports only the regular expression features
+required by the JavaScript language specification, and has only the functions
+needed by JavaScriptCore and the rest of WebKit.
+
+                 Originally written by Philip Hazel
+           Copyright (c) 1997-2006 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
+    Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+
+-----------------------------------------------------------------------------
+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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains the external function jsRegExpExecute(), along with
+supporting internal functions that are not used by other modules. */
+
+#include "config.h"
+
+#include "pcre_internal.h"
+
+#include <string.h>
+#include "ASCIICType.h"
+
+/* Negative values for the firstchar and reqchar variables */
+
+#define REQ_UNSET (-2)
+#define REQ_NONE  (-1)
+
+/*************************************************
+*      Code parameters and static tables         *
+*************************************************/
+
+/* Maximum number of items on the nested bracket stacks at compile time. This
+applies to the nesting of all kinds of parentheses. It does not limit
+un-nested, non-capturing parentheses. This number can be made bigger if
+necessary - it is used to dimension one int and one unsigned char vector at
+compile time. */
+
+#define BRASTACK_SIZE 200
+
+/* Table for handling escaped characters in the range '0'-'z'. Positive returns
+are simple data values; negative values are for special things like \d and so
+on. Zero means further processing is needed (for things like \x), or the escape
+is invalid. */
+
+static const short escapes[] = {
+     0,      0,      0,      0,      0,      0,      0,      0,   /* 0 - 7 */
+     0,      0,    ':',    ';',    '<',    '=',    '>',    '?',   /* 8 - ? */
+   '@',      0, -ESC_B,      0, -ESC_D,      0,      0,      0,   /* @ - G */
+     0,      0,      0,      0,      0,      0,      0,      0,   /* H - O */
+     0,      0,      0, -ESC_S,      0,      0,      0, -ESC_W,   /* P - W */
+     0,      0,      0,    '[',   '\\',    ']',    '^',    '_',   /* X - _ */
+   '`',      7, -ESC_b,      0, -ESC_d,      0,   '\f',      0,   /* ` - g */
+     0,      0,      0,      0,      0,      0,   '\n',      0,   /* h - o */
+     0,      0,    '\r', -ESC_s,   '\t',      0,  '\v', -ESC_w,   /* p - w */
+     0,      0,      0                                            /* x - z */
+};
+
+/* Error code numbers. They are given names so that they can more easily be
+tracked. */
+
+enum ErrorCode {
+    ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9,
+    ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17
+};
+
+/* The texts of compile-time error messages. These are "char *" because they
+are passed to the outside world. */
+
+static const char* errorText(ErrorCode code)
+{
+    static const char errorTexts[] =
+      /* 1 */
+      "\\ at end of pattern\0"
+      "\\c at end of pattern\0"
+      "character value in \\x{...} sequence is too large\0"
+      "numbers out of order in {} quantifier\0"
+      /* 5 */
+      "number too big in {} quantifier\0"
+      "missing terminating ] for character class\0"
+      "internal error: code overflow\0"
+      "range out of order in character class\0"
+      "nothing to repeat\0"
+      /* 10 */
+      "unmatched parentheses\0"
+      "internal error: unexpected repeat\0"
+      "unrecognized character after (?\0"
+      "failed to get memory\0"
+      "missing )\0"
+      /* 15 */
+      "reference to non-existent subpattern\0"
+      "regular expression too large\0"
+      "parentheses nested too deeply"
+    ;
+
+    int i = code;
+    const char* text = errorTexts;
+    while (i > 1)
+        i -= !*text++;
+    return text;
+}
+
+/* Structure for passing "static" information around between the functions
+doing the compiling. */
+
+struct CompileData {
+    CompileData() {
+        top_backref = 0;
+        backrefMap = 0;
+        req_varyopt = 0;
+        needOuterBracket = false;
+        numCapturingBrackets = 0;
+    }
+    int top_backref;            /* Maximum back reference */
+    unsigned backrefMap;       /* Bitmap of low back refs */
+    int req_varyopt;            /* "After variable item" flag for reqbyte */
+    bool needOuterBracket;
+    int numCapturingBrackets;
+};
+
+/* Definitions to allow mutual recursion */
+
+static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&);
+static bool bracketIsAnchored(const unsigned char* code);
+static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap);
+static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert);
+
+/*************************************************
+*            Handle escapes                      *
+*************************************************/
+
+/* This function is called when a \ has been encountered. It either returns a
+positive value for a simple escape such as \n, or a negative value which
+encodes one of the more complicated things such as \d. When UTF-8 is enabled,
+a positive value greater than 255 may be returned. On entry, ptr is pointing at
+the \. On exit, it is on the final character of the escape sequence.
+
+Arguments:
+  ptrptr         points to the pattern position pointer
+  errorcodeptr   points to the errorcode variable
+  bracount       number of previous extracting brackets
+  options        the options bits
+  isclass        true if inside a character class
+
+Returns:         zero or positive => a data character
+                 negative => a special escape sequence
+                 on error, errorptr is set
+*/
+
+static int checkEscape(const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int bracount, bool isclass)
+{
+    const UChar* ptr = *ptrptr + 1;
+
+    /* If backslash is at the end of the pattern, it's an error. */
+    if (ptr == patternEnd) {
+        *errorcodeptr = ERR1;
+        *ptrptr = ptr;
+        return 0;
+    }
+    
+    int c = *ptr;
+    
+    /* Non-alphamerics are literals. For digits or letters, do an initial lookup in
+     a table. A non-zero result is something that can be returned immediately.
+     Otherwise further processing may be required. */
+    
+    if (c < '0' || c > 'z') { /* Not alphameric */
+    } else if (int escapeValue = escapes[c - '0']) {
+        c = escapeValue;
+        if (isclass) {
+            if (-c == ESC_b)
+                c = '\b'; /* \b is backslash in a class */
+            else if (-c == ESC_B)
+                c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */
+        }
+    /* Escapes that need further processing, or are illegal. */
+    
+    } else {
+        switch (c) {
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                /* Escape sequences starting with a non-zero digit are backreferences,
+                 unless there are insufficient brackets, in which case they are octal
+                 escape sequences. Those sequences end on the first non-octal character
+                 or when we overflow 0-255, whichever comes first. */
+                
+                if (!isclass) {
+                    const UChar* oldptr = ptr;
+                    c -= '0';
+                    while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount)
+                        c = c * 10 + *(++ptr) - '0';
+                    if (c <= bracount) {
+                        c = -(ESC_REF + c);
+                        break;
+                    }
+                    ptr = oldptr;      /* Put the pointer back and fall through */
+                }
+                
+                /* Handle an octal number following \. If the first digit is 8 or 9,
+                 this is not octal. */
+                
+                if ((c = *ptr) >= '8')
+                    break;
+
+            /* \0 always starts an octal number, but we may drop through to here with a
+             larger first octal digit. */
+
+            case '0': {
+                c -= '0';
+                int i;
+                for (i = 1; i <= 2; ++i) {
+                    if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7')
+                        break;
+                    int cc = c * 8 + ptr[i] - '0';
+                    if (cc > 255)
+                        break;
+                    c = cc;
+                }
+                ptr += i - 1;
+                break;
+            }
+
+            case 'x': {
+                c = 0;
+                int i;
+                for (i = 1; i <= 2; ++i) {
+                    if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) {
+                        c = 'x';
+                        i = 1;
+                        break;
+                    }
+                    int cc = ptr[i];
+                    if (cc >= 'a')
+                        cc -= 32;             /* Convert to upper case */
+                    c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10));
+                }
+                ptr += i - 1;
+                break;
+            }
+
+            case 'u': {
+                c = 0;
+                int i;
+                for (i = 1; i <= 4; ++i) {
+                    if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) {
+                        c = 'u';
+                        i = 1;
+                        break;
+                    }
+                    int cc = ptr[i];
+                    if (cc >= 'a')
+                        cc -= 32;             /* Convert to upper case */
+                    c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10));
+                }
+                ptr += i - 1;
+                break;
+            }
+
+            case 'c':
+                if (++ptr == patternEnd) {
+                    *errorcodeptr = ERR2;
+                    return 0;
+                }
+                c = *ptr;
+                
+                /* A letter is upper-cased; then the 0x40 bit is flipped. This coding
+                 is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */
+                c = toASCIIUpper(c) ^ 0x40;
+                break;
+            }
+    }
+    
+    *ptrptr = ptr;
+    return c;
+}
+
+/*************************************************
+*            Check for counted repeat            *
+*************************************************/
+
+/* This function is called when a '{' is encountered in a place where it might
+start a quantifier. It looks ahead to see if it really is a quantifier or not.
+It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
+where the ddds are digits.
+
+Arguments:
+  p         pointer to the first char after '{'
+
+Returns:    true or false
+*/
+
+static bool isCountedRepeat(const UChar* p, const UChar* patternEnd)
+{
+    if (p >= patternEnd || !isASCIIDigit(*p))
+        return false;
+    p++;
+    while (p < patternEnd && isASCIIDigit(*p))
+        p++;
+    if (p < patternEnd && *p == '}')
+        return true;
+    
+    if (p >= patternEnd || *p++ != ',')
+        return false;
+    if (p < patternEnd && *p == '}')
+        return true;
+    
+    if (p >= patternEnd || !isASCIIDigit(*p))
+        return false;
+    p++;
+    while (p < patternEnd && isASCIIDigit(*p))
+        p++;
+    
+    return (p < patternEnd && *p == '}');
+}
+
+/*************************************************
+*         Read repeat counts                     *
+*************************************************/
+
+/* Read an item of the form {n,m} and return the values. This is called only
+after isCountedRepeat() has confirmed that a repeat-count quantifier exists,
+so the syntax is guaranteed to be correct, but we need to check the values.
+
+Arguments:
+  p              pointer to first char after '{'
+  minp           pointer to int for min
+  maxp           pointer to int for max
+                 returned as -1 if no max
+  errorcodeptr   points to error code variable
+
+Returns:         pointer to '}' on success;
+                 current ptr on error, with errorcodeptr set non-zero
+*/
+
+static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorcodeptr)
+{
+    int min = 0;
+    int max = -1;
+    
+    /* Read the minimum value and do a paranoid check: a negative value indicates
+     an integer overflow. */
+    
+    while (isASCIIDigit(*p))
+        min = min * 10 + *p++ - '0';
+    if (min < 0 || min > 65535) {
+        *errorcodeptr = ERR5;
+        return p;
+    }
+    
+    /* Read the maximum value if there is one, and again do a paranoid on its size.
+     Also, max must not be less than min. */
+    
+    if (*p == '}')
+        max = min;
+    else {
+        if (*(++p) != '}') {
+            max = 0;
+            while (isASCIIDigit(*p))
+                max = max * 10 + *p++ - '0';
+            if (max < 0 || max > 65535) {
+                *errorcodeptr = ERR5;
+                return p;
+            }
+            if (max < min) {
+                *errorcodeptr = ERR4;
+                return p;
+            }
+        }
+    }
+    
+    /* Fill in the required variables, and pass back the pointer to the terminating
+     '}'. */
+    
+    *minp = min;
+    *maxp = max;
+    return p;
+}
+
+/*************************************************
+*      Find first significant op code            *
+*************************************************/
+
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring op code etc. It skips over things
+that do not influence this.
+
+Arguments:
+  code         pointer to the start of the group
+Returns:       pointer to the first significant opcode
+*/
+
+static const unsigned char* firstSignificantOpcode(const unsigned char* code)
+{
+    while (*code == OP_BRANUMBER)
+        code += 3;
+    return code;
+}
+
+static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code)
+{
+    while (true) {
+        switch (*code) {
+            case OP_ASSERT_NOT:
+                advanceToEndOfBracket(code);
+                code += 1 + LINK_SIZE;
+                break;
+            case OP_WORD_BOUNDARY:
+            case OP_NOT_WORD_BOUNDARY:
+                ++code;
+                break;
+            case OP_BRANUMBER:
+                code += 3;
+                break;
+            default:
+                return code;
+        }
+    }
+}
+
+/*************************************************
+*           Get othercase range                  *
+*************************************************/
+
+/* This function is passed the start and end of a class range, in UTF-8 mode
+with UCP support. It searches up the characters, looking for internal ranges of
+characters in the "other" case. Each call returns the next one, updating the
+start address.
+
+Arguments:
+  cptr        points to starting character value; updated
+  d           end value
+  ocptr       where to put start of othercase range
+  odptr       where to put end of othercase range
+
+Yield:        true when range returned; false when no more
+*/
+
+static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr)
+{
+    int c, othercase = 0;
+    
+    for (c = *cptr; c <= d; c++) {
+        if ((othercase = kjs_pcre_ucp_othercase(c)) >= 0)
+            break;
+    }
+    
+    if (c > d)
+        return false;
+    
+    *ocptr = othercase;
+    int next = othercase + 1;
+    
+    for (++c; c <= d; c++) {
+        if (kjs_pcre_ucp_othercase(c) != next)
+            break;
+        next++;
+    }
+    
+    *odptr = next - 1;
+    *cptr = c;
+    
+    return true;
+}
+
+/*************************************************
+ *       Convert character value to UTF-8         *
+ *************************************************/
+
+/* This function takes an integer value in the range 0 - 0x7fffffff
+ and encodes it as a UTF-8 character in 0 to 6 bytes.
+ Arguments:
+ cvalue     the character value
+ buffer     pointer to buffer for result - at least 6 bytes long
+ Returns:     number of characters placed in the buffer
+ */
+
+static int encodeUTF8(int cvalue, unsigned char *buffer)
+{
+    int i;
+    for (i = 0; i < kjs_pcre_utf8_table1_size; i++)
+        if (cvalue <= kjs_pcre_utf8_table1[i])
+            break;
+    buffer += i;
+    for (int j = i; j > 0; j--) {
+        *buffer-- = 0x80 | (cvalue & 0x3f);
+        cvalue >>= 6;
+    }
+    *buffer = kjs_pcre_utf8_table2[i] | cvalue;
+    return i + 1;
+}
+
+/*************************************************
+*           Compile one branch                   *
+*************************************************/
+
+/* Scan the pattern, compiling it into the code vector.
+
+Arguments:
+  options        the option bits
+  brackets       points to number of extracting brackets used
+  codeptr        points to the pointer to the current code point
+  ptrptr         points to the current pattern pointer
+  errorcodeptr   points to error code variable
+  firstbyteptr   set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)
+  reqbyteptr     set to the last literal character required, else < 0
+  cd             contains pointers to tables etc.
+
+Returns:         true on success
+                 false, with *errorcodeptr set non-zero on error
+*/
+
+static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected)
+{
+    return ((ptr + 1 < patternEnd) && ptr[1] == expected);
+}
+
+static bool
+compileBranch(int options, int* brackets, unsigned char** codeptr,
+               const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int *firstbyteptr,
+               int* reqbyteptr, CompileData& cd)
+{
+    int repeat_type, op_type;
+    int repeat_min = 0, repeat_max = 0;      /* To please picky compilers */
+    int bravalue = 0;
+    int reqvary, tempreqvary;
+    int c;
+    unsigned char* code = *codeptr;
+    unsigned char* tempcode;
+    bool groupsetfirstbyte = false;
+    const UChar* ptr = *ptrptr;
+    const UChar* tempptr;
+    unsigned char* previous = NULL;
+    unsigned char classbits[32];
+    
+    bool class_utf8;
+    unsigned char* class_utf8data;
+    unsigned char utf8_char[6];
+    
+    /* Initialize no first byte, no required byte. REQ_UNSET means "no char
+     matching encountered yet". It gets changed to REQ_NONE if we hit something that
+     matches a non-fixed char first char; reqbyte just remains unset if we never
+     find one.
+     
+     When we hit a repeat whose minimum is zero, we may have to adjust these values
+     to take the zero repeat into account. This is implemented by setting them to
+     zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual
+     item types that can be repeated set these backoff variables appropriately. */
+    
+    int firstbyte = REQ_UNSET;
+    int reqbyte = REQ_UNSET;
+    int zeroreqbyte = REQ_UNSET;
+    int zerofirstbyte = REQ_UNSET;
+    
+    /* The variable req_caseopt contains either the REQ_IGNORE_CASE value or zero,
+     according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit
+     value > 255. It is added into the firstbyte or reqbyte variables to record the
+     case status of the value. This is used only for ASCII characters. */
+    
+    int req_caseopt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0;
+    
+    /* Switch on next character until the end of the branch */
+    
+    for (;; ptr++) {
+        bool negate_class;
+        bool should_flip_negation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */
+        int class_charcount;
+        int class_lastchar;
+        int skipbytes;
+        int subreqbyte;
+        int subfirstbyte;
+        int mclength;
+        unsigned char mcbuffer[8];
+        
+        /* Next byte in the pattern */
+        
+        c = ptr < patternEnd ? *ptr : 0;
+        
+        /* Fill in length of a previous callout, except when the next thing is
+         a quantifier. */
+        
+        bool is_quantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd));
+        
+        switch (c) {
+            /* The branch terminates at end of string, |, or ). */
+                
+            case 0:
+                if (ptr < patternEnd)
+                    goto NORMAL_CHAR;
+                // End of string; fall through
+            case '|':
+            case ')':
+                *firstbyteptr = firstbyte;
+                *reqbyteptr = reqbyte;
+                *codeptr = code;
+                *ptrptr = ptr;
+                return true;
+                
+            /* Handle single-character metacharacters. In multiline mode, ^ disables
+             the setting of any following char as a first character. */
+
+            case '^':
+                if (options & MatchAcrossMultipleLinesOption) {
+                    if (firstbyte == REQ_UNSET)
+                        firstbyte = REQ_NONE;
+                    *code++ = OP_BOL;
+                } else
+                    *code++ = OP_CIRC;
+                previous = NULL;
+                break;
+
+            case '$':
+                previous = NULL;
+                if (options & MatchAcrossMultipleLinesOption)
+                  *code++ = OP_EOL;
+                else
+                  *code++ = OP_DOLL;
+                break;
+
+            /* There can never be a first char if '.' is first, whatever happens about
+             repeats. The value of reqbyte doesn't change either. */
+
+            case '.':
+                if (firstbyte == REQ_UNSET)
+                    firstbyte = REQ_NONE;
+                zerofirstbyte = firstbyte;
+                zeroreqbyte = reqbyte;
+                previous = code;
+                *code++ = OP_NOT_NEWLINE;
+                break;
+                
+            /* Character classes. If the included characters are all < 256, we build a
+             32-byte bitmap of the permitted characters, except in the special case
+             where there is only one such character. For negated classes, we build the
+             map as usual, then invert it at the end. However, we use a different opcode
+             so that data characters > 255 can be handled correctly.
+             
+             If the class contains characters outside the 0-255 range, a different
+             opcode is compiled. It may optionally have a bit map for characters < 256,
+             but those above are are explicitly listed afterwards. A flag byte tells
+             whether the bitmap is present, and whether this is a negated class or not.
+             */
+                
+            case '[': {
+                previous = code;
+                should_flip_negation = false;
+                
+                /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
+                 they are encountered at the top level, so we'll do that too. */
+                
+                /* If the first character is '^', set the negation flag and skip it. */
+
+                if (ptr + 1 >= patternEnd) {
+                    *errorcodeptr = ERR6;
+                    return false;
+                }
+
+                if (ptr[1] == '^') {
+                    negate_class = true;
+                    ++ptr;
+                } else
+                    negate_class = false;
+                
+                /* Keep a count of chars with values < 256 so that we can optimize the case
+                 of just a single character (as long as it's < 256). For higher valued UTF-8
+                 characters, we don't yet do any optimization. */
+                
+                class_charcount = 0;
+                class_lastchar = -1;
+                
+                class_utf8 = false;                       /* No chars >= 256 */
+                class_utf8data = code + LINK_SIZE + 34;   /* For UTF-8 items */
+                
+                /* Initialize the 32-char bit map to all zeros. We have to build the
+                 map in a temporary bit of store, in case the class contains only 1
+                 character (< 256), because in that case the compiled code doesn't use the
+                 bit map. */
+                
+                memset(classbits, 0, 32 * sizeof(unsigned char));
+                
+                /* Process characters until ] is reached. The first pass
+                 through the regex checked the overall syntax, so we don't need to be very
+                 strict here. At the start of the loop, c contains the first byte of the
+                 character. */
+
+                while ((++ptr < patternEnd) && (c = *ptr) != ']') {
+                    /* Backslash may introduce a single character, or it may introduce one
+                     of the specials, which just set a flag. Escaped items are checked for
+                     validity in the pre-compiling pass. The sequence \b is a special case.
+                     Inside a class (and only there) it is treated as backspace. Elsewhere
+                     it marks a word boundary. Other escapes have preset maps ready to
+                     or into the one we are building. We assume they have more than one
+                     character in them, so set class_charcount bigger than one. */
+                    
+                    if (c == '\\') {
+                        c = checkEscape(&ptr, patternEnd, errorcodeptr, cd.numCapturingBrackets, true);
+                        if (c < 0) {
+                            class_charcount += 2;     /* Greater than 1 is what matters */
+                            switch (-c) {
+                                case ESC_d:
+                                    for (c = 0; c < 32; c++)
+                                        classbits[c] |= classBitmapForChar(c + cbit_digit);
+                                    continue;
+                                    
+                                case ESC_D:
+                                    should_flip_negation = true;
+                                    for (c = 0; c < 32; c++)
+                                        classbits[c] |= ~classBitmapForChar(c + cbit_digit);
+                                    continue;
+                                    
+                                case ESC_w:
+                                    for (c = 0; c < 32; c++)
+                                        classbits[c] |= classBitmapForChar(c + cbit_word);
+                                    continue;
+                                    
+                                case ESC_W:
+                                    should_flip_negation = true;
+                                    for (c = 0; c < 32; c++)
+                                        classbits[c] |= ~classBitmapForChar(c + cbit_word);
+                                    continue;
+                                    
+                                case ESC_s:
+                                    for (c = 0; c < 32; c++)
+                                         classbits[c] |= classBitmapForChar(c + cbit_space);
+                                    continue;
+                                    
+                                case ESC_S:
+                                    should_flip_negation = true;
+                                    for (c = 0; c < 32; c++)
+                                         classbits[c] |= ~classBitmapForChar(c + cbit_space);
+                                    continue;
+                                    
+                                    /* Unrecognized escapes are faulted if PCRE is running in its
+                                     strict mode. By default, for compatibility with Perl, they are
+                                     treated as literals. */
+                                    
+                                default:
+                                    c = *ptr;              /* The final character */
+                                    class_charcount -= 2;  /* Undo the default count from above */
+                            }
+                        }
+                        
+                        /* Fall through if we have a single character (c >= 0). This may be
+                         > 256 in UTF-8 mode. */
+                        
+                    }   /* End of backslash handling */
+                    
+                    /* A single character may be followed by '-' to form a range. However,
+                     Perl does not permit ']' to be the end of the range. A '-' character
+                     here is treated as a literal. */
+                    
+                    if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') {
+                        ptr += 2;
+                        
+                        int d = *ptr;
+                        
+                        /* The second part of a range can be a single-character escape, but
+                         not any of the other escapes. Perl 5.6 treats a hyphen as a literal
+                         in such circumstances. */
+                        
+                        if (d == '\\') {
+                            const UChar* oldptr = ptr;
+                            d = checkEscape(&ptr, patternEnd, errorcodeptr, cd.numCapturingBrackets, true);
+                            
+                            /* \X is literal X; any other special means the '-' was literal */
+                            if (d < 0) {
+                                ptr = oldptr - 2;
+                                goto LONE_SINGLE_CHARACTER;  /* A few lines below */
+                            }
+                        }
+                        
+                        /* The check that the two values are in the correct order happens in
+                         the pre-pass. Optimize one-character ranges */
+                        
+                        if (d == c)
+                            goto LONE_SINGLE_CHARACTER;  /* A few lines below */
+                        
+                        /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless
+                         matching, we have to use an XCLASS with extra data items. Caseless
+                         matching for characters > 127 is available only if UCP support is
+                         available. */
+                        
+                        if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) {
+                            class_utf8 = true;
+                            
+                            /* With UCP support, we can find the other case equivalents of
+                             the relevant characters. There may be several ranges. Optimize how
+                             they fit with the basic range. */
+                            
+                            if (options & IgnoreCaseOption) {
+                                int occ, ocd;
+                                int cc = c;
+                                int origd = d;
+                                while (getOthercaseRange(&cc, origd, &occ, &ocd)) {
+                                    if (occ >= c && ocd <= d)
+                                        continue;  /* Skip embedded ranges */
+                                    
+                                    if (occ < c  && ocd >= c - 1)        /* Extend the basic range */
+                                    {                                  /* if there is overlap,   */
+                                        c = occ;                           /* noting that if occ < c */
+                                        continue;                          /* we can't have ocd > d  */
+                                    }                                  /* because a subrange is  */
+                                    if (ocd > d && occ <= d + 1)         /* always shorter than    */
+                                    {                                  /* the basic range.       */
+                                        d = ocd;
+                                        continue;
+                                    }
+                                    
+                                    if (occ == ocd)
+                                        *class_utf8data++ = XCL_SINGLE;
+                                    else {
+                                        *class_utf8data++ = XCL_RANGE;
+                                        class_utf8data += encodeUTF8(occ, class_utf8data);
+                                    }
+                                    class_utf8data += encodeUTF8(ocd, class_utf8data);
+                                }
+                            }
+                            
+                            /* Now record the original range, possibly modified for UCP caseless
+                             overlapping ranges. */
+                            
+                            *class_utf8data++ = XCL_RANGE;
+                            class_utf8data += encodeUTF8(c, class_utf8data);
+                            class_utf8data += encodeUTF8(d, class_utf8data);
+                            
+                            /* With UCP support, we are done. Without UCP support, there is no
+                             caseless matching for UTF-8 characters > 127; we can use the bit map
+                             for the smaller ones. */
+                            
+                            continue;    /* With next character in the class */
+                        }
+                        
+                        /* We use the bit map for all cases when not in UTF-8 mode; else
+                         ranges that lie entirely within 0-127 when there is UCP support; else
+                         for partial ranges without UCP support. */
+                        
+                        for (; c <= d; c++) {
+                            classbits[c/8] |= (1 << (c&7));
+                            if (options & IgnoreCaseOption) {
+                                int uc = flipCase(c);
+                                classbits[uc/8] |= (1 << (uc&7));
+                            }
+                            class_charcount++;                /* in case a one-char range */
+                            class_lastchar = c;
+                        }
+                        
+                        continue;   /* Go get the next char in the class */
+                    }
+                    
+                    /* Handle a lone single character - we can get here for a normal
+                     non-escape char, or after \ that introduces a single character or for an
+                     apparent range that isn't. */
+                    
+                LONE_SINGLE_CHARACTER:
+                    
+                    /* Handle a character that cannot go in the bit map */
+                    
+                    if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) {
+                        class_utf8 = true;
+                        *class_utf8data++ = XCL_SINGLE;
+                        class_utf8data += encodeUTF8(c, class_utf8data);
+                        
+                        if (options & IgnoreCaseOption) {
+                            int othercase;
+                            if ((othercase = kjs_pcre_ucp_othercase(c)) >= 0) {
+                                *class_utf8data++ = XCL_SINGLE;
+                                class_utf8data += encodeUTF8(othercase, class_utf8data);
+                            }
+                        }
+                    } else {
+                        /* Handle a single-byte character */
+                        classbits[c/8] |= (1 << (c&7));
+                        if (options & IgnoreCaseOption) {
+                            c = flipCase(c);
+                            classbits[c/8] |= (1 << (c&7));
+                        }
+                        class_charcount++;
+                        class_lastchar = c;
+                    }
+                }
+                
+                /* If class_charcount is 1, we saw precisely one character whose value is
+                 less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we
+                 can optimize the negative case only if there were no characters >= 128
+                 because OP_NOT and the related opcodes like OP_NOTSTAR operate on
+                 single-bytes only. This is an historical hangover. Maybe one day we can
+                 tidy these opcodes to handle multi-byte characters.
+                 
+                 The optimization throws away the bit map. We turn the item into a
+                 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note
+                 that OP_NOT does not support multibyte characters. In the positive case, it
+                 can cause firstbyte to be set. Otherwise, there can be no first char if
+                 this item is first, whatever repeat count may follow. In the case of
+                 reqbyte, save the previous value for reinstating. */
+                
+                if (class_charcount == 1 && (!class_utf8 && (!negate_class || class_lastchar < 128))) {
+                    zeroreqbyte = reqbyte;
+                    
+                    /* The OP_NOT opcode works on one-byte characters only. */
+                    
+                    if (negate_class) {
+                        if (firstbyte == REQ_UNSET)
+                            firstbyte = REQ_NONE;
+                        zerofirstbyte = firstbyte;
+                        *code++ = OP_NOT;
+                        *code++ = class_lastchar;
+                        break;
+                    }
+                    
+                    /* For a single, positive character, get the value into c, and
+                     then we can handle this with the normal one-character code. */
+                    
+                    c = class_lastchar;
+                    goto NORMAL_CHAR;
+                }       /* End of 1-char optimization */
+                
+                /* The general case - not the one-char optimization. If this is the first
+                 thing in the branch, there can be no first char setting, whatever the
+                 repeat count. Any reqbyte setting must remain unchanged after any kind of
+                 repeat. */
+                
+                if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+                zerofirstbyte = firstbyte;
+                zeroreqbyte = reqbyte;
+                
+                /* If there are characters with values > 255, we have to compile an
+                 extended class, with its own opcode. If there are no characters < 256,
+                 we can omit the bitmap. */
+                
+                if (class_utf8 && !should_flip_negation) {
+                    *class_utf8data++ = XCL_END;    /* Marks the end of extra data */
+                    *code++ = OP_XCLASS;
+                    code += LINK_SIZE;
+                    *code = negate_class? XCL_NOT : 0;
+                    
+                    /* If the map is required, install it, and move on to the end of
+                     the extra data */
+                    
+                    if (class_charcount > 0) {
+                        *code++ |= XCL_MAP;
+                        memcpy(code, classbits, 32);
+                        code = class_utf8data;
+                    }
+                    
+                    /* If the map is not required, slide down the extra data. */
+                    
+                    else {
+                        int len = class_utf8data - (code + 33);
+                        memmove(code + 1, code + 33, len);
+                        code += len + 1;
+                    }
+                    
+                    /* Now fill in the complete length of the item */
+                    
+                    putLinkValue(previous + 1, code - previous);
+                    break;   /* End of class handling */
+                }
+                
+                /* If there are no characters > 255, negate the 32-byte map if necessary,
+                 and copy it into the code vector. If this is the first thing in the branch,
+                 there can be no first char setting, whatever the repeat count. Any reqbyte
+                 setting must remain unchanged after any kind of repeat. */
+                
+                *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS;
+                if (negate_class)
+                    for (c = 0; c < 32; c++)
+                        code[c] = ~classbits[c];
+                else
+                    memcpy(code, classbits, 32);
+                code += 32;
+                break;
+            }
+                
+            /* Various kinds of repeat; '{' is not necessarily a quantifier, but this
+             has been tested above. */
+
+            case '{':
+                if (!is_quantifier)
+                    goto NORMAL_CHAR;
+                ptr = readRepeatCounts(ptr + 1, &repeat_min, &repeat_max, errorcodeptr);
+                if (*errorcodeptr)
+                    goto FAILED;
+                goto REPEAT;
+                
+            case '*':
+                repeat_min = 0;
+                repeat_max = -1;
+                goto REPEAT;
+                
+            case '+':
+                repeat_min = 1;
+                repeat_max = -1;
+                goto REPEAT;
+                
+            case '?':
+                repeat_min = 0;
+                repeat_max = 1;
+                
+            REPEAT:
+                if (!previous) {
+                    *errorcodeptr = ERR9;
+                    goto FAILED;
+                }
+                
+                if (repeat_min == 0) {
+                    firstbyte = zerofirstbyte;    /* Adjust for zero repeat */
+                    reqbyte = zeroreqbyte;        /* Ditto */
+                }
+                
+                /* Remember whether this is a variable length repeat */
+                
+                reqvary = (repeat_min == repeat_max) ? 0 : REQ_VARY;
+                
+                op_type = 0;                    /* Default single-char op codes */
+                
+                /* Save start of previous item, in case we have to move it up to make space
+                 for an inserted OP_ONCE for the additional '+' extension. */
+                /* FIXME: Probably don't need this because we don't use OP_ONCE. */
+                
+                tempcode = previous;
+                
+                /* If the next character is '+', we have a possessive quantifier. This
+                 implies greediness, whatever the setting of the PCRE_UNGREEDY option.
+                 If the next character is '?' this is a minimizing repeat, by default,
+                 but if PCRE_UNGREEDY is set, it works the other way round. We change the
+                 repeat type to the non-default. */
+                
+                if (safelyCheckNextChar(ptr, patternEnd, '?')) {
+                    repeat_type = 1;
+                    ptr++;
+                } else
+                    repeat_type = 0;
+                
+                /* If previous was a character match, abolish the item and generate a
+                 repeat item instead. If a char item has a minumum of more than one, ensure
+                 that it is set in reqbyte - it might not be if a sequence such as x{3} is
+                 the first thing in a branch because the x will have gone into firstbyte
+                 instead.  */
+                
+                if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) {
+                    /* Deal with UTF-8 characters that take up more than one byte. It's
+                     easier to write this out separately than try to macrify it. Use c to
+                     hold the length of the character in bytes, plus 0x80 to flag that it's a
+                     length rather than a small character. */
+                    
+                    if (code[-1] & 0x80) {
+                        unsigned char *lastchar = code - 1;
+                        while((*lastchar & 0xc0) == 0x80)
+                            lastchar--;
+                        c = code - lastchar;            /* Length of UTF-8 character */
+                        memcpy(utf8_char, lastchar, c); /* Save the char */
+                        c |= 0x80;                      /* Flag c as a length */
+                    }
+                    else {
+                        c = code[-1];
+                        if (repeat_min > 1)
+                            reqbyte = c | req_caseopt | cd.req_varyopt;
+                    }
+                    
+                    goto OUTPUT_SINGLE_REPEAT;   /* Code shared with single character types */
+                }
+                
+                else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) {
+                    c = previous[1];
+                    if (repeat_min > 1)
+                        reqbyte = c | req_caseopt | cd.req_varyopt;
+                    goto OUTPUT_SINGLE_REPEAT;
+                }
+                
+                /* If previous was a single negated character ([^a] or similar), we use
+                 one of the special opcodes, replacing it. The code is shared with single-
+                 character repeats by setting opt_type to add a suitable offset into
+                 repeat_type. OP_NOT is currently used only for single-byte chars. */
+                
+                else if (*previous == OP_NOT) {
+                    op_type = OP_NOTSTAR - OP_STAR;  /* Use "not" opcodes */
+                    c = previous[1];
+                    goto OUTPUT_SINGLE_REPEAT;
+                }
+                
+                /* If previous was a character type match (\d or similar), abolish it and
+                 create a suitable repeat item. The code is shared with single-character
+                 repeats by setting op_type to add a suitable offset into repeat_type. */
+                
+                else if (*previous <= OP_NOT_NEWLINE) {
+                    op_type = OP_TYPESTAR - OP_STAR;  /* Use type opcodes */
+                    c = *previous;
+                    
+                OUTPUT_SINGLE_REPEAT:
+                    int prop_type = -1;
+                    int prop_value = -1;
+                    
+                    unsigned char* oldcode = code;
+                    code = previous;                  /* Usually overwrite previous item */
+                    
+                    /* If the maximum is zero then the minimum must also be zero; Perl allows
+                     this case, so we do too - by simply omitting the item altogether. */
+                    
+                    if (repeat_max == 0)
+                        goto END_REPEAT;
+                    
+                    /* Combine the op_type with the repeat_type */
+                    
+                    repeat_type += op_type;
+                    
+                    /* A minimum of zero is handled either as the special case * or ?, or as
+                     an UPTO, with the maximum given. */
+                    
+                    if (repeat_min == 0) {
+                        if (repeat_max == -1)
+                            *code++ = OP_STAR + repeat_type;
+                        else if (repeat_max == 1)
+                            *code++ = OP_QUERY + repeat_type;
+                        else {
+                            *code++ = OP_UPTO + repeat_type;
+                            put2ByteValueAndAdvance(code, repeat_max);
+                        }
+                    }
+                    
+                    /* A repeat minimum of 1 is optimized into some special cases. If the
+                     maximum is unlimited, we use OP_PLUS. Otherwise, the original item it
+                     left in place and, if the maximum is greater than 1, we use OP_UPTO with
+                     one less than the maximum. */
+                    
+                    else if (repeat_min == 1) {
+                        if (repeat_max == -1)
+                            *code++ = OP_PLUS + repeat_type;
+                        else {
+                            code = oldcode;                 /* leave previous item in place */
+                            if (repeat_max == 1)
+                                goto END_REPEAT;
+                            *code++ = OP_UPTO + repeat_type;
+                            put2ByteValueAndAdvance(code, repeat_max - 1);
+                        }
+                    }
+                    
+                    /* The case {n,n} is just an EXACT, while the general case {n,m} is
+                     handled as an EXACT followed by an UPTO. */
+                    
+                    else {
+                        *code++ = OP_EXACT + op_type;  /* NB EXACT doesn't have repeat_type */
+                        put2ByteValueAndAdvance(code, repeat_min);
+                        
+                        /* If the maximum is unlimited, insert an OP_STAR. Before doing so,
+                         we have to insert the character for the previous code. For a repeated
+                         Unicode property match, there are two extra bytes that define the
+                         required property. In UTF-8 mode, long characters have their length in
+                         c, with the 0x80 bit as a flag. */
+                        
+                        if (repeat_max < 0) {
+                            if (c >= 128) {
+                                memcpy(code, utf8_char, c & 7);
+                                code += c & 7;
+                            } else {
+                                *code++ = c;
+                                if (prop_type >= 0) {
+                                    *code++ = prop_type;
+                                    *code++ = prop_value;
+                                }
+                            }
+                            *code++ = OP_STAR + repeat_type;
+                        }
+                        
+                        /* Else insert an UPTO if the max is greater than the min, again
+                         preceded by the character, for the previously inserted code. */
+                        
+                        else if (repeat_max != repeat_min) {
+                            if (c >= 128) {
+                                memcpy(code, utf8_char, c & 7);
+                                code += c & 7;
+                            } else
+                                *code++ = c;
+                            if (prop_type >= 0) {
+                                *code++ = prop_type;
+                                *code++ = prop_value;
+                            }
+                            repeat_max -= repeat_min;
+                            *code++ = OP_UPTO + repeat_type;
+                            put2ByteValueAndAdvance(code, repeat_max);
+                        }
+                    }
+                    
+                    /* The character or character type itself comes last in all cases. */
+                    
+                    if (c >= 128) {
+                        memcpy(code, utf8_char, c & 7);
+                        code += c & 7;
+                    } else
+                        *code++ = c;
+                    
+                    /* For a repeated Unicode property match, there are two extra bytes that
+                     define the required property. */
+                    
+                    if (prop_type >= 0) {
+                        *code++ = prop_type;
+                        *code++ = prop_value;
+                    }
+                }
+                
+                /* If previous was a character class or a back reference, we put the repeat
+                 stuff after it, but just skip the item if the repeat was {0,0}. */
+                
+                else if (*previous == OP_CLASS ||
+                         *previous == OP_NCLASS ||
+                         *previous == OP_XCLASS ||
+                         *previous == OP_REF)
+                {
+                    if (repeat_max == 0) {
+                        code = previous;
+                        goto END_REPEAT;
+                    }
+                    
+                    if (repeat_min == 0 && repeat_max == -1)
+                        *code++ = OP_CRSTAR + repeat_type;
+                    else if (repeat_min == 1 && repeat_max == -1)
+                        *code++ = OP_CRPLUS + repeat_type;
+                    else if (repeat_min == 0 && repeat_max == 1)
+                        *code++ = OP_CRQUERY + repeat_type;
+                    else {
+                        *code++ = OP_CRRANGE + repeat_type;
+                        put2ByteValueAndAdvance(code, repeat_min);
+                        if (repeat_max == -1)
+                            repeat_max = 0;  /* 2-byte encoding for max */
+                        put2ByteValueAndAdvance(code, repeat_max);
+                    }
+                }
+                
+                /* If previous was a bracket group, we may have to replicate it in certain
+                 cases. */
+                
+                else if (*previous >= OP_BRA) {
+                    int ketoffset = 0;
+                    int len = code - previous;
+                    unsigned char* bralink = NULL;
+                    
+                    /* If the maximum repeat count is unlimited, find the end of the bracket
+                     by scanning through from the start, and compute the offset back to it
+                     from the current code pointer. There may be an OP_OPT setting following
+                     the final KET, so we can't find the end just by going back from the code
+                     pointer. */
+                    
+                    if (repeat_max == -1) {
+                        const unsigned char* ket = previous;
+                        advanceToEndOfBracket(ket);
+                        ketoffset = code - ket;
+                    }
+                    
+                    /* The case of a zero minimum is special because of the need to stick
+                     OP_BRAZERO in front of it, and because the group appears once in the
+                     data, whereas in other cases it appears the minimum number of times. For
+                     this reason, it is simplest to treat this case separately, as otherwise
+                     the code gets far too messy. There are several special subcases when the
+                     minimum is zero. */
+                    
+                    if (repeat_min == 0) {
+                        /* If the maximum is also zero, we just omit the group from the output
+                         altogether. */
+                        
+                        if (repeat_max == 0) {
+                            code = previous;
+                            goto END_REPEAT;
+                        }
+                        
+                        /* If the maximum is 1 or unlimited, we just have to stick in the
+                         BRAZERO and do no more at this point. However, we do need to adjust
+                         any OP_RECURSE calls inside the group that refer to the group itself or
+                         any internal group, because the offset is from the start of the whole
+                         regex. Temporarily terminate the pattern while doing this. */
+                        
+                        if (repeat_max <= 1) {
+                            *code = OP_END;
+                            memmove(previous+1, previous, len);
+                            code++;
+                            *previous++ = OP_BRAZERO + repeat_type;
+                        }
+                        
+                        /* If the maximum is greater than 1 and limited, we have to replicate
+                         in a nested fashion, sticking OP_BRAZERO before each set of brackets.
+                         The first one has to be handled carefully because it's the original
+                         copy, which has to be moved up. The remainder can be handled by code
+                         that is common with the non-zero minimum case below. We have to
+                         adjust the value of repeat_max, since one less copy is required. */
+                        
+                        else {
+                            *code = OP_END;
+                            memmove(previous + 2 + LINK_SIZE, previous, len);
+                            code += 2 + LINK_SIZE;
+                            *previous++ = OP_BRAZERO + repeat_type;
+                            *previous++ = OP_BRA;
+                            
+                            /* We chain together the bracket offset fields that have to be
+                             filled in later when the ends of the brackets are reached. */
+                            
+                            int offset = (!bralink) ? 0 : previous - bralink;
+                            bralink = previous;
+                            putLinkValueAllowZeroAndAdvance(previous, offset);
+                        }
+                        
+                        repeat_max--;
+                    }
+                    
+                    /* If the minimum is greater than zero, replicate the group as many
+                     times as necessary, and adjust the maximum to the number of subsequent
+                     copies that we need. If we set a first char from the group, and didn't
+                     set a required char, copy the latter from the former. */
+                    
+                    else {
+                        if (repeat_min > 1) {
+                            if (groupsetfirstbyte && reqbyte < 0)
+                                reqbyte = firstbyte;
+                            for (int i = 1; i < repeat_min; i++) {
+                                memcpy(code, previous, len);
+                                code += len;
+                            }
+                        }
+                        if (repeat_max > 0)
+                            repeat_max -= repeat_min;
+                    }
+                    
+                    /* This code is common to both the zero and non-zero minimum cases. If
+                     the maximum is limited, it replicates the group in a nested fashion,
+                     remembering the bracket starts on a stack. In the case of a zero minimum,
+                     the first one was set up above. In all cases the repeat_max now specifies
+                     the number of additional copies needed. */
+                    
+                    if (repeat_max >= 0) {
+                        for (int i = repeat_max - 1; i >= 0; i--) {
+                            *code++ = OP_BRAZERO + repeat_type;
+                            
+                            /* All but the final copy start a new nesting, maintaining the
+                             chain of brackets outstanding. */
+                            
+                            if (i != 0) {
+                                *code++ = OP_BRA;
+                                int offset = (!bralink) ? 0 : code - bralink;
+                                bralink = code;
+                                putLinkValueAllowZeroAndAdvance(code, offset);
+                            }
+                            
+                            memcpy(code, previous, len);
+                            code += len;
+                        }
+                        
+                        /* Now chain through the pending brackets, and fill in their length
+                         fields (which are holding the chain links pro tem). */
+                        
+                        while (bralink) {
+                            int offset = code - bralink + 1;
+                            unsigned char* bra = code - offset;
+                            int oldlinkoffset = getLinkValueAllowZero(bra + 1);
+                            bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset;
+                            *code++ = OP_KET;
+                            putLinkValueAndAdvance(code, offset);
+                            putLinkValue(bra + 1, offset);
+                        }
+                    }
+                    
+                    /* If the maximum is unlimited, set a repeater in the final copy. We
+                     can't just offset backwards from the current code point, because we
+                     don't know if there's been an options resetting after the ket. The
+                     correct offset was computed above. */
+                    
+                    else
+                        code[-ketoffset] = OP_KETRMAX + repeat_type;
+                }
+                
+                /* Else there's some kind of shambles */
+                
+                else {
+                    *errorcodeptr = ERR11;
+                    goto FAILED;
+                }
+                
+                /* In all case we no longer have a previous item. We also set the
+                 "follows varying string" flag for subsequently encountered reqbytes if
+                 it isn't already set and we have just passed a varying length item. */
+                
+            END_REPEAT:
+                previous = NULL;
+                cd.req_varyopt |= reqvary;
+                break;
+                
+            /* Start of nested bracket sub-expression, or comment or lookahead or
+             lookbehind or option setting or condition. First deal with special things
+             that can come after a bracket; all are introduced by ?, and the appearance
+             of any of them means that this is not a referencing group. They were
+             checked for validity in the first pass over the string, so we don't have to
+             check for syntax errors here.  */
+                
+            case '(':
+                skipbytes = 0;
+                
+                if (*(++ptr) == '?') {
+                    switch (*(++ptr)) {
+                        case ':':                 /* Non-extracting bracket */
+                            bravalue = OP_BRA;
+                            ptr++;
+                            break;
+                            
+                        case '=':                 /* Positive lookahead */
+                            bravalue = OP_ASSERT;
+                            ptr++;
+                            break;
+                            
+                        case '!':                 /* Negative lookahead */
+                            bravalue = OP_ASSERT_NOT;
+                            ptr++;
+                            break;
+                            
+                        /* Character after (? not specially recognized */
+                            
+                        default:
+                            *errorcodeptr = ERR12;
+                            goto FAILED;
+                        }
+                }
+                
+                /* Else we have a referencing group; adjust the opcode. If the bracket
+                 number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and
+                 arrange for the true number to follow later, in an OP_BRANUMBER item. */
+                
+                else {
+                    if (++(*brackets) > EXTRACT_BASIC_MAX) {
+                        bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1;
+                        code[1 + LINK_SIZE] = OP_BRANUMBER;
+                        put2ByteValue(code + 2 + LINK_SIZE, *brackets);
+                        skipbytes = 3;
+                    }
+                    else
+                        bravalue = OP_BRA + *brackets;
+                }
+                
+                /* Process nested bracketed re. Assertions may not be repeated, but other
+                 kinds can be. We copy code into a non-variable in order to be able
+                 to pass its address because some compilers complain otherwise. Pass in a
+                 new setting for the ims options if they have changed. */
+                
+                previous = (bravalue >= OP_BRAZERO) ? code : 0;
+                *code = bravalue;
+                tempcode = code;
+                tempreqvary = cd.req_varyopt;     /* Save value before bracket */
+                
+                if (!compileBracket(
+                                   options,
+                                   brackets,                     /* Extracting bracket count */
+                                   &tempcode,                    /* Where to put code (updated) */
+                                   &ptr,                         /* Input pointer (updated) */
+                                   patternEnd,
+                                   errorcodeptr,                 /* Where to put an error message */
+                                   skipbytes,                    /* Skip over OP_BRANUMBER */
+                                   &subfirstbyte,                /* For possible first char */
+                                   &subreqbyte,                  /* For possible last char */
+                                   cd))                          /* Tables block */
+                    goto FAILED;
+                
+                /* At the end of compiling, code is still pointing to the start of the
+                 group, while tempcode has been updated to point past the end of the group
+                 and any option resetting that may follow it. The pattern pointer (ptr)
+                 is on the bracket. */
+                
+                /* Handle updating of the required and first characters. Update for normal
+                 brackets of all kinds, and conditions with two branches (see code above).
+                 If the bracket is followed by a quantifier with zero repeat, we have to
+                 back off. Hence the definition of zeroreqbyte and zerofirstbyte outside the
+                 main loop so that they can be accessed for the back off. */
+                
+                zeroreqbyte = reqbyte;
+                zerofirstbyte = firstbyte;
+                groupsetfirstbyte = false;
+                
+                if (bravalue >= OP_BRA) {
+                    /* If we have not yet set a firstbyte in this branch, take it from the
+                     subpattern, remembering that it was set here so that a repeat of more
+                     than one can replicate it as reqbyte if necessary. If the subpattern has
+                     no firstbyte, set "none" for the whole branch. In both cases, a zero
+                     repeat forces firstbyte to "none". */
+                    
+                    if (firstbyte == REQ_UNSET) {
+                        if (subfirstbyte >= 0) {
+                            firstbyte = subfirstbyte;
+                            groupsetfirstbyte = true;
+                        }
+                        else
+                            firstbyte = REQ_NONE;
+                        zerofirstbyte = REQ_NONE;
+                    }
+                    
+                    /* If firstbyte was previously set, convert the subpattern's firstbyte
+                     into reqbyte if there wasn't one, using the vary flag that was in
+                     existence beforehand. */
+                    
+                    else if (subfirstbyte >= 0 && subreqbyte < 0)
+                        subreqbyte = subfirstbyte | tempreqvary;
+                    
+                    /* If the subpattern set a required byte (or set a first byte that isn't
+                     really the first byte - see above), set it. */
+                    
+                    if (subreqbyte >= 0)
+                        reqbyte = subreqbyte;
+                }
+                
+                /* For a forward assertion, we take the reqbyte, if set. This can be
+                 helpful if the pattern that follows the assertion doesn't set a different
+                 char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte
+                 for an assertion, however because it leads to incorrect effect for patterns
+                 such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead
+                 of a firstbyte. This is overcome by a scan at the end if there's no
+                 firstbyte, looking for an asserted first char. */
+                
+                else if (bravalue == OP_ASSERT && subreqbyte >= 0)
+                    reqbyte = subreqbyte;
+                
+                /* Now update the main code pointer to the end of the group. */
+                
+                code = tempcode;
+                
+                /* Error if hit end of pattern */
+                
+                if (ptr >= patternEnd || *ptr != ')') {
+                    *errorcodeptr = ERR14;
+                    goto FAILED;
+                }
+                break;
+                
+            /* Check \ for being a real metacharacter; if not, fall through and handle
+             it as a data character at the start of a string. Escape items are checked
+             for validity in the pre-compiling pass. */
+                
+            case '\\':
+                tempptr = ptr;
+                c = checkEscape(&ptr, patternEnd, errorcodeptr, cd.numCapturingBrackets, false);
+                
+                /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
+                 are arranged to be the negation of the corresponding OP_values. For the
+                 back references, the values are ESC_REF plus the reference number. Only
+                 back references and those types that consume a character may be repeated.
+                 We can test for values between ESC_b and ESC_w for the latter; this may
+                 have to change if any new ones are ever created. */
+                
+                if (c < 0) {
+                    /* For metasequences that actually match a character, we disable the
+                     setting of a first character if it hasn't already been set. */
+                    
+                    if (firstbyte == REQ_UNSET && -c > ESC_b && -c <= ESC_w)
+                        firstbyte = REQ_NONE;
+                    
+                    /* Set values to reset to if this is followed by a zero repeat. */
+                    
+                    zerofirstbyte = firstbyte;
+                    zeroreqbyte = reqbyte;
+                    
+                    /* Back references are handled specially */
+                    
+                    if (-c >= ESC_REF) {
+                        int number = -c - ESC_REF;
+                        previous = code;
+                        *code++ = OP_REF;
+                        put2ByteValueAndAdvance(code, number);
+                    }
+                    
+                    /* For the rest, we can obtain the OP value by negating the escape
+                     value */
+                    
+                    else {
+                        previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL;
+                        *code++ = -c;
+                    }
+                    continue;
+                }
+                
+                /* Fall through. */
+                
+                /* Handle a literal character. It is guaranteed not to be whitespace or #
+                 when the extended flag is set. If we are in UTF-8 mode, it may be a
+                 multi-byte literal character. */
+                
+                default:
+            NORMAL_CHAR:
+                
+                previous = code;
+                
+                if (c < 128) {
+                    mclength = 1;
+                    mcbuffer[0] = c;
+                    
+                    if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') {
+                        *code++ = OP_ASCII_LETTER_IGNORING_CASE;
+                        *code++ = c | 0x20;
+                    } else {
+                        *code++ = OP_ASCII_CHAR;
+                        *code++ = c;
+                    }
+                } else {
+                    mclength = encodeUTF8(c, mcbuffer);
+                    
+                    *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR;
+                    for (c = 0; c < mclength; c++)
+                        *code++ = mcbuffer[c];
+                }
+                
+                /* Set the first and required bytes appropriately. If no previous first
+                 byte, set it from this character, but revert to none on a zero repeat.
+                 Otherwise, leave the firstbyte value alone, and don't change it on a zero
+                 repeat. */
+                
+                if (firstbyte == REQ_UNSET) {
+                    zerofirstbyte = REQ_NONE;
+                    zeroreqbyte = reqbyte;
+                    
+                    /* If the character is more than one byte long, we can set firstbyte
+                     only if it is not to be matched caselessly. */
+                    
+                    if (mclength == 1 || req_caseopt == 0) {
+                        firstbyte = mcbuffer[0] | req_caseopt;
+                        if (mclength != 1)
+                            reqbyte = code[-1] | cd.req_varyopt;
+                    }
+                    else
+                        firstbyte = reqbyte = REQ_NONE;
+                }
+                
+                /* firstbyte was previously set; we can set reqbyte only the length is
+                 1 or the matching is caseful. */
+                
+                else {
+                    zerofirstbyte = firstbyte;
+                    zeroreqbyte = reqbyte;
+                    if (mclength == 1 || req_caseopt == 0)
+                        reqbyte = code[-1] | req_caseopt | cd.req_varyopt;
+                }
+                
+                break;            /* End of literal character handling */
+        }
+    }                   /* end of big loop */
+    
+    /* Control never reaches here by falling through, only by a goto for all the
+     error states. Pass back the position in the pattern so that it can be displayed
+     to the user for diagnosing the error. */
+    
+FAILED:
+    *ptrptr = ptr;
+    return false;
+}
+
+/*************************************************
+*     Compile sequence of alternatives           *
+*************************************************/
+
+/* On entry, ptr is pointing past the bracket character, but on return
+it points to the closing bracket, or vertical bar, or end of string.
+The code variable is pointing at the byte into which the BRA operator has been
+stored. If the ims options are changed at the start (for a (?ims: group) or
+during any branch, we need to insert an OP_OPT item at the start of every
+following branch to ensure they get set correctly at run time, and also pass
+the new options into every subsequent branch compile.
+
+Argument:
+  options        option bits, including any changes for this subpattern
+  brackets       -> int containing the number of extracting brackets used
+  codeptr        -> the address of the current code pointer
+  ptrptr         -> the address of the current pattern pointer
+  errorcodeptr   -> pointer to error code variable
+  skipbytes      skip this many bytes at start (for OP_BRANUMBER)
+  firstbyteptr   place to put the first required character, or a negative number
+  reqbyteptr     place to put the last required character, or a negative number
+  cd             points to the data block with tables pointers etc.
+
+Returns:      true on success
+*/
+
+static bool
+compileBracket(int options, int* brackets, unsigned char** codeptr,
+    const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int skipbytes,
+    int* firstbyteptr, int* reqbyteptr, CompileData& cd)
+{
+    const UChar* ptr = *ptrptr;
+    unsigned char* code = *codeptr;
+    unsigned char* last_branch = code;
+    unsigned char* start_bracket = code;
+    int firstbyte = REQ_UNSET;
+    int reqbyte = REQ_UNSET;
+    
+    /* Offset is set zero to mark that this bracket is still open */
+    
+    putLinkValueAllowZero(code + 1, 0);
+    code += 1 + LINK_SIZE + skipbytes;
+    
+    /* Loop for each alternative branch */
+    
+    while (true) {
+        /* Now compile the branch */
+        
+        int branchfirstbyte;
+        int branchreqbyte;
+        if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorcodeptr,
+                            &branchfirstbyte, &branchreqbyte, cd)) {
+            *ptrptr = ptr;
+            return false;
+        }
+        
+        /* If this is the first branch, the firstbyte and reqbyte values for the
+         branch become the values for the regex. */
+        
+        if (*last_branch != OP_ALT) {
+            firstbyte = branchfirstbyte;
+            reqbyte = branchreqbyte;
+        }
+        
+        /* If this is not the first branch, the first char and reqbyte have to
+         match the values from all the previous branches, except that if the previous
+         value for reqbyte didn't have REQ_VARY set, it can still match, and we set
+         REQ_VARY for the regex. */
+        
+        else {
+            /* If we previously had a firstbyte, but it doesn't match the new branch,
+             we have to abandon the firstbyte for the regex, but if there was previously
+             no reqbyte, it takes on the value of the old firstbyte. */
+            
+            if (firstbyte >= 0 && firstbyte != branchfirstbyte) {
+                if (reqbyte < 0)
+                    reqbyte = firstbyte;
+                firstbyte = REQ_NONE;
+            }
+            
+            /* If we (now or from before) have no firstbyte, a firstbyte from the
+             branch becomes a reqbyte if there isn't a branch reqbyte. */
+            
+            if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0)
+                branchreqbyte = branchfirstbyte;
+            
+            /* Now ensure that the reqbytes match */
+            
+            if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY))
+                reqbyte = REQ_NONE;
+            else
+                reqbyte |= branchreqbyte;   /* To "or" REQ_VARY */
+        }
+        
+        /* Reached end of expression, either ')' or end of pattern. Go back through
+         the alternative branches and reverse the chain of offsets, with the field in
+         the BRA item now becoming an offset to the first alternative. If there are
+         no alternatives, it points to the end of the group. The length in the
+         terminating ket is always the length of the whole bracketed item. If any of
+         the ims options were changed inside the group, compile a resetting op-code
+         following, except at the very end of the pattern. Return leaving the pointer
+         at the terminating char. */
+        
+        if (ptr >= patternEnd || *ptr != '|') {
+            int length = code - last_branch;
+            do {
+                int prev_length = getLinkValueAllowZero(last_branch + 1);
+                putLinkValue(last_branch + 1, length);
+                length = prev_length;
+                last_branch -= length;
+            } while (length > 0);
+            
+            /* Fill in the ket */
+            
+            *code = OP_KET;
+            putLinkValue(code + 1, code - start_bracket);
+            code += 1 + LINK_SIZE;
+            
+            /* Set values to pass back */
+            
+            *codeptr = code;
+            *ptrptr = ptr;
+            *firstbyteptr = firstbyte;
+            *reqbyteptr = reqbyte;
+            return true;
+        }
+        
+        /* Another branch follows; insert an "or" node. Its length field points back
+         to the previous branch while the bracket remains open. At the end the chain
+         is reversed. It's done like this so that the start of the bracket has a
+         zero offset until it is closed, making it possible to detect recursion. */
+        
+        *code = OP_ALT;
+        putLinkValue(code + 1, code - last_branch);
+        last_branch = code;
+        code += 1 + LINK_SIZE;
+        ptr++;
+    }
+    ASSERT_NOT_REACHED();
+}
+
+/*************************************************
+*          Check for anchored expression         *
+*************************************************/
+
+/* Try to find out if this is an anchored regular expression. Consider each
+alternative branch. If they all start OP_CIRC, or with a bracket
+all of whose alternatives start OP_CIRC (recurse ad lib), then
+it's anchored.
+
+Arguments:
+  code          points to start of expression (the bracket)
+  captureMap    a bitmap of which brackets we are inside while testing; this
+                 handles up to substring 31; all brackets after that share
+                 the zero bit
+  backrefMap    the back reference bitmap
+*/
+
+static bool branchIsAnchored(const unsigned char* code)
+{
+    const unsigned char* scode = firstSignificantOpcode(code);
+    int op = *scode;
+
+    /* Brackets */
+    if (op >= OP_BRA || op == OP_ASSERT)
+        return bracketIsAnchored(scode);
+
+    /* Check for explicit anchoring */    
+    return op == OP_CIRC;
+}
+
+static bool bracketIsAnchored(const unsigned char* code)
+{
+    do {
+        if (!branchIsAnchored(code + 1 + LINK_SIZE))
+            return false;
+        code += getLinkValue(code + 1);
+    } while (*code == OP_ALT);   /* Loop for each alternative */
+    return true;
+}
+
+/*************************************************
+*         Check for starting with ^ or .*        *
+*************************************************/
+
+/* This is called to find out if every branch starts with ^ or .* so that
+"first char" processing can be done to speed things up in multiline
+matching and for non-DOTALL patterns that start with .* (which must start at
+the beginning or after \n)
+
+Except when the .* appears inside capturing parentheses, and there is a
+subsequent back reference to those parentheses. By keeping a bitmap of the
+first 31 back references, we can catch some of the more common cases more
+precisely; all the greater back references share a single bit.
+
+Arguments:
+  code          points to start of expression (the bracket)
+  captureMap    a bitmap of which brackets we are inside while testing; this
+                 handles up to substring 31; all brackets after that share
+                 the zero bit
+  backrefMap    the back reference bitmap
+*/
+
+static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap)
+{
+    const unsigned char* scode = firstSignificantOpcode(code);
+    int op = *scode;
+    
+    /* Capturing brackets */
+    if (op > OP_BRA) {
+        int captureNum = op - OP_BRA;
+        if (captureNum > EXTRACT_BASIC_MAX)
+            captureNum = get2ByteValue(scode + 2 + LINK_SIZE);
+        int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1;
+        return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap);
+    }
+    
+    /* Other brackets */
+    if (op == OP_BRA || op == OP_ASSERT)
+        return bracketNeedsLineStart(scode, captureMap, backrefMap);
+    
+    /* .* means "start at start or after \n" if it isn't in brackets that
+     may be referenced. */
+    
+    if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
+        return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap);
+
+    /* Explicit ^ */
+    return op == OP_CIRC || op == OP_BOL;
+}
+
+static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap)
+{
+    do {
+        if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap))
+            return false;
+        code += getLinkValue(code + 1);
+    } while (*code == OP_ALT);  /* Loop for each alternative */
+    return true;
+}
+
+/*************************************************
+*       Check for asserted fixed first char      *
+*************************************************/
+
+/* During compilation, the "first char" settings from forward assertions are
+discarded, because they can cause conflicts with actual literals that follow.
+However, if we end up without a first char setting for an unanchored pattern,
+it is worth scanning the regex to see if there is an initial asserted first
+char. If all branches start with the same asserted char, or with a bracket all
+of whose alternatives start with the same asserted char (recurse ad lib), then
+we return that char, otherwise -1.
+
+Arguments:
+  code       points to start of expression (the bracket)
+  options    pointer to the options (used to check casing changes)
+  inassert   true if in an assertion
+
+Returns:     -1 or the fixed first char
+*/
+
+static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert)
+{
+    const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code);
+    int op = *scode;
+    
+    if (op >= OP_BRA)
+        op = OP_BRA;
+    
+    switch (op) {
+        default:
+            return -1;
+            
+        case OP_BRA:
+        case OP_ASSERT:
+            return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT);
+
+        case OP_EXACT:
+            scode += 2;
+            /* Fall through */
+
+        case OP_CHAR:
+        case OP_CHAR_IGNORING_CASE:
+        case OP_ASCII_CHAR:
+        case OP_ASCII_LETTER_IGNORING_CASE:
+        case OP_PLUS:
+        case OP_MINPLUS:
+            if (!inassert)
+                return -1;
+            return scode[1];
+    }
+}
+
+static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert)
+{
+    int c = -1;
+    do {
+        int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert);
+        if (d < 0)
+            return -1;
+        if (c < 0)
+            c = d;
+        else if (c != d)
+            return -1;
+        code += getLinkValue(code + 1);
+    } while (*code == OP_ALT);
+    return c;
+}
+
+static inline int multiplyWithOverflowCheck(int a, int b)
+{
+    if (!a || !b)
+        return 0;
+    if (a > MAX_PATTERN_SIZE / b)
+        return -1;
+    return a * b;
+}
+
+static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase,
+    CompileData& cd, ErrorCode& errorcode)
+{
+    /* Make a pass over the pattern to compute the
+     amount of store required to hold the compiled code. This does not have to be
+     perfect as long as errors are overestimates. */
+
+    if (patternLength > MAX_PATTERN_SIZE) {
+        errorcode = ERR16;
+        return -1;
+    }
+
+    int length = 1 + LINK_SIZE;      /* For initial BRA plus length */
+    int branch_extra = 0;
+    int lastitemlength = 0;
+    unsigned brastackptr = 0;
+    int brastack[BRASTACK_SIZE];
+    unsigned char bralenstack[BRASTACK_SIZE];
+    int bracount = 0;
+    
+    const UChar* ptr = (const UChar*)(pattern - 1);
+    const UChar* patternEnd = (const UChar*)(pattern + patternLength);
+    
+    while (++ptr < patternEnd) {
+        int minRepeats = 0, maxRepeats = 0;
+        int c = *ptr;
+
+        switch (c) {
+            /* A backslashed item may be an escaped data character or it may be a
+             character type. */
+
+            case '\\':
+                c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false);
+                if (errorcode != 0)
+                    return -1;
+                
+                lastitemlength = 1;     /* Default length of last item for repeats */
+                
+                if (c >= 0) {            /* Data character */
+                    length += 2;          /* For a one-byte character */
+                    
+                    if (c > 127) {
+                        int i;
+                        for (i = 0; i < kjs_pcre_utf8_table1_size; i++)
+                            if (c <= kjs_pcre_utf8_table1[i]) break;
+                        length += i;
+                        lastitemlength += i;
+                    }
+                    
+                    continue;
+                }
+                
+                /* Other escapes need one byte */
+                
+                length++;
+                
+                /* A back reference needs an additional 2 bytes, plus either one or 5
+                 bytes for a repeat. We also need to keep the value of the highest
+                 back reference. */
+                
+                if (c <= -ESC_REF) {
+                    int refnum = -c - ESC_REF;
+                    cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1;
+                    if (refnum > cd.top_backref)
+                        cd.top_backref = refnum;
+                    length += 2;   /* For single back reference */
+                    if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) {
+                        ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
+                        if (errorcode)
+                            return -1;
+                        if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
+                            (minRepeats == 1 && maxRepeats == -1))
+                            length++;
+                        else
+                            length += 5;
+                        if (safelyCheckNextChar(ptr, patternEnd, '?'))
+                            ptr++;
+                    }
+                }
+                continue;
+                
+            case '^':     /* Single-byte metacharacters */
+            case '.':
+            case '$':
+                length++;
+                lastitemlength = 1;
+                continue;
+                
+            case '*':            /* These repeats won't be after brackets; */
+            case '+':            /* those are handled separately */
+            case '?':
+                length++;
+                goto POSSESSIVE;
+                
+            /* This covers the cases of braced repeats after a single char, metachar,
+             class, or back reference. */
+
+            case '{':
+                if (!isCountedRepeat(ptr + 1, patternEnd))
+                    goto NORMAL_CHAR;
+                ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode);
+                if (errorcode != 0)
+                    return -1;
+                
+                /* These special cases just insert one extra opcode */
+                
+                if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
+                    (minRepeats == 1 && maxRepeats == -1))
+                    length++;
+                
+                /* These cases might insert additional copies of a preceding character. */
+                
+                else {
+                    if (minRepeats != 1) {
+                        length -= lastitemlength;   /* Uncount the original char or metachar */
+                        if (minRepeats > 0)
+                            length += 3 + lastitemlength;
+                    }
+                    length += lastitemlength + ((maxRepeats > 0) ? 3 : 1);
+                }
+                
+                if (safelyCheckNextChar(ptr, patternEnd, '?'))
+                    ptr++;      /* Needs no extra length */
+
+            POSSESSIVE:                     /* Test for possessive quantifier */
+                if (safelyCheckNextChar(ptr, patternEnd, '+')) {
+                    ptr++;
+                    length += 2 + 2 * LINK_SIZE;   /* Allow for atomic brackets */
+                }
+                continue;
+                
+            /* An alternation contains an offset to the next branch or ket. If any ims
+             options changed in the previous branch(es), and/or if we are in a
+             lookbehind assertion, extra space will be needed at the start of the
+             branch. This is handled by branch_extra. */
+                
+            case '|':
+                if (brastackptr == 0)
+                    cd.needOuterBracket = true;
+                length += 1 + LINK_SIZE + branch_extra;
+                continue;
+                
+            /* A character class uses 33 characters provided that all the character
+             values are less than 256. Otherwise, it uses a bit map for low valued
+             characters, and individual items for others. Don't worry about character
+             types that aren't allowed in classes - they'll get picked up during the
+             compile. A character class that contains only one single-byte character
+             uses 2 or 3 bytes, depending on whether it is negated or not. Notice this
+             where we can. (In UTF-8 mode we can do this only for chars < 128.) */
+                
+            case '[': {
+                int class_optcount;
+                if (*(++ptr) == '^') {
+                    class_optcount = 10;  /* Greater than one */
+                    ptr++;
+                }
+                else
+                    class_optcount = 0;
+                
+                bool class_utf8 = false;
+                
+                for (; ptr < patternEnd && *ptr != ']'; ++ptr) {
+                    /* Check for escapes */
+                    
+                    if (*ptr == '\\') {
+                        c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true);
+                        if (errorcode != 0)
+                            return -1;
+                        
+                        /* Handle escapes that turn into characters */
+                        
+                        if (c >= 0)
+                            goto NON_SPECIAL_CHARACTER;
+                        
+                        /* Escapes that are meta-things. The normal ones just affect the
+                         bit map, but Unicode properties require an XCLASS extended item. */
+                        
+                        else
+                            class_optcount = 10;         /* \d, \s etc; make sure > 1 */
+                    }
+                    
+                    /* Anything else increments the possible optimization count. We have to
+                     detect ranges here so that we can compute the number of extra ranges for
+                     caseless wide characters when UCP support is available. If there are wide
+                     characters, we are going to have to use an XCLASS, even for single
+                     characters. */
+                    
+                    else {
+                        c = *ptr;
+                        
+                        /* Come here from handling \ above when it escapes to a char value */
+                        
+                    NON_SPECIAL_CHARACTER:
+                        class_optcount++;
+                        
+                        int d = -1;
+                        if (safelyCheckNextChar(ptr, patternEnd, '-')) {
+                            UChar const *hyptr = ptr++;
+                            if (safelyCheckNextChar(ptr, patternEnd, '\\')) {
+                                ptr++;
+                                d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true);
+                                if (errorcode != 0)
+                                    return -1;
+                            }
+                            else if ((ptr + 1 < patternEnd) && ptr[1] != ']')
+                                d = *++ptr;
+                            if (d < 0)
+                                ptr = hyptr;      /* go back to hyphen as data */
+                        }
+                        
+                        /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or >
+                         127 for caseless matching, we will need to use an XCLASS. */
+                        
+                        if (d >= 0) {
+                            class_optcount = 10;     /* Ensure > 1 */
+                            if (d < c) {
+                                errorcode = ERR8;
+                                return -1;
+                            }
+                            
+                            if ((d > 255 || (ignoreCase && d > 127))) {
+                                unsigned char buffer[6];
+                                if (!class_utf8)         /* Allow for XCLASS overhead */
+                                {
+                                    class_utf8 = true;
+                                    length += LINK_SIZE + 2;
+                                }
+                                
+                                /* If we have UCP support, find out how many extra ranges are
+                                 needed to map the other case of characters within this range. We
+                                 have to mimic the range optimization here, because extending the
+                                 range upwards might push d over a boundary that makes it use
+                                 another byte in the UTF-8 representation. */
+                                
+                                if (ignoreCase) {
+                                    int occ, ocd;
+                                    int cc = c;
+                                    int origd = d;
+                                    while (getOthercaseRange(&cc, origd, &occ, &ocd)) {
+                                        if (occ >= c && ocd <= d)
+                                            continue;   /* Skip embedded */
+                                        
+                                        if (occ < c  && ocd >= c - 1)  /* Extend the basic range */
+                                        {                            /* if there is overlap,   */
+                                            c = occ;                     /* noting that if occ < c */
+                                            continue;                    /* we can't have ocd > d  */
+                                        }                            /* because a subrange is  */
+                                        if (ocd > d && occ <= d + 1)   /* always shorter than    */
+                                        {                            /* the basic range.       */
+                                            d = ocd;
+                                            continue;
+                                        }
+                                        
+                                        /* An extra item is needed */
+                                        
+                                        length += 1 + encodeUTF8(occ, buffer) +
+                                        ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer));
+                                    }
+                                }
+                                
+                                /* The length of the (possibly extended) range */
+                                
+                                length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer);
+                            }
+                            
+                        }
+                        
+                        /* We have a single character. There is nothing to be done unless we
+                         are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must
+                         allow for an XCL_SINGLE item, doubled for caselessness if there is UCP
+                         support. */
+                        
+                        else {
+                            if ((c > 255 || (ignoreCase && c > 127))) {
+                                unsigned char buffer[6];
+                                class_optcount = 10;     /* Ensure > 1 */
+                                if (!class_utf8)         /* Allow for XCLASS overhead */
+                                {
+                                    class_utf8 = true;
+                                    length += LINK_SIZE + 2;
+                                }
+                                length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer));
+                            }
+                        }
+                    }
+                }
+                
+                if (ptr >= patternEnd) {   /* Missing terminating ']' */
+                    errorcode = ERR6;
+                    return -1;
+                }
+                
+                /* We can optimize when there was only one optimizable character.
+                 Note that this does not detect the case of a negated single character.
+                 In that case we do an incorrect length computation, but it's not a serious
+                 problem because the computed length is too large rather than too small. */
+
+                if (class_optcount == 1)
+                    goto NORMAL_CHAR;
+
+                /* Here, we handle repeats for the class opcodes. */
+                {
+                    length += 33;
+                    
+                    /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier,
+                     we also need extra for wrapping the whole thing in a sub-pattern. */
+                    
+                    if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) {
+                        ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
+                        if (errorcode != 0)
+                            return -1;
+                        if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
+                            (minRepeats == 1 && maxRepeats == -1))
+                            length++;
+                        else
+                            length += 5;
+                        if (safelyCheckNextChar(ptr, patternEnd, '+')) {
+                            ptr++;
+                            length += 2 + 2 * LINK_SIZE;
+                        } else if (safelyCheckNextChar(ptr, patternEnd, '?'))
+                            ptr++;
+                    }
+                }
+                continue;
+            }
+
+            /* Brackets may be genuine groups or special things */
+                
+            case '(': {
+                int branch_newextra = 0;
+                int bracket_length = 1 + LINK_SIZE;
+                bool capturing = false;
+                
+                /* Handle special forms of bracket, which all start (? */
+                
+                if (safelyCheckNextChar(ptr, patternEnd, '?')) {
+                    switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) {
+                        /* Non-referencing groups and lookaheads just move the pointer on, and
+                         then behave like a non-special bracket, except that they don't increment
+                         the count of extracting brackets. Ditto for the "once only" bracket,
+                         which is in Perl from version 5.005. */
+                            
+                        case ':':
+                        case '=':
+                        case '!':
+                            ptr += 2;
+                            break;
+                            
+                        /* Else loop checking valid options until ) is met. Anything else is an
+                         error. If we are without any brackets, i.e. at top level, the settings
+                         act as if specified in the options, so massage the options immediately.
+                         This is for backward compatibility with Perl 5.004. */
+                            
+                        default:
+                            errorcode = ERR12;
+                            return -1;
+                    }
+                } else
+                    capturing = 1;
+                
+                /* Capturing brackets must be counted so we can process escapes in a
+                 Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need
+                 an additional 3 bytes of memory per capturing bracket. */
+                
+                if (capturing) {
+                    bracount++;
+                    if (bracount > EXTRACT_BASIC_MAX)
+                        bracket_length += 3;
+                }
+                
+                /* Save length for computing whole length at end if there's a repeat that
+                 requires duplication of the group. Also save the current value of
+                 branch_extra, and start the new group with the new value. If non-zero, this
+                 will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */
+                
+                if (brastackptr >= sizeof(brastack)/sizeof(int)) {
+                    errorcode = ERR17;
+                    return -1;
+                }
+                
+                bralenstack[brastackptr] = branch_extra;
+                branch_extra = branch_newextra;
+                
+                brastack[brastackptr++] = length;
+                length += bracket_length;
+                continue;
+            }
+
+            /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we
+             have to replicate this bracket up to that many times. If brastackptr is
+             0 this is an unmatched bracket which will generate an error, but take care
+             not to try to access brastack[-1] when computing the length and restoring
+             the branch_extra value. */
+
+            case ')': {
+                int duplength;
+                length += 1 + LINK_SIZE;
+                if (brastackptr > 0) {
+                    duplength = length - brastack[--brastackptr];
+                    branch_extra = bralenstack[brastackptr];
+                }
+                else
+                    duplength = 0;
+                
+                /* Leave ptr at the final char; for readRepeatCounts this happens
+                 automatically; for the others we need an increment. */
+                
+                if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) {
+                    ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
+                    if (errorcode)
+                        return -1;
+                } else if (c == '*') {
+                    minRepeats = 0;
+                    maxRepeats = -1;
+                    ptr++;
+                } else if (c == '+') {
+                    minRepeats = 1;
+                    maxRepeats = -1;
+                    ptr++;
+                } else if (c == '?') {
+                    minRepeats = 0;
+                    maxRepeats = 1;
+                    ptr++;
+                } else {
+                    minRepeats = 1;
+                    maxRepeats = 1;
+                }
+                
+                /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
+                 group, and if the maximum is greater than zero, we have to replicate
+                 maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
+                 bracket set. */
+                
+                int repeatsLength;
+                if (minRepeats == 0) {
+                    length++;
+                    if (maxRepeats > 0) {
+                        repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + 3 + 2 * LINK_SIZE);
+                        if (repeatsLength < 0) {
+                            errorcode = ERR16;
+                            return -1;
+                        }
+                        length += repeatsLength;
+                        if (length > MAX_PATTERN_SIZE) {
+                            errorcode = ERR16;
+                            return -1;
+                        }
+                    }
+                }
+                
+                /* When the minimum is greater than zero, we have to replicate up to
+                 minval-1 times, with no additions required in the copies. Then, if there
+                 is a limited maximum we have to replicate up to maxval-1 times allowing
+                 for a BRAZERO item before each optional copy and nesting brackets for all
+                 but one of the optional copies. */
+                
+                else {
+                    repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength);
+                    if (repeatsLength < 0) {
+                        errorcode = ERR16;
+                        return -1;
+                    }
+                    length += repeatsLength;
+                    if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */
+                        repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + 3 + 2 * LINK_SIZE);
+                        if (repeatsLength < 0) {
+                            errorcode = ERR16;
+                            return -1;
+                        }
+                        length += repeatsLength - (2 + 2 * LINK_SIZE);
+                    }
+                    if (length > MAX_PATTERN_SIZE) {
+                        errorcode = ERR16;
+                        return -1;
+                    }
+                }
+                
+                /* Allow space for once brackets for "possessive quantifier" */
+                
+                if (safelyCheckNextChar(ptr, patternEnd, '+')) {
+                    ptr++;
+                    length += 2 + 2 * LINK_SIZE;
+                }
+                continue;
+            }
+
+            /* Non-special character. It won't be space or # in extended mode, so it is
+             always a genuine character. If we are in a \Q...\E sequence, check for the
+             end; if not, we have a literal. */
+                
+            default:
+            NORMAL_CHAR:
+                length += 2;          /* For a one-byte character */
+                lastitemlength = 1;   /* Default length of last item for repeats */
+
+                if (c > 127) {
+                    int i;
+                    for (i = 0; i < kjs_pcre_utf8_table1_size; i++)
+                        if (c <= kjs_pcre_utf8_table1[i])
+                            break;
+                    length += i;
+                    lastitemlength += i;
+                }
+                
+                continue;
+        }
+    }
+    
+    length += 2 + LINK_SIZE;    /* For final KET and END */
+
+    cd.numCapturingBrackets = bracount;
+    return length;
+}
+
+/*************************************************
+*        Compile a Regular Expression            *
+*************************************************/
+
+/* This function takes a string and returns a pointer to a block of store
+holding a compiled version of the expression. The original API for this
+function had no error code return variable; it is retained for backwards
+compatibility. The new function is given a new name.
+
+Arguments:
+  pattern       the regular expression
+  options       various option bits
+  errorcodeptr  pointer to error code variable (pcre_compile2() only)
+                  can be NULL if you don't want a code value
+  errorptr      pointer to pointer to error text
+  erroroffset   ptr offset in pattern where error was detected
+  tables        pointer to character tables or NULL
+
+Returns:        pointer to compiled data block, or NULL on error,
+                with errorptr and erroroffset set
+*/
+
+static inline JSRegExp* returnError(ErrorCode errorcode, const char** errorptr)
+{
+    *errorptr = errorText(errorcode);
+    return 0;
+}
+
+JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
+                JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline,
+                unsigned* numSubpatterns, const char** errorptr,
+                malloc_t* allocate_function, free_t* free_function)
+{
+    /* We can't pass back an error message if errorptr is NULL; I guess the best we
+     can do is just return NULL, but we can set a code value if there is a code pointer. */
+    if (!errorptr)
+        return 0;
+    *errorptr = NULL;
+    
+    CompileData cd;
+    
+    ErrorCode errorcode = ERR0;
+    /* Call this once just to count the brackets. */
+    calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode);
+    /* Call it again to compute the length. */
+    int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode);
+    if (errorcode)
+        return returnError(errorcode, errorptr);
+    
+    if (length > MAX_PATTERN_SIZE)
+        return returnError(ERR16, errorptr);
+    
+    size_t size = length + sizeof(JSRegExp);
+    JSRegExp* re = reinterpret_cast<JSRegExp*>((*allocate_function)(size));
+    
+    if (!re)
+        return returnError(ERR13, errorptr);
+    
+    re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0);
+    
+    /* The starting points of the name/number translation table and of the code are
+     passed around in the compile data block. */
+    
+    const unsigned char* codeStart = (const unsigned char*)(re + 1);
+    
+    /* Set up a starting, non-extracting bracket, then compile the expression. On
+     error, errorcode will be set non-zero, so we don't need to look at the result
+     of the function here. */
+    
+    const UChar* ptr = (const UChar*)pattern;
+    const UChar* patternEnd = pattern + patternLength;
+    unsigned char* code = (unsigned char*)codeStart;
+    int firstbyte, reqbyte;
+    int bracketCount = 0;
+    if (!cd.needOuterBracket)
+        compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstbyte, &reqbyte, cd);
+    else {
+        *code = OP_BRA;
+        compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 0, &firstbyte, &reqbyte, cd);
+    }
+    re->top_bracket = bracketCount;
+    re->top_backref = cd.top_backref;
+    
+    /* If not reached end of pattern on success, there's an excess bracket. */
+    
+    if (errorcode == 0 && ptr < patternEnd)
+        errorcode = ERR10;
+    
+    /* Fill in the terminating state and check for disastrous overflow, but
+     if debugging, leave the test till after things are printed out. */
+    
+    *code++ = OP_END;
+
+    ASSERT(code - codeStart <= length);
+    if (code - codeStart > length)
+        errorcode = ERR7;
+    
+    /* Give an error if there's back reference to a non-existent capturing
+     subpattern. */
+    
+    if (re->top_backref > re->top_bracket)
+        errorcode = ERR15;
+    
+    /* Failed to compile, or error while post-processing */
+    
+    if (errorcode != ERR0) {
+        (*free_function)(reinterpret_cast<void*>(re));
+        return returnError(errorcode, errorptr);
+    }
+    
+    /* If the anchored option was not passed, set the flag if we can determine that
+     the pattern is anchored by virtue of ^ characters or \A or anything else (such
+     as starting with .* when DOTALL is set).
+     
+     Otherwise, if we know what the first character has to be, save it, because that
+     speeds up unanchored matches no end. If not, see if we can set the
+     UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches
+     start with ^. and also when all branches start with .* for non-DOTALL matches.
+     */
+    
+    if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart))
+        re->options |= IsAnchoredOption;
+    else {
+        if (firstbyte < 0) {
+            firstbyte = (cd.needOuterBracket
+                    ? bracketFindFirstAssertedCharacter(codeStart, false)
+                    : branchFindFirstAssertedCharacter(codeStart, false))
+                | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0);
+        }
+        if (firstbyte >= 0) {
+            int ch = firstbyte & 255;
+            if (ch < 127) {
+                re->first_byte = ((firstbyte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstbyte;
+                re->options |= UseFirstByteOptimizationOption;
+            }
+        } else {
+            if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap))
+                re->options |= UseMultiLineFirstByteOptimizationOption;
+        }
+    }
+    
+    /* For an anchored pattern, we use the "required byte" only if it follows a
+     variable length item in the regex. Remove the caseless flag for non-caseable
+     bytes. */
+    
+    if (reqbyte >= 0 && (!(re->options & IsAnchoredOption) || (reqbyte & REQ_VARY))) {
+        int ch = reqbyte & 255;
+        if (ch < 127) {
+            re->req_byte = ((reqbyte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqbyte & ~REQ_IGNORE_CASE) : reqbyte;
+            re->options |= UseRequiredByteOptimizationOption;
+        }
+    }
+    
+    if (numSubpatterns)
+        *numSubpatterns = re->top_bracket;
+    return re;
+}
+
+void jsRegExpFree(JSRegExp* re, free_t* free_function)
+{
+    (*free_function)(reinterpret_cast<void*>(re));
+}
diff --git a/regexp2000/src/third_party/jscre/pcre_exec.cpp b/regexp2000/src/third_party/jscre/pcre_exec.cpp
new file mode 100644 (file)
index 0000000..d78e839
--- /dev/null
@@ -0,0 +1,2081 @@
+/* This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed. This library now supports only the regular expression features
+required by the JavaScript language specification, and has only the functions
+needed by JavaScriptCore and the rest of WebKit.
+
+                 Originally written by Philip Hazel
+           Copyright (c) 1997-2006 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
+    Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+
+-----------------------------------------------------------------------------
+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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains jsRegExpExecute(), the externally visible function
+that does pattern matching using an NFA algorithm, following the rules from
+the JavaScript specification. There are also some supporting functions. */
+
+#include "config.h"
+
+#include "pcre_internal.h"
+
+#include "ASCIICType.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <string.h> /* for memcpy */
+
+#ifdef __GNUC__
+#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
+//#define USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
+#endif
+
+/* Avoid warnings on Windows. */
+#undef min
+#undef max
+
+#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
+typedef int ReturnLocation;
+#else
+typedef void* ReturnLocation;
+#endif
+
+/* Structure for building a chain of data for holding the values of
+the subject pointer at the start of each bracket, used to detect when
+an empty string has been matched by a bracket to break infinite loops. */ 
+struct BracketChainNode {
+    BracketChainNode* previousBracket;
+    const UChar* bracketStart;
+};
+
+struct MatchFrame {
+    ReturnLocation returnLocation;
+    struct MatchFrame* previousFrame;
+    
+    /* Function arguments that may change */
+    struct {
+        const UChar* subjectPtr;
+        const unsigned char* instructionPtr;
+        int offsetTop;
+        BracketChainNode* bracketChain;
+    } args;
+    
+    
+    /* PCRE uses "fake" recursion built off of gotos, thus
+     stack-based local variables are not safe to use.  Instead we have to
+     store local variables on the current MatchFrame. */
+    struct {
+        const unsigned char* data;
+        const unsigned char* startOfRepeatingBracket;
+        const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare
+        const unsigned char* instructionPtrAtStartOfOnce;
+        
+        int repeatOthercase;
+        
+        int ctype;
+        int fc;
+        int fi;
+        int length;
+        int max;
+        int number;
+        int offset;
+        int saveOffset1;
+        int saveOffset2;
+        int saveOffset3;
+        
+        BracketChainNode bracketChainNode;
+    } locals;
+};
+
+/* Structure for passing "static" information around between the functions
+doing traditional NFA matching, so that they are thread-safe. */
+
+struct MatchData {
+  int*   offsetVector;         /* Offset vector */
+  int    offsetEnd;            /* One past the end */
+  int    offsetMax;            /* The maximum usable for return data */
+  bool   offsetOverflow;       /* Set if too many extractions */
+  const UChar*  startSubject;         /* Start of the subject string */
+  const UChar*  endSubject;           /* End of the subject string */
+  const UChar*  endMatchPtr;         /* Subject position at end match */
+  int    endOffsetTop;        /* Highwater mark at end of match */
+  bool   multiline;
+  bool   ignoreCase;
+};
+
+/* The maximum remaining length of subject we are prepared to search for a
+req_byte match. */
+
+#define REQ_BYTE_MAX 1000
+
+/* The below limit restricts the number of "recursive" match calls in order to
+avoid spending exponential time on complex regular expressions. */
+
+static const unsigned matchLimit = 100000;
+
+#ifdef DEBUG
+/*************************************************
+*        Debugging function to print chars       *
+*************************************************/
+
+/* Print a sequence of chars in printable format, stopping at the end of the
+subject if the requested.
+
+Arguments:
+  p           points to characters
+  length      number to print
+  isSubject  true if printing from within md.startSubject
+  md          pointer to matching data block, if isSubject is true
+*/
+
+static void pchars(const UChar* p, int length, bool isSubject, const MatchData& md)
+{
+    if (isSubject && length > md.endSubject - p)
+        length = md.endSubject - p;
+    while (length-- > 0) {
+        int c;
+        if (isprint(c = *(p++)))
+            printf("%c", c);
+        else if (c < 256)
+            printf("\\x%02x", c);
+        else
+            printf("\\x{%x}", c);
+    }
+}
+#endif
+
+/*************************************************
+*          Match a back-reference                *
+*************************************************/
+
+/* If a back reference hasn't been set, the length that is passed is greater
+than the number of characters left in the string, so the match fails.
+
+Arguments:
+  offset      index into the offset vector
+  subjectPtr        points into the subject
+  length      length to be matched
+  md          points to match data block
+
+Returns:      true if matched
+*/
+
+static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md)
+{
+    const UChar* p = md.startSubject + md.offsetVector[offset];
+    
+#ifdef DEBUG
+    if (subjectPtr >= md.endSubject)
+        printf("matching subject <null>");
+    else {
+        printf("matching subject ");
+        pchars(subjectPtr, length, true, md);
+    }
+    printf(" against backref ");
+    pchars(p, length, false, md);
+    printf("\n");
+#endif
+    
+    /* Always fail if not enough characters left */
+    
+    if (length > md.endSubject - subjectPtr)
+        return false;
+    
+    /* Separate the caselesss case for speed */
+    
+    if (md.ignoreCase) {
+        while (length-- > 0) {
+            UChar c = *p++;
+            int othercase = kjs_pcre_ucp_othercase(c);
+            UChar d = *subjectPtr++;
+            if (c != d && othercase != d)
+                return false;
+        }
+    }
+    else {
+        while (length-- > 0)
+            if (*p++ != *subjectPtr++)
+                return false;
+    }
+    
+    return true;
+}
+
+#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
+
+/* Use numbered labels and switch statement at the bottom of the match function. */
+
+#define RMATCH_WHERE(num) num
+#define RRETURN_LABEL RRETURN_SWITCH
+
+#else
+
+/* Use GCC's computed goto extension. */
+
+/* For one test case this is more than 40% faster than the switch statement.
+We could avoid the use of the num argument entirely by using local labels,
+but using it for the GCC case as well as the non-GCC case allows us to share
+a bit more code and notice if we use conflicting numbers.*/
+
+#define RMATCH_WHERE(num) &&RRETURN_##num
+#define RRETURN_LABEL *stack.currentFrame->returnLocation
+
+#endif
+
+#define RECURSIVE_MATCH_COMMON(num) \
+    goto RECURSE;\
+    RRETURN_##num: \
+    stack.popCurrentFrame();
+
+#define RECURSIVE_MATCH(num, ra, rb) \
+    do { \
+        stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
+        RECURSIVE_MATCH_COMMON(num) \
+    } while (0)
+
+#define RECURSIVE_MATCH_STARTNG_NEW_GROUP(num, ra, rb) \
+    do { \
+        stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
+        startNewGroup(stack.currentFrame); \
+        RECURSIVE_MATCH_COMMON(num) \
+    } while (0)
+
+#define RRETURN goto RRETURN_LABEL
+
+#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0)
+
+/*************************************************
+*         Match from current position            *
+*************************************************/
+
+/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character
+in the subject string, while substringStart holds the value of subjectPtr at the start of the
+last bracketed group - used for breaking infinite loops matching zero-length
+strings. This function is called recursively in many circumstances. Whenever it
+returns a negative (error) response, the outer match() call must also return the
+same response.
+
+Arguments:
+   subjectPtr        pointer in subject
+   instructionPtr       position in code
+   offsetTop  current top pointer
+   md          pointer to "static" info for the match
+
+Returns:       1 if matched          )  these values are >= 0
+               0 if failed to match  )
+               a negative error value if aborted by an error condition
+                 (e.g. stopped by repeated call or recursion limit)
+*/
+
+static const unsigned FRAMES_ON_STACK = 16;
+
+struct MatchStack {
+    MatchStack()
+        : framesEnd(frames + FRAMES_ON_STACK)
+        , currentFrame(frames)
+        , size(1) // match() creates accesses the first frame w/o calling pushNewFrame
+    {
+        ASSERT((sizeof(frames) / sizeof(frames[0])) == FRAMES_ON_STACK);
+    }
+    
+    MatchFrame frames[FRAMES_ON_STACK];
+    MatchFrame* framesEnd;
+    MatchFrame* currentFrame;
+    unsigned size;
+    
+    inline bool canUseStackBufferForNextFrame()
+    {
+        return size < FRAMES_ON_STACK;
+    }
+    
+    inline MatchFrame* allocateNextFrame()
+    {
+        if (canUseStackBufferForNextFrame())
+            return currentFrame + 1;
+        return new MatchFrame;
+    }
+    
+    inline void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation)
+    {
+        MatchFrame* newframe = allocateNextFrame();
+        newframe->previousFrame = currentFrame;
+
+        newframe->args.subjectPtr = currentFrame->args.subjectPtr;
+        newframe->args.offsetTop = currentFrame->args.offsetTop;
+        newframe->args.instructionPtr = instructionPtr;
+        newframe->args.bracketChain = bracketChain;
+        newframe->returnLocation = returnLocation;
+        size++;
+
+        currentFrame = newframe;
+    }
+    
+    inline void popCurrentFrame()
+    {
+        MatchFrame* oldFrame = currentFrame;
+        currentFrame = currentFrame->previousFrame;
+        if (size > FRAMES_ON_STACK)
+            delete oldFrame;
+        size--;
+    }
+
+    void popAllFrames()
+    {
+        while (size)
+            popCurrentFrame();
+    }
+};
+
+static int matchError(int errorCode, MatchStack& stack)
+{
+    stack.popAllFrames();
+    return errorCode;
+}
+
+/* Get the next UTF-8 character, not advancing the pointer, incrementing length
+ if there are extra bytes. This is called when we know we are in UTF-8 mode. */
+
+static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len)
+{
+    c = *subjectPtr;
+    if ((c & 0xc0) == 0xc0) {
+        int gcaa = kjs_pcre_utf8_table4[c & 0x3f];  /* Number of additional bytes */
+        int gcss = 6 * gcaa;
+        c = (c & kjs_pcre_utf8_table3[gcaa]) << gcss;
+        for (int gcii = 1; gcii <= gcaa; gcii++) {
+            gcss -= 6;
+            c |= (subjectPtr[gcii] & 0x3f) << gcss;
+        }
+        len += gcaa;
+    }
+}
+
+static inline void startNewGroup(MatchFrame* currentFrame)
+{
+    /* At the start of a bracketed group, add the current subject pointer to the
+     stack of such pointers, to be re-instated at the end of the group when we hit
+     the closing ket. When match() is called in other circumstances, we don't add to
+     this stack. */
+    
+    currentFrame->locals.bracketChainNode.previousBracket = currentFrame->args.bracketChain;
+    currentFrame->locals.bracketChainNode.bracketStart = currentFrame->args.subjectPtr;
+    currentFrame->args.bracketChain = &currentFrame->locals.bracketChainNode;
+}
+
+// FIXME: "minimize" means "not greedy", we should invert the callers to ask for "greedy" to be less confusing
+static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats)
+{
+    // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR
+    static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 };
+    static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 };
+
+    ASSERT(instructionOffset >= 0);
+    ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR));
+
+    minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2
+    minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset];
+    maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset];
+}
+
+static int match(const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md)
+{
+    bool isMatch = false;
+    int min;
+    bool minimize = false; /* Initialization not really needed, but some compilers think so. */
+    unsigned matchCount = 0;
+    
+    MatchStack stack;
+
+    /* The opcode jump table. */
+#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
+#define EMIT_JUMP_TABLE_ENTRY(opcode) &&LABEL_OP_##opcode,
+    static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) };
+#undef EMIT_JUMP_TABLE_ENTRY
+#endif
+    
+    /* One-time setup of the opcode jump table. */
+#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
+    for (int i = 255; !opcodeJumpTable[i]; i--)
+        opcodeJumpTable[i] = &&CAPTURING_BRACKET;
+#endif
+    
+#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
+    // Shark shows this as a hot line
+    // Using a static const here makes this line disappear, but makes later access hotter (not sure why)
+    stack.currentFrame->returnLocation = &&RETURN;
+#else
+    stack.currentFrame->returnLocation = 0;
+#endif
+    stack.currentFrame->args.subjectPtr = subjectPtr;
+    stack.currentFrame->args.instructionPtr = instructionPtr;
+    stack.currentFrame->args.offsetTop = offsetTop;
+    stack.currentFrame->args.bracketChain = 0;
+    startNewGroup(stack.currentFrame);
+    
+    /* This is where control jumps back to to effect "recursion" */
+    
+RECURSE:
+    if (++matchCount > matchLimit)
+        return matchError(JSRegExpErrorHitLimit, stack);
+
+    /* Now start processing the operations. */
+    
+#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
+    while (true)
+#endif
+    {
+        
+#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
+#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode
+#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr]
+#else
+#define BEGIN_OPCODE(opcode) case OP_##opcode
+#define NEXT_OPCODE continue
+#endif
+        
+#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
+        NEXT_OPCODE;
+#else
+        switch (*stack.currentFrame->args.instructionPtr)
+#endif
+        {
+            /* Non-capturing bracket: optimized */
+                
+            BEGIN_OPCODE(BRA):
+            NON_CAPTURING_BRACKET:
+                DPRINTF(("start bracket 0\n"));
+                do {
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
+                    if (isMatch)
+                        RRETURN;
+                    stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
+                } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
+                DPRINTF(("bracket 0 failed\n"));
+                RRETURN;
+                
+            /* Skip over large extraction number data if encountered. */
+                
+            BEGIN_OPCODE(BRANUMBER):
+                stack.currentFrame->args.instructionPtr += 3;
+                NEXT_OPCODE;
+                
+            /* End of the pattern. */
+                
+            BEGIN_OPCODE(END):
+                md.endMatchPtr = stack.currentFrame->args.subjectPtr;          /* Record where we ended */
+                md.endOffsetTop = stack.currentFrame->args.offsetTop;   /* and how many extracts were taken */
+                isMatch = true;
+                RRETURN;
+                
+            /* Assertion brackets. Check the alternative branches in turn - the
+             matching won't pass the KET for an assertion. If any one branch matches,
+             the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
+             start of each branch to move the current point backwards, so the code at
+             this level is identical to the lookahead case. */
+                
+            BEGIN_OPCODE(ASSERT):
+                do {
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
+                    if (isMatch)
+                        break;
+                    stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
+                } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
+                if (*stack.currentFrame->args.instructionPtr == OP_KET)
+                    RRETURN_NO_MATCH;
+                
+                /* Continue from after the assertion, updating the offsets high water
+                 mark, since extracts may have been taken during the assertion. */
+                
+                advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
+                stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
+                stack.currentFrame->args.offsetTop = md.endOffsetTop;
+                NEXT_OPCODE;
+                
+            /* Negative assertion: all branches must fail to match */
+                
+            BEGIN_OPCODE(ASSERT_NOT):
+                do {
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
+                    if (isMatch)
+                        RRETURN_NO_MATCH;
+                    stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
+                } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
+                
+                stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
+                NEXT_OPCODE;
+                
+            /* An alternation is the end of a branch; scan along to find the end of the
+             bracketed group and go to there. */
+                
+            BEGIN_OPCODE(ALT):
+                advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
+                NEXT_OPCODE;
+                
+            /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
+             that it may occur zero times. It may repeat infinitely, or not at all -
+             i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
+             repeat limits are compiled as a number of copies, with the optional ones
+             preceded by BRAZERO or BRAMINZERO. */
+                
+            BEGIN_OPCODE(BRAZERO): {
+                stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
+                RECURSIVE_MATCH_STARTNG_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain);
+                if (isMatch)
+                    RRETURN;
+                advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
+                stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE;
+                NEXT_OPCODE;
+            }
+                
+            BEGIN_OPCODE(BRAMINZERO): {
+                stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
+                advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
+                RECURSIVE_MATCH_STARTNG_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
+                if (isMatch)
+                    RRETURN;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+            }
+                
+            /* End of a group, repeated or non-repeating. If we are at the end of
+             an assertion "group", stop matching and return 1, but record the
+             current high water mark for use by positive assertions. Do this also
+             for the "once" (not-backup up) groups. */
+                
+            BEGIN_OPCODE(KET):
+            BEGIN_OPCODE(KETRMIN):
+            BEGIN_OPCODE(KETRMAX):
+                stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1);
+                stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart;
+
+                /* Back up the stack of bracket start pointers. */
+
+                stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket;
+
+                if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) {
+                    md.endOffsetTop = stack.currentFrame->args.offsetTop;
+                    isMatch = true;
+                    RRETURN;
+                }
+                
+                /* In all other cases except a conditional group we have to check the
+                 group number back at the start and if necessary complete handling an
+                 extraction by setting the offsets and bumping the high water mark. */
+                
+                stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA;
+                
+                /* For extended extraction brackets (large number), we have to fish out
+                 the number from a dummy opcode at the start. */
+                
+                if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
+                    stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 2 + LINK_SIZE);
+                stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
+                
+#ifdef DEBUG
+                printf("end bracket %d", stack.currentFrame->locals.number);
+                printf("\n");
+#endif
+                
+                /* Test for a numbered group. This includes groups called as a result
+                 of recursion. Note that whole-pattern recursion is coded as a recurse
+                 into group 0, so it won't be picked up here. Instead, we catch it when
+                 the OP_END is reached. */
+                
+                if (stack.currentFrame->locals.number > 0) {
+                    if (stack.currentFrame->locals.offset >= md.offsetMax)
+                        md.offsetOverflow = true;
+                    else {
+                        md.offsetVector[stack.currentFrame->locals.offset] =
+                        md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
+                        md.offsetVector[stack.currentFrame->locals.offset+1] = stack.currentFrame->args.subjectPtr - md.startSubject;
+                        if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset)
+                            stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2;
+                    }
+                }
+                
+                /* For a non-repeating ket, just continue at this level. This also
+                 happens for a repeating ket if no characters were matched in the group.
+                 This is the forcible breaking of infinite loops as implemented in Perl
+                 5.005. If there is an options reset, it will get obeyed in the normal
+                 course of events. */
+                
+                if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
+                    stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
+                    NEXT_OPCODE;
+                }
+                
+                /* The repeating kets try the rest of the pattern or restart from the
+                 preceding bracket, in the appropriate order. */
+                
+                if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) {
+                    RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
+                    if (isMatch)
+                        RRETURN;
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(17, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
+                    if (isMatch)
+                        RRETURN;
+                } else { /* OP_KETRMAX */
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(18, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
+                    if (isMatch)
+                        RRETURN;
+                    RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
+                    if (isMatch)
+                        RRETURN;
+                }
+                RRETURN;
+                
+            /* Start of subject. */
+
+            BEGIN_OPCODE(CIRC):
+                if (stack.currentFrame->args.subjectPtr != md.startSubject)
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+
+            /* After internal newline if multiline. */
+
+            BEGIN_OPCODE(BOL):
+                if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1]))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+
+            /* End of subject. */
+
+            BEGIN_OPCODE(DOLL):
+                if (stack.currentFrame->args.subjectPtr < md.endSubject)
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+
+            /* Before internal newline if multiline. */
+
+            BEGIN_OPCODE(EOL):
+                if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+                
+            /* Word boundary assertions */
+                
+            BEGIN_OPCODE(NOT_WORD_BOUNDARY):
+            BEGIN_OPCODE(WORD_BOUNDARY): {
+                bool currentCharIsWordChar = false;
+                bool previousCharIsWordChar = false;
+                
+                if (stack.currentFrame->args.subjectPtr > md.startSubject)
+                    previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]);
+                if (stack.currentFrame->args.subjectPtr < md.endSubject)
+                    currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr);
+                
+                /* Now see if the situation is what we want */
+                bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY);
+                if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar)
+                    RRETURN_NO_MATCH;
+                NEXT_OPCODE;
+            }
+                
+            /* Match a single character type; inline for speed */
+                
+            BEGIN_OPCODE(NOT_NEWLINE):
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (isNewline(*stack.currentFrame->args.subjectPtr++))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+
+            BEGIN_OPCODE(NOT_DIGIT):
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+
+            BEGIN_OPCODE(DIGIT):
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+
+            BEGIN_OPCODE(NOT_WHITESPACE):
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (isSpaceChar(*stack.currentFrame->args.subjectPtr++))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+
+            BEGIN_OPCODE(WHITESPACE):
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+                
+            BEGIN_OPCODE(NOT_WORDCHAR):
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (isWordChar(*stack.currentFrame->args.subjectPtr++))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+                
+            BEGIN_OPCODE(WORDCHAR):
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (!isWordChar(*stack.currentFrame->args.subjectPtr++))
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                NEXT_OPCODE;
+                
+            /* Match a back reference, possibly repeatedly. Look past the end of the
+             item to see if there is repeat information following. The code is similar
+             to that for character classes, but repeated for efficiency. Then obey
+             similar code to character type repeats - written out again for speed.
+             However, if the referenced string is the empty string, always treat
+             it as matched, any number of times (otherwise there could be infinite
+             loops). */
+                
+            BEGIN_OPCODE(REF):
+                stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1;               /* Doubled ref number */
+                stack.currentFrame->args.instructionPtr += 3;                                 /* Advance past item */
+                
+                /* If the reference is unset, set the length to be longer than the amount
+                 of subject left; this ensures that every attempt at a match fails. We
+                 can't just fail here, because of the possibility of quantifiers with zero
+                 minima. */
+                
+                if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0)
+                    stack.currentFrame->locals.length = 0;
+                else
+                    stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset];
+                
+                /* Set up for repetition, or handle the non-repeated case */
+                
+                switch (*stack.currentFrame->args.instructionPtr) {
+                    case OP_CRSTAR:
+                    case OP_CRMINSTAR:
+                    case OP_CRPLUS:
+                    case OP_CRMINPLUS:
+                    case OP_CRQUERY:
+                    case OP_CRMINQUERY:
+                        repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
+                        break;
+                        
+                    case OP_CRRANGE:
+                    case OP_CRMINRANGE:
+                        minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
+                        min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                        stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
+                        if (stack.currentFrame->locals.max == 0)
+                            stack.currentFrame->locals.max = INT_MAX;
+                        stack.currentFrame->args.instructionPtr += 5;
+                        break;
+                    
+                    default:               /* No repeat follows */
+                        if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
+                            RRETURN_NO_MATCH;
+                        stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
+                        NEXT_OPCODE;
+                }
+                
+                /* If the length of the reference is zero, just continue with the
+                 main loop. */
+                
+                if (stack.currentFrame->locals.length == 0)
+                    NEXT_OPCODE;
+                
+                /* First, ensure the minimum number of matches are present. */
+                
+                for (int i = 1; i <= min; i++) {
+                    if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
+                        RRETURN_NO_MATCH;
+                    stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
+                }
+                
+                /* If min = max, continue at the same level without recursion.
+                 They are not both allowed to be zero. */
+                
+                if (min == stack.currentFrame->locals.max)
+                    NEXT_OPCODE;
+                
+                /* If minimizing, keep trying and advancing the pointer */
+                
+                if (minimize) {
+                    for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                        RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
+                            RRETURN;
+                        stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
+                    }
+                    /* Control never reaches here */
+                }
+                
+                /* If maximizing, find the longest string and work backwards */
+                
+                else {
+                    stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
+                    for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                        if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
+                            break;
+                        stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
+                    }
+                    while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
+                        RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length;
+                    }
+                    RRETURN_NO_MATCH;
+                }
+                /* Control never reaches here */
+                
+            /* Match a bit-mapped character class, possibly repeatedly. This op code is
+             used when all the characters in the class have values in the range 0-255,
+             and either the matching is caseful, or the characters are in the range
+             0-127 when UTF-8 processing is enabled. The only difference between
+             OP_CLASS and OP_NCLASS occurs when a data character outside the range is
+             encountered.
+             
+             First, look past the end of the item to see if there is repeat information
+             following. Then obey similar code to character type repeats - written out
+             again for speed. */
+                
+            BEGIN_OPCODE(NCLASS):
+            BEGIN_OPCODE(CLASS):
+                stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1;                /* Save for matching */
+                stack.currentFrame->args.instructionPtr += 33;                     /* Advance past the item */
+                
+                switch (*stack.currentFrame->args.instructionPtr) {
+                    case OP_CRSTAR:
+                    case OP_CRMINSTAR:
+                    case OP_CRPLUS:
+                    case OP_CRMINPLUS:
+                    case OP_CRQUERY:
+                    case OP_CRMINQUERY:
+                        repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
+                        break;
+                        
+                    case OP_CRRANGE:
+                    case OP_CRMINRANGE:
+                        minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
+                        min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                        stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
+                        if (stack.currentFrame->locals.max == 0)
+                            stack.currentFrame->locals.max = INT_MAX;
+                        stack.currentFrame->args.instructionPtr += 5;
+                        break;
+                        
+                    default:               /* No repeat follows */
+                        min = stack.currentFrame->locals.max = 1;
+                        break;
+                }
+                
+                /* First, ensure the minimum number of matches are present. */
+                
+                for (int i = 1; i <= min; i++) {
+                    if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                        RRETURN_NO_MATCH;
+                    int c = *stack.currentFrame->args.subjectPtr++;
+                    if (c > 255) {
+                        if (stack.currentFrame->locals.data[-1] == OP_CLASS)
+                            RRETURN_NO_MATCH;
+                    } else {
+                        if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
+                            RRETURN_NO_MATCH;
+                    }
+                }
+                
+                /* If max == min we can continue with the main loop without the
+                 need to recurse. */
+                
+                if (min == stack.currentFrame->locals.max)
+                    NEXT_OPCODE;      
+                
+                /* If minimizing, keep testing the rest of the expression and advancing
+                 the pointer while it matches the class. */
+                if (minimize) {
+                    for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                        RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
+                            RRETURN;
+                        int c = *stack.currentFrame->args.subjectPtr++;
+                        if (c > 255) {
+                            if (stack.currentFrame->locals.data[-1] == OP_CLASS)
+                                RRETURN;
+                        } else {
+                            if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0)
+                                RRETURN;
+                        }
+                    }
+                    /* Control never reaches here */
+                }
+                /* If maximizing, find the longest possible run, then work backwards. */
+                else {
+                    stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
+                    
+                    for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                        if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                            break;
+                        int c = *stack.currentFrame->args.subjectPtr;
+                        if (c > 255) {
+                            if (stack.currentFrame->locals.data[-1] == OP_CLASS)
+                                break;
+                        } else {
+                            if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
+                                break;
+                        }
+                        ++stack.currentFrame->args.subjectPtr;
+                    }
+                    for (;;) {
+                        RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
+                            break;        /* Stop if tried at original pos */
+                    }
+                    
+                    RRETURN;
+                }
+                /* Control never reaches here */
+                
+            /* Match an extended character class. */
+                
+            BEGIN_OPCODE(XCLASS):
+                stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE;                /* Save for matching */
+                stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);                      /* Advance past the item */
+                
+                switch (*stack.currentFrame->args.instructionPtr) {
+                    case OP_CRSTAR:
+                    case OP_CRMINSTAR:
+                    case OP_CRPLUS:
+                    case OP_CRMINPLUS:
+                    case OP_CRQUERY:
+                    case OP_CRMINQUERY:
+                        repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
+                        break;
+                        
+                    case OP_CRRANGE:
+                    case OP_CRMINRANGE:
+                        minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
+                        min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                        stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
+                        if (stack.currentFrame->locals.max == 0)
+                            stack.currentFrame->locals.max = INT_MAX;
+                        stack.currentFrame->args.instructionPtr += 5;
+                        break;
+                        
+                    default:               /* No repeat follows */
+                        min = stack.currentFrame->locals.max = 1;
+                }
+                
+                /* First, ensure the minimum number of matches are present. */
+                
+                for (int i = 1; i <= min; i++) {
+                    if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                        RRETURN_NO_MATCH;
+                    int c = *stack.currentFrame->args.subjectPtr++;
+                    if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
+                        RRETURN_NO_MATCH;
+                }
+                
+                /* If max == min we can continue with the main loop without the
+                 need to recurse. */
+                
+                if (min == stack.currentFrame->locals.max)
+                    NEXT_OPCODE;
+                
+                /* If minimizing, keep testing the rest of the expression and advancing
+                 the pointer while it matches the class. */
+                
+                if (minimize) {
+                    for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                        RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
+                            RRETURN;
+                        int c = *stack.currentFrame->args.subjectPtr++;
+                        if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
+                            RRETURN;
+                    }
+                    /* Control never reaches here */
+                }
+                
+                /* If maximizing, find the longest possible run, then work backwards. */
+                
+                else {
+                    stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
+                    for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                        if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                            break;
+                        int c = *stack.currentFrame->args.subjectPtr;
+                        if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
+                            break;
+                        ++stack.currentFrame->args.subjectPtr;
+                    }
+                    for(;;) {
+                        RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
+                            break;        /* Stop if tried at original pos */
+                    }
+                    RRETURN;
+                }
+                
+                /* Control never reaches here */
+                
+            /* Match a single character, casefully */
+                
+            BEGIN_OPCODE(CHAR):
+                stack.currentFrame->locals.length = 1;
+                stack.currentFrame->args.instructionPtr++;
+                getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
+                stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++)
+                    RRETURN_NO_MATCH;
+                NEXT_OPCODE;
+                
+            /* Match a single character, caselessly */
+                
+            BEGIN_OPCODE(CHAR_IGNORING_CASE): {
+                stack.currentFrame->locals.length = 1;
+                stack.currentFrame->args.instructionPtr++;
+                getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
+                stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                int dc = *stack.currentFrame->args.subjectPtr++;
+                if (stack.currentFrame->locals.fc != dc && kjs_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc)
+                    RRETURN_NO_MATCH;
+                NEXT_OPCODE;
+            }
+                
+            /* Match a single ASCII character. */
+                
+            BEGIN_OPCODE(ASCII_CHAR):
+                if (md.endSubject == stack.currentFrame->args.subjectPtr)
+                    RRETURN_NO_MATCH;
+                if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1])
+                    RRETURN_NO_MATCH;
+                ++stack.currentFrame->args.subjectPtr;
+                stack.currentFrame->args.instructionPtr += 2;
+                NEXT_OPCODE;
+                
+            /* Match one of two cases of an ASCII letter. */
+                
+            BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE):
+                if (md.endSubject == stack.currentFrame->args.subjectPtr)
+                    RRETURN_NO_MATCH;
+                if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1])
+                    RRETURN_NO_MATCH;
+                ++stack.currentFrame->args.subjectPtr;
+                stack.currentFrame->args.instructionPtr += 2;
+                NEXT_OPCODE;
+                
+            /* Match a single character repeatedly; different opcodes share code. */
+                
+            BEGIN_OPCODE(EXACT):
+                min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                minimize = false;
+                stack.currentFrame->args.instructionPtr += 3;
+                goto REPEATCHAR;
+                
+            BEGIN_OPCODE(UPTO):
+            BEGIN_OPCODE(MINUPTO):
+                min = 0;
+                stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO;
+                stack.currentFrame->args.instructionPtr += 3;
+                goto REPEATCHAR;
+                
+            BEGIN_OPCODE(STAR):
+            BEGIN_OPCODE(MINSTAR):
+            BEGIN_OPCODE(PLUS):
+            BEGIN_OPCODE(MINPLUS):
+            BEGIN_OPCODE(QUERY):
+            BEGIN_OPCODE(MINQUERY):
+                repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max);
+                
+                /* Common code for all repeated single-character matches. We can give
+                 up quickly if there are fewer than the minimum number of characters left in
+                 the subject. */
+                
+            REPEATCHAR:
+                
+                stack.currentFrame->locals.length = 1;
+                getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
+                if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr)
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
+                
+                if (stack.currentFrame->locals.fc <= 0xFFFF) {
+                    int othercase = md.ignoreCase ? kjs_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1;
+                    
+                    for (int i = 1; i <= min; i++) {
+                        if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
+                            RRETURN_NO_MATCH;
+                        ++stack.currentFrame->args.subjectPtr;
+                    }
+                    
+                    if (min == stack.currentFrame->locals.max)
+                        NEXT_OPCODE;
+                    
+                    if (minimize) {
+                        stack.currentFrame->locals.repeatOthercase = othercase;
+                        for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                            RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                RRETURN;
+                            if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase)
+                                RRETURN;
+                            ++stack.currentFrame->args.subjectPtr;
+                        }
+                        /* Control never reaches here */
+                    } else {
+                        stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
+                        for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                            if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                break;
+                            if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
+                                break;
+                            ++stack.currentFrame->args.subjectPtr;
+                        }
+                        while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
+                            RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            --stack.currentFrame->args.subjectPtr;
+                        }
+                        RRETURN_NO_MATCH;
+                    }
+                    /* Control never reaches here */
+                } else {
+                    /* No case on surrogate pairs, so no need to bother with "othercase". */
+                    
+                    for (int i = 1; i <= min; i++) {
+                        if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
+                            RRETURN_NO_MATCH;
+                        stack.currentFrame->args.subjectPtr += 2;
+                    }
+                    
+                    if (min == stack.currentFrame->locals.max)
+                        NEXT_OPCODE;
+                    
+                    if (minimize) {
+                        for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                            RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                RRETURN;
+                            if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
+                                RRETURN;
+                            stack.currentFrame->args.subjectPtr += 2;
+                        }
+                        /* Control never reaches here */
+                    } else {
+                        stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
+                        for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                            if (stack.currentFrame->args.subjectPtr > md.endSubject - 2)
+                                break;
+                            if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
+                                break;
+                            stack.currentFrame->args.subjectPtr += 2;
+                        }
+                        while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
+                            RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            stack.currentFrame->args.subjectPtr -= 2;
+                        }
+                        RRETURN_NO_MATCH;
+                    }
+                    /* Control never reaches here */
+                }
+                /* Control never reaches here */
+                
+            /* Match a negated single one-byte character. */
+                
+            BEGIN_OPCODE(NOT): {
+                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->args.instructionPtr++;
+                int c = *stack.currentFrame->args.subjectPtr++;
+                if (md.ignoreCase) {
+                    if (c < 128)
+                        c = toLowerCase(c);
+                    if (toLowerCase(*stack.currentFrame->args.instructionPtr++) == c)
+                        RRETURN_NO_MATCH;
+                } else {
+                    if (*stack.currentFrame->args.instructionPtr++ == c)
+                        RRETURN_NO_MATCH;
+                }
+                NEXT_OPCODE;
+            }
+                
+            /* Match a negated single one-byte character repeatedly. This is almost a
+             repeat of the code for a repeated single character, but I haven't found a
+             nice way of commoning these up that doesn't require a test of the
+             positive/negative option for each character match. Maybe that wouldn't add
+             very much to the time taken, but character matching *is* what this is all
+             about... */
+                
+            BEGIN_OPCODE(NOTEXACT):
+                min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                minimize = false;
+                stack.currentFrame->args.instructionPtr += 3;
+                goto REPEATNOTCHAR;
+                
+            BEGIN_OPCODE(NOTUPTO):
+            BEGIN_OPCODE(NOTMINUPTO):
+                min = 0;
+                stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO;
+                stack.currentFrame->args.instructionPtr += 3;
+                goto REPEATNOTCHAR;
+                
+            BEGIN_OPCODE(NOTSTAR):
+            BEGIN_OPCODE(NOTMINSTAR):
+            BEGIN_OPCODE(NOTPLUS):
+            BEGIN_OPCODE(NOTMINPLUS):
+            BEGIN_OPCODE(NOTQUERY):
+            BEGIN_OPCODE(NOTMINQUERY):
+                repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max);
+                
+            /* Common code for all repeated single-byte matches. We can give up quickly
+             if there are fewer than the minimum number of bytes left in the
+             subject. */
+                
+            REPEATNOTCHAR:
+                if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
+                    RRETURN_NO_MATCH;
+                stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++;
+                
+                /* The code is duplicated for the caseless and caseful cases, for speed,
+                 since matching characters is likely to be quite common. First, ensure the
+                 minimum number of matches are present. If min = max, continue at the same
+                 level without recursing. Otherwise, if minimizing, keep trying the rest of
+                 the expression and advancing one matching character if failing, up to the
+                 maximum. Alternatively, if maximizing, find the maximum number of
+                 characters and work backwards. */
+                
+                DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max));
+                
+                if (md.ignoreCase) {
+                    if (stack.currentFrame->locals.fc < 128)
+                        stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc);
+                    
+                    for (int i = 1; i <= min; i++) {
+                        int d = *stack.currentFrame->args.subjectPtr++;
+                        if (d < 128)
+                            d = toLowerCase(d);
+                        if (stack.currentFrame->locals.fc == d)
+                            RRETURN_NO_MATCH;
+                    }
+                    
+                    if (min == stack.currentFrame->locals.max)
+                        NEXT_OPCODE;      
+                    
+                    if (minimize) {
+                        for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                            RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            int d = *stack.currentFrame->args.subjectPtr++;
+                            if (d < 128)
+                                d = toLowerCase(d);
+                            if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
+                                RRETURN;
+                        }
+                        /* Control never reaches here */
+                    }
+                    
+                    /* Maximize case */
+                    
+                    else {
+                        stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
+                        
+                        for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                            if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                break;
+                            int d = *stack.currentFrame->args.subjectPtr;
+                            if (d < 128)
+                                d = toLowerCase(d);
+                            if (stack.currentFrame->locals.fc == d)
+                                break;
+                            ++stack.currentFrame->args.subjectPtr;
+                        }
+                        for (;;) {
+                            RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
+                                break;        /* Stop if tried at original pos */
+                        }
+                        
+                        RRETURN;
+                    }
+                    /* Control never reaches here */
+                }
+                
+                /* Caseful comparisons */
+                
+                else {
+                    for (int i = 1; i <= min; i++) {
+                        int d = *stack.currentFrame->args.subjectPtr++;
+                        if (stack.currentFrame->locals.fc == d)
+                            RRETURN_NO_MATCH;
+                    }
+
+                    if (min == stack.currentFrame->locals.max)
+                        NEXT_OPCODE;
+                    
+                    if (minimize) {
+                        for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                            RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            int d = *stack.currentFrame->args.subjectPtr++;
+                            if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
+                                RRETURN;
+                        }
+                        /* Control never reaches here */
+                    }
+                    
+                    /* Maximize case */
+                    
+                    else {
+                        stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
+                        
+                        for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                            if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                break;
+                            int d = *stack.currentFrame->args.subjectPtr;
+                            if (stack.currentFrame->locals.fc == d)
+                                break;
+                            ++stack.currentFrame->args.subjectPtr;
+                        }
+                        for (;;) {
+                            RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                            if (isMatch)
+                                RRETURN;
+                            if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
+                                break;        /* Stop if tried at original pos */
+                        }
+
+                        RRETURN;
+                    }
+                }
+                /* Control never reaches here */
+                
+            /* Match a single character type repeatedly; several different opcodes
+             share code. This is very similar to the code for single characters, but we
+             repeat it in the interests of efficiency. */
+                
+            BEGIN_OPCODE(TYPEEXACT):
+                min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                minimize = true;
+                stack.currentFrame->args.instructionPtr += 3;
+                goto REPEATTYPE;
+                
+            BEGIN_OPCODE(TYPEUPTO):
+            BEGIN_OPCODE(TYPEMINUPTO):
+                min = 0;
+                stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
+                minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO;
+                stack.currentFrame->args.instructionPtr += 3;
+                goto REPEATTYPE;
+                
+            BEGIN_OPCODE(TYPESTAR):
+            BEGIN_OPCODE(TYPEMINSTAR):
+            BEGIN_OPCODE(TYPEPLUS):
+            BEGIN_OPCODE(TYPEMINPLUS):
+            BEGIN_OPCODE(TYPEQUERY):
+            BEGIN_OPCODE(TYPEMINQUERY):
+                repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max);
+                
+                /* Common code for all repeated single character type matches. Note that
+                 in UTF-8 mode, '.' matches a character of any length, but for the other
+                 character types, the valid characters are all one-byte long. */
+                
+            REPEATTYPE:
+                stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++;      /* Code for the character type */
+                
+                /* First, ensure the minimum number of matches are present. Use inline
+                 code for maximizing the speed, and do the type test once at the start
+                 (i.e. keep it out of the loop). Also we can test that there are at least
+                 the minimum number of characters before we start. */
+                
+                if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
+                    RRETURN_NO_MATCH;
+                if (min > 0) {
+                    switch (stack.currentFrame->locals.ctype) {
+                        case OP_NOT_NEWLINE:
+                            for (int i = 1; i <= min; i++) {
+                                if (isNewline(*stack.currentFrame->args.subjectPtr))
+                                    RRETURN_NO_MATCH;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_NOT_DIGIT:
+                            for (int i = 1; i <= min; i++) {
+                                if (isASCIIDigit(*stack.currentFrame->args.subjectPtr))
+                                    RRETURN_NO_MATCH;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_DIGIT:
+                            for (int i = 1; i <= min; i++) {
+                                if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr))
+                                    RRETURN_NO_MATCH;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_NOT_WHITESPACE:
+                            for (int i = 1; i <= min; i++) {
+                                if (isSpaceChar(*stack.currentFrame->args.subjectPtr))
+                                    RRETURN_NO_MATCH;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_WHITESPACE:
+                            for (int i = 1; i <= min; i++) {
+                                if (!isSpaceChar(*stack.currentFrame->args.subjectPtr))
+                                    RRETURN_NO_MATCH;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_NOT_WORDCHAR:
+                            for (int i = 1; i <= min; i++) {
+                                if (isWordChar(*stack.currentFrame->args.subjectPtr))
+                                    RRETURN_NO_MATCH;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_WORDCHAR:
+                            for (int i = 1; i <= min; i++) {
+                                if (!isWordChar(*stack.currentFrame->args.subjectPtr))
+                                    RRETURN_NO_MATCH;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        default:
+                            ASSERT_NOT_REACHED();
+                            return matchError(JSRegExpErrorInternal, stack);
+                    }  /* End switch(stack.currentFrame->locals.ctype) */
+                }
+                
+                /* If min = max, continue at the same level without recursing */
+                
+                if (min == stack.currentFrame->locals.max)
+                    NEXT_OPCODE;    
+                
+                /* If minimizing, we have to test the rest of the pattern before each
+                 subsequent match. */
+                
+                if (minimize) {
+                    for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
+                        RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
+                            RRETURN;
+                        
+                        int c = *stack.currentFrame->args.subjectPtr++;
+                        switch (stack.currentFrame->locals.ctype) {
+                            case OP_NOT_NEWLINE:
+                                if (isNewline(c))
+                                    RRETURN;
+                                break;
+                                
+                            case OP_NOT_DIGIT:
+                                if (isASCIIDigit(c))
+                                    RRETURN;
+                                break;
+                                
+                            case OP_DIGIT:
+                                if (!isASCIIDigit(c))
+                                    RRETURN;
+                                break;
+                                
+                            case OP_NOT_WHITESPACE:
+                                if (isSpaceChar(c))
+                                    RRETURN;
+                                break;
+                                
+                            case OP_WHITESPACE:
+                                if (!isSpaceChar(c))
+                                    RRETURN;
+                                break;
+                                
+                            case OP_NOT_WORDCHAR:
+                                if (isWordChar(c))
+                                    RRETURN;
+                                break;
+                                
+                            case OP_WORDCHAR:
+                                if (!isWordChar(c))
+                                    RRETURN;
+                                break;
+                                
+                            default:
+                                ASSERT_NOT_REACHED();
+                                return matchError(JSRegExpErrorInternal, stack);
+                        }
+                    }
+                    /* Control never reaches here */
+                }
+                
+                /* If maximizing it is worth using inline code for speed, doing the type
+                 test once at the start (i.e. keep it out of the loop). */
+                
+                else {
+                    stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;  /* Remember where we started */
+                    
+                    switch (stack.currentFrame->locals.ctype) {
+                        case OP_NOT_NEWLINE:
+                            for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                                if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr))
+                                    break;
+                                stack.currentFrame->args.subjectPtr++;
+                            }
+                            break;
+                            
+                        case OP_NOT_DIGIT:
+                            for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                    break;
+                                int c = *stack.currentFrame->args.subjectPtr;
+                                if (isASCIIDigit(c))
+                                    break;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_DIGIT:
+                            for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                    break;
+                                int c = *stack.currentFrame->args.subjectPtr;
+                                if (!isASCIIDigit(c))
+                                    break;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_NOT_WHITESPACE:
+                            for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                    break;
+                                int c = *stack.currentFrame->args.subjectPtr;
+                                if (isSpaceChar(c))
+                                    break;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_WHITESPACE:
+                            for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                    break;
+                                int c = *stack.currentFrame->args.subjectPtr;
+                                if (!isSpaceChar(c))
+                                    break;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_NOT_WORDCHAR:
+                            for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                    break;
+                                int c = *stack.currentFrame->args.subjectPtr;
+                                if (isWordChar(c))
+                                    break;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        case OP_WORDCHAR:
+                            for (int i = min; i < stack.currentFrame->locals.max; i++) {
+                                if (stack.currentFrame->args.subjectPtr >= md.endSubject)
+                                    break;
+                                int c = *stack.currentFrame->args.subjectPtr;
+                                if (!isWordChar(c))
+                                    break;
+                                ++stack.currentFrame->args.subjectPtr;
+                            }
+                            break;
+                            
+                        default:
+                            ASSERT_NOT_REACHED();
+                            return matchError(JSRegExpErrorInternal, stack);
+                    }
+                    
+                    /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */
+                    
+                    for (;;) {
+                        RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
+                            break;        /* Stop if tried at original pos */
+                    }
+                    
+                    /* Get here if we can't make it match with any permitted repetitions */
+                    
+                    RRETURN;
+                }
+                /* Control never reaches here */
+                
+            BEGIN_OPCODE(CRMINPLUS):
+            BEGIN_OPCODE(CRMINQUERY):
+            BEGIN_OPCODE(CRMINRANGE):
+            BEGIN_OPCODE(CRMINSTAR):
+            BEGIN_OPCODE(CRPLUS):
+            BEGIN_OPCODE(CRQUERY):
+            BEGIN_OPCODE(CRRANGE):
+            BEGIN_OPCODE(CRSTAR):
+                ASSERT_NOT_REACHED();
+                return matchError(JSRegExpErrorInternal, stack);
+                
+#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
+            CAPTURING_BRACKET:
+#else
+            default:
+#endif
+                /* Opening capturing bracket. If there is space in the offset vector, save
+                 the current subject position in the working slot at the top of the vector. We
+                 mustn't change the current values of the data slot, because they may be set
+                 from a previous iteration of this group, and be referred to by a reference
+                 inside the group.
+                 
+                 If the bracket fails to match, we need to restore this value and also the
+                 values of the final offsets, in case they were set by a previous iteration of
+                 the same bracket.
+                 
+                 If there isn't enough space in the offset vector, treat this as if it were a
+                 non-capturing bracket. Don't worry about setting the flag for the error case
+                 here; that is handled in the code for KET. */
+                
+                ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA);
+                
+                stack.currentFrame->locals.number = *stack.currentFrame->args.instructionPtr - OP_BRA;
+                
+                /* For extended extraction brackets (large number), we have to fish out the
+                 number from a dummy opcode at the start. */
+                
+                if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
+                    stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 2 + LINK_SIZE);
+                stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
+                
+#ifdef DEBUG
+                printf("start bracket %d subject=", stack.currentFrame->locals.number);
+                pchars(stack.currentFrame->args.subjectPtr, 16, true, md);
+                printf("\n");
+#endif
+                
+                if (stack.currentFrame->locals.offset < md.offsetMax) {
+                    stack.currentFrame->locals.saveOffset1 = md.offsetVector[stack.currentFrame->locals.offset];
+                    stack.currentFrame->locals.saveOffset2 = md.offsetVector[stack.currentFrame->locals.offset + 1];
+                    stack.currentFrame->locals.saveOffset3 = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
+                    
+                    DPRINTF(("saving %d %d %d\n", stack.currentFrame->locals.saveOffset1, stack.currentFrame->locals.saveOffset2, stack.currentFrame->locals.saveOffset3));
+                    md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject;
+                    
+                    do {
+                        RECURSIVE_MATCH_STARTNG_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
+                        if (isMatch)
+                            RRETURN;
+                        stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
+                    } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
+                    
+                    DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number));
+                    
+                    md.offsetVector[stack.currentFrame->locals.offset] = stack.currentFrame->locals.saveOffset1;
+                    md.offsetVector[stack.currentFrame->locals.offset + 1] = stack.currentFrame->locals.saveOffset2;
+                    md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.saveOffset3;
+                    
+                    RRETURN;
+                }
+                
+                /* Insufficient room for saving captured contents */
+                
+                goto NON_CAPTURING_BRACKET;
+        }
+        
+        /* Do not stick any code in here without much thought; it is assumed
+         that "continue" in the code above comes out to here to repeat the main
+         loop. */
+        
+    } /* End of main loop */
+    
+    ASSERT_NOT_REACHED();
+    
+#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
+    
+RRETURN_SWITCH:
+    switch (stack.currentFrame->returnLocation) {
+        case 0: goto RETURN;
+        case 1: goto RRETURN_1;
+        case 2: goto RRETURN_2;
+        case 6: goto RRETURN_6;
+        case 7: goto RRETURN_7;
+        case 14: goto RRETURN_14;
+        case 15: goto RRETURN_15;
+        case 16: goto RRETURN_16;
+        case 17: goto RRETURN_17;
+        case 18: goto RRETURN_18;
+        case 19: goto RRETURN_19;
+        case 20: goto RRETURN_20;
+        case 21: goto RRETURN_21;
+        case 22: goto RRETURN_22;
+        case 24: goto RRETURN_24;
+        case 26: goto RRETURN_26;
+        case 27: goto RRETURN_27;
+        case 28: goto RRETURN_28;
+        case 29: goto RRETURN_29;
+        case 30: goto RRETURN_30;
+        case 31: goto RRETURN_31;
+        case 38: goto RRETURN_38;
+        case 40: goto RRETURN_40;
+        case 42: goto RRETURN_42;
+        case 44: goto RRETURN_44;
+        case 48: goto RRETURN_48;
+        case 52: goto RRETURN_52;
+    }
+    
+    ASSERT_NOT_REACHED();
+    return matchError(JSRegExpErrorInternal, stack);
+    
+#endif
+    
+RETURN:
+    return isMatch;
+}
+
+
+/*************************************************
+*         Execute a Regular Expression           *
+*************************************************/
+
+/* This function applies a compiled re to a subject string and picks out
+portions of the string if it matches. Two elements in the vector are set for
+each substring: the offsets to the start and end of the substring.
+
+Arguments:
+  re              points to the compiled expression
+  extra_data      points to extra data or is NULL
+  subject         points to the subject string
+  length          length of subject string (may contain binary zeros)
+  start_offset    where to start in the subject string
+  options         option bits
+  offsets         points to a vector of ints to be filled in with offsets
+  offsetcount     the number of elements in the vector
+
+Returns:          > 0 => success; value is the number of elements filled in
+                  = 0 => success, but offsets is not big enough
+                   -1 => failed to match
+                 < -1 => some kind of unexpected problem
+*/
+
+static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int first_byte, bool first_byte_caseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart)
+{
+    // If first_byte is set, try scanning to the first instance of that byte
+    // no need to try and match against any earlier part of the subject string.
+    if (first_byte >= 0) {
+        UChar first_char = first_byte;
+        if (first_byte_caseless)
+            while (subjectPtr < endSubject) {
+                int c = *subjectPtr;
+                if (c > 127)
+                    break;
+                if (toLowerCase(c) == first_char)
+                    break;
+                subjectPtr++;
+            }
+        else {
+            while (subjectPtr < endSubject && *subjectPtr != first_char)
+                subjectPtr++;
+        }
+    } else if (useMultiLineFirstCharOptimization) {
+        /* Or to just after \n for a multiline match if possible */
+        // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07
+        if (subjectPtr > originalSubjectStart) {
+            while (subjectPtr < endSubject && !isNewline(subjectPtr[-1]))
+                subjectPtr++;
+        }
+    }
+}
+
+static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int req_byte, int req_byte2, bool req_byte_caseless, bool hasFirstByte, const UChar*& reqBytePtr)
+{
+    /* If req_byte is set, we know that that character must appear in the subject
+     for the match to succeed. If the first character is set, req_byte must be
+     later in the subject; otherwise the test starts at the match point. This
+     optimization can save a huge amount of backtracking in patterns with nested
+     unlimited repeats that aren't going to match. Writing separate code for
+     cased/caseless versions makes it go faster, as does using an autoincrement
+     and backing off on a match.
+     
+     HOWEVER: when the subject string is very, very long, searching to its end can
+     take a long time, and give bad performance on quite ordinary patterns. This
+     showed up when somebody was matching /^C/ on a 32-megabyte string... so we
+     don't do this when the string is sufficiently long.
+    */
+
+    if (req_byte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) {
+        const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0);
+
+        /* We don't need to repeat the search if we haven't yet reached the
+         place we found it at last time. */
+
+        if (p > reqBytePtr) {
+            if (req_byte_caseless) {
+                while (p < endSubject) {
+                    int pp = *p++;
+                    if (pp == req_byte || pp == req_byte2) {
+                        p--;
+                        break;
+                    }
+                }
+            } else {
+                while (p < endSubject) {
+                    if (*p++ == req_byte) {
+                        p--;
+                        break;
+                    }
+                }
+            }
+
+            /* If we can't find the required character, break the matching loop */
+
+            if (p >= endSubject)
+                return true;
+
+            /* If we have found the required character, save the point where we
+             found it, so that we don't search again next time round the loop if
+             the start hasn't passed this character yet. */
+
+            reqBytePtr = p;
+        }
+    }
+    return false;
+}
+
+int jsRegExpExecute(const JSRegExp* re,
+                    const UChar* subject, int length, int start_offset, int* offsets,
+                    int offsetcount)
+{
+    ASSERT(re);
+    ASSERT(subject);
+    ASSERT(offsetcount >= 0);
+    ASSERT(offsets || offsetcount == 0);
+    
+    MatchData matchBlock;
+    matchBlock.startSubject = subject;
+    matchBlock.endSubject = matchBlock.startSubject + length;
+    const UChar* endSubject = matchBlock.endSubject;
+    
+    matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption);
+    matchBlock.ignoreCase = (re->options & IgnoreCaseOption);
+    
+    /* If the expression has got more back references than the offsets supplied can
+     hold, we get a temporary chunk of working store to use during the matching.
+     Otherwise, we can use the vector supplied, rounding down its size to a multiple
+     of 3. */
+    
+    int ocount = offsetcount - (offsetcount % 3);
+    
+    // FIXME: This is lame that we have to second-guess our caller here.
+    // The API should change to either fail-hard when we don't have enough offset space
+    // or that we shouldn't ask our callers to pre-allocate in the first place.
+    bool using_temporary_offsets = false;
+    if (re->top_backref > 0 && re->top_backref >= ocount/3) {
+        ocount = re->top_backref * 3 + 3;
+        matchBlock.offsetVector = new int[ocount];
+        if (!matchBlock.offsetVector)
+            return JSRegExpErrorNoMemory;
+        using_temporary_offsets = true;
+    } else
+        matchBlock.offsetVector = offsets;
+    
+    matchBlock.offsetEnd = ocount;
+    matchBlock.offsetMax = (2*ocount)/3;
+    matchBlock.offsetOverflow = false;
+    
+    /* Compute the minimum number of offsets that we need to reset each time. Doing
+     this makes a huge difference to execution time when there aren't many brackets
+     in the pattern. */
+    
+    int resetcount = 2 + re->top_bracket * 2;
+    if (resetcount > offsetcount)
+        resetcount = ocount;
+    
+    /* Reset the working variable associated with each extraction. These should
+     never be used unless previously set, but they get saved and restored, and so we
+     initialize them to avoid reading uninitialized locations. */
+    
+    if (matchBlock.offsetVector) {
+        int* iptr = matchBlock.offsetVector + ocount;
+        int* iend = iptr - resetcount/2 + 1;
+        while (--iptr >= iend)
+            *iptr = -1;
+    }
+    
+    /* Set up the first character to match, if available. The first_byte value is
+     never set for an anchored regular expression, but the anchoring may be forced
+     at run time, so we have to test for anchoring. The first char may be unset for
+     an unanchored pattern, of course. If there's no first char and the pattern was
+     studied, there may be a bitmap of possible first characters. */
+    
+    bool first_byte_caseless = false;
+    int first_byte = -1;
+    if (re->options & UseFirstByteOptimizationOption) {
+        first_byte = re->first_byte & 255;
+        if ((first_byte_caseless = (re->first_byte & REQ_IGNORE_CASE)))
+            first_byte = toLowerCase(first_byte);
+    }
+    
+    /* For anchored or unanchored matches, there may be a "last known required
+     character" set. */
+    
+    bool req_byte_caseless = false;
+    int req_byte = -1;
+    int req_byte2 = -1;
+    if (re->options & UseRequiredByteOptimizationOption) {
+        req_byte = re->req_byte & 255; // FIXME: This optimization could be made to work for UTF16 chars as well...
+        req_byte_caseless = (re->req_byte & REQ_IGNORE_CASE);
+        req_byte2 = flipCase(req_byte);
+    }
+    
+    /* Loop for handling unanchored repeated matching attempts; for anchored regexs
+     the loop runs just once. */
+    
+    const UChar* startMatch = subject + start_offset;
+    const UChar* reqBytePtr = startMatch - 1;
+    bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption;
+    
+    do {
+        /* Reset the maximum number of extractions we might see. */
+        if (matchBlock.offsetVector) {
+            int* iptr = matchBlock.offsetVector;
+            int* iend = iptr + resetcount;
+            while (iptr < iend)
+                *iptr++ = -1;
+        }
+        
+        tryFirstByteOptimization(startMatch, endSubject, first_byte, first_byte_caseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset);
+        if (tryRequiredByteOptimization(startMatch, endSubject, req_byte, req_byte2, req_byte_caseless, first_byte >= 0, reqBytePtr))
+            break;
+                
+        /* When a match occurs, substrings will be set for all internal extractions;
+         we just need to set up the whole thing as substring 0 before returning. If
+         there were too many extractions, set the return code to zero. In the case
+         where we had to get some local store to hold offsets for backreferences, copy
+         those back references that we can. In this case there need not be overflow
+         if certain parts of the pattern were not used. */
+        
+        /* The code starts after the JSRegExp block and the capture name table. */
+        const unsigned char* start_code = (const unsigned char*)(re + 1);
+        
+        int returnCode = match(startMatch, start_code, 2, matchBlock);
+        
+        /* When the result is no match, advance the pointer to the next character
+         and continue. */
+        if (returnCode == 0) {
+            startMatch++;
+            continue;
+        }
+
+        if (returnCode != 1) {
+            ASSERT(returnCode == JSRegExpErrorHitLimit || returnCode == JSRegExpErrorNoMemory);
+            DPRINTF((">>>> error: returning %d\n", returnCode));
+            return returnCode;
+        }
+        
+        /* We have a match! Copy the offset information from temporary store if
+         necessary */
+        
+        if (using_temporary_offsets) {
+            if (offsetcount >= 4) {
+                memcpy(offsets + 2, matchBlock.offsetVector + 2, (offsetcount - 2) * sizeof(int));
+                DPRINTF(("Copied offsets from temporary memory\n"));
+            }
+            if (matchBlock.endOffsetTop > offsetcount)
+                matchBlock.offsetOverflow = true;
+            
+            DPRINTF(("Freeing temporary memory\n"));
+            delete [] matchBlock.offsetVector;
+        }
+        
+        returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2;
+        
+        if (offsetcount < 2)
+            returnCode = 0;
+        else {
+            offsets[0] = startMatch - matchBlock.startSubject;
+            offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject;
+        }
+        
+        DPRINTF((">>>> returning %d\n", returnCode));
+        return returnCode;
+    } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject);
+    
+    if (using_temporary_offsets) {
+        DPRINTF(("Freeing temporary memory\n"));
+        delete [] matchBlock.offsetVector;
+    }
+    
+    DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
+    return JSRegExpErrorNoMatch;
+}
diff --git a/regexp2000/src/third_party/jscre/pcre_internal.h b/regexp2000/src/third_party/jscre/pcre_internal.h
new file mode 100644 (file)
index 0000000..8480c90
--- /dev/null
@@ -0,0 +1,423 @@
+/* This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed. This library now supports only the regular expression features
+required by the JavaScript language specification, and has only the functions
+needed by JavaScriptCore and the rest of WebKit.
+
+                 Originally written by Philip Hazel
+           Copyright (c) 1997-2006 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. 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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+/* This header contains definitions that are shared between the different
+modules, but which are not relevant to the exported API. This includes some
+functions whose names all begin with "_pcre_". */
+
+#ifndef PCRE_INTERNAL_H
+#define PCRE_INTERNAL_H
+
+/* Bit definitions for entries in the pcre_ctypes table. */
+
+#define ctype_space   0x01
+#define ctype_xdigit  0x08
+#define ctype_word    0x10   /* alphameric or '_' */
+
+/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
+of bits for a class map. Some classes are built by combining these tables. */
+
+#define cbit_space     0      /* \s */
+#define cbit_digit    32      /* \d */
+#define cbit_word     64      /* \w */
+#define cbit_length   96      /* Length of the cbits table */
+
+/* Offsets of the various tables from the base tables pointer, and
+total length. */
+
+#define lcc_offset      0
+#define fcc_offset    128
+#define cbits_offset  256
+#define ctypes_offset (cbits_offset + cbit_length)
+#define tables_length (ctypes_offset + 128)
+
+#ifndef DFTABLES
+
+// TODO: Hook this up to something that checks assertions.
+#define ASSERT(x) do { } while(0)
+#define ASSERT_NOT_REACHED() do {} while(0)
+
+#ifdef WIN32
+#pragma warning(disable: 4232)
+#pragma warning(disable: 4244)
+#endif
+
+#include "pcre.h"
+
+/* The value of LINK_SIZE determines the number of bytes used to store links as
+offsets within the compiled regex. The default is 2, which allows for compiled
+patterns up to 64K long. */
+
+#define LINK_SIZE   2
+
+/* Define DEBUG to get debugging output on stdout. */
+
+#if 0
+#define DEBUG
+#endif
+
+/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
+inline, and there are *still* stupid compilers about that don't like indented
+pre-processor statements, or at least there were when I first wrote this. After
+all, it had only been about 10 years then... */
+
+#ifdef DEBUG
+#define DPRINTF(p) printf p
+#else
+#define DPRINTF(p) /*nothing*/
+#endif
+
+/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored
+in big-endian order) by default. These are used, for example, to link from the
+start of a subpattern to its alternatives and its end. The use of 2 bytes per
+offset limits the size of the compiled regex to around 64K, which is big enough
+for almost everybody. However, I received a request for an even bigger limit.
+For this reason, and also to make the code easier to maintain, the storing and
+loading of offsets from the byte string is now handled by the functions that are
+defined here. */
+
+/* PCRE uses some other 2-byte quantities that do not change when the size of
+offsets changes. There are used for repeat counts and for other things such as
+capturing parenthesis numbers in back references. */
+
+static inline void put2ByteValue(unsigned char* opcodePtr, int value)
+{
+    ASSERT(value >= 0 && value <= 0xFFFF);
+    opcodePtr[0] = value >> 8;
+    opcodePtr[1] = value;
+}
+
+static inline int get2ByteValue(const unsigned char* opcodePtr)
+{
+    return (opcodePtr[0] << 8) | opcodePtr[1];
+}
+
+static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value)
+{
+    put2ByteValue(opcodePtr, value);
+    opcodePtr += 2;
+}
+
+static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value)
+{
+    put2ByteValue(opcodePtr, value);
+}
+
+static inline int getLinkValueAllowZero(const unsigned char* opcodePtr)
+{
+    return get2ByteValue(opcodePtr);
+}
+
+#define MAX_PATTERN_SIZE (1 << 16)
+
+static inline void putLinkValue(unsigned char* opcodePtr, int value)
+{
+    ASSERT(value);
+    putLinkValueAllowZero(opcodePtr, value);
+}
+
+static inline int getLinkValue(const unsigned char* opcodePtr)
+{
+    int value = getLinkValueAllowZero(opcodePtr);
+    ASSERT(value);
+    return value;
+}
+
+static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value)
+{
+    putLinkValue(opcodePtr, value);
+    opcodePtr += LINK_SIZE;
+}
+
+static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value)
+{
+    putLinkValueAllowZero(opcodePtr, value);
+    opcodePtr += LINK_SIZE;
+}
+
+// FIXME: These are really more of a "compiled regexp state" than "regexp options"
+enum RegExpOptions {
+    UseFirstByteOptimizationOption = 0x40000000,  /* first_byte is set */
+    UseRequiredByteOptimizationOption = 0x20000000,  /* req_byte is set */
+    UseMultiLineFirstByteOptimizationOption = 0x10000000,  /* start after \n for multiline */
+    IsAnchoredOption = 0x02000000,  /* can't use partial with this regex */
+    IgnoreCaseOption = 0x00000001,
+    MatchAcrossMultipleLinesOption = 0x00000002
+};
+
+/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a
+variable-length repeat, or a anything other than literal characters. */
+
+#define REQ_IGNORE_CASE 0x0100    /* indicates should ignore case */
+#define REQ_VARY     0x0200    /* reqbyte followed non-literal item */
+
+/* Miscellaneous definitions */
+
+/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
+contain UTF-8 characters with values greater than 255. */
+
+#define XCL_NOT    0x01    /* Flag: this is a negative class */
+#define XCL_MAP    0x02    /* Flag: a 32-byte map is present */
+
+#define XCL_END       0    /* Marks end of individual items */
+#define XCL_SINGLE    1    /* Single item (one multibyte char) follows */
+#define XCL_RANGE     2    /* A range (two multibyte chars) follows */
+
+/* These are escaped items that aren't just an encoding of a particular data
+value such as \n. They must have non-zero values, as check_escape() returns
+their negation. Also, they must appear in the same order as in the opcode
+definitions below, up to ESC_w. The final one must be
+ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two
+tests in the code for an escape > ESC_b and <= ESC_w to
+detect the types that may be repeated. These are the types that consume
+characters. If any new escapes are put in between that don't consume a
+character, that code will have to change. */
+
+enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF };
+
+/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
+that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
+OP_EOD must correspond in order to the list of escapes immediately above.
+Note that whenever this list is updated, the two macro definitions that follow
+must also be updated to match. */
+
+#define FOR_EACH_OPCODE(macro) \
+    macro(END) \
+    \
+    macro(NOT_WORD_BOUNDARY) \
+    macro(WORD_BOUNDARY) \
+    macro(NOT_DIGIT) \
+    macro(DIGIT) \
+    macro(NOT_WHITESPACE) \
+    macro(WHITESPACE) \
+    macro(NOT_WORDCHAR) \
+    macro(WORDCHAR) \
+    \
+    macro(NOT_NEWLINE) \
+    \
+    macro(CIRC) \
+    macro(DOLL) \
+    macro(BOL) \
+    macro(EOL) \
+    macro(CHAR) \
+    macro(CHAR_IGNORING_CASE) \
+    macro(ASCII_CHAR) \
+    macro(ASCII_LETTER_IGNORING_CASE) \
+    macro(NOT) \
+    \
+    macro(STAR) \
+    macro(MINSTAR) \
+    macro(PLUS) \
+    macro(MINPLUS) \
+    macro(QUERY) \
+    macro(MINQUERY) \
+    macro(UPTO) \
+    macro(MINUPTO) \
+    macro(EXACT) \
+    \
+    macro(NOTSTAR) \
+    macro(NOTMINSTAR) \
+    macro(NOTPLUS) \
+    macro(NOTMINPLUS) \
+    macro(NOTQUERY) \
+    macro(NOTMINQUERY) \
+    macro(NOTUPTO) \
+    macro(NOTMINUPTO) \
+    macro(NOTEXACT) \
+    \
+    macro(TYPESTAR) \
+    macro(TYPEMINSTAR) \
+    macro(TYPEPLUS) \
+    macro(TYPEMINPLUS) \
+    macro(TYPEQUERY) \
+    macro(TYPEMINQUERY) \
+    macro(TYPEUPTO) \
+    macro(TYPEMINUPTO) \
+    macro(TYPEEXACT) \
+    \
+    macro(CRSTAR) \
+    macro(CRMINSTAR) \
+    macro(CRPLUS) \
+    macro(CRMINPLUS) \
+    macro(CRQUERY) \
+    macro(CRMINQUERY) \
+    macro(CRRANGE) \
+    macro(CRMINRANGE) \
+    \
+    macro(CLASS) \
+    macro(NCLASS) \
+    macro(XCLASS) \
+    \
+    macro(REF) \
+    \
+    macro(ALT) \
+    macro(KET) \
+    macro(KETRMAX) \
+    macro(KETRMIN) \
+    \
+    macro(ASSERT) \
+    macro(ASSERT_NOT) \
+    \
+    macro(BRAZERO) \
+    macro(BRAMINZERO) \
+    macro(BRANUMBER) \
+    macro(BRA)
+
+#define OPCODE_ENUM_VALUE(opcode) OP_##opcode,
+enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) };
+
+/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and
+study.c that all opcodes are less than 128 in value. This makes handling UTF-8
+character sequences easier. */
+
+/* The highest extraction number before we have to start using additional
+bytes. (Originally PCRE didn't have support for extraction counts higher than
+this number.) The value is limited by the number of opcodes left after OP_BRA,
+i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
+opcodes. */
+
+/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above
+are in conflict! */
+
+#define EXTRACT_BASIC_MAX  100
+
+/* The index of names and the
+code vector run on as long as necessary after the end. We store an explicit
+offset to the name table so that if a regex is compiled on one host, saved, and
+then run on another where the size of pointers is different, all might still
+be well. For the case of compiled-on-4 and run-on-8, we include an extra
+pointer that is always NULL.
+*/
+
+struct JSRegExp {
+    unsigned options;
+
+    unsigned short top_bracket;
+    unsigned short top_backref;
+    
+    unsigned short first_byte;
+    unsigned short req_byte;
+};
+
+/* Internal shared data tables. These are tables that are used by more than one
+ of the exported public functions. They have to be "external" in the C sense,
+ but are not part of the PCRE public API. The data for these tables is in the
+ pcre_tables.c module. */
+
+#define kjs_pcre_utf8_table1_size 6
+
+extern const int    kjs_pcre_utf8_table1[6];
+extern const int    kjs_pcre_utf8_table2[6];
+extern const int    kjs_pcre_utf8_table3[6];
+extern const unsigned char kjs_pcre_utf8_table4[0x40];
+
+extern const unsigned char kjs_pcre_default_tables[tables_length];
+
+static inline unsigned char toLowerCase(unsigned char c)
+{
+    static const unsigned char* lowerCaseChars = kjs_pcre_default_tables + lcc_offset;
+    return lowerCaseChars[c];
+}
+
+static inline unsigned char flipCase(unsigned char c)
+{
+    static const unsigned char* flippedCaseChars = kjs_pcre_default_tables + fcc_offset;
+    return flippedCaseChars[c];
+}
+
+static inline unsigned char classBitmapForChar(unsigned char c)
+{
+    static const unsigned char* charClassBitmaps = kjs_pcre_default_tables + cbits_offset;
+    return charClassBitmaps[c];
+}
+
+static inline unsigned char charTypeForChar(unsigned char c)
+{
+    const unsigned char* charTypeMap = kjs_pcre_default_tables + ctypes_offset;
+    return charTypeMap[c];
+}
+
+static inline bool isWordChar(UChar c)
+{
+    return c < 128 && (charTypeForChar(c) & ctype_word);
+}
+
+static inline bool isSpaceChar(UChar c)
+{
+    return (c < 128 && (charTypeForChar(c) & ctype_space));
+}
+
+static inline bool isNewline(UChar nl)
+{
+    return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029);
+}
+
+static inline bool isBracketStartOpcode(unsigned char opcode)
+{
+    if (opcode >= OP_BRA)
+        return true;
+    switch (opcode) {
+        case OP_ASSERT:
+        case OP_ASSERT_NOT:
+            return true;
+        default:
+            return false;
+    }
+}
+
+static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr)
+{
+    ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT);
+    do
+        opcodePtr += getLinkValue(opcodePtr + 1);
+    while (*opcodePtr == OP_ALT);
+}
+
+/* Internal shared functions. These are functions that are used in more
+that one of the source files. They have to have external linkage, but
+but are not part of the public API and so not exported from the library. */
+
+extern int kjs_pcre_ucp_othercase(unsigned);
+extern bool kjs_pcre_xclass(int, const unsigned char*);
+
+#endif
+
+#endif
+
+/* End of pcre_internal.h */
diff --git a/regexp2000/src/third_party/jscre/pcre_tables.cpp b/regexp2000/src/third_party/jscre/pcre_tables.cpp
new file mode 100644 (file)
index 0000000..a41cb27
--- /dev/null
@@ -0,0 +1,71 @@
+/* This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed. This library now supports only the regular expression features
+required by the JavaScript language specification, and has only the functions
+needed by JavaScriptCore and the rest of WebKit.
+
+                 Originally written by Philip Hazel
+           Copyright (c) 1997-2006 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. 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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains some fixed tables that are used by more than one of the
+PCRE code modules. */
+
+#include "pcre_internal.h"
+
+/*************************************************
+*           Tables for UTF-8 support             *
+*************************************************/
+
+/* These are the breakpoints for different numbers of bytes in a UTF-8
+character. */
+
+const int kjs_pcre_utf8_table1[6] =
+  { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
+
+/* These are the indicator bits and the mask for the data bits to set in the
+first byte of a character, indexed by the number of additional bytes. */
+
+const int kjs_pcre_utf8_table2[6] = { 0,    0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+const int kjs_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+/* Table of the number of extra characters, indexed by the first character
+masked with 0x3f. The highest number for a valid UTF-8 character is in fact
+0x3d. */
+
+const unsigned char kjs_pcre_utf8_table4[0x40] = {
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+#include "pcre_chartables.c"
diff --git a/regexp2000/src/third_party/jscre/pcre_ucp_searchfuncs.cpp b/regexp2000/src/third_party/jscre/pcre_ucp_searchfuncs.cpp
new file mode 100644 (file)
index 0000000..f63bdbc
--- /dev/null
@@ -0,0 +1,98 @@
+/* This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed. This library now supports only the regular expression features
+required by the JavaScript language specification, and has only the functions
+needed by JavaScriptCore and the rest of WebKit.
+
+                 Originally written by Philip Hazel
+           Copyright (c) 1997-2006 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. 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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains code for searching the table of Unicode character
+properties. */
+
+#include "pcre_internal.h"
+
+#include "ucpinternal.h"       /* Internal table details */
+#include "ucptable.cpp"        /* The table itself */
+
+/*************************************************
+*       Search table and return other case       *
+*************************************************/
+
+/* If the given character is a letter, and there is another case for the
+letter, return the other case. Otherwise, return -1.
+
+Arguments:
+  c           the character value
+
+Returns:      the other case or -1 if none
+*/
+
+int kjs_pcre_ucp_othercase(unsigned c)
+{
+    int bot = 0;
+    int top = sizeof(ucp_table) / sizeof(cnode);
+    int mid;
+    
+    /* The table is searched using a binary chop. You might think that using
+     intermediate variables to hold some of the common expressions would speed
+     things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it
+     makes things a lot slower. */
+    
+    for (;;) {
+        if (top <= bot)
+            return -1;
+        mid = (bot + top) >> 1;
+        if (c == (ucp_table[mid].f0 & f0_charmask))
+            break;
+        if (c < (ucp_table[mid].f0 & f0_charmask))
+            top = mid;
+        else {
+            if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask)))
+                break;
+            bot = mid + 1;
+        }
+    }
+    
+    /* Found an entry in the table. Return -1 for a range entry. Otherwise return
+     the other case if there is one, else -1. */
+    
+    if (ucp_table[mid].f0 & f0_rangeflag)
+        return -1;
+    
+    int offset = ucp_table[mid].f1 & f1_casemask;
+    if (offset & f1_caseneg)
+        offset |= f1_caseneg;
+    return !offset ? -1 : c + offset;
+}
diff --git a/regexp2000/src/third_party/jscre/pcre_xclass.cpp b/regexp2000/src/third_party/jscre/pcre_xclass.cpp
new file mode 100644 (file)
index 0000000..4bf2a25
--- /dev/null
@@ -0,0 +1,114 @@
+/* This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed. This library now supports only the regular expression features
+required by the JavaScript language specification, and has only the functions
+needed by JavaScriptCore and the rest of WebKit.
+
+                 Originally written by Philip Hazel
+           Copyright (c) 1997-2006 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. 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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains an internal function that is used to match an extended
+class (one that contains characters whose values are > 255). */
+
+#include "pcre_internal.h"
+
+/*************************************************
+*       Match character against an XCLASS        *
+*************************************************/
+
+/* This function is called to match a character against an extended class that
+might contain values > 255.
+
+Arguments:
+  c           the character
+  data        points to the flag byte of the XCLASS data
+
+Returns:      true if character matches, else false
+*/
+
+/* Get the next UTF-8 character, advancing the pointer. This is called when we
+ know we are in UTF-8 mode. */
+
+static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr)
+{
+    c = *subjectPtr++;
+    if ((c & 0xc0) == 0xc0) {
+        int gcaa = kjs_pcre_utf8_table4[c & 0x3f];  /* Number of additional bytes */
+        int gcss = 6 * gcaa;
+        c = (c & kjs_pcre_utf8_table3[gcaa]) << gcss;
+        while (gcaa-- > 0) {
+            gcss -= 6;
+            c |= (*subjectPtr++ & 0x3f) << gcss;
+        }
+    }
+}
+
+bool kjs_pcre_xclass(int c, const unsigned char* data)
+{
+    bool negated = (*data & XCL_NOT);
+    
+    /* Character values < 256 are matched against a bitmap, if one is present. If
+     not, we still carry on, because there may be ranges that start below 256 in the
+     additional data. */
+    
+    if (c < 256) {
+        if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0)
+            return !negated;   /* char found */
+    }
+    
+    /* First skip the bit map if present. Then match against the list of Unicode
+     properties or large chars or ranges that end with a large char. We won't ever
+     encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */
+    
+    if ((*data++ & XCL_MAP) != 0)
+        data += 32;
+    
+    int t;
+    while ((t = *data++) != XCL_END) {
+        if (t == XCL_SINGLE) {
+            int x;
+            getUTF8CharAndAdvancePointer(x, data);
+            if (c == x)
+                return !negated;
+        }
+        else if (t == XCL_RANGE) {
+            int x, y;
+            getUTF8CharAndAdvancePointer(x, data);
+            getUTF8CharAndAdvancePointer(y, data);
+            if (c >= x && c <= y)
+                return !negated;
+        }
+    }
+    
+    return negated;   /* char did not match */
+}
diff --git a/regexp2000/src/third_party/jscre/ucpinternal.h b/regexp2000/src/third_party/jscre/ucpinternal.h
new file mode 100644 (file)
index 0000000..c8bc4aa
--- /dev/null
@@ -0,0 +1,126 @@
+/* This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed. This library now supports only the regular expression features
+required by the JavaScript language specification, and has only the functions
+needed by JavaScriptCore and the rest of WebKit.
+
+                 Originally written by Philip Hazel
+           Copyright (c) 1997-2006 University of Cambridge
+    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. 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 the University of Cambridge 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.
+-----------------------------------------------------------------------------
+*/
+
+/*************************************************
+*           Unicode Property Table handler       *
+*************************************************/
+
+/* Internal header file defining the layout of the bits in each pair of 32-bit
+words that form a data item in the table. */
+
+typedef struct cnode {
+  unsigned f0;
+  unsigned f1;
+} cnode;
+
+/* Things for the f0 field */
+
+#define f0_scriptmask   0xff000000  /* Mask for script field */
+#define f0_scriptshift          24  /* Shift for script value */
+#define f0_rangeflag    0x00f00000  /* Flag for a range item */
+#define f0_charmask     0x001fffff  /* Mask for code point value */
+
+/* Things for the f1 field */
+
+#define f1_typemask     0xfc000000  /* Mask for char type field */
+#define f1_typeshift            26  /* Shift for the type field */
+#define f1_rangemask    0x0000ffff  /* Mask for a range offset */
+#define f1_casemask     0x0000ffff  /* Mask for a case offset */
+#define f1_caseneg      0xffff8000  /* Bits for negation */
+
+/* The data consists of a vector of structures of type cnode. The two unsigned
+32-bit integers are used as follows:
+
+(f0) (1) The most significant byte holds the script number. The numbers are
+         defined by the enum in ucp.h.
+
+     (2) The 0x00800000 bit is set if this entry defines a range of characters.
+         It is not set if this entry defines a single character
+
+     (3) The 0x00600000 bits are spare.
+
+     (4) The 0x001fffff bits contain the code point. No Unicode code point will
+         ever be greater than 0x0010ffff, so this should be OK for ever.
+
+(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are
+         defined by an enum in ucp.h.
+
+     (2) The 0x03ff0000 bits are spare.
+
+     (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of
+         range if this entry defines a range, OR the *signed* offset to the
+         character's "other case" partner if this entry defines a single
+         character. There is no partner if the value is zero.
+
+-------------------------------------------------------------------------------
+| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) |
+-------------------------------------------------------------------------------
+              | | |                              | |
+              | | |-> spare                      | |-> spare
+              | |                                |
+              | |-> spare                        |-> spare
+              |
+              |-> range flag
+
+The upper/lower casing information is set only for characters that come in
+pairs. The non-one-to-one mappings in the Unicode data are ignored.
+
+When searching the data, proceed as follows:
+
+(1) Set up for a binary chop search.
+
+(2) If the top is not greater than the bottom, the character is not in the
+    table. Its type must therefore be "Cn" ("Undefined").
+
+(3) Find the middle vector element.
+
+(4) Extract the code point and compare. If equal, we are done.
+
+(5) If the test character is smaller, set the top to the current point, and
+    goto (2).
+
+(6) If the current entry defines a range, compute the last character by adding
+    the offset, and see if the test character is within the range. If it is,
+    we are done.
+
+(7) Otherwise, set the bottom to one element past the current point and goto
+    (2).
+*/
+
+/* End of ucpinternal.h */
diff --git a/regexp2000/src/third_party/jscre/ucptable.cpp b/regexp2000/src/third_party/jscre/ucptable.cpp
new file mode 100644 (file)
index 0000000..011f7f5
--- /dev/null
@@ -0,0 +1,2968 @@
+/* This source module is automatically generated from the Unicode
+property table. See ucpinternal.h for a description of the layout. */
+
+static const cnode ucp_table[] = {
+  { 0x09800000, 0x0000001f },
+  { 0x09000020, 0x74000000 },
+  { 0x09800021, 0x54000002 },
+  { 0x09000024, 0x5c000000 },
+  { 0x09800025, 0x54000002 },
+  { 0x09000028, 0x58000000 },
+  { 0x09000029, 0x48000000 },
+  { 0x0900002a, 0x54000000 },
+  { 0x0900002b, 0x64000000 },
+  { 0x0900002c, 0x54000000 },
+  { 0x0900002d, 0x44000000 },
+  { 0x0980002e, 0x54000001 },
+  { 0x09800030, 0x34000009 },
+  { 0x0980003a, 0x54000001 },
+  { 0x0980003c, 0x64000002 },
+  { 0x0980003f, 0x54000001 },
+  { 0x21000041, 0x24000020 },
+  { 0x21000042, 0x24000020 },
+  { 0x21000043, 0x24000020 },
+  { 0x21000044, 0x24000020 },
+  { 0x21000045, 0x24000020 },
+  { 0x21000046, 0x24000020 },
+  { 0x21000047, 0x24000020 },
+  { 0x21000048, 0x24000020 },
+  { 0x21000049, 0x24000020 },
+  { 0x2100004a, 0x24000020 },
+  { 0x2100004b, 0x24000020 },
+  { 0x2100004c, 0x24000020 },
+  { 0x2100004d, 0x24000020 },
+  { 0x2100004e, 0x24000020 },
+  { 0x2100004f, 0x24000020 },
+  { 0x21000050, 0x24000020 },
+  { 0x21000051, 0x24000020 },
+  { 0x21000052, 0x24000020 },
+  { 0x21000053, 0x24000020 },
+  { 0x21000054, 0x24000020 },
+  { 0x21000055, 0x24000020 },
+  { 0x21000056, 0x24000020 },
+  { 0x21000057, 0x24000020 },
+  { 0x21000058, 0x24000020 },
+  { 0x21000059, 0x24000020 },
+  { 0x2100005a, 0x24000020 },
+  { 0x0900005b, 0x58000000 },
+  { 0x0900005c, 0x54000000 },
+  { 0x0900005d, 0x48000000 },
+  { 0x0900005e, 0x60000000 },
+  { 0x0900005f, 0x40000000 },
+  { 0x09000060, 0x60000000 },
+  { 0x21000061, 0x1400ffe0 },
+  { 0x21000062, 0x1400ffe0 },
+  { 0x21000063, 0x1400ffe0 },
+  { 0x21000064, 0x1400ffe0 },
+  { 0x21000065, 0x1400ffe0 },
+  { 0x21000066, 0x1400ffe0 },
+  { 0x21000067, 0x1400ffe0 },
+  { 0x21000068, 0x1400ffe0 },
+  { 0x21000069, 0x1400ffe0 },
+  { 0x2100006a, 0x1400ffe0 },
+  { 0x2100006b, 0x1400ffe0 },
+  { 0x2100006c, 0x1400ffe0 },
+  { 0x2100006d, 0x1400ffe0 },
+  { 0x2100006e, 0x1400ffe0 },
+  { 0x2100006f, 0x1400ffe0 },
+  { 0x21000070, 0x1400ffe0 },
+  { 0x21000071, 0x1400ffe0 },
+  { 0x21000072, 0x1400ffe0 },
+  { 0x21000073, 0x1400ffe0 },
+  { 0x21000074, 0x1400ffe0 },
+  { 0x21000075, 0x1400ffe0 },
+  { 0x21000076, 0x1400ffe0 },
+  { 0x21000077, 0x1400ffe0 },
+  { 0x21000078, 0x1400ffe0 },
+  { 0x21000079, 0x1400ffe0 },
+  { 0x2100007a, 0x1400ffe0 },
+  { 0x0900007b, 0x58000000 },
+  { 0x0900007c, 0x64000000 },
+  { 0x0900007d, 0x48000000 },
+  { 0x0900007e, 0x64000000 },
+  { 0x0980007f, 0x00000020 },
+  { 0x090000a0, 0x74000000 },
+  { 0x090000a1, 0x54000000 },
+  { 0x098000a2, 0x5c000003 },
+  { 0x098000a6, 0x68000001 },
+  { 0x090000a8, 0x60000000 },
+  { 0x090000a9, 0x68000000 },
+  { 0x210000aa, 0x14000000 },
+  { 0x090000ab, 0x50000000 },
+  { 0x090000ac, 0x64000000 },
+  { 0x090000ad, 0x04000000 },
+  { 0x090000ae, 0x68000000 },
+  { 0x090000af, 0x60000000 },
+  { 0x090000b0, 0x68000000 },
+  { 0x090000b1, 0x64000000 },
+  { 0x098000b2, 0x3c000001 },
+  { 0x090000b4, 0x60000000 },
+  { 0x090000b5, 0x140002e7 },
+  { 0x090000b6, 0x68000000 },
+  { 0x090000b7, 0x54000000 },
+  { 0x090000b8, 0x60000000 },
+  { 0x090000b9, 0x3c000000 },
+  { 0x210000ba, 0x14000000 },
+  { 0x090000bb, 0x4c000000 },
+  { 0x098000bc, 0x3c000002 },
+  { 0x090000bf, 0x54000000 },
+  { 0x210000c0, 0x24000020 },
+  { 0x210000c1, 0x24000020 },
+  { 0x210000c2, 0x24000020 },
+  { 0x210000c3, 0x24000020 },
+  { 0x210000c4, 0x24000020 },
+  { 0x210000c5, 0x24000020 },
+  { 0x210000c6, 0x24000020 },
+  { 0x210000c7, 0x24000020 },
+  { 0x210000c8, 0x24000020 },
+  { 0x210000c9, 0x24000020 },
+  { 0x210000ca, 0x24000020 },
+  { 0x210000cb, 0x24000020 },
+  { 0x210000cc, 0x24000020 },
+  { 0x210000cd, 0x24000020 },
+  { 0x210000ce, 0x24000020 },
+  { 0x210000cf, 0x24000020 },
+  { 0x210000d0, 0x24000020 },
+  { 0x210000d1, 0x24000020 },
+  { 0x210000d2, 0x24000020 },
+  { 0x210000d3, 0x24000020 },
+  { 0x210000d4, 0x24000020 },
+  { 0x210000d5, 0x24000020 },
+  { 0x210000d6, 0x24000020 },
+  { 0x090000d7, 0x64000000 },
+  { 0x210000d8, 0x24000020 },
+  { 0x210000d9, 0x24000020 },
+  { 0x210000da, 0x24000020 },
+  { 0x210000db, 0x24000020 },
+  { 0x210000dc, 0x24000020 },
+  { 0x210000dd, 0x24000020 },
+  { 0x210000de, 0x24000020 },
+  { 0x210000df, 0x14000000 },
+  { 0x210000e0, 0x1400ffe0 },
+  { 0x210000e1, 0x1400ffe0 },
+  { 0x210000e2, 0x1400ffe0 },
+  { 0x210000e3, 0x1400ffe0 },
+  { 0x210000e4, 0x1400ffe0 },
+  { 0x210000e5, 0x1400ffe0 },
+  { 0x210000e6, 0x1400ffe0 },
+  { 0x210000e7, 0x1400ffe0 },
+  { 0x210000e8, 0x1400ffe0 },
+  { 0x210000e9, 0x1400ffe0 },
+  { 0x210000ea, 0x1400ffe0 },
+  { 0x210000eb, 0x1400ffe0 },
+  { 0x210000ec, 0x1400ffe0 },
+  { 0x210000ed, 0x1400ffe0 },
+  { 0x210000ee, 0x1400ffe0 },
+  { 0x210000ef, 0x1400ffe0 },
+  { 0x210000f0, 0x1400ffe0 },
+  { 0x210000f1, 0x1400ffe0 },
+  { 0x210000f2, 0x1400ffe0 },
+  { 0x210000f3, 0x1400ffe0 },
+  { 0x210000f4, 0x1400ffe0 },
+  { 0x210000f5, 0x1400ffe0 },
+  { 0x210000f6, 0x1400ffe0 },
+  { 0x090000f7, 0x64000000 },
+  { 0x210000f8, 0x1400ffe0 },
+  { 0x210000f9, 0x1400ffe0 },
+  { 0x210000fa, 0x1400ffe0 },
+  { 0x210000fb, 0x1400ffe0 },
+  { 0x210000fc, 0x1400ffe0 },
+  { 0x210000fd, 0x1400ffe0 },
+  { 0x210000fe, 0x1400ffe0 },
+  { 0x210000ff, 0x14000079 },
+  { 0x21000100, 0x24000001 },
+  { 0x21000101, 0x1400ffff },
+  { 0x21000102, 0x24000001 },
+  { 0x21000103, 0x1400ffff },
+  { 0x21000104, 0x24000001 },
+  { 0x21000105, 0x1400ffff },
+  { 0x21000106, 0x24000001 },
+  { 0x21000107, 0x1400ffff },
+  { 0x21000108, 0x24000001 },
+  { 0x21000109, 0x1400ffff },
+  { 0x2100010a, 0x24000001 },
+  { 0x2100010b, 0x1400ffff },
+  { 0x2100010c, 0x24000001 },
+  { 0x2100010d, 0x1400ffff },
+  { 0x2100010e, 0x24000001 },
+  { 0x2100010f, 0x1400ffff },
+  { 0x21000110, 0x24000001 },
+  { 0x21000111, 0x1400ffff },
+  { 0x21000112, 0x24000001 },
+  { 0x21000113, 0x1400ffff },
+  { 0x21000114, 0x24000001 },
+  { 0x21000115, 0x1400ffff },
+  { 0x21000116, 0x24000001 },
+  { 0x21000117, 0x1400ffff },
+  { 0x21000118, 0x24000001 },
+  { 0x21000119, 0x1400ffff },
+  { 0x2100011a, 0x24000001 },
+  { 0x2100011b, 0x1400ffff },
+  { 0x2100011c, 0x24000001 },
+  { 0x2100011d, 0x1400ffff },
+  { 0x2100011e, 0x24000001 },
+  { 0x2100011f, 0x1400ffff },
+  { 0x21000120, 0x24000001 },
+  { 0x21000121, 0x1400ffff },
+  { 0x21000122, 0x24000001 },
+  { 0x21000123, 0x1400ffff },
+  { 0x21000124, 0x24000001 },
+  { 0x21000125, 0x1400ffff },
+  { 0x21000126, 0x24000001 },
+  { 0x21000127, 0x1400ffff },
+  { 0x21000128, 0x24000001 },
+  { 0x21000129, 0x1400ffff },
+  { 0x2100012a, 0x24000001 },
+  { 0x2100012b, 0x1400ffff },
+  { 0x2100012c, 0x24000001 },
+  { 0x2100012d, 0x1400ffff },
+  { 0x2100012e, 0x24000001 },
+  { 0x2100012f, 0x1400ffff },
+  { 0x21000130, 0x2400ff39 },
+  { 0x21000131, 0x1400ff18 },
+  { 0x21000132, 0x24000001 },
+  { 0x21000133, 0x1400ffff },
+  { 0x21000134, 0x24000001 },
+  { 0x21000135, 0x1400ffff },
+  { 0x21000136, 0x24000001 },
+  { 0x21000137, 0x1400ffff },
+  { 0x21000138, 0x14000000 },
+  { 0x21000139, 0x24000001 },
+  { 0x2100013a, 0x1400ffff },
+  { 0x2100013b, 0x24000001 },
+  { 0x2100013c, 0x1400ffff },
+  { 0x2100013d, 0x24000001 },
+  { 0x2100013e, 0x1400ffff },
+  { 0x2100013f, 0x24000001 },
+  { 0x21000140, 0x1400ffff },
+  { 0x21000141, 0x24000001 },
+  { 0x21000142, 0x1400ffff },
+  { 0x21000143, 0x24000001 },
+  { 0x21000144, 0x1400ffff },
+  { 0x21000145, 0x24000001 },
+  { 0x21000146, 0x1400ffff },
+  { 0x21000147, 0x24000001 },
+  { 0x21000148, 0x1400ffff },
+  { 0x21000149, 0x14000000 },
+  { 0x2100014a, 0x24000001 },
+  { 0x2100014b, 0x1400ffff },
+  { 0x2100014c, 0x24000001 },
+  { 0x2100014d, 0x1400ffff },
+  { 0x2100014e, 0x24000001 },
+  { 0x2100014f, 0x1400ffff },
+  { 0x21000150, 0x24000001 },
+  { 0x21000151, 0x1400ffff },
+  { 0x21000152, 0x24000001 },
+  { 0x21000153, 0x1400ffff },
+  { 0x21000154, 0x24000001 },
+  { 0x21000155, 0x1400ffff },
+  { 0x21000156, 0x24000001 },
+  { 0x21000157, 0x1400ffff },
+  { 0x21000158, 0x24000001 },
+  { 0x21000159, 0x1400ffff },
+  { 0x2100015a, 0x24000001 },
+  { 0x2100015b, 0x1400ffff },
+  { 0x2100015c, 0x24000001 },
+  { 0x2100015d, 0x1400ffff },
+  { 0x2100015e, 0x24000001 },
+  { 0x2100015f, 0x1400ffff },
+  { 0x21000160, 0x24000001 },
+  { 0x21000161, 0x1400ffff },
+  { 0x21000162, 0x24000001 },
+  { 0x21000163, 0x1400ffff },
+  { 0x21000164, 0x24000001 },
+  { 0x21000165, 0x1400ffff },
+  { 0x21000166, 0x24000001 },
+  { 0x21000167, 0x1400ffff },
+  { 0x21000168, 0x24000001 },
+  { 0x21000169, 0x1400ffff },
+  { 0x2100016a, 0x24000001 },
+  { 0x2100016b, 0x1400ffff },
+  { 0x2100016c, 0x24000001 },
+  { 0x2100016d, 0x1400ffff },
+  { 0x2100016e, 0x24000001 },
+  { 0x2100016f, 0x1400ffff },
+  { 0x21000170, 0x24000001 },
+  { 0x21000171, 0x1400ffff },
+  { 0x21000172, 0x24000001 },
+  { 0x21000173, 0x1400ffff },
+  { 0x21000174, 0x24000001 },
+  { 0x21000175, 0x1400ffff },
+  { 0x21000176, 0x24000001 },
+  { 0x21000177, 0x1400ffff },
+  { 0x21000178, 0x2400ff87 },
+  { 0x21000179, 0x24000001 },
+  { 0x2100017a, 0x1400ffff },
+  { 0x2100017b, 0x24000001 },
+  { 0x2100017c, 0x1400ffff },
+  { 0x2100017d, 0x24000001 },
+  { 0x2100017e, 0x1400ffff },
+  { 0x2100017f, 0x1400fed4 },
+  { 0x21000180, 0x14000000 },
+  { 0x21000181, 0x240000d2 },
+  { 0x21000182, 0x24000001 },
+  { 0x21000183, 0x1400ffff },
+  { 0x21000184, 0x24000001 },
+  { 0x21000185, 0x1400ffff },
+  { 0x21000186, 0x240000ce },
+  { 0x21000187, 0x24000001 },
+  { 0x21000188, 0x1400ffff },
+  { 0x21000189, 0x240000cd },
+  { 0x2100018a, 0x240000cd },
+  { 0x2100018b, 0x24000001 },
+  { 0x2100018c, 0x1400ffff },
+  { 0x2100018d, 0x14000000 },
+  { 0x2100018e, 0x2400004f },
+  { 0x2100018f, 0x240000ca },
+  { 0x21000190, 0x240000cb },
+  { 0x21000191, 0x24000001 },
+  { 0x21000192, 0x1400ffff },
+  { 0x21000193, 0x240000cd },
+  { 0x21000194, 0x240000cf },
+  { 0x21000195, 0x14000061 },
+  { 0x21000196, 0x240000d3 },
+  { 0x21000197, 0x240000d1 },
+  { 0x21000198, 0x24000001 },
+  { 0x21000199, 0x1400ffff },
+  { 0x2100019a, 0x140000a3 },
+  { 0x2100019b, 0x14000000 },
+  { 0x2100019c, 0x240000d3 },
+  { 0x2100019d, 0x240000d5 },
+  { 0x2100019e, 0x14000082 },
+  { 0x2100019f, 0x240000d6 },
+  { 0x210001a0, 0x24000001 },
+  { 0x210001a1, 0x1400ffff },
+  { 0x210001a2, 0x24000001 },
+  { 0x210001a3, 0x1400ffff },
+  { 0x210001a4, 0x24000001 },
+  { 0x210001a5, 0x1400ffff },
+  { 0x210001a6, 0x240000da },
+  { 0x210001a7, 0x24000001 },
+  { 0x210001a8, 0x1400ffff },
+  { 0x210001a9, 0x240000da },
+  { 0x218001aa, 0x14000001 },
+  { 0x210001ac, 0x24000001 },
+  { 0x210001ad, 0x1400ffff },
+  { 0x210001ae, 0x240000da },
+  { 0x210001af, 0x24000001 },
+  { 0x210001b0, 0x1400ffff },
+  { 0x210001b1, 0x240000d9 },
+  { 0x210001b2, 0x240000d9 },
+  { 0x210001b3, 0x24000001 },
+  { 0x210001b4, 0x1400ffff },
+  { 0x210001b5, 0x24000001 },
+  { 0x210001b6, 0x1400ffff },
+  { 0x210001b7, 0x240000db },
+  { 0x210001b8, 0x24000001 },
+  { 0x210001b9, 0x1400ffff },
+  { 0x210001ba, 0x14000000 },
+  { 0x210001bb, 0x1c000000 },
+  { 0x210001bc, 0x24000001 },
+  { 0x210001bd, 0x1400ffff },
+  { 0x210001be, 0x14000000 },
+  { 0x210001bf, 0x14000038 },
+  { 0x218001c0, 0x1c000003 },
+  { 0x210001c4, 0x24000002 },
+  { 0x210001c5, 0x2000ffff },
+  { 0x210001c6, 0x1400fffe },
+  { 0x210001c7, 0x24000002 },
+  { 0x210001c8, 0x2000ffff },
+  { 0x210001c9, 0x1400fffe },
+  { 0x210001ca, 0x24000002 },
+  { 0x210001cb, 0x2000ffff },
+  { 0x210001cc, 0x1400fffe },
+  { 0x210001cd, 0x24000001 },
+  { 0x210001ce, 0x1400ffff },
+  { 0x210001cf, 0x24000001 },
+  { 0x210001d0, 0x1400ffff },
+  { 0x210001d1, 0x24000001 },
+  { 0x210001d2, 0x1400ffff },
+  { 0x210001d3, 0x24000001 },
+  { 0x210001d4, 0x1400ffff },
+  { 0x210001d5, 0x24000001 },
+  { 0x210001d6, 0x1400ffff },
+  { 0x210001d7, 0x24000001 },
+  { 0x210001d8, 0x1400ffff },
+  { 0x210001d9, 0x24000001 },
+  { 0x210001da, 0x1400ffff },
+  { 0x210001db, 0x24000001 },
+  { 0x210001dc, 0x1400ffff },
+  { 0x210001dd, 0x1400ffb1 },
+  { 0x210001de, 0x24000001 },
+  { 0x210001df, 0x1400ffff },
+  { 0x210001e0, 0x24000001 },
+  { 0x210001e1, 0x1400ffff },
+  { 0x210001e2, 0x24000001 },
+  { 0x210001e3, 0x1400ffff },
+  { 0x210001e4, 0x24000001 },
+  { 0x210001e5, 0x1400ffff },
+  { 0x210001e6, 0x24000001 },
+  { 0x210001e7, 0x1400ffff },
+  { 0x210001e8, 0x24000001 },
+  { 0x210001e9, 0x1400ffff },
+  { 0x210001ea, 0x24000001 },
+  { 0x210001eb, 0x1400ffff },
+  { 0x210001ec, 0x24000001 },
+  { 0x210001ed, 0x1400ffff },
+  { 0x210001ee, 0x24000001 },
+  { 0x210001ef, 0x1400ffff },
+  { 0x210001f0, 0x14000000 },
+  { 0x210001f1, 0x24000002 },
+  { 0x210001f2, 0x2000ffff },
+  { 0x210001f3, 0x1400fffe },
+  { 0x210001f4, 0x24000001 },
+  { 0x210001f5, 0x1400ffff },
+  { 0x210001f6, 0x2400ff9f },
+  { 0x210001f7, 0x2400ffc8 },
+  { 0x210001f8, 0x24000001 },
+  { 0x210001f9, 0x1400ffff },
+  { 0x210001fa, 0x24000001 },
+  { 0x210001fb, 0x1400ffff },
+  { 0x210001fc, 0x24000001 },
+  { 0x210001fd, 0x1400ffff },
+  { 0x210001fe, 0x24000001 },
+  { 0x210001ff, 0x1400ffff },
+  { 0x21000200, 0x24000001 },
+  { 0x21000201, 0x1400ffff },
+  { 0x21000202, 0x24000001 },
+  { 0x21000203, 0x1400ffff },
+  { 0x21000204, 0x24000001 },
+  { 0x21000205, 0x1400ffff },
+  { 0x21000206, 0x24000001 },
+  { 0x21000207, 0x1400ffff },
+  { 0x21000208, 0x24000001 },
+  { 0x21000209, 0x1400ffff },
+  { 0x2100020a, 0x24000001 },
+  { 0x2100020b, 0x1400ffff },
+  { 0x2100020c, 0x24000001 },
+  { 0x2100020d, 0x1400ffff },
+  { 0x2100020e, 0x24000001 },
+  { 0x2100020f, 0x1400ffff },
+  { 0x21000210, 0x24000001 },
+  { 0x21000211, 0x1400ffff },
+  { 0x21000212, 0x24000001 },
+  { 0x21000213, 0x1400ffff },
+  { 0x21000214, 0x24000001 },
+  { 0x21000215, 0x1400ffff },
+  { 0x21000216, 0x24000001 },
+  { 0x21000217, 0x1400ffff },
+  { 0x21000218, 0x24000001 },
+  { 0x21000219, 0x1400ffff },
+  { 0x2100021a, 0x24000001 },
+  { 0x2100021b, 0x1400ffff },
+  { 0x2100021c, 0x24000001 },
+  { 0x2100021d, 0x1400ffff },
+  { 0x2100021e, 0x24000001 },
+  { 0x2100021f, 0x1400ffff },
+  { 0x21000220, 0x2400ff7e },
+  { 0x21000221, 0x14000000 },
+  { 0x21000222, 0x24000001 },
+  { 0x21000223, 0x1400ffff },
+  { 0x21000224, 0x24000001 },
+  { 0x21000225, 0x1400ffff },
+  { 0x21000226, 0x24000001 },
+  { 0x21000227, 0x1400ffff },
+  { 0x21000228, 0x24000001 },
+  { 0x21000229, 0x1400ffff },
+  { 0x2100022a, 0x24000001 },
+  { 0x2100022b, 0x1400ffff },
+  { 0x2100022c, 0x24000001 },
+  { 0x2100022d, 0x1400ffff },
+  { 0x2100022e, 0x24000001 },
+  { 0x2100022f, 0x1400ffff },
+  { 0x21000230, 0x24000001 },
+  { 0x21000231, 0x1400ffff },
+  { 0x21000232, 0x24000001 },
+  { 0x21000233, 0x1400ffff },
+  { 0x21800234, 0x14000005 },
+  { 0x2100023a, 0x24000000 },
+  { 0x2100023b, 0x24000001 },
+  { 0x2100023c, 0x1400ffff },
+  { 0x2100023d, 0x2400ff5d },
+  { 0x2100023e, 0x24000000 },
+  { 0x2180023f, 0x14000001 },
+  { 0x21000241, 0x24000053 },
+  { 0x21800250, 0x14000002 },
+  { 0x21000253, 0x1400ff2e },
+  { 0x21000254, 0x1400ff32 },
+  { 0x21000255, 0x14000000 },
+  { 0x21000256, 0x1400ff33 },
+  { 0x21000257, 0x1400ff33 },
+  { 0x21000258, 0x14000000 },
+  { 0x21000259, 0x1400ff36 },
+  { 0x2100025a, 0x14000000 },
+  { 0x2100025b, 0x1400ff35 },
+  { 0x2180025c, 0x14000003 },
+  { 0x21000260, 0x1400ff33 },
+  { 0x21800261, 0x14000001 },
+  { 0x21000263, 0x1400ff31 },
+  { 0x21800264, 0x14000003 },
+  { 0x21000268, 0x1400ff2f },
+  { 0x21000269, 0x1400ff2d },
+  { 0x2180026a, 0x14000004 },
+  { 0x2100026f, 0x1400ff2d },
+  { 0x21800270, 0x14000001 },
+  { 0x21000272, 0x1400ff2b },
+  { 0x21800273, 0x14000001 },
+  { 0x21000275, 0x1400ff2a },
+  { 0x21800276, 0x14000009 },
+  { 0x21000280, 0x1400ff26 },
+  { 0x21800281, 0x14000001 },
+  { 0x21000283, 0x1400ff26 },
+  { 0x21800284, 0x14000003 },
+  { 0x21000288, 0x1400ff26 },
+  { 0x21000289, 0x14000000 },
+  { 0x2100028a, 0x1400ff27 },
+  { 0x2100028b, 0x1400ff27 },
+  { 0x2180028c, 0x14000005 },
+  { 0x21000292, 0x1400ff25 },
+  { 0x21000293, 0x14000000 },
+  { 0x21000294, 0x1400ffad },
+  { 0x21800295, 0x1400001a },
+  { 0x218002b0, 0x18000011 },
+  { 0x098002c2, 0x60000003 },
+  { 0x098002c6, 0x1800000b },
+  { 0x098002d2, 0x6000000d },
+  { 0x218002e0, 0x18000004 },
+  { 0x098002e5, 0x60000008 },
+  { 0x090002ee, 0x18000000 },
+  { 0x098002ef, 0x60000010 },
+  { 0x1b800300, 0x30000044 },
+  { 0x1b000345, 0x30000054 },
+  { 0x1b800346, 0x30000029 },
+  { 0x13800374, 0x60000001 },
+  { 0x1300037a, 0x18000000 },
+  { 0x0900037e, 0x54000000 },
+  { 0x13800384, 0x60000001 },
+  { 0x13000386, 0x24000026 },
+  { 0x09000387, 0x54000000 },
+  { 0x13000388, 0x24000025 },
+  { 0x13000389, 0x24000025 },
+  { 0x1300038a, 0x24000025 },
+  { 0x1300038c, 0x24000040 },
+  { 0x1300038e, 0x2400003f },
+  { 0x1300038f, 0x2400003f },
+  { 0x13000390, 0x14000000 },
+  { 0x13000391, 0x24000020 },
+  { 0x13000392, 0x24000020 },
+  { 0x13000393, 0x24000020 },
+  { 0x13000394, 0x24000020 },
+  { 0x13000395, 0x24000020 },
+  { 0x13000396, 0x24000020 },
+  { 0x13000397, 0x24000020 },
+  { 0x13000398, 0x24000020 },
+  { 0x13000399, 0x24000020 },
+  { 0x1300039a, 0x24000020 },
+  { 0x1300039b, 0x24000020 },
+  { 0x1300039c, 0x24000020 },
+  { 0x1300039d, 0x24000020 },
+  { 0x1300039e, 0x24000020 },
+  { 0x1300039f, 0x24000020 },
+  { 0x130003a0, 0x24000020 },
+  { 0x130003a1, 0x24000020 },
+  { 0x130003a3, 0x24000020 },
+  { 0x130003a4, 0x24000020 },
+  { 0x130003a5, 0x24000020 },
+  { 0x130003a6, 0x24000020 },
+  { 0x130003a7, 0x24000020 },
+  { 0x130003a8, 0x24000020 },
+  { 0x130003a9, 0x24000020 },
+  { 0x130003aa, 0x24000020 },
+  { 0x130003ab, 0x24000020 },
+  { 0x130003ac, 0x1400ffda },
+  { 0x130003ad, 0x1400ffdb },
+  { 0x130003ae, 0x1400ffdb },
+  { 0x130003af, 0x1400ffdb },
+  { 0x130003b0, 0x14000000 },
+  { 0x130003b1, 0x1400ffe0 },
+  { 0x130003b2, 0x1400ffe0 },
+  { 0x130003b3, 0x1400ffe0 },
+  { 0x130003b4, 0x1400ffe0 },
+  { 0x130003b5, 0x1400ffe0 },
+  { 0x130003b6, 0x1400ffe0 },
+  { 0x130003b7, 0x1400ffe0 },
+  { 0x130003b8, 0x1400ffe0 },
+  { 0x130003b9, 0x1400ffe0 },
+  { 0x130003ba, 0x1400ffe0 },
+  { 0x130003bb, 0x1400ffe0 },
+  { 0x130003bc, 0x1400ffe0 },
+  { 0x130003bd, 0x1400ffe0 },
+  { 0x130003be, 0x1400ffe0 },
+  { 0x130003bf, 0x1400ffe0 },
+  { 0x130003c0, 0x1400ffe0 },
+  { 0x130003c1, 0x1400ffe0 },
+  { 0x130003c2, 0x1400ffe1 },
+  { 0x130003c3, 0x1400ffe0 },
+  { 0x130003c4, 0x1400ffe0 },
+  { 0x130003c5, 0x1400ffe0 },
+  { 0x130003c6, 0x1400ffe0 },
+  { 0x130003c7, 0x1400ffe0 },
+  { 0x130003c8, 0x1400ffe0 },
+  { 0x130003c9, 0x1400ffe0 },
+  { 0x130003ca, 0x1400ffe0 },
+  { 0x130003cb, 0x1400ffe0 },
+  { 0x130003cc, 0x1400ffc0 },
+  { 0x130003cd, 0x1400ffc1 },
+  { 0x130003ce, 0x1400ffc1 },
+  { 0x130003d0, 0x1400ffc2 },
+  { 0x130003d1, 0x1400ffc7 },
+  { 0x138003d2, 0x24000002 },
+  { 0x130003d5, 0x1400ffd1 },
+  { 0x130003d6, 0x1400ffca },
+  { 0x130003d7, 0x14000000 },
+  { 0x130003d8, 0x24000001 },
+  { 0x130003d9, 0x1400ffff },
+  { 0x130003da, 0x24000001 },
+  { 0x130003db, 0x1400ffff },
+  { 0x130003dc, 0x24000001 },
+  { 0x130003dd, 0x1400ffff },
+  { 0x130003de, 0x24000001 },
+  { 0x130003df, 0x1400ffff },
+  { 0x130003e0, 0x24000001 },
+  { 0x130003e1, 0x1400ffff },
+  { 0x0a0003e2, 0x24000001 },
+  { 0x0a0003e3, 0x1400ffff },
+  { 0x0a0003e4, 0x24000001 },
+  { 0x0a0003e5, 0x1400ffff },
+  { 0x0a0003e6, 0x24000001 },
+  { 0x0a0003e7, 0x1400ffff },
+  { 0x0a0003e8, 0x24000001 },
+  { 0x0a0003e9, 0x1400ffff },
+  { 0x0a0003ea, 0x24000001 },
+  { 0x0a0003eb, 0x1400ffff },
+  { 0x0a0003ec, 0x24000001 },
+  { 0x0a0003ed, 0x1400ffff },
+  { 0x0a0003ee, 0x24000001 },
+  { 0x0a0003ef, 0x1400ffff },
+  { 0x130003f0, 0x1400ffaa },
+  { 0x130003f1, 0x1400ffb0 },
+  { 0x130003f2, 0x14000007 },
+  { 0x130003f3, 0x14000000 },
+  { 0x130003f4, 0x2400ffc4 },
+  { 0x130003f5, 0x1400ffa0 },
+  { 0x130003f6, 0x64000000 },
+  { 0x130003f7, 0x24000001 },
+  { 0x130003f8, 0x1400ffff },
+  { 0x130003f9, 0x2400fff9 },
+  { 0x130003fa, 0x24000001 },
+  { 0x130003fb, 0x1400ffff },
+  { 0x130003fc, 0x14000000 },
+  { 0x138003fd, 0x24000002 },
+  { 0x0c000400, 0x24000050 },
+  { 0x0c000401, 0x24000050 },
+  { 0x0c000402, 0x24000050 },
+  { 0x0c000403, 0x24000050 },
+  { 0x0c000404, 0x24000050 },
+  { 0x0c000405, 0x24000050 },
+  { 0x0c000406, 0x24000050 },
+  { 0x0c000407, 0x24000050 },
+  { 0x0c000408, 0x24000050 },
+  { 0x0c000409, 0x24000050 },
+  { 0x0c00040a, 0x24000050 },
+  { 0x0c00040b, 0x24000050 },
+  { 0x0c00040c, 0x24000050 },
+  { 0x0c00040d, 0x24000050 },
+  { 0x0c00040e, 0x24000050 },
+  { 0x0c00040f, 0x24000050 },
+  { 0x0c000410, 0x24000020 },
+  { 0x0c000411, 0x24000020 },
+  { 0x0c000412, 0x24000020 },
+  { 0x0c000413, 0x24000020 },
+  { 0x0c000414, 0x24000020 },
+  { 0x0c000415, 0x24000020 },
+  { 0x0c000416, 0x24000020 },
+  { 0x0c000417, 0x24000020 },
+  { 0x0c000418, 0x24000020 },
+  { 0x0c000419, 0x24000020 },
+  { 0x0c00041a, 0x24000020 },
+  { 0x0c00041b, 0x24000020 },
+  { 0x0c00041c, 0x24000020 },
+  { 0x0c00041d, 0x24000020 },
+  { 0x0c00041e, 0x24000020 },
+  { 0x0c00041f, 0x24000020 },
+  { 0x0c000420, 0x24000020 },
+  { 0x0c000421, 0x24000020 },
+  { 0x0c000422, 0x24000020 },
+  { 0x0c000423, 0x24000020 },
+  { 0x0c000424, 0x24000020 },
+  { 0x0c000425, 0x24000020 },
+  { 0x0c000426, 0x24000020 },
+  { 0x0c000427, 0x24000020 },
+  { 0x0c000428, 0x24000020 },
+  { 0x0c000429, 0x24000020 },
+  { 0x0c00042a, 0x24000020 },
+  { 0x0c00042b, 0x24000020 },
+  { 0x0c00042c, 0x24000020 },
+  { 0x0c00042d, 0x24000020 },
+  { 0x0c00042e, 0x24000020 },
+  { 0x0c00042f, 0x24000020 },
+  { 0x0c000430, 0x1400ffe0 },
+  { 0x0c000431, 0x1400ffe0 },
+  { 0x0c000432, 0x1400ffe0 },
+  { 0x0c000433, 0x1400ffe0 },
+  { 0x0c000434, 0x1400ffe0 },
+  { 0x0c000435, 0x1400ffe0 },
+  { 0x0c000436, 0x1400ffe0 },
+  { 0x0c000437, 0x1400ffe0 },
+  { 0x0c000438, 0x1400ffe0 },
+  { 0x0c000439, 0x1400ffe0 },
+  { 0x0c00043a, 0x1400ffe0 },
+  { 0x0c00043b, 0x1400ffe0 },
+  { 0x0c00043c, 0x1400ffe0 },
+  { 0x0c00043d, 0x1400ffe0 },
+  { 0x0c00043e, 0x1400ffe0 },
+  { 0x0c00043f, 0x1400ffe0 },
+  { 0x0c000440, 0x1400ffe0 },
+  { 0x0c000441, 0x1400ffe0 },
+  { 0x0c000442, 0x1400ffe0 },
+  { 0x0c000443, 0x1400ffe0 },
+  { 0x0c000444, 0x1400ffe0 },
+  { 0x0c000445, 0x1400ffe0 },
+  { 0x0c000446, 0x1400ffe0 },
+  { 0x0c000447, 0x1400ffe0 },
+  { 0x0c000448, 0x1400ffe0 },
+  { 0x0c000449, 0x1400ffe0 },
+  { 0x0c00044a, 0x1400ffe0 },
+  { 0x0c00044b, 0x1400ffe0 },
+  { 0x0c00044c, 0x1400ffe0 },
+  { 0x0c00044d, 0x1400ffe0 },
+  { 0x0c00044e, 0x1400ffe0 },
+  { 0x0c00044f, 0x1400ffe0 },
+  { 0x0c000450, 0x1400ffb0 },
+  { 0x0c000451, 0x1400ffb0 },
+  { 0x0c000452, 0x1400ffb0 },
+  { 0x0c000453, 0x1400ffb0 },
+  { 0x0c000454, 0x1400ffb0 },
+  { 0x0c000455, 0x1400ffb0 },
+  { 0x0c000456, 0x1400ffb0 },
+  { 0x0c000457, 0x1400ffb0 },
+  { 0x0c000458, 0x1400ffb0 },
+  { 0x0c000459, 0x1400ffb0 },
+  { 0x0c00045a, 0x1400ffb0 },
+  { 0x0c00045b, 0x1400ffb0 },
+  { 0x0c00045c, 0x1400ffb0 },
+  { 0x0c00045d, 0x1400ffb0 },
+  { 0x0c00045e, 0x1400ffb0 },
+  { 0x0c00045f, 0x1400ffb0 },
+  { 0x0c000460, 0x24000001 },
+  { 0x0c000461, 0x1400ffff },
+  { 0x0c000462, 0x24000001 },
+  { 0x0c000463, 0x1400ffff },
+  { 0x0c000464, 0x24000001 },
+  { 0x0c000465, 0x1400ffff },
+  { 0x0c000466, 0x24000001 },
+  { 0x0c000467, 0x1400ffff },
+  { 0x0c000468, 0x24000001 },
+  { 0x0c000469, 0x1400ffff },
+  { 0x0c00046a, 0x24000001 },
+  { 0x0c00046b, 0x1400ffff },
+  { 0x0c00046c, 0x24000001 },
+  { 0x0c00046d, 0x1400ffff },
+  { 0x0c00046e, 0x24000001 },
+  { 0x0c00046f, 0x1400ffff },
+  { 0x0c000470, 0x24000001 },
+  { 0x0c000471, 0x1400ffff },
+  { 0x0c000472, 0x24000001 },
+  { 0x0c000473, 0x1400ffff },
+  { 0x0c000474, 0x24000001 },
+  { 0x0c000475, 0x1400ffff },
+  { 0x0c000476, 0x24000001 },
+  { 0x0c000477, 0x1400ffff },
+  { 0x0c000478, 0x24000001 },
+  { 0x0c000479, 0x1400ffff },
+  { 0x0c00047a, 0x24000001 },
+  { 0x0c00047b, 0x1400ffff },
+  { 0x0c00047c, 0x24000001 },
+  { 0x0c00047d, 0x1400ffff },
+  { 0x0c00047e, 0x24000001 },
+  { 0x0c00047f, 0x1400ffff },
+  { 0x0c000480, 0x24000001 },
+  { 0x0c000481, 0x1400ffff },
+  { 0x0c000482, 0x68000000 },
+  { 0x0c800483, 0x30000003 },
+  { 0x0c800488, 0x2c000001 },
+  { 0x0c00048a, 0x24000001 },
+  { 0x0c00048b, 0x1400ffff },
+  { 0x0c00048c, 0x24000001 },
+  { 0x0c00048d, 0x1400ffff },
+  { 0x0c00048e, 0x24000001 },
+  { 0x0c00048f, 0x1400ffff },
+  { 0x0c000490, 0x24000001 },
+  { 0x0c000491, 0x1400ffff },
+  { 0x0c000492, 0x24000001 },
+  { 0x0c000493, 0x1400ffff },
+  { 0x0c000494, 0x24000001 },
+  { 0x0c000495, 0x1400ffff },
+  { 0x0c000496, 0x24000001 },
+  { 0x0c000497, 0x1400ffff },
+  { 0x0c000498, 0x24000001 },
+  { 0x0c000499, 0x1400ffff },
+  { 0x0c00049a, 0x24000001 },
+  { 0x0c00049b, 0x1400ffff },
+  { 0x0c00049c, 0x24000001 },
+  { 0x0c00049d, 0x1400ffff },
+  { 0x0c00049e, 0x24000001 },
+  { 0x0c00049f, 0x1400ffff },
+  { 0x0c0004a0, 0x24000001 },
+  { 0x0c0004a1, 0x1400ffff },
+  { 0x0c0004a2, 0x24000001 },
+  { 0x0c0004a3, 0x1400ffff },
+  { 0x0c0004a4, 0x24000001 },
+  { 0x0c0004a5, 0x1400ffff },
+  { 0x0c0004a6, 0x24000001 },
+  { 0x0c0004a7, 0x1400ffff },
+  { 0x0c0004a8, 0x24000001 },
+  { 0x0c0004a9, 0x1400ffff },
+  { 0x0c0004aa, 0x24000001 },
+  { 0x0c0004ab, 0x1400ffff },
+  { 0x0c0004ac, 0x24000001 },
+  { 0x0c0004ad, 0x1400ffff },
+  { 0x0c0004ae, 0x24000001 },
+  { 0x0c0004af, 0x1400ffff },
+  { 0x0c0004b0, 0x24000001 },
+  { 0x0c0004b1, 0x1400ffff },
+  { 0x0c0004b2, 0x24000001 },
+  { 0x0c0004b3, 0x1400ffff },
+  { 0x0c0004b4, 0x24000001 },
+  { 0x0c0004b5, 0x1400ffff },
+  { 0x0c0004b6, 0x24000001 },
+  { 0x0c0004b7, 0x1400ffff },
+  { 0x0c0004b8, 0x24000001 },
+  { 0x0c0004b9, 0x1400ffff },
+  { 0x0c0004ba, 0x24000001 },
+  { 0x0c0004bb, 0x1400ffff },
+  { 0x0c0004bc, 0x24000001 },
+  { 0x0c0004bd, 0x1400ffff },
+  { 0x0c0004be, 0x24000001 },
+  { 0x0c0004bf, 0x1400ffff },
+  { 0x0c0004c0, 0x24000000 },
+  { 0x0c0004c1, 0x24000001 },
+  { 0x0c0004c2, 0x1400ffff },
+  { 0x0c0004c3, 0x24000001 },
+  { 0x0c0004c4, 0x1400ffff },
+  { 0x0c0004c5, 0x24000001 },
+  { 0x0c0004c6, 0x1400ffff },
+  { 0x0c0004c7, 0x24000001 },
+  { 0x0c0004c8, 0x1400ffff },
+  { 0x0c0004c9, 0x24000001 },
+  { 0x0c0004ca, 0x1400ffff },
+  { 0x0c0004cb, 0x24000001 },
+  { 0x0c0004cc, 0x1400ffff },
+  { 0x0c0004cd, 0x24000001 },
+  { 0x0c0004ce, 0x1400ffff },
+  { 0x0c0004d0, 0x24000001 },
+  { 0x0c0004d1, 0x1400ffff },
+  { 0x0c0004d2, 0x24000001 },
+  { 0x0c0004d3, 0x1400ffff },
+  { 0x0c0004d4, 0x24000001 },
+  { 0x0c0004d5, 0x1400ffff },
+  { 0x0c0004d6, 0x24000001 },
+  { 0x0c0004d7, 0x1400ffff },
+  { 0x0c0004d8, 0x24000001 },
+  { 0x0c0004d9, 0x1400ffff },
+  { 0x0c0004da, 0x24000001 },
+  { 0x0c0004db, 0x1400ffff },
+  { 0x0c0004dc, 0x24000001 },
+  { 0x0c0004dd, 0x1400ffff },
+  { 0x0c0004de, 0x24000001 },
+  { 0x0c0004df, 0x1400ffff },
+  { 0x0c0004e0, 0x24000001 },
+  { 0x0c0004e1, 0x1400ffff },
+  { 0x0c0004e2, 0x24000001 },
+  { 0x0c0004e3, 0x1400ffff },
+  { 0x0c0004e4, 0x24000001 },
+  { 0x0c0004e5, 0x1400ffff },
+  { 0x0c0004e6, 0x24000001 },
+  { 0x0c0004e7, 0x1400ffff },
+  { 0x0c0004e8, 0x24000001 },
+  { 0x0c0004e9, 0x1400ffff },
+  { 0x0c0004ea, 0x24000001 },
+  { 0x0c0004eb, 0x1400ffff },
+  { 0x0c0004ec, 0x24000001 },
+  { 0x0c0004ed, 0x1400ffff },
+  { 0x0c0004ee, 0x24000001 },
+  { 0x0c0004ef, 0x1400ffff },
+  { 0x0c0004f0, 0x24000001 },
+  { 0x0c0004f1, 0x1400ffff },
+  { 0x0c0004f2, 0x24000001 },
+  { 0x0c0004f3, 0x1400ffff },
+  { 0x0c0004f4, 0x24000001 },
+  { 0x0c0004f5, 0x1400ffff },
+  { 0x0c0004f6, 0x24000001 },
+  { 0x0c0004f7, 0x1400ffff },
+  { 0x0c0004f8, 0x24000001 },
+  { 0x0c0004f9, 0x1400ffff },
+  { 0x0c000500, 0x24000001 },
+  { 0x0c000501, 0x1400ffff },
+  { 0x0c000502, 0x24000001 },
+  { 0x0c000503, 0x1400ffff },
+  { 0x0c000504, 0x24000001 },
+  { 0x0c000505, 0x1400ffff },
+  { 0x0c000506, 0x24000001 },
+  { 0x0c000507, 0x1400ffff },
+  { 0x0c000508, 0x24000001 },
+  { 0x0c000509, 0x1400ffff },
+  { 0x0c00050a, 0x24000001 },
+  { 0x0c00050b, 0x1400ffff },
+  { 0x0c00050c, 0x24000001 },
+  { 0x0c00050d, 0x1400ffff },
+  { 0x0c00050e, 0x24000001 },
+  { 0x0c00050f, 0x1400ffff },
+  { 0x01000531, 0x24000030 },
+  { 0x01000532, 0x24000030 },
+  { 0x01000533, 0x24000030 },
+  { 0x01000534, 0x24000030 },
+  { 0x01000535, 0x24000030 },
+  { 0x01000536, 0x24000030 },
+  { 0x01000537, 0x24000030 },
+  { 0x01000538, 0x24000030 },
+  { 0x01000539, 0x24000030 },
+  { 0x0100053a, 0x24000030 },
+  { 0x0100053b, 0x24000030 },
+  { 0x0100053c, 0x24000030 },
+  { 0x0100053d, 0x24000030 },
+  { 0x0100053e, 0x24000030 },
+  { 0x0100053f, 0x24000030 },
+  { 0x01000540, 0x24000030 },
+  { 0x01000541, 0x24000030 },
+  { 0x01000542, 0x24000030 },
+  { 0x01000543, 0x24000030 },
+  { 0x01000544, 0x24000030 },
+  { 0x01000545, 0x24000030 },
+  { 0x01000546, 0x24000030 },
+  { 0x01000547, 0x24000030 },
+  { 0x01000548, 0x24000030 },
+  { 0x01000549, 0x24000030 },
+  { 0x0100054a, 0x24000030 },
+  { 0x0100054b, 0x24000030 },
+  { 0x0100054c, 0x24000030 },
+  { 0x0100054d, 0x24000030 },
+  { 0x0100054e, 0x24000030 },
+  { 0x0100054f, 0x24000030 },
+  { 0x01000550, 0x24000030 },
+  { 0x01000551, 0x24000030 },
+  { 0x01000552, 0x24000030 },
+  { 0x01000553, 0x24000030 },
+  { 0x01000554, 0x24000030 },
+  { 0x01000555, 0x24000030 },
+  { 0x01000556, 0x24000030 },
+  { 0x01000559, 0x18000000 },
+  { 0x0180055a, 0x54000005 },
+  { 0x01000561, 0x1400ffd0 },
+  { 0x01000562, 0x1400ffd0 },
+  { 0x01000563, 0x1400ffd0 },
+  { 0x01000564, 0x1400ffd0 },
+  { 0x01000565, 0x1400ffd0 },
+  { 0x01000566, 0x1400ffd0 },
+  { 0x01000567, 0x1400ffd0 },
+  { 0x01000568, 0x1400ffd0 },
+  { 0x01000569, 0x1400ffd0 },
+  { 0x0100056a, 0x1400ffd0 },
+  { 0x0100056b, 0x1400ffd0 },
+  { 0x0100056c, 0x1400ffd0 },
+  { 0x0100056d, 0x1400ffd0 },
+  { 0x0100056e, 0x1400ffd0 },
+  { 0x0100056f, 0x1400ffd0 },
+  { 0x01000570, 0x1400ffd0 },
+  { 0x01000571, 0x1400ffd0 },
+  { 0x01000572, 0x1400ffd0 },
+  { 0x01000573, 0x1400ffd0 },
+  { 0x01000574, 0x1400ffd0 },
+  { 0x01000575, 0x1400ffd0 },
+  { 0x01000576, 0x1400ffd0 },
+  { 0x01000577, 0x1400ffd0 },
+  { 0x01000578, 0x1400ffd0 },
+  { 0x01000579, 0x1400ffd0 },
+  { 0x0100057a, 0x1400ffd0 },
+  { 0x0100057b, 0x1400ffd0 },
+  { 0x0100057c, 0x1400ffd0 },
+  { 0x0100057d, 0x1400ffd0 },
+  { 0x0100057e, 0x1400ffd0 },
+  { 0x0100057f, 0x1400ffd0 },
+  { 0x01000580, 0x1400ffd0 },
+  { 0x01000581, 0x1400ffd0 },
+  { 0x01000582, 0x1400ffd0 },
+  { 0x01000583, 0x1400ffd0 },
+  { 0x01000584, 0x1400ffd0 },
+  { 0x01000585, 0x1400ffd0 },
+  { 0x01000586, 0x1400ffd0 },
+  { 0x01000587, 0x14000000 },
+  { 0x09000589, 0x54000000 },
+  { 0x0100058a, 0x44000000 },
+  { 0x19800591, 0x30000028 },
+  { 0x198005bb, 0x30000002 },
+  { 0x190005be, 0x54000000 },
+  { 0x190005bf, 0x30000000 },
+  { 0x190005c0, 0x54000000 },
+  { 0x198005c1, 0x30000001 },
+  { 0x190005c3, 0x54000000 },
+  { 0x198005c4, 0x30000001 },
+  { 0x190005c6, 0x54000000 },
+  { 0x190005c7, 0x30000000 },
+  { 0x198005d0, 0x1c00001a },
+  { 0x198005f0, 0x1c000002 },
+  { 0x198005f3, 0x54000001 },
+  { 0x09800600, 0x04000003 },
+  { 0x0000060b, 0x5c000000 },
+  { 0x0980060c, 0x54000001 },
+  { 0x0080060e, 0x68000001 },
+  { 0x00800610, 0x30000005 },
+  { 0x0900061b, 0x54000000 },
+  { 0x0080061e, 0x54000001 },
+  { 0x00800621, 0x1c000019 },
+  { 0x09000640, 0x18000000 },
+  { 0x00800641, 0x1c000009 },
+  { 0x1b80064b, 0x30000013 },
+  { 0x09800660, 0x34000009 },
+  { 0x0080066a, 0x54000003 },
+  { 0x0080066e, 0x1c000001 },
+  { 0x1b000670, 0x30000000 },
+  { 0x00800671, 0x1c000062 },
+  { 0x000006d4, 0x54000000 },
+  { 0x000006d5, 0x1c000000 },
+  { 0x008006d6, 0x30000006 },
+  { 0x090006dd, 0x04000000 },
+  { 0x000006de, 0x2c000000 },
+  { 0x008006df, 0x30000005 },
+  { 0x008006e5, 0x18000001 },
+  { 0x008006e7, 0x30000001 },
+  { 0x000006e9, 0x68000000 },
+  { 0x008006ea, 0x30000003 },
+  { 0x008006ee, 0x1c000001 },
+  { 0x008006f0, 0x34000009 },
+  { 0x008006fa, 0x1c000002 },
+  { 0x008006fd, 0x68000001 },
+  { 0x000006ff, 0x1c000000 },
+  { 0x31800700, 0x5400000d },
+  { 0x3100070f, 0x04000000 },
+  { 0x31000710, 0x1c000000 },
+  { 0x31000711, 0x30000000 },
+  { 0x31800712, 0x1c00001d },
+  { 0x31800730, 0x3000001a },
+  { 0x3180074d, 0x1c000020 },
+  { 0x37800780, 0x1c000025 },
+  { 0x378007a6, 0x3000000a },
+  { 0x370007b1, 0x1c000000 },
+  { 0x0e800901, 0x30000001 },
+  { 0x0e000903, 0x28000000 },
+  { 0x0e800904, 0x1c000035 },
+  { 0x0e00093c, 0x30000000 },
+  { 0x0e00093d, 0x1c000000 },
+  { 0x0e80093e, 0x28000002 },
+  { 0x0e800941, 0x30000007 },
+  { 0x0e800949, 0x28000003 },
+  { 0x0e00094d, 0x30000000 },
+  { 0x0e000950, 0x1c000000 },
+  { 0x0e800951, 0x30000003 },
+  { 0x0e800958, 0x1c000009 },
+  { 0x0e800962, 0x30000001 },
+  { 0x09800964, 0x54000001 },
+  { 0x0e800966, 0x34000009 },
+  { 0x09000970, 0x54000000 },
+  { 0x0e00097d, 0x1c000000 },
+  { 0x02000981, 0x30000000 },
+  { 0x02800982, 0x28000001 },
+  { 0x02800985, 0x1c000007 },
+  { 0x0280098f, 0x1c000001 },
+  { 0x02800993, 0x1c000015 },
+  { 0x028009aa, 0x1c000006 },
+  { 0x020009b2, 0x1c000000 },
+  { 0x028009b6, 0x1c000003 },
+  { 0x020009bc, 0x30000000 },
+  { 0x020009bd, 0x1c000000 },
+  { 0x028009be, 0x28000002 },
+  { 0x028009c1, 0x30000003 },
+  { 0x028009c7, 0x28000001 },
+  { 0x028009cb, 0x28000001 },
+  { 0x020009cd, 0x30000000 },
+  { 0x020009ce, 0x1c000000 },
+  { 0x020009d7, 0x28000000 },
+  { 0x028009dc, 0x1c000001 },
+  { 0x028009df, 0x1c000002 },
+  { 0x028009e2, 0x30000001 },
+  { 0x028009e6, 0x34000009 },
+  { 0x028009f0, 0x1c000001 },
+  { 0x028009f2, 0x5c000001 },
+  { 0x028009f4, 0x3c000005 },
+  { 0x020009fa, 0x68000000 },
+  { 0x15800a01, 0x30000001 },
+  { 0x15000a03, 0x28000000 },
+  { 0x15800a05, 0x1c000005 },
+  { 0x15800a0f, 0x1c000001 },
+  { 0x15800a13, 0x1c000015 },
+  { 0x15800a2a, 0x1c000006 },
+  { 0x15800a32, 0x1c000001 },
+  { 0x15800a35, 0x1c000001 },
+  { 0x15800a38, 0x1c000001 },
+  { 0x15000a3c, 0x30000000 },
+  { 0x15800a3e, 0x28000002 },
+  { 0x15800a41, 0x30000001 },
+  { 0x15800a47, 0x30000001 },
+  { 0x15800a4b, 0x30000002 },
+  { 0x15800a59, 0x1c000003 },
+  { 0x15000a5e, 0x1c000000 },
+  { 0x15800a66, 0x34000009 },
+  { 0x15800a70, 0x30000001 },
+  { 0x15800a72, 0x1c000002 },
+  { 0x14800a81, 0x30000001 },
+  { 0x14000a83, 0x28000000 },
+  { 0x14800a85, 0x1c000008 },
+  { 0x14800a8f, 0x1c000002 },
+  { 0x14800a93, 0x1c000015 },
+  { 0x14800aaa, 0x1c000006 },
+  { 0x14800ab2, 0x1c000001 },
+  { 0x14800ab5, 0x1c000004 },
+  { 0x14000abc, 0x30000000 },
+  { 0x14000abd, 0x1c000000 },
+  { 0x14800abe, 0x28000002 },
+  { 0x14800ac1, 0x30000004 },
+  { 0x14800ac7, 0x30000001 },
+  { 0x14000ac9, 0x28000000 },
+  { 0x14800acb, 0x28000001 },
+  { 0x14000acd, 0x30000000 },
+  { 0x14000ad0, 0x1c000000 },
+  { 0x14800ae0, 0x1c000001 },
+  { 0x14800ae2, 0x30000001 },
+  { 0x14800ae6, 0x34000009 },
+  { 0x14000af1, 0x5c000000 },
+  { 0x2b000b01, 0x30000000 },
+  { 0x2b800b02, 0x28000001 },
+  { 0x2b800b05, 0x1c000007 },
+  { 0x2b800b0f, 0x1c000001 },
+  { 0x2b800b13, 0x1c000015 },
+  { 0x2b800b2a, 0x1c000006 },
+  { 0x2b800b32, 0x1c000001 },
+  { 0x2b800b35, 0x1c000004 },
+  { 0x2b000b3c, 0x30000000 },
+  { 0x2b000b3d, 0x1c000000 },
+  { 0x2b000b3e, 0x28000000 },
+  { 0x2b000b3f, 0x30000000 },
+  { 0x2b000b40, 0x28000000 },
+  { 0x2b800b41, 0x30000002 },
+  { 0x2b800b47, 0x28000001 },
+  { 0x2b800b4b, 0x28000001 },
+  { 0x2b000b4d, 0x30000000 },
+  { 0x2b000b56, 0x30000000 },
+  { 0x2b000b57, 0x28000000 },
+  { 0x2b800b5c, 0x1c000001 },
+  { 0x2b800b5f, 0x1c000002 },
+  { 0x2b800b66, 0x34000009 },
+  { 0x2b000b70, 0x68000000 },
+  { 0x2b000b71, 0x1c000000 },
+  { 0x35000b82, 0x30000000 },
+  { 0x35000b83, 0x1c000000 },
+  { 0x35800b85, 0x1c000005 },
+  { 0x35800b8e, 0x1c000002 },
+  { 0x35800b92, 0x1c000003 },
+  { 0x35800b99, 0x1c000001 },
+  { 0x35000b9c, 0x1c000000 },
+  { 0x35800b9e, 0x1c000001 },
+  { 0x35800ba3, 0x1c000001 },
+  { 0x35800ba8, 0x1c000002 },
+  { 0x35800bae, 0x1c00000b },
+  { 0x35800bbe, 0x28000001 },
+  { 0x35000bc0, 0x30000000 },
+  { 0x35800bc1, 0x28000001 },
+  { 0x35800bc6, 0x28000002 },
+  { 0x35800bca, 0x28000002 },
+  { 0x35000bcd, 0x30000000 },
+  { 0x35000bd7, 0x28000000 },
+  { 0x35800be6, 0x34000009 },
+  { 0x35800bf0, 0x3c000002 },
+  { 0x35800bf3, 0x68000005 },
+  { 0x35000bf9, 0x5c000000 },
+  { 0x35000bfa, 0x68000000 },
+  { 0x36800c01, 0x28000002 },
+  { 0x36800c05, 0x1c000007 },
+  { 0x36800c0e, 0x1c000002 },
+  { 0x36800c12, 0x1c000016 },
+  { 0x36800c2a, 0x1c000009 },
+  { 0x36800c35, 0x1c000004 },
+  { 0x36800c3e, 0x30000002 },
+  { 0x36800c41, 0x28000003 },
+  { 0x36800c46, 0x30000002 },
+  { 0x36800c4a, 0x30000003 },
+  { 0x36800c55, 0x30000001 },
+  { 0x36800c60, 0x1c000001 },
+  { 0x36800c66, 0x34000009 },
+  { 0x1c800c82, 0x28000001 },
+  { 0x1c800c85, 0x1c000007 },
+  { 0x1c800c8e, 0x1c000002 },
+  { 0x1c800c92, 0x1c000016 },
+  { 0x1c800caa, 0x1c000009 },
+  { 0x1c800cb5, 0x1c000004 },
+  { 0x1c000cbc, 0x30000000 },
+  { 0x1c000cbd, 0x1c000000 },
+  { 0x1c000cbe, 0x28000000 },
+  { 0x1c000cbf, 0x30000000 },
+  { 0x1c800cc0, 0x28000004 },
+  { 0x1c000cc6, 0x30000000 },
+  { 0x1c800cc7, 0x28000001 },
+  { 0x1c800cca, 0x28000001 },
+  { 0x1c800ccc, 0x30000001 },
+  { 0x1c800cd5, 0x28000001 },
+  { 0x1c000cde, 0x1c000000 },
+  { 0x1c800ce0, 0x1c000001 },
+  { 0x1c800ce6, 0x34000009 },
+  { 0x24800d02, 0x28000001 },
+  { 0x24800d05, 0x1c000007 },
+  { 0x24800d0e, 0x1c000002 },
+  { 0x24800d12, 0x1c000016 },
+  { 0x24800d2a, 0x1c00000f },
+  { 0x24800d3e, 0x28000002 },
+  { 0x24800d41, 0x30000002 },
+  { 0x24800d46, 0x28000002 },
+  { 0x24800d4a, 0x28000002 },
+  { 0x24000d4d, 0x30000000 },
+  { 0x24000d57, 0x28000000 },
+  { 0x24800d60, 0x1c000001 },
+  { 0x24800d66, 0x34000009 },
+  { 0x2f800d82, 0x28000001 },
+  { 0x2f800d85, 0x1c000011 },
+  { 0x2f800d9a, 0x1c000017 },
+  { 0x2f800db3, 0x1c000008 },
+  { 0x2f000dbd, 0x1c000000 },
+  { 0x2f800dc0, 0x1c000006 },
+  { 0x2f000dca, 0x30000000 },
+  { 0x2f800dcf, 0x28000002 },
+  { 0x2f800dd2, 0x30000002 },
+  { 0x2f000dd6, 0x30000000 },
+  { 0x2f800dd8, 0x28000007 },
+  { 0x2f800df2, 0x28000001 },
+  { 0x2f000df4, 0x54000000 },
+  { 0x38800e01, 0x1c00002f },
+  { 0x38000e31, 0x30000000 },
+  { 0x38800e32, 0x1c000001 },
+  { 0x38800e34, 0x30000006 },
+  { 0x09000e3f, 0x5c000000 },
+  { 0x38800e40, 0x1c000005 },
+  { 0x38000e46, 0x18000000 },
+  { 0x38800e47, 0x30000007 },
+  { 0x38000e4f, 0x54000000 },
+  { 0x38800e50, 0x34000009 },
+  { 0x38800e5a, 0x54000001 },
+  { 0x20800e81, 0x1c000001 },
+  { 0x20000e84, 0x1c000000 },
+  { 0x20800e87, 0x1c000001 },
+  { 0x20000e8a, 0x1c000000 },
+  { 0x20000e8d, 0x1c000000 },
+  { 0x20800e94, 0x1c000003 },
+  { 0x20800e99, 0x1c000006 },
+  { 0x20800ea1, 0x1c000002 },
+  { 0x20000ea5, 0x1c000000 },
+  { 0x20000ea7, 0x1c000000 },
+  { 0x20800eaa, 0x1c000001 },
+  { 0x20800ead, 0x1c000003 },
+  { 0x20000eb1, 0x30000000 },
+  { 0x20800eb2, 0x1c000001 },
+  { 0x20800eb4, 0x30000005 },
+  { 0x20800ebb, 0x30000001 },
+  { 0x20000ebd, 0x1c000000 },
+  { 0x20800ec0, 0x1c000004 },
+  { 0x20000ec6, 0x18000000 },
+  { 0x20800ec8, 0x30000005 },
+  { 0x20800ed0, 0x34000009 },
+  { 0x20800edc, 0x1c000001 },
+  { 0x39000f00, 0x1c000000 },
+  { 0x39800f01, 0x68000002 },
+  { 0x39800f04, 0x5400000e },
+  { 0x39800f13, 0x68000004 },
+  { 0x39800f18, 0x30000001 },
+  { 0x39800f1a, 0x68000005 },
+  { 0x39800f20, 0x34000009 },
+  { 0x39800f2a, 0x3c000009 },
+  { 0x39000f34, 0x68000000 },
+  { 0x39000f35, 0x30000000 },
+  { 0x39000f36, 0x68000000 },
+  { 0x39000f37, 0x30000000 },
+  { 0x39000f38, 0x68000000 },
+  { 0x39000f39, 0x30000000 },
+  { 0x39000f3a, 0x58000000 },
+  { 0x39000f3b, 0x48000000 },
+  { 0x39000f3c, 0x58000000 },
+  { 0x39000f3d, 0x48000000 },
+  { 0x39800f3e, 0x28000001 },
+  { 0x39800f40, 0x1c000007 },
+  { 0x39800f49, 0x1c000021 },
+  { 0x39800f71, 0x3000000d },
+  { 0x39000f7f, 0x28000000 },
+  { 0x39800f80, 0x30000004 },
+  { 0x39000f85, 0x54000000 },
+  { 0x39800f86, 0x30000001 },
+  { 0x39800f88, 0x1c000003 },
+  { 0x39800f90, 0x30000007 },
+  { 0x39800f99, 0x30000023 },
+  { 0x39800fbe, 0x68000007 },
+  { 0x39000fc6, 0x30000000 },
+  { 0x39800fc7, 0x68000005 },
+  { 0x39000fcf, 0x68000000 },
+  { 0x39800fd0, 0x54000001 },
+  { 0x26801000, 0x1c000021 },
+  { 0x26801023, 0x1c000004 },
+  { 0x26801029, 0x1c000001 },
+  { 0x2600102c, 0x28000000 },
+  { 0x2680102d, 0x30000003 },
+  { 0x26001031, 0x28000000 },
+  { 0x26001032, 0x30000000 },
+  { 0x26801036, 0x30000001 },
+  { 0x26001038, 0x28000000 },
+  { 0x26001039, 0x30000000 },
+  { 0x26801040, 0x34000009 },
+  { 0x2680104a, 0x54000005 },
+  { 0x26801050, 0x1c000005 },
+  { 0x26801056, 0x28000001 },
+  { 0x26801058, 0x30000001 },
+  { 0x100010a0, 0x24001c60 },
+  { 0x100010a1, 0x24001c60 },
+  { 0x100010a2, 0x24001c60 },
+  { 0x100010a3, 0x24001c60 },
+  { 0x100010a4, 0x24001c60 },
+  { 0x100010a5, 0x24001c60 },
+  { 0x100010a6, 0x24001c60 },
+  { 0x100010a7, 0x24001c60 },
+  { 0x100010a8, 0x24001c60 },
+  { 0x100010a9, 0x24001c60 },
+  { 0x100010aa, 0x24001c60 },
+  { 0x100010ab, 0x24001c60 },
+  { 0x100010ac, 0x24001c60 },
+  { 0x100010ad, 0x24001c60 },
+  { 0x100010ae, 0x24001c60 },
+  { 0x100010af, 0x24001c60 },
+  { 0x100010b0, 0x24001c60 },
+  { 0x100010b1, 0x24001c60 },
+  { 0x100010b2, 0x24001c60 },
+  { 0x100010b3, 0x24001c60 },
+  { 0x100010b4, 0x24001c60 },
+  { 0x100010b5, 0x24001c60 },
+  { 0x100010b6, 0x24001c60 },
+  { 0x100010b7, 0x24001c60 },
+  { 0x100010b8, 0x24001c60 },
+  { 0x100010b9, 0x24001c60 },
+  { 0x100010ba, 0x24001c60 },
+  { 0x100010bb, 0x24001c60 },
+  { 0x100010bc, 0x24001c60 },
+  { 0x100010bd, 0x24001c60 },
+  { 0x100010be, 0x24001c60 },
+  { 0x100010bf, 0x24001c60 },
+  { 0x100010c0, 0x24001c60 },
+  { 0x100010c1, 0x24001c60 },
+  { 0x100010c2, 0x24001c60 },
+  { 0x100010c3, 0x24001c60 },
+  { 0x100010c4, 0x24001c60 },
+  { 0x100010c5, 0x24001c60 },
+  { 0x108010d0, 0x1c00002a },
+  { 0x090010fb, 0x54000000 },
+  { 0x100010fc, 0x18000000 },
+  { 0x17801100, 0x1c000059 },
+  { 0x1780115f, 0x1c000043 },
+  { 0x178011a8, 0x1c000051 },
+  { 0x0f801200, 0x1c000048 },
+  { 0x0f80124a, 0x1c000003 },
+  { 0x0f801250, 0x1c000006 },
+  { 0x0f001258, 0x1c000000 },
+  { 0x0f80125a, 0x1c000003 },
+  { 0x0f801260, 0x1c000028 },
+  { 0x0f80128a, 0x1c000003 },
+  { 0x0f801290, 0x1c000020 },
+  { 0x0f8012b2, 0x1c000003 },
+  { 0x0f8012b8, 0x1c000006 },
+  { 0x0f0012c0, 0x1c000000 },
+  { 0x0f8012c2, 0x1c000003 },
+  { 0x0f8012c8, 0x1c00000e },
+  { 0x0f8012d8, 0x1c000038 },
+  { 0x0f801312, 0x1c000003 },
+  { 0x0f801318, 0x1c000042 },
+  { 0x0f00135f, 0x30000000 },
+  { 0x0f001360, 0x68000000 },
+  { 0x0f801361, 0x54000007 },
+  { 0x0f801369, 0x3c000013 },
+  { 0x0f801380, 0x1c00000f },
+  { 0x0f801390, 0x68000009 },
+  { 0x088013a0, 0x1c000054 },
+  { 0x07801401, 0x1c00026b },
+  { 0x0780166d, 0x54000001 },
+  { 0x0780166f, 0x1c000007 },
+  { 0x28001680, 0x74000000 },
+  { 0x28801681, 0x1c000019 },
+  { 0x2800169b, 0x58000000 },
+  { 0x2800169c, 0x48000000 },
+  { 0x2d8016a0, 0x1c00004a },
+  { 0x098016eb, 0x54000002 },
+  { 0x2d8016ee, 0x38000002 },
+  { 0x32801700, 0x1c00000c },
+  { 0x3280170e, 0x1c000003 },
+  { 0x32801712, 0x30000002 },
+  { 0x18801720, 0x1c000011 },
+  { 0x18801732, 0x30000002 },
+  { 0x09801735, 0x54000001 },
+  { 0x06801740, 0x1c000011 },
+  { 0x06801752, 0x30000001 },
+  { 0x33801760, 0x1c00000c },
+  { 0x3380176e, 0x1c000002 },
+  { 0x33801772, 0x30000001 },
+  { 0x1f801780, 0x1c000033 },
+  { 0x1f8017b4, 0x04000001 },
+  { 0x1f0017b6, 0x28000000 },
+  { 0x1f8017b7, 0x30000006 },
+  { 0x1f8017be, 0x28000007 },
+  { 0x1f0017c6, 0x30000000 },
+  { 0x1f8017c7, 0x28000001 },
+  { 0x1f8017c9, 0x3000000a },
+  { 0x1f8017d4, 0x54000002 },
+  { 0x1f0017d7, 0x18000000 },
+  { 0x1f8017d8, 0x54000002 },
+  { 0x1f0017db, 0x5c000000 },
+  { 0x1f0017dc, 0x1c000000 },
+  { 0x1f0017dd, 0x30000000 },
+  { 0x1f8017e0, 0x34000009 },
+  { 0x1f8017f0, 0x3c000009 },
+  { 0x25801800, 0x54000005 },
+  { 0x25001806, 0x44000000 },
+  { 0x25801807, 0x54000003 },
+  { 0x2580180b, 0x30000002 },
+  { 0x2500180e, 0x74000000 },
+  { 0x25801810, 0x34000009 },
+  { 0x25801820, 0x1c000022 },
+  { 0x25001843, 0x18000000 },
+  { 0x25801844, 0x1c000033 },
+  { 0x25801880, 0x1c000028 },
+  { 0x250018a9, 0x30000000 },
+  { 0x22801900, 0x1c00001c },
+  { 0x22801920, 0x30000002 },
+  { 0x22801923, 0x28000003 },
+  { 0x22801927, 0x30000001 },
+  { 0x22801929, 0x28000002 },
+  { 0x22801930, 0x28000001 },
+  { 0x22001932, 0x30000000 },
+  { 0x22801933, 0x28000005 },
+  { 0x22801939, 0x30000002 },
+  { 0x22001940, 0x68000000 },
+  { 0x22801944, 0x54000001 },
+  { 0x22801946, 0x34000009 },
+  { 0x34801950, 0x1c00001d },
+  { 0x34801970, 0x1c000004 },
+  { 0x27801980, 0x1c000029 },
+  { 0x278019b0, 0x28000010 },
+  { 0x278019c1, 0x1c000006 },
+  { 0x278019c8, 0x28000001 },
+  { 0x278019d0, 0x34000009 },
+  { 0x278019de, 0x54000001 },
+  { 0x1f8019e0, 0x6800001f },
+  { 0x05801a00, 0x1c000016 },
+  { 0x05801a17, 0x30000001 },
+  { 0x05801a19, 0x28000002 },
+  { 0x05801a1e, 0x54000001 },
+  { 0x21801d00, 0x1400002b },
+  { 0x21801d2c, 0x18000035 },
+  { 0x21801d62, 0x14000015 },
+  { 0x0c001d78, 0x18000000 },
+  { 0x21801d79, 0x14000021 },
+  { 0x21801d9b, 0x18000024 },
+  { 0x1b801dc0, 0x30000003 },
+  { 0x21001e00, 0x24000001 },
+  { 0x21001e01, 0x1400ffff },
+  { 0x21001e02, 0x24000001 },
+  { 0x21001e03, 0x1400ffff },
+  { 0x21001e04, 0x24000001 },
+  { 0x21001e05, 0x1400ffff },
+  { 0x21001e06, 0x24000001 },
+  { 0x21001e07, 0x1400ffff },
+  { 0x21001e08, 0x24000001 },
+  { 0x21001e09, 0x1400ffff },
+  { 0x21001e0a, 0x24000001 },
+  { 0x21001e0b, 0x1400ffff },
+  { 0x21001e0c, 0x24000001 },
+  { 0x21001e0d, 0x1400ffff },
+  { 0x21001e0e, 0x24000001 },
+  { 0x21001e0f, 0x1400ffff },
+  { 0x21001e10, 0x24000001 },
+  { 0x21001e11, 0x1400ffff },
+  { 0x21001e12, 0x24000001 },
+  { 0x21001e13, 0x1400ffff },
+  { 0x21001e14, 0x24000001 },
+  { 0x21001e15, 0x1400ffff },
+  { 0x21001e16, 0x24000001 },
+  { 0x21001e17, 0x1400ffff },
+  { 0x21001e18, 0x24000001 },
+  { 0x21001e19, 0x1400ffff },
+  { 0x21001e1a, 0x24000001 },
+  { 0x21001e1b, 0x1400ffff },
+  { 0x21001e1c, 0x24000001 },
+  { 0x21001e1d, 0x1400ffff },
+  { 0x21001e1e, 0x24000001 },
+  { 0x21001e1f, 0x1400ffff },
+  { 0x21001e20, 0x24000001 },
+  { 0x21001e21, 0x1400ffff },
+  { 0x21001e22, 0x24000001 },
+  { 0x21001e23, 0x1400ffff },
+  { 0x21001e24, 0x24000001 },
+  { 0x21001e25, 0x1400ffff },
+  { 0x21001e26, 0x24000001 },
+  { 0x21001e27, 0x1400ffff },
+  { 0x21001e28, 0x24000001 },
+  { 0x21001e29, 0x1400ffff },
+  { 0x21001e2a, 0x24000001 },
+  { 0x21001e2b, 0x1400ffff },
+  { 0x21001e2c, 0x24000001 },
+  { 0x21001e2d, 0x1400ffff },
+  { 0x21001e2e, 0x24000001 },
+  { 0x21001e2f, 0x1400ffff },
+  { 0x21001e30, 0x24000001 },
+  { 0x21001e31, 0x1400ffff },
+  { 0x21001e32, 0x24000001 },
+  { 0x21001e33, 0x1400ffff },
+  { 0x21001e34, 0x24000001 },
+  { 0x21001e35, 0x1400ffff },
+  { 0x21001e36, 0x24000001 },
+  { 0x21001e37, 0x1400ffff },
+  { 0x21001e38, 0x24000001 },
+  { 0x21001e39, 0x1400ffff },
+  { 0x21001e3a, 0x24000001 },
+  { 0x21001e3b, 0x1400ffff },
+  { 0x21001e3c, 0x24000001 },
+  { 0x21001e3d, 0x1400ffff },
+  { 0x21001e3e, 0x24000001 },
+  { 0x21001e3f, 0x1400ffff },
+  { 0x21001e40, 0x24000001 },
+  { 0x21001e41, 0x1400ffff },
+  { 0x21001e42, 0x24000001 },
+  { 0x21001e43, 0x1400ffff },
+  { 0x21001e44, 0x24000001 },
+  { 0x21001e45, 0x1400ffff },
+  { 0x21001e46, 0x24000001 },
+  { 0x21001e47, 0x1400ffff },
+  { 0x21001e48, 0x24000001 },
+  { 0x21001e49, 0x1400ffff },
+  { 0x21001e4a, 0x24000001 },
+  { 0x21001e4b, 0x1400ffff },
+  { 0x21001e4c, 0x24000001 },
+  { 0x21001e4d, 0x1400ffff },
+  { 0x21001e4e, 0x24000001 },
+  { 0x21001e4f, 0x1400ffff },
+  { 0x21001e50, 0x24000001 },
+  { 0x21001e51, 0x1400ffff },
+  { 0x21001e52, 0x24000001 },
+  { 0x21001e53, 0x1400ffff },
+  { 0x21001e54, 0x24000001 },
+  { 0x21001e55, 0x1400ffff },
+  { 0x21001e56, 0x24000001 },
+  { 0x21001e57, 0x1400ffff },
+  { 0x21001e58, 0x24000001 },
+  { 0x21001e59, 0x1400ffff },
+  { 0x21001e5a, 0x24000001 },
+  { 0x21001e5b, 0x1400ffff },
+  { 0x21001e5c, 0x24000001 },
+  { 0x21001e5d, 0x1400ffff },
+  { 0x21001e5e, 0x24000001 },
+  { 0x21001e5f, 0x1400ffff },
+  { 0x21001e60, 0x24000001 },
+  { 0x21001e61, 0x1400ffff },
+  { 0x21001e62, 0x24000001 },
+  { 0x21001e63, 0x1400ffff },
+  { 0x21001e64, 0x24000001 },
+  { 0x21001e65, 0x1400ffff },
+  { 0x21001e66, 0x24000001 },
+  { 0x21001e67, 0x1400ffff },
+  { 0x21001e68, 0x24000001 },
+  { 0x21001e69, 0x1400ffff },
+  { 0x21001e6a, 0x24000001 },
+  { 0x21001e6b, 0x1400ffff },
+  { 0x21001e6c, 0x24000001 },
+  { 0x21001e6d, 0x1400ffff },
+  { 0x21001e6e, 0x24000001 },
+  { 0x21001e6f, 0x1400ffff },
+  { 0x21001e70, 0x24000001 },
+  { 0x21001e71, 0x1400ffff },
+  { 0x21001e72, 0x24000001 },
+  { 0x21001e73, 0x1400ffff },
+  { 0x21001e74, 0x24000001 },
+  { 0x21001e75, 0x1400ffff },
+  { 0x21001e76, 0x24000001 },
+  { 0x21001e77, 0x1400ffff },
+  { 0x21001e78, 0x24000001 },
+  { 0x21001e79, 0x1400ffff },
+  { 0x21001e7a, 0x24000001 },
+  { 0x21001e7b, 0x1400ffff },
+  { 0x21001e7c, 0x24000001 },
+  { 0x21001e7d, 0x1400ffff },
+  { 0x21001e7e, 0x24000001 },
+  { 0x21001e7f, 0x1400ffff },
+  { 0x21001e80, 0x24000001 },
+  { 0x21001e81, 0x1400ffff },
+  { 0x21001e82, 0x24000001 },
+  { 0x21001e83, 0x1400ffff },
+  { 0x21001e84, 0x24000001 },
+  { 0x21001e85, 0x1400ffff },
+  { 0x21001e86, 0x24000001 },
+  { 0x21001e87, 0x1400ffff },
+  { 0x21001e88, 0x24000001 },
+  { 0x21001e89, 0x1400ffff },
+  { 0x21001e8a, 0x24000001 },
+  { 0x21001e8b, 0x1400ffff },
+  { 0x21001e8c, 0x24000001 },
+  { 0x21001e8d, 0x1400ffff },
+  { 0x21001e8e, 0x24000001 },
+  { 0x21001e8f, 0x1400ffff },
+  { 0x21001e90, 0x24000001 },
+  { 0x21001e91, 0x1400ffff },
+  { 0x21001e92, 0x24000001 },
+  { 0x21001e93, 0x1400ffff },
+  { 0x21001e94, 0x24000001 },
+  { 0x21001e95, 0x1400ffff },
+  { 0x21801e96, 0x14000004 },
+  { 0x21001e9b, 0x1400ffc5 },
+  { 0x21001ea0, 0x24000001 },
+  { 0x21001ea1, 0x1400ffff },
+  { 0x21001ea2, 0x24000001 },
+  { 0x21001ea3, 0x1400ffff },
+  { 0x21001ea4, 0x24000001 },
+  { 0x21001ea5, 0x1400ffff },
+  { 0x21001ea6, 0x24000001 },
+  { 0x21001ea7, 0x1400ffff },
+  { 0x21001ea8, 0x24000001 },
+  { 0x21001ea9, 0x1400ffff },
+  { 0x21001eaa, 0x24000001 },
+  { 0x21001eab, 0x1400ffff },
+  { 0x21001eac, 0x24000001 },
+  { 0x21001ead, 0x1400ffff },
+  { 0x21001eae, 0x24000001 },
+  { 0x21001eaf, 0x1400ffff },
+  { 0x21001eb0, 0x24000001 },
+  { 0x21001eb1, 0x1400ffff },
+  { 0x21001eb2, 0x24000001 },
+  { 0x21001eb3, 0x1400ffff },
+  { 0x21001eb4, 0x24000001 },
+  { 0x21001eb5, 0x1400ffff },
+  { 0x21001eb6, 0x24000001 },
+  { 0x21001eb7, 0x1400ffff },
+  { 0x21001eb8, 0x24000001 },
+  { 0x21001eb9, 0x1400ffff },
+  { 0x21001eba, 0x24000001 },
+  { 0x21001ebb, 0x1400ffff },
+  { 0x21001ebc, 0x24000001 },
+  { 0x21001ebd, 0x1400ffff },
+  { 0x21001ebe, 0x24000001 },
+  { 0x21001ebf, 0x1400ffff },
+  { 0x21001ec0, 0x24000001 },
+  { 0x21001ec1, 0x1400ffff },
+  { 0x21001ec2, 0x24000001 },
+  { 0x21001ec3, 0x1400ffff },
+  { 0x21001ec4, 0x24000001 },
+  { 0x21001ec5, 0x1400ffff },
+  { 0x21001ec6, 0x24000001 },
+  { 0x21001ec7, 0x1400ffff },
+  { 0x21001ec8, 0x24000001 },
+  { 0x21001ec9, 0x1400ffff },
+  { 0x21001eca, 0x24000001 },
+  { 0x21001ecb, 0x1400ffff },
+  { 0x21001ecc, 0x24000001 },
+  { 0x21001ecd, 0x1400ffff },
+  { 0x21001ece, 0x24000001 },
+  { 0x21001ecf, 0x1400ffff },
+  { 0x21001ed0, 0x24000001 },
+  { 0x21001ed1, 0x1400ffff },
+  { 0x21001ed2, 0x24000001 },
+  { 0x21001ed3, 0x1400ffff },
+  { 0x21001ed4, 0x24000001 },
+  { 0x21001ed5, 0x1400ffff },
+  { 0x21001ed6, 0x24000001 },
+  { 0x21001ed7, 0x1400ffff },
+  { 0x21001ed8, 0x24000001 },
+  { 0x21001ed9, 0x1400ffff },
+  { 0x21001eda, 0x24000001 },
+  { 0x21001edb, 0x1400ffff },
+  { 0x21001edc, 0x24000001 },
+  { 0x21001edd, 0x1400ffff },
+  { 0x21001ede, 0x24000001 },
+  { 0x21001edf, 0x1400ffff },
+  { 0x21001ee0, 0x24000001 },
+  { 0x21001ee1, 0x1400ffff },
+  { 0x21001ee2, 0x24000001 },
+  { 0x21001ee3, 0x1400ffff },
+  { 0x21001ee4, 0x24000001 },
+  { 0x21001ee5, 0x1400ffff },
+  { 0x21001ee6, 0x24000001 },
+  { 0x21001ee7, 0x1400ffff },
+  { 0x21001ee8, 0x24000001 },
+  { 0x21001ee9, 0x1400ffff },
+  { 0x21001eea, 0x24000001 },
+  { 0x21001eeb, 0x1400ffff },
+  { 0x21001eec, 0x24000001 },
+  { 0x21001eed, 0x1400ffff },
+  { 0x21001eee, 0x24000001 },
+  { 0x21001eef, 0x1400ffff },
+  { 0x21001ef0, 0x24000001 },
+  { 0x21001ef1, 0x1400ffff },
+  { 0x21001ef2, 0x24000001 },
+  { 0x21001ef3, 0x1400ffff },
+  { 0x21001ef4, 0x24000001 },
+  { 0x21001ef5, 0x1400ffff },
+  { 0x21001ef6, 0x24000001 },
+  { 0x21001ef7, 0x1400ffff },
+  { 0x21001ef8, 0x24000001 },
+  { 0x21001ef9, 0x1400ffff },
+  { 0x13001f00, 0x14000008 },
+  { 0x13001f01, 0x14000008 },
+  { 0x13001f02, 0x14000008 },
+  { 0x13001f03, 0x14000008 },
+  { 0x13001f04, 0x14000008 },
+  { 0x13001f05, 0x14000008 },
+  { 0x13001f06, 0x14000008 },
+  { 0x13001f07, 0x14000008 },
+  { 0x13001f08, 0x2400fff8 },
+  { 0x13001f09, 0x2400fff8 },
+  { 0x13001f0a, 0x2400fff8 },
+  { 0x13001f0b, 0x2400fff8 },
+  { 0x13001f0c, 0x2400fff8 },
+  { 0x13001f0d, 0x2400fff8 },
+  { 0x13001f0e, 0x2400fff8 },
+  { 0x13001f0f, 0x2400fff8 },
+  { 0x13001f10, 0x14000008 },
+  { 0x13001f11, 0x14000008 },
+  { 0x13001f12, 0x14000008 },
+  { 0x13001f13, 0x14000008 },
+  { 0x13001f14, 0x14000008 },
+  { 0x13001f15, 0x14000008 },
+  { 0x13001f18, 0x2400fff8 },
+  { 0x13001f19, 0x2400fff8 },
+  { 0x13001f1a, 0x2400fff8 },
+  { 0x13001f1b, 0x2400fff8 },
+  { 0x13001f1c, 0x2400fff8 },
+  { 0x13001f1d, 0x2400fff8 },
+  { 0x13001f20, 0x14000008 },
+  { 0x13001f21, 0x14000008 },
+  { 0x13001f22, 0x14000008 },
+  { 0x13001f23, 0x14000008 },
+  { 0x13001f24, 0x14000008 },
+  { 0x13001f25, 0x14000008 },
+  { 0x13001f26, 0x14000008 },
+  { 0x13001f27, 0x14000008 },
+  { 0x13001f28, 0x2400fff8 },
+  { 0x13001f29, 0x2400fff8 },
+  { 0x13001f2a, 0x2400fff8 },
+  { 0x13001f2b, 0x2400fff8 },
+  { 0x13001f2c, 0x2400fff8 },
+  { 0x13001f2d, 0x2400fff8 },
+  { 0x13001f2e, 0x2400fff8 },
+  { 0x13001f2f, 0x2400fff8 },
+  { 0x13001f30, 0x14000008 },
+  { 0x13001f31, 0x14000008 },
+  { 0x13001f32, 0x14000008 },
+  { 0x13001f33, 0x14000008 },
+  { 0x13001f34, 0x14000008 },
+  { 0x13001f35, 0x14000008 },
+  { 0x13001f36, 0x14000008 },
+  { 0x13001f37, 0x14000008 },
+  { 0x13001f38, 0x2400fff8 },
+  { 0x13001f39, 0x2400fff8 },
+  { 0x13001f3a, 0x2400fff8 },
+  { 0x13001f3b, 0x2400fff8 },
+  { 0x13001f3c, 0x2400fff8 },
+  { 0x13001f3d, 0x2400fff8 },
+  { 0x13001f3e, 0x2400fff8 },
+  { 0x13001f3f, 0x2400fff8 },
+  { 0x13001f40, 0x14000008 },
+  { 0x13001f41, 0x14000008 },
+  { 0x13001f42, 0x14000008 },
+  { 0x13001f43, 0x14000008 },
+  { 0x13001f44, 0x14000008 },
+  { 0x13001f45, 0x14000008 },
+  { 0x13001f48, 0x2400fff8 },
+  { 0x13001f49, 0x2400fff8 },
+  { 0x13001f4a, 0x2400fff8 },
+  { 0x13001f4b, 0x2400fff8 },
+  { 0x13001f4c, 0x2400fff8 },
+  { 0x13001f4d, 0x2400fff8 },
+  { 0x13001f50, 0x14000000 },
+  { 0x13001f51, 0x14000008 },
+  { 0x13001f52, 0x14000000 },
+  { 0x13001f53, 0x14000008 },
+  { 0x13001f54, 0x14000000 },
+  { 0x13001f55, 0x14000008 },
+  { 0x13001f56, 0x14000000 },
+  { 0x13001f57, 0x14000008 },
+  { 0x13001f59, 0x2400fff8 },
+  { 0x13001f5b, 0x2400fff8 },
+  { 0x13001f5d, 0x2400fff8 },
+  { 0x13001f5f, 0x2400fff8 },
+  { 0x13001f60, 0x14000008 },
+  { 0x13001f61, 0x14000008 },
+  { 0x13001f62, 0x14000008 },
+  { 0x13001f63, 0x14000008 },
+  { 0x13001f64, 0x14000008 },
+  { 0x13001f65, 0x14000008 },
+  { 0x13001f66, 0x14000008 },
+  { 0x13001f67, 0x14000008 },
+  { 0x13001f68, 0x2400fff8 },
+  { 0x13001f69, 0x2400fff8 },
+  { 0x13001f6a, 0x2400fff8 },
+  { 0x13001f6b, 0x2400fff8 },
+  { 0x13001f6c, 0x2400fff8 },
+  { 0x13001f6d, 0x2400fff8 },
+  { 0x13001f6e, 0x2400fff8 },
+  { 0x13001f6f, 0x2400fff8 },
+  { 0x13001f70, 0x1400004a },
+  { 0x13001f71, 0x1400004a },
+  { 0x13001f72, 0x14000056 },
+  { 0x13001f73, 0x14000056 },
+  { 0x13001f74, 0x14000056 },
+  { 0x13001f75, 0x14000056 },
+  { 0x13001f76, 0x14000064 },
+  { 0x13001f77, 0x14000064 },
+  { 0x13001f78, 0x14000080 },
+  { 0x13001f79, 0x14000080 },
+  { 0x13001f7a, 0x14000070 },
+  { 0x13001f7b, 0x14000070 },
+  { 0x13001f7c, 0x1400007e },
+  { 0x13001f7d, 0x1400007e },
+  { 0x13001f80, 0x14000008 },
+  { 0x13001f81, 0x14000008 },
+  { 0x13001f82, 0x14000008 },
+  { 0x13001f83, 0x14000008 },
+  { 0x13001f84, 0x14000008 },
+  { 0x13001f85, 0x14000008 },
+  { 0x13001f86, 0x14000008 },
+  { 0x13001f87, 0x14000008 },
+  { 0x13001f88, 0x2000fff8 },
+  { 0x13001f89, 0x2000fff8 },
+  { 0x13001f8a, 0x2000fff8 },
+  { 0x13001f8b, 0x2000fff8 },
+  { 0x13001f8c, 0x2000fff8 },
+  { 0x13001f8d, 0x2000fff8 },
+  { 0x13001f8e, 0x2000fff8 },
+  { 0x13001f8f, 0x2000fff8 },
+  { 0x13001f90, 0x14000008 },
+  { 0x13001f91, 0x14000008 },
+  { 0x13001f92, 0x14000008 },
+  { 0x13001f93, 0x14000008 },
+  { 0x13001f94, 0x14000008 },
+  { 0x13001f95, 0x14000008 },
+  { 0x13001f96, 0x14000008 },
+  { 0x13001f97, 0x14000008 },
+  { 0x13001f98, 0x2000fff8 },
+  { 0x13001f99, 0x2000fff8 },
+  { 0x13001f9a, 0x2000fff8 },
+  { 0x13001f9b, 0x2000fff8 },
+  { 0x13001f9c, 0x2000fff8 },
+  { 0x13001f9d, 0x2000fff8 },
+  { 0x13001f9e, 0x2000fff8 },
+  { 0x13001f9f, 0x2000fff8 },
+  { 0x13001fa0, 0x14000008 },
+  { 0x13001fa1, 0x14000008 },
+  { 0x13001fa2, 0x14000008 },
+  { 0x13001fa3, 0x14000008 },
+  { 0x13001fa4, 0x14000008 },
+  { 0x13001fa5, 0x14000008 },
+  { 0x13001fa6, 0x14000008 },
+  { 0x13001fa7, 0x14000008 },
+  { 0x13001fa8, 0x2000fff8 },
+  { 0x13001fa9, 0x2000fff8 },
+  { 0x13001faa, 0x2000fff8 },
+  { 0x13001fab, 0x2000fff8 },
+  { 0x13001fac, 0x2000fff8 },
+  { 0x13001fad, 0x2000fff8 },
+  { 0x13001fae, 0x2000fff8 },
+  { 0x13001faf, 0x2000fff8 },
+  { 0x13001fb0, 0x14000008 },
+  { 0x13001fb1, 0x14000008 },
+  { 0x13001fb2, 0x14000000 },
+  { 0x13001fb3, 0x14000009 },
+  { 0x13001fb4, 0x14000000 },
+  { 0x13801fb6, 0x14000001 },
+  { 0x13001fb8, 0x2400fff8 },
+  { 0x13001fb9, 0x2400fff8 },
+  { 0x13001fba, 0x2400ffb6 },
+  { 0x13001fbb, 0x2400ffb6 },
+  { 0x13001fbc, 0x2000fff7 },
+  { 0x13001fbd, 0x60000000 },
+  { 0x13001fbe, 0x1400e3db },
+  { 0x13801fbf, 0x60000002 },
+  { 0x13001fc2, 0x14000000 },
+  { 0x13001fc3, 0x14000009 },
+  { 0x13001fc4, 0x14000000 },
+  { 0x13801fc6, 0x14000001 },
+  { 0x13001fc8, 0x2400ffaa },
+  { 0x13001fc9, 0x2400ffaa },
+  { 0x13001fca, 0x2400ffaa },
+  { 0x13001fcb, 0x2400ffaa },
+  { 0x13001fcc, 0x2000fff7 },
+  { 0x13801fcd, 0x60000002 },
+  { 0x13001fd0, 0x14000008 },
+  { 0x13001fd1, 0x14000008 },
+  { 0x13801fd2, 0x14000001 },
+  { 0x13801fd6, 0x14000001 },
+  { 0x13001fd8, 0x2400fff8 },
+  { 0x13001fd9, 0x2400fff8 },
+  { 0x13001fda, 0x2400ff9c },
+  { 0x13001fdb, 0x2400ff9c },
+  { 0x13801fdd, 0x60000002 },
+  { 0x13001fe0, 0x14000008 },
+  { 0x13001fe1, 0x14000008 },
+  { 0x13801fe2, 0x14000002 },
+  { 0x13001fe5, 0x14000007 },
+  { 0x13801fe6, 0x14000001 },
+  { 0x13001fe8, 0x2400fff8 },
+  { 0x13001fe9, 0x2400fff8 },
+  { 0x13001fea, 0x2400ff90 },
+  { 0x13001feb, 0x2400ff90 },
+  { 0x13001fec, 0x2400fff9 },
+  { 0x13801fed, 0x60000002 },
+  { 0x13001ff2, 0x14000000 },
+  { 0x13001ff3, 0x14000009 },
+  { 0x13001ff4, 0x14000000 },
+  { 0x13801ff6, 0x14000001 },
+  { 0x13001ff8, 0x2400ff80 },
+  { 0x13001ff9, 0x2400ff80 },
+  { 0x13001ffa, 0x2400ff82 },
+  { 0x13001ffb, 0x2400ff82 },
+  { 0x13001ffc, 0x2000fff7 },
+  { 0x13801ffd, 0x60000001 },
+  { 0x09802000, 0x7400000a },
+  { 0x0980200b, 0x04000004 },
+  { 0x09802010, 0x44000005 },
+  { 0x09802016, 0x54000001 },
+  { 0x09002018, 0x50000000 },
+  { 0x09002019, 0x4c000000 },
+  { 0x0900201a, 0x58000000 },
+  { 0x0980201b, 0x50000001 },
+  { 0x0900201d, 0x4c000000 },
+  { 0x0900201e, 0x58000000 },
+  { 0x0900201f, 0x50000000 },
+  { 0x09802020, 0x54000007 },
+  { 0x09002028, 0x6c000000 },
+  { 0x09002029, 0x70000000 },
+  { 0x0980202a, 0x04000004 },
+  { 0x0900202f, 0x74000000 },
+  { 0x09802030, 0x54000008 },
+  { 0x09002039, 0x50000000 },
+  { 0x0900203a, 0x4c000000 },
+  { 0x0980203b, 0x54000003 },
+  { 0x0980203f, 0x40000001 },
+  { 0x09802041, 0x54000002 },
+  { 0x09002044, 0x64000000 },
+  { 0x09002045, 0x58000000 },
+  { 0x09002046, 0x48000000 },
+  { 0x09802047, 0x5400000a },
+  { 0x09002052, 0x64000000 },
+  { 0x09002053, 0x54000000 },
+  { 0x09002054, 0x40000000 },
+  { 0x09802055, 0x54000009 },
+  { 0x0900205f, 0x74000000 },
+  { 0x09802060, 0x04000003 },
+  { 0x0980206a, 0x04000005 },
+  { 0x09002070, 0x3c000000 },
+  { 0x21002071, 0x14000000 },
+  { 0x09802074, 0x3c000005 },
+  { 0x0980207a, 0x64000002 },
+  { 0x0900207d, 0x58000000 },
+  { 0x0900207e, 0x48000000 },
+  { 0x2100207f, 0x14000000 },
+  { 0x09802080, 0x3c000009 },
+  { 0x0980208a, 0x64000002 },
+  { 0x0900208d, 0x58000000 },
+  { 0x0900208e, 0x48000000 },
+  { 0x21802090, 0x18000004 },
+  { 0x098020a0, 0x5c000015 },
+  { 0x1b8020d0, 0x3000000c },
+  { 0x1b8020dd, 0x2c000003 },
+  { 0x1b0020e1, 0x30000000 },
+  { 0x1b8020e2, 0x2c000002 },
+  { 0x1b8020e5, 0x30000006 },
+  { 0x09802100, 0x68000001 },
+  { 0x09002102, 0x24000000 },
+  { 0x09802103, 0x68000003 },
+  { 0x09002107, 0x24000000 },
+  { 0x09802108, 0x68000001 },
+  { 0x0900210a, 0x14000000 },
+  { 0x0980210b, 0x24000002 },
+  { 0x0980210e, 0x14000001 },
+  { 0x09802110, 0x24000002 },
+  { 0x09002113, 0x14000000 },
+  { 0x09002114, 0x68000000 },
+  { 0x09002115, 0x24000000 },
+  { 0x09802116, 0x68000002 },
+  { 0x09802119, 0x24000004 },
+  { 0x0980211e, 0x68000005 },
+  { 0x09002124, 0x24000000 },
+  { 0x09002125, 0x68000000 },
+  { 0x13002126, 0x2400e2a3 },
+  { 0x09002127, 0x68000000 },
+  { 0x09002128, 0x24000000 },
+  { 0x09002129, 0x68000000 },
+  { 0x2100212a, 0x2400df41 },
+  { 0x2100212b, 0x2400dfba },
+  { 0x0980212c, 0x24000001 },
+  { 0x0900212e, 0x68000000 },
+  { 0x0900212f, 0x14000000 },
+  { 0x09802130, 0x24000001 },
+  { 0x09002132, 0x68000000 },
+  { 0x09002133, 0x24000000 },
+  { 0x09002134, 0x14000000 },
+  { 0x09802135, 0x1c000003 },
+  { 0x09002139, 0x14000000 },
+  { 0x0980213a, 0x68000001 },
+  { 0x0980213c, 0x14000001 },
+  { 0x0980213e, 0x24000001 },
+  { 0x09802140, 0x64000004 },
+  { 0x09002145, 0x24000000 },
+  { 0x09802146, 0x14000003 },
+  { 0x0900214a, 0x68000000 },
+  { 0x0900214b, 0x64000000 },
+  { 0x0900214c, 0x68000000 },
+  { 0x09802153, 0x3c00000c },
+  { 0x09002160, 0x38000010 },
+  { 0x09002161, 0x38000010 },
+  { 0x09002162, 0x38000010 },
+  { 0x09002163, 0x38000010 },
+  { 0x09002164, 0x38000010 },
+  { 0x09002165, 0x38000010 },
+  { 0x09002166, 0x38000010 },
+  { 0x09002167, 0x38000010 },
+  { 0x09002168, 0x38000010 },
+  { 0x09002169, 0x38000010 },
+  { 0x0900216a, 0x38000010 },
+  { 0x0900216b, 0x38000010 },
+  { 0x0900216c, 0x38000010 },
+  { 0x0900216d, 0x38000010 },
+  { 0x0900216e, 0x38000010 },
+  { 0x0900216f, 0x38000010 },
+  { 0x09002170, 0x3800fff0 },
+  { 0x09002171, 0x3800fff0 },
+  { 0x09002172, 0x3800fff0 },
+  { 0x09002173, 0x3800fff0 },
+  { 0x09002174, 0x3800fff0 },
+  { 0x09002175, 0x3800fff0 },
+  { 0x09002176, 0x3800fff0 },
+  { 0x09002177, 0x3800fff0 },
+  { 0x09002178, 0x3800fff0 },
+  { 0x09002179, 0x3800fff0 },
+  { 0x0900217a, 0x3800fff0 },
+  { 0x0900217b, 0x3800fff0 },
+  { 0x0900217c, 0x3800fff0 },
+  { 0x0900217d, 0x3800fff0 },
+  { 0x0900217e, 0x3800fff0 },
+  { 0x0900217f, 0x3800fff0 },
+  { 0x09802180, 0x38000003 },
+  { 0x09802190, 0x64000004 },
+  { 0x09802195, 0x68000004 },
+  { 0x0980219a, 0x64000001 },
+  { 0x0980219c, 0x68000003 },
+  { 0x090021a0, 0x64000000 },
+  { 0x098021a1, 0x68000001 },
+  { 0x090021a3, 0x64000000 },
+  { 0x098021a4, 0x68000001 },
+  { 0x090021a6, 0x64000000 },
+  { 0x098021a7, 0x68000006 },
+  { 0x090021ae, 0x64000000 },
+  { 0x098021af, 0x6800001e },
+  { 0x098021ce, 0x64000001 },
+  { 0x098021d0, 0x68000001 },
+  { 0x090021d2, 0x64000000 },
+  { 0x090021d3, 0x68000000 },
+  { 0x090021d4, 0x64000000 },
+  { 0x098021d5, 0x6800001e },
+  { 0x098021f4, 0x6400010b },
+  { 0x09802300, 0x68000007 },
+  { 0x09802308, 0x64000003 },
+  { 0x0980230c, 0x68000013 },
+  { 0x09802320, 0x64000001 },
+  { 0x09802322, 0x68000006 },
+  { 0x09002329, 0x58000000 },
+  { 0x0900232a, 0x48000000 },
+  { 0x0980232b, 0x68000050 },
+  { 0x0900237c, 0x64000000 },
+  { 0x0980237d, 0x6800001d },
+  { 0x0980239b, 0x64000018 },
+  { 0x090023b4, 0x58000000 },
+  { 0x090023b5, 0x48000000 },
+  { 0x090023b6, 0x54000000 },
+  { 0x098023b7, 0x68000024 },
+  { 0x09802400, 0x68000026 },
+  { 0x09802440, 0x6800000a },
+  { 0x09802460, 0x3c00003b },
+  { 0x0980249c, 0x68000019 },
+  { 0x090024b6, 0x6800001a },
+  { 0x090024b7, 0x6800001a },
+  { 0x090024b8, 0x6800001a },
+  { 0x090024b9, 0x6800001a },
+  { 0x090024ba, 0x6800001a },
+  { 0x090024bb, 0x6800001a },
+  { 0x090024bc, 0x6800001a },
+  { 0x090024bd, 0x6800001a },
+  { 0x090024be, 0x6800001a },
+  { 0x090024bf, 0x6800001a },
+  { 0x090024c0, 0x6800001a },
+  { 0x090024c1, 0x6800001a },
+  { 0x090024c2, 0x6800001a },
+  { 0x090024c3, 0x6800001a },
+  { 0x090024c4, 0x6800001a },
+  { 0x090024c5, 0x6800001a },
+  { 0x090024c6, 0x6800001a },
+  { 0x090024c7, 0x6800001a },
+  { 0x090024c8, 0x6800001a },
+  { 0x090024c9, 0x6800001a },
+  { 0x090024ca, 0x6800001a },
+  { 0x090024cb, 0x6800001a },
+  { 0x090024cc, 0x6800001a },
+  { 0x090024cd, 0x6800001a },
+  { 0x090024ce, 0x6800001a },
+  { 0x090024cf, 0x6800001a },
+  { 0x090024d0, 0x6800ffe6 },
+  { 0x090024d1, 0x6800ffe6 },
+  { 0x090024d2, 0x6800ffe6 },
+  { 0x090024d3, 0x6800ffe6 },
+  { 0x090024d4, 0x6800ffe6 },
+  { 0x090024d5, 0x6800ffe6 },
+  { 0x090024d6, 0x6800ffe6 },
+  { 0x090024d7, 0x6800ffe6 },
+  { 0x090024d8, 0x6800ffe6 },
+  { 0x090024d9, 0x6800ffe6 },
+  { 0x090024da, 0x6800ffe6 },
+  { 0x090024db, 0x6800ffe6 },
+  { 0x090024dc, 0x6800ffe6 },
+  { 0x090024dd, 0x6800ffe6 },
+  { 0x090024de, 0x6800ffe6 },
+  { 0x090024df, 0x6800ffe6 },
+  { 0x090024e0, 0x6800ffe6 },
+  { 0x090024e1, 0x6800ffe6 },
+  { 0x090024e2, 0x6800ffe6 },
+  { 0x090024e3, 0x6800ffe6 },
+  { 0x090024e4, 0x6800ffe6 },
+  { 0x090024e5, 0x6800ffe6 },
+  { 0x090024e6, 0x6800ffe6 },
+  { 0x090024e7, 0x6800ffe6 },
+  { 0x090024e8, 0x6800ffe6 },
+  { 0x090024e9, 0x6800ffe6 },
+  { 0x098024ea, 0x3c000015 },
+  { 0x09802500, 0x680000b6 },
+  { 0x090025b7, 0x64000000 },
+  { 0x098025b8, 0x68000008 },
+  { 0x090025c1, 0x64000000 },
+  { 0x098025c2, 0x68000035 },
+  { 0x098025f8, 0x64000007 },
+  { 0x09802600, 0x6800006e },
+  { 0x0900266f, 0x64000000 },
+  { 0x09802670, 0x6800002c },
+  { 0x098026a0, 0x68000011 },
+  { 0x09802701, 0x68000003 },
+  { 0x09802706, 0x68000003 },
+  { 0x0980270c, 0x6800001b },
+  { 0x09802729, 0x68000022 },
+  { 0x0900274d, 0x68000000 },
+  { 0x0980274f, 0x68000003 },
+  { 0x09002756, 0x68000000 },
+  { 0x09802758, 0x68000006 },
+  { 0x09802761, 0x68000006 },
+  { 0x09002768, 0x58000000 },
+  { 0x09002769, 0x48000000 },
+  { 0x0900276a, 0x58000000 },
+  { 0x0900276b, 0x48000000 },
+  { 0x0900276c, 0x58000000 },
+  { 0x0900276d, 0x48000000 },
+  { 0x0900276e, 0x58000000 },
+  { 0x0900276f, 0x48000000 },
+  { 0x09002770, 0x58000000 },
+  { 0x09002771, 0x48000000 },
+  { 0x09002772, 0x58000000 },
+  { 0x09002773, 0x48000000 },
+  { 0x09002774, 0x58000000 },
+  { 0x09002775, 0x48000000 },
+  { 0x09802776, 0x3c00001d },
+  { 0x09002794, 0x68000000 },
+  { 0x09802798, 0x68000017 },
+  { 0x098027b1, 0x6800000d },
+  { 0x098027c0, 0x64000004 },
+  { 0x090027c5, 0x58000000 },
+  { 0x090027c6, 0x48000000 },
+  { 0x098027d0, 0x64000015 },
+  { 0x090027e6, 0x58000000 },
+  { 0x090027e7, 0x48000000 },
+  { 0x090027e8, 0x58000000 },
+  { 0x090027e9, 0x48000000 },
+  { 0x090027ea, 0x58000000 },
+  { 0x090027eb, 0x48000000 },
+  { 0x098027f0, 0x6400000f },
+  { 0x04802800, 0x680000ff },
+  { 0x09802900, 0x64000082 },
+  { 0x09002983, 0x58000000 },
+  { 0x09002984, 0x48000000 },
+  { 0x09002985, 0x58000000 },
+  { 0x09002986, 0x48000000 },
+  { 0x09002987, 0x58000000 },
+  { 0x09002988, 0x48000000 },
+  { 0x09002989, 0x58000000 },
+  { 0x0900298a, 0x48000000 },
+  { 0x0900298b, 0x58000000 },
+  { 0x0900298c, 0x48000000 },
+  { 0x0900298d, 0x58000000 },
+  { 0x0900298e, 0x48000000 },
+  { 0x0900298f, 0x58000000 },
+  { 0x09002990, 0x48000000 },
+  { 0x09002991, 0x58000000 },
+  { 0x09002992, 0x48000000 },
+  { 0x09002993, 0x58000000 },
+  { 0x09002994, 0x48000000 },
+  { 0x09002995, 0x58000000 },
+  { 0x09002996, 0x48000000 },
+  { 0x09002997, 0x58000000 },
+  { 0x09002998, 0x48000000 },
+  { 0x09802999, 0x6400003e },
+  { 0x090029d8, 0x58000000 },
+  { 0x090029d9, 0x48000000 },
+  { 0x090029da, 0x58000000 },
+  { 0x090029db, 0x48000000 },
+  { 0x098029dc, 0x6400001f },
+  { 0x090029fc, 0x58000000 },
+  { 0x090029fd, 0x48000000 },
+  { 0x098029fe, 0x64000101 },
+  { 0x09802b00, 0x68000013 },
+  { 0x11002c00, 0x24000030 },
+  { 0x11002c01, 0x24000030 },
+  { 0x11002c02, 0x24000030 },
+  { 0x11002c03, 0x24000030 },
+  { 0x11002c04, 0x24000030 },
+  { 0x11002c05, 0x24000030 },
+  { 0x11002c06, 0x24000030 },
+  { 0x11002c07, 0x24000030 },
+  { 0x11002c08, 0x24000030 },
+  { 0x11002c09, 0x24000030 },
+  { 0x11002c0a, 0x24000030 },
+  { 0x11002c0b, 0x24000030 },
+  { 0x11002c0c, 0x24000030 },
+  { 0x11002c0d, 0x24000030 },
+  { 0x11002c0e, 0x24000030 },
+  { 0x11002c0f, 0x24000030 },
+  { 0x11002c10, 0x24000030 },
+  { 0x11002c11, 0x24000030 },
+  { 0x11002c12, 0x24000030 },
+  { 0x11002c13, 0x24000030 },
+  { 0x11002c14, 0x24000030 },
+  { 0x11002c15, 0x24000030 },
+  { 0x11002c16, 0x24000030 },
+  { 0x11002c17, 0x24000030 },
+  { 0x11002c18, 0x24000030 },
+  { 0x11002c19, 0x24000030 },
+  { 0x11002c1a, 0x24000030 },
+  { 0x11002c1b, 0x24000030 },
+  { 0x11002c1c, 0x24000030 },
+  { 0x11002c1d, 0x24000030 },
+  { 0x11002c1e, 0x24000030 },
+  { 0x11002c1f, 0x24000030 },
+  { 0x11002c20, 0x24000030 },
+  { 0x11002c21, 0x24000030 },
+  { 0x11002c22, 0x24000030 },
+  { 0x11002c23, 0x24000030 },
+  { 0x11002c24, 0x24000030 },
+  { 0x11002c25, 0x24000030 },
+  { 0x11002c26, 0x24000030 },
+  { 0x11002c27, 0x24000030 },
+  { 0x11002c28, 0x24000030 },
+  { 0x11002c29, 0x24000030 },
+  { 0x11002c2a, 0x24000030 },
+  { 0x11002c2b, 0x24000030 },
+  { 0x11002c2c, 0x24000030 },
+  { 0x11002c2d, 0x24000030 },
+  { 0x11002c2e, 0x24000030 },
+  { 0x11002c30, 0x1400ffd0 },
+  { 0x11002c31, 0x1400ffd0 },
+  { 0x11002c32, 0x1400ffd0 },
+  { 0x11002c33, 0x1400ffd0 },
+  { 0x11002c34, 0x1400ffd0 },
+  { 0x11002c35, 0x1400ffd0 },
+  { 0x11002c36, 0x1400ffd0 },
+  { 0x11002c37, 0x1400ffd0 },
+  { 0x11002c38, 0x1400ffd0 },
+  { 0x11002c39, 0x1400ffd0 },
+  { 0x11002c3a, 0x1400ffd0 },
+  { 0x11002c3b, 0x1400ffd0 },
+  { 0x11002c3c, 0x1400ffd0 },
+  { 0x11002c3d, 0x1400ffd0 },
+  { 0x11002c3e, 0x1400ffd0 },
+  { 0x11002c3f, 0x1400ffd0 },
+  { 0x11002c40, 0x1400ffd0 },
+  { 0x11002c41, 0x1400ffd0 },
+  { 0x11002c42, 0x1400ffd0 },
+  { 0x11002c43, 0x1400ffd0 },
+  { 0x11002c44, 0x1400ffd0 },
+  { 0x11002c45, 0x1400ffd0 },
+  { 0x11002c46, 0x1400ffd0 },
+  { 0x11002c47, 0x1400ffd0 },
+  { 0x11002c48, 0x1400ffd0 },
+  { 0x11002c49, 0x1400ffd0 },
+  { 0x11002c4a, 0x1400ffd0 },
+  { 0x11002c4b, 0x1400ffd0 },
+  { 0x11002c4c, 0x1400ffd0 },
+  { 0x11002c4d, 0x1400ffd0 },
+  { 0x11002c4e, 0x1400ffd0 },
+  { 0x11002c4f, 0x1400ffd0 },
+  { 0x11002c50, 0x1400ffd0 },
+  { 0x11002c51, 0x1400ffd0 },
+  { 0x11002c52, 0x1400ffd0 },
+  { 0x11002c53, 0x1400ffd0 },
+  { 0x11002c54, 0x1400ffd0 },
+  { 0x11002c55, 0x1400ffd0 },
+  { 0x11002c56, 0x1400ffd0 },
+  { 0x11002c57, 0x1400ffd0 },
+  { 0x11002c58, 0x1400ffd0 },
+  { 0x11002c59, 0x1400ffd0 },
+  { 0x11002c5a, 0x1400ffd0 },
+  { 0x11002c5b, 0x1400ffd0 },
+  { 0x11002c5c, 0x1400ffd0 },
+  { 0x11002c5d, 0x1400ffd0 },
+  { 0x11002c5e, 0x1400ffd0 },
+  { 0x0a002c80, 0x24000001 },
+  { 0x0a002c81, 0x1400ffff },
+  { 0x0a002c82, 0x24000001 },
+  { 0x0a002c83, 0x1400ffff },
+  { 0x0a002c84, 0x24000001 },
+  { 0x0a002c85, 0x1400ffff },
+  { 0x0a002c86, 0x24000001 },
+  { 0x0a002c87, 0x1400ffff },
+  { 0x0a002c88, 0x24000001 },
+  { 0x0a002c89, 0x1400ffff },
+  { 0x0a002c8a, 0x24000001 },
+  { 0x0a002c8b, 0x1400ffff },
+  { 0x0a002c8c, 0x24000001 },
+  { 0x0a002c8d, 0x1400ffff },
+  { 0x0a002c8e, 0x24000001 },
+  { 0x0a002c8f, 0x1400ffff },
+  { 0x0a002c90, 0x24000001 },
+  { 0x0a002c91, 0x1400ffff },
+  { 0x0a002c92, 0x24000001 },
+  { 0x0a002c93, 0x1400ffff },
+  { 0x0a002c94, 0x24000001 },
+  { 0x0a002c95, 0x1400ffff },
+  { 0x0a002c96, 0x24000001 },
+  { 0x0a002c97, 0x1400ffff },
+  { 0x0a002c98, 0x24000001 },
+  { 0x0a002c99, 0x1400ffff },
+  { 0x0a002c9a, 0x24000001 },
+  { 0x0a002c9b, 0x1400ffff },
+  { 0x0a002c9c, 0x24000001 },
+  { 0x0a002c9d, 0x1400ffff },
+  { 0x0a002c9e, 0x24000001 },
+  { 0x0a002c9f, 0x1400ffff },
+  { 0x0a002ca0, 0x24000001 },
+  { 0x0a002ca1, 0x1400ffff },
+  { 0x0a002ca2, 0x24000001 },
+  { 0x0a002ca3, 0x1400ffff },
+  { 0x0a002ca4, 0x24000001 },
+  { 0x0a002ca5, 0x1400ffff },
+  { 0x0a002ca6, 0x24000001 },
+  { 0x0a002ca7, 0x1400ffff },
+  { 0x0a002ca8, 0x24000001 },
+  { 0x0a002ca9, 0x1400ffff },
+  { 0x0a002caa, 0x24000001 },
+  { 0x0a002cab, 0x1400ffff },
+  { 0x0a002cac, 0x24000001 },
+  { 0x0a002cad, 0x1400ffff },
+  { 0x0a002cae, 0x24000001 },
+  { 0x0a002caf, 0x1400ffff },
+  { 0x0a002cb0, 0x24000001 },
+  { 0x0a002cb1, 0x1400ffff },
+  { 0x0a002cb2, 0x24000001 },
+  { 0x0a002cb3, 0x1400ffff },
+  { 0x0a002cb4, 0x24000001 },
+  { 0x0a002cb5, 0x1400ffff },
+  { 0x0a002cb6, 0x24000001 },
+  { 0x0a002cb7, 0x1400ffff },
+  { 0x0a002cb8, 0x24000001 },
+  { 0x0a002cb9, 0x1400ffff },
+  { 0x0a002cba, 0x24000001 },
+  { 0x0a002cbb, 0x1400ffff },
+  { 0x0a002cbc, 0x24000001 },
+  { 0x0a002cbd, 0x1400ffff },
+  { 0x0a002cbe, 0x24000001 },
+  { 0x0a002cbf, 0x1400ffff },
+  { 0x0a002cc0, 0x24000001 },
+  { 0x0a002cc1, 0x1400ffff },
+  { 0x0a002cc2, 0x24000001 },
+  { 0x0a002cc3, 0x1400ffff },
+  { 0x0a002cc4, 0x24000001 },
+  { 0x0a002cc5, 0x1400ffff },
+  { 0x0a002cc6, 0x24000001 },
+  { 0x0a002cc7, 0x1400ffff },
+  { 0x0a002cc8, 0x24000001 },
+  { 0x0a002cc9, 0x1400ffff },
+  { 0x0a002cca, 0x24000001 },
+  { 0x0a002ccb, 0x1400ffff },
+  { 0x0a002ccc, 0x24000001 },
+  { 0x0a002ccd, 0x1400ffff },
+  { 0x0a002cce, 0x24000001 },
+  { 0x0a002ccf, 0x1400ffff },
+  { 0x0a002cd0, 0x24000001 },
+  { 0x0a002cd1, 0x1400ffff },
+  { 0x0a002cd2, 0x24000001 },
+  { 0x0a002cd3, 0x1400ffff },
+  { 0x0a002cd4, 0x24000001 },
+  { 0x0a002cd5, 0x1400ffff },
+  { 0x0a002cd6, 0x24000001 },
+  { 0x0a002cd7, 0x1400ffff },
+  { 0x0a002cd8, 0x24000001 },
+  { 0x0a002cd9, 0x1400ffff },
+  { 0x0a002cda, 0x24000001 },
+  { 0x0a002cdb, 0x1400ffff },
+  { 0x0a002cdc, 0x24000001 },
+  { 0x0a002cdd, 0x1400ffff },
+  { 0x0a002cde, 0x24000001 },
+  { 0x0a002cdf, 0x1400ffff },
+  { 0x0a002ce0, 0x24000001 },
+  { 0x0a002ce1, 0x1400ffff },
+  { 0x0a002ce2, 0x24000001 },
+  { 0x0a002ce3, 0x1400ffff },
+  { 0x0a002ce4, 0x14000000 },
+  { 0x0a802ce5, 0x68000005 },
+  { 0x0a802cf9, 0x54000003 },
+  { 0x0a002cfd, 0x3c000000 },
+  { 0x0a802cfe, 0x54000001 },
+  { 0x10002d00, 0x1400e3a0 },
+  { 0x10002d01, 0x1400e3a0 },
+  { 0x10002d02, 0x1400e3a0 },
+  { 0x10002d03, 0x1400e3a0 },
+  { 0x10002d04, 0x1400e3a0 },
+  { 0x10002d05, 0x1400e3a0 },
+  { 0x10002d06, 0x1400e3a0 },
+  { 0x10002d07, 0x1400e3a0 },
+  { 0x10002d08, 0x1400e3a0 },
+  { 0x10002d09, 0x1400e3a0 },
+  { 0x10002d0a, 0x1400e3a0 },
+  { 0x10002d0b, 0x1400e3a0 },
+  { 0x10002d0c, 0x1400e3a0 },
+  { 0x10002d0d, 0x1400e3a0 },
+  { 0x10002d0e, 0x1400e3a0 },
+  { 0x10002d0f, 0x1400e3a0 },
+  { 0x10002d10, 0x1400e3a0 },
+  { 0x10002d11, 0x1400e3a0 },
+  { 0x10002d12, 0x1400e3a0 },
+  { 0x10002d13, 0x1400e3a0 },
+  { 0x10002d14, 0x1400e3a0 },
+  { 0x10002d15, 0x1400e3a0 },
+  { 0x10002d16, 0x1400e3a0 },
+  { 0x10002d17, 0x1400e3a0 },
+  { 0x10002d18, 0x1400e3a0 },
+  { 0x10002d19, 0x1400e3a0 },
+  { 0x10002d1a, 0x1400e3a0 },
+  { 0x10002d1b, 0x1400e3a0 },
+  { 0x10002d1c, 0x1400e3a0 },
+  { 0x10002d1d, 0x1400e3a0 },
+  { 0x10002d1e, 0x1400e3a0 },
+  { 0x10002d1f, 0x1400e3a0 },
+  { 0x10002d20, 0x1400e3a0 },
+  { 0x10002d21, 0x1400e3a0 },
+  { 0x10002d22, 0x1400e3a0 },
+  { 0x10002d23, 0x1400e3a0 },
+  { 0x10002d24, 0x1400e3a0 },
+  { 0x10002d25, 0x1400e3a0 },
+  { 0x3a802d30, 0x1c000035 },
+  { 0x3a002d6f, 0x18000000 },
+  { 0x0f802d80, 0x1c000016 },
+  { 0x0f802da0, 0x1c000006 },
+  { 0x0f802da8, 0x1c000006 },
+  { 0x0f802db0, 0x1c000006 },
+  { 0x0f802db8, 0x1c000006 },
+  { 0x0f802dc0, 0x1c000006 },
+  { 0x0f802dc8, 0x1c000006 },
+  { 0x0f802dd0, 0x1c000006 },
+  { 0x0f802dd8, 0x1c000006 },
+  { 0x09802e00, 0x54000001 },
+  { 0x09002e02, 0x50000000 },
+  { 0x09002e03, 0x4c000000 },
+  { 0x09002e04, 0x50000000 },
+  { 0x09002e05, 0x4c000000 },
+  { 0x09802e06, 0x54000002 },
+  { 0x09002e09, 0x50000000 },
+  { 0x09002e0a, 0x4c000000 },
+  { 0x09002e0b, 0x54000000 },
+  { 0x09002e0c, 0x50000000 },
+  { 0x09002e0d, 0x4c000000 },
+  { 0x09802e0e, 0x54000008 },
+  { 0x09002e17, 0x44000000 },
+  { 0x09002e1c, 0x50000000 },
+  { 0x09002e1d, 0x4c000000 },
+  { 0x16802e80, 0x68000019 },
+  { 0x16802e9b, 0x68000058 },
+  { 0x16802f00, 0x680000d5 },
+  { 0x09802ff0, 0x6800000b },
+  { 0x09003000, 0x74000000 },
+  { 0x09803001, 0x54000002 },
+  { 0x09003004, 0x68000000 },
+  { 0x16003005, 0x18000000 },
+  { 0x09003006, 0x1c000000 },
+  { 0x16003007, 0x38000000 },
+  { 0x09003008, 0x58000000 },
+  { 0x09003009, 0x48000000 },
+  { 0x0900300a, 0x58000000 },
+  { 0x0900300b, 0x48000000 },
+  { 0x0900300c, 0x58000000 },
+  { 0x0900300d, 0x48000000 },
+  { 0x0900300e, 0x58000000 },
+  { 0x0900300f, 0x48000000 },
+  { 0x09003010, 0x58000000 },
+  { 0x09003011, 0x48000000 },
+  { 0x09803012, 0x68000001 },
+  { 0x09003014, 0x58000000 },
+  { 0x09003015, 0x48000000 },
+  { 0x09003016, 0x58000000 },
+  { 0x09003017, 0x48000000 },
+  { 0x09003018, 0x58000000 },
+  { 0x09003019, 0x48000000 },
+  { 0x0900301a, 0x58000000 },
+  { 0x0900301b, 0x48000000 },
+  { 0x0900301c, 0x44000000 },
+  { 0x0900301d, 0x58000000 },
+  { 0x0980301e, 0x48000001 },
+  { 0x09003020, 0x68000000 },
+  { 0x16803021, 0x38000008 },
+  { 0x1b80302a, 0x30000005 },
+  { 0x09003030, 0x44000000 },
+  { 0x09803031, 0x18000004 },
+  { 0x09803036, 0x68000001 },
+  { 0x16803038, 0x38000002 },
+  { 0x1600303b, 0x18000000 },
+  { 0x0900303c, 0x1c000000 },
+  { 0x0900303d, 0x54000000 },
+  { 0x0980303e, 0x68000001 },
+  { 0x1a803041, 0x1c000055 },
+  { 0x1b803099, 0x30000001 },
+  { 0x0980309b, 0x60000001 },
+  { 0x1a80309d, 0x18000001 },
+  { 0x1a00309f, 0x1c000000 },
+  { 0x090030a0, 0x44000000 },
+  { 0x1d8030a1, 0x1c000059 },
+  { 0x090030fb, 0x54000000 },
+  { 0x098030fc, 0x18000002 },
+  { 0x1d0030ff, 0x1c000000 },
+  { 0x03803105, 0x1c000027 },
+  { 0x17803131, 0x1c00005d },
+  { 0x09803190, 0x68000001 },
+  { 0x09803192, 0x3c000003 },
+  { 0x09803196, 0x68000009 },
+  { 0x038031a0, 0x1c000017 },
+  { 0x098031c0, 0x6800000f },
+  { 0x1d8031f0, 0x1c00000f },
+  { 0x17803200, 0x6800001e },
+  { 0x09803220, 0x3c000009 },
+  { 0x0980322a, 0x68000019 },
+  { 0x09003250, 0x68000000 },
+  { 0x09803251, 0x3c00000e },
+  { 0x17803260, 0x6800001f },
+  { 0x09803280, 0x3c000009 },
+  { 0x0980328a, 0x68000026 },
+  { 0x098032b1, 0x3c00000e },
+  { 0x098032c0, 0x6800003e },
+  { 0x09803300, 0x680000ff },
+  { 0x16803400, 0x1c0019b5 },
+  { 0x09804dc0, 0x6800003f },
+  { 0x16804e00, 0x1c0051bb },
+  { 0x3c80a000, 0x1c000014 },
+  { 0x3c00a015, 0x18000000 },
+  { 0x3c80a016, 0x1c000476 },
+  { 0x3c80a490, 0x68000036 },
+  { 0x0980a700, 0x60000016 },
+  { 0x3080a800, 0x1c000001 },
+  { 0x3000a802, 0x28000000 },
+  { 0x3080a803, 0x1c000002 },
+  { 0x3000a806, 0x30000000 },
+  { 0x3080a807, 0x1c000003 },
+  { 0x3000a80b, 0x30000000 },
+  { 0x3080a80c, 0x1c000016 },
+  { 0x3080a823, 0x28000001 },
+  { 0x3080a825, 0x30000001 },
+  { 0x3000a827, 0x28000000 },
+  { 0x3080a828, 0x68000003 },
+  { 0x1780ac00, 0x1c002ba3 },
+  { 0x0980d800, 0x1000037f },
+  { 0x0980db80, 0x1000007f },
+  { 0x0980dc00, 0x100003ff },
+  { 0x0980e000, 0x0c0018ff },
+  { 0x1680f900, 0x1c00012d },
+  { 0x1680fa30, 0x1c00003a },
+  { 0x1680fa70, 0x1c000069 },
+  { 0x2180fb00, 0x14000006 },
+  { 0x0180fb13, 0x14000004 },
+  { 0x1900fb1d, 0x1c000000 },
+  { 0x1900fb1e, 0x30000000 },
+  { 0x1980fb1f, 0x1c000009 },
+  { 0x1900fb29, 0x64000000 },
+  { 0x1980fb2a, 0x1c00000c },
+  { 0x1980fb38, 0x1c000004 },
+  { 0x1900fb3e, 0x1c000000 },
+  { 0x1980fb40, 0x1c000001 },
+  { 0x1980fb43, 0x1c000001 },
+  { 0x1980fb46, 0x1c00006b },
+  { 0x0080fbd3, 0x1c00016a },
+  { 0x0900fd3e, 0x58000000 },
+  { 0x0900fd3f, 0x48000000 },
+  { 0x0080fd50, 0x1c00003f },
+  { 0x0080fd92, 0x1c000035 },
+  { 0x0080fdf0, 0x1c00000b },
+  { 0x0000fdfc, 0x5c000000 },
+  { 0x0900fdfd, 0x68000000 },
+  { 0x1b80fe00, 0x3000000f },
+  { 0x0980fe10, 0x54000006 },
+  { 0x0900fe17, 0x58000000 },
+  { 0x0900fe18, 0x48000000 },
+  { 0x0900fe19, 0x54000000 },
+  { 0x1b80fe20, 0x30000003 },
+  { 0x0900fe30, 0x54000000 },
+  { 0x0980fe31, 0x44000001 },
+  { 0x0980fe33, 0x40000001 },
+  { 0x0900fe35, 0x58000000 },
+  { 0x0900fe36, 0x48000000 },
+  { 0x0900fe37, 0x58000000 },
+  { 0x0900fe38, 0x48000000 },
+  { 0x0900fe39, 0x58000000 },
+  { 0x0900fe3a, 0x48000000 },
+  { 0x0900fe3b, 0x58000000 },
+  { 0x0900fe3c, 0x48000000 },
+  { 0x0900fe3d, 0x58000000 },
+  { 0x0900fe3e, 0x48000000 },
+  { 0x0900fe3f, 0x58000000 },
+  { 0x0900fe40, 0x48000000 },
+  { 0x0900fe41, 0x58000000 },
+  { 0x0900fe42, 0x48000000 },
+  { 0x0900fe43, 0x58000000 },
+  { 0x0900fe44, 0x48000000 },
+  { 0x0980fe45, 0x54000001 },
+  { 0x0900fe47, 0x58000000 },
+  { 0x0900fe48, 0x48000000 },
+  { 0x0980fe49, 0x54000003 },
+  { 0x0980fe4d, 0x40000002 },
+  { 0x0980fe50, 0x54000002 },
+  { 0x0980fe54, 0x54000003 },
+  { 0x0900fe58, 0x44000000 },
+  { 0x0900fe59, 0x58000000 },
+  { 0x0900fe5a, 0x48000000 },
+  { 0x0900fe5b, 0x58000000 },
+  { 0x0900fe5c, 0x48000000 },
+  { 0x0900fe5d, 0x58000000 },
+  { 0x0900fe5e, 0x48000000 },
+  { 0x0980fe5f, 0x54000002 },
+  { 0x0900fe62, 0x64000000 },
+  { 0x0900fe63, 0x44000000 },
+  { 0x0980fe64, 0x64000002 },
+  { 0x0900fe68, 0x54000000 },
+  { 0x0900fe69, 0x5c000000 },
+  { 0x0980fe6a, 0x54000001 },
+  { 0x0080fe70, 0x1c000004 },
+  { 0x0080fe76, 0x1c000086 },
+  { 0x0900feff, 0x04000000 },
+  { 0x0980ff01, 0x54000002 },
+  { 0x0900ff04, 0x5c000000 },
+  { 0x0980ff05, 0x54000002 },
+  { 0x0900ff08, 0x58000000 },
+  { 0x0900ff09, 0x48000000 },
+  { 0x0900ff0a, 0x54000000 },
+  { 0x0900ff0b, 0x64000000 },
+  { 0x0900ff0c, 0x54000000 },
+  { 0x0900ff0d, 0x44000000 },
+  { 0x0980ff0e, 0x54000001 },
+  { 0x0980ff10, 0x34000009 },
+  { 0x0980ff1a, 0x54000001 },
+  { 0x0980ff1c, 0x64000002 },
+  { 0x0980ff1f, 0x54000001 },
+  { 0x2100ff21, 0x24000020 },
+  { 0x2100ff22, 0x24000020 },
+  { 0x2100ff23, 0x24000020 },
+  { 0x2100ff24, 0x24000020 },
+  { 0x2100ff25, 0x24000020 },
+  { 0x2100ff26, 0x24000020 },
+  { 0x2100ff27, 0x24000020 },
+  { 0x2100ff28, 0x24000020 },
+  { 0x2100ff29, 0x24000020 },
+  { 0x2100ff2a, 0x24000020 },
+  { 0x2100ff2b, 0x24000020 },
+  { 0x2100ff2c, 0x24000020 },
+  { 0x2100ff2d, 0x24000020 },
+  { 0x2100ff2e, 0x24000020 },
+  { 0x2100ff2f, 0x24000020 },
+  { 0x2100ff30, 0x24000020 },
+  { 0x2100ff31, 0x24000020 },
+  { 0x2100ff32, 0x24000020 },
+  { 0x2100ff33, 0x24000020 },
+  { 0x2100ff34, 0x24000020 },
+  { 0x2100ff35, 0x24000020 },
+  { 0x2100ff36, 0x24000020 },
+  { 0x2100ff37, 0x24000020 },
+  { 0x2100ff38, 0x24000020 },
+  { 0x2100ff39, 0x24000020 },
+  { 0x2100ff3a, 0x24000020 },
+  { 0x0900ff3b, 0x58000000 },
+  { 0x0900ff3c, 0x54000000 },
+  { 0x0900ff3d, 0x48000000 },
+  { 0x0900ff3e, 0x60000000 },
+  { 0x0900ff3f, 0x40000000 },
+  { 0x0900ff40, 0x60000000 },
+  { 0x2100ff41, 0x1400ffe0 },
+  { 0x2100ff42, 0x1400ffe0 },
+  { 0x2100ff43, 0x1400ffe0 },
+  { 0x2100ff44, 0x1400ffe0 },
+  { 0x2100ff45, 0x1400ffe0 },
+  { 0x2100ff46, 0x1400ffe0 },
+  { 0x2100ff47, 0x1400ffe0 },
+  { 0x2100ff48, 0x1400ffe0 },
+  { 0x2100ff49, 0x1400ffe0 },
+  { 0x2100ff4a, 0x1400ffe0 },
+  { 0x2100ff4b, 0x1400ffe0 },
+  { 0x2100ff4c, 0x1400ffe0 },
+  { 0x2100ff4d, 0x1400ffe0 },
+  { 0x2100ff4e, 0x1400ffe0 },
+  { 0x2100ff4f, 0x1400ffe0 },
+  { 0x2100ff50, 0x1400ffe0 },
+  { 0x2100ff51, 0x1400ffe0 },
+  { 0x2100ff52, 0x1400ffe0 },
+  { 0x2100ff53, 0x1400ffe0 },
+  { 0x2100ff54, 0x1400ffe0 },
+  { 0x2100ff55, 0x1400ffe0 },
+  { 0x2100ff56, 0x1400ffe0 },
+  { 0x2100ff57, 0x1400ffe0 },
+  { 0x2100ff58, 0x1400ffe0 },
+  { 0x2100ff59, 0x1400ffe0 },
+  { 0x2100ff5a, 0x1400ffe0 },
+  { 0x0900ff5b, 0x58000000 },
+  { 0x0900ff5c, 0x64000000 },
+  { 0x0900ff5d, 0x48000000 },
+  { 0x0900ff5e, 0x64000000 },
+  { 0x0900ff5f, 0x58000000 },
+  { 0x0900ff60, 0x48000000 },
+  { 0x0900ff61, 0x54000000 },
+  { 0x0900ff62, 0x58000000 },
+  { 0x0900ff63, 0x48000000 },
+  { 0x0980ff64, 0x54000001 },
+  { 0x1d80ff66, 0x1c000009 },
+  { 0x0900ff70, 0x18000000 },
+  { 0x1d80ff71, 0x1c00002c },
+  { 0x0980ff9e, 0x18000001 },
+  { 0x1780ffa0, 0x1c00001e },
+  { 0x1780ffc2, 0x1c000005 },
+  { 0x1780ffca, 0x1c000005 },
+  { 0x1780ffd2, 0x1c000005 },
+  { 0x1780ffda, 0x1c000002 },
+  { 0x0980ffe0, 0x5c000001 },
+  { 0x0900ffe2, 0x64000000 },
+  { 0x0900ffe3, 0x60000000 },
+  { 0x0900ffe4, 0x68000000 },
+  { 0x0980ffe5, 0x5c000001 },
+  { 0x0900ffe8, 0x68000000 },
+  { 0x0980ffe9, 0x64000003 },
+  { 0x0980ffed, 0x68000001 },
+  { 0x0980fff9, 0x04000002 },
+  { 0x0980fffc, 0x68000001 },
+  { 0x23810000, 0x1c00000b },
+  { 0x2381000d, 0x1c000019 },
+  { 0x23810028, 0x1c000012 },
+  { 0x2381003c, 0x1c000001 },
+  { 0x2381003f, 0x1c00000e },
+  { 0x23810050, 0x1c00000d },
+  { 0x23810080, 0x1c00007a },
+  { 0x09810100, 0x54000001 },
+  { 0x09010102, 0x68000000 },
+  { 0x09810107, 0x3c00002c },
+  { 0x09810137, 0x68000008 },
+  { 0x13810140, 0x38000034 },
+  { 0x13810175, 0x3c000003 },
+  { 0x13810179, 0x68000010 },
+  { 0x1301018a, 0x3c000000 },
+  { 0x29810300, 0x1c00001e },
+  { 0x29810320, 0x3c000003 },
+  { 0x12810330, 0x1c000019 },
+  { 0x1201034a, 0x38000000 },
+  { 0x3b810380, 0x1c00001d },
+  { 0x3b01039f, 0x54000000 },
+  { 0x2a8103a0, 0x1c000023 },
+  { 0x2a8103c8, 0x1c000007 },
+  { 0x2a0103d0, 0x68000000 },
+  { 0x2a8103d1, 0x38000004 },
+  { 0x0d010400, 0x24000028 },
+  { 0x0d010401, 0x24000028 },
+  { 0x0d010402, 0x24000028 },
+  { 0x0d010403, 0x24000028 },
+  { 0x0d010404, 0x24000028 },
+  { 0x0d010405, 0x24000028 },
+  { 0x0d010406, 0x24000028 },
+  { 0x0d010407, 0x24000028 },
+  { 0x0d010408, 0x24000028 },
+  { 0x0d010409, 0x24000028 },
+  { 0x0d01040a, 0x24000028 },
+  { 0x0d01040b, 0x24000028 },
+  { 0x0d01040c, 0x24000028 },
+  { 0x0d01040d, 0x24000028 },
+  { 0x0d01040e, 0x24000028 },
+  { 0x0d01040f, 0x24000028 },
+  { 0x0d010410, 0x24000028 },
+  { 0x0d010411, 0x24000028 },
+  { 0x0d010412, 0x24000028 },
+  { 0x0d010413, 0x24000028 },
+  { 0x0d010414, 0x24000028 },
+  { 0x0d010415, 0x24000028 },
+  { 0x0d010416, 0x24000028 },
+  { 0x0d010417, 0x24000028 },
+  { 0x0d010418, 0x24000028 },
+  { 0x0d010419, 0x24000028 },
+  { 0x0d01041a, 0x24000028 },
+  { 0x0d01041b, 0x24000028 },
+  { 0x0d01041c, 0x24000028 },
+  { 0x0d01041d, 0x24000028 },
+  { 0x0d01041e, 0x24000028 },
+  { 0x0d01041f, 0x24000028 },
+  { 0x0d010420, 0x24000028 },
+  { 0x0d010421, 0x24000028 },
+  { 0x0d010422, 0x24000028 },
+  { 0x0d010423, 0x24000028 },
+  { 0x0d010424, 0x24000028 },
+  { 0x0d010425, 0x24000028 },
+  { 0x0d010426, 0x24000028 },
+  { 0x0d010427, 0x24000028 },
+  { 0x0d010428, 0x1400ffd8 },
+  { 0x0d010429, 0x1400ffd8 },
+  { 0x0d01042a, 0x1400ffd8 },
+  { 0x0d01042b, 0x1400ffd8 },
+  { 0x0d01042c, 0x1400ffd8 },
+  { 0x0d01042d, 0x1400ffd8 },
+  { 0x0d01042e, 0x1400ffd8 },
+  { 0x0d01042f, 0x1400ffd8 },
+  { 0x0d010430, 0x1400ffd8 },
+  { 0x0d010431, 0x1400ffd8 },
+  { 0x0d010432, 0x1400ffd8 },
+  { 0x0d010433, 0x1400ffd8 },
+  { 0x0d010434, 0x1400ffd8 },
+  { 0x0d010435, 0x1400ffd8 },
+  { 0x0d010436, 0x1400ffd8 },
+  { 0x0d010437, 0x1400ffd8 },
+  { 0x0d010438, 0x1400ffd8 },
+  { 0x0d010439, 0x1400ffd8 },
+  { 0x0d01043a, 0x1400ffd8 },
+  { 0x0d01043b, 0x1400ffd8 },
+  { 0x0d01043c, 0x1400ffd8 },
+  { 0x0d01043d, 0x1400ffd8 },
+  { 0x0d01043e, 0x1400ffd8 },
+  { 0x0d01043f, 0x1400ffd8 },
+  { 0x0d010440, 0x1400ffd8 },
+  { 0x0d010441, 0x1400ffd8 },
+  { 0x0d010442, 0x1400ffd8 },
+  { 0x0d010443, 0x1400ffd8 },
+  { 0x0d010444, 0x1400ffd8 },
+  { 0x0d010445, 0x1400ffd8 },
+  { 0x0d010446, 0x1400ffd8 },
+  { 0x0d010447, 0x1400ffd8 },
+  { 0x0d010448, 0x1400ffd8 },
+  { 0x0d010449, 0x1400ffd8 },
+  { 0x0d01044a, 0x1400ffd8 },
+  { 0x0d01044b, 0x1400ffd8 },
+  { 0x0d01044c, 0x1400ffd8 },
+  { 0x0d01044d, 0x1400ffd8 },
+  { 0x0d01044e, 0x1400ffd8 },
+  { 0x0d01044f, 0x1400ffd8 },
+  { 0x2e810450, 0x1c00004d },
+  { 0x2c8104a0, 0x34000009 },
+  { 0x0b810800, 0x1c000005 },
+  { 0x0b010808, 0x1c000000 },
+  { 0x0b81080a, 0x1c00002b },
+  { 0x0b810837, 0x1c000001 },
+  { 0x0b01083c, 0x1c000000 },
+  { 0x0b01083f, 0x1c000000 },
+  { 0x1e010a00, 0x1c000000 },
+  { 0x1e810a01, 0x30000002 },
+  { 0x1e810a05, 0x30000001 },
+  { 0x1e810a0c, 0x30000003 },
+  { 0x1e810a10, 0x1c000003 },
+  { 0x1e810a15, 0x1c000002 },
+  { 0x1e810a19, 0x1c00001a },
+  { 0x1e810a38, 0x30000002 },
+  { 0x1e010a3f, 0x30000000 },
+  { 0x1e810a40, 0x3c000007 },
+  { 0x1e810a50, 0x54000008 },
+  { 0x0981d000, 0x680000f5 },
+  { 0x0981d100, 0x68000026 },
+  { 0x0981d12a, 0x6800003a },
+  { 0x0981d165, 0x28000001 },
+  { 0x1b81d167, 0x30000002 },
+  { 0x0981d16a, 0x68000002 },
+  { 0x0981d16d, 0x28000005 },
+  { 0x0981d173, 0x04000007 },
+  { 0x1b81d17b, 0x30000007 },
+  { 0x0981d183, 0x68000001 },
+  { 0x1b81d185, 0x30000006 },
+  { 0x0981d18c, 0x6800001d },
+  { 0x1b81d1aa, 0x30000003 },
+  { 0x0981d1ae, 0x6800002f },
+  { 0x1381d200, 0x68000041 },
+  { 0x1381d242, 0x30000002 },
+  { 0x1301d245, 0x68000000 },
+  { 0x0981d300, 0x68000056 },
+  { 0x0981d400, 0x24000019 },
+  { 0x0981d41a, 0x14000019 },
+  { 0x0981d434, 0x24000019 },
+  { 0x0981d44e, 0x14000006 },
+  { 0x0981d456, 0x14000011 },
+  { 0x0981d468, 0x24000019 },
+  { 0x0981d482, 0x14000019 },
+  { 0x0901d49c, 0x24000000 },
+  { 0x0981d49e, 0x24000001 },
+  { 0x0901d4a2, 0x24000000 },
+  { 0x0981d4a5, 0x24000001 },
+  { 0x0981d4a9, 0x24000003 },
+  { 0x0981d4ae, 0x24000007 },
+  { 0x0981d4b6, 0x14000003 },
+  { 0x0901d4bb, 0x14000000 },
+  { 0x0981d4bd, 0x14000006 },
+  { 0x0981d4c5, 0x1400000a },
+  { 0x0981d4d0, 0x24000019 },
+  { 0x0981d4ea, 0x14000019 },
+  { 0x0981d504, 0x24000001 },
+  { 0x0981d507, 0x24000003 },
+  { 0x0981d50d, 0x24000007 },
+  { 0x0981d516, 0x24000006 },
+  { 0x0981d51e, 0x14000019 },
+  { 0x0981d538, 0x24000001 },
+  { 0x0981d53b, 0x24000003 },
+  { 0x0981d540, 0x24000004 },
+  { 0x0901d546, 0x24000000 },
+  { 0x0981d54a, 0x24000006 },
+  { 0x0981d552, 0x14000019 },
+  { 0x0981d56c, 0x24000019 },
+  { 0x0981d586, 0x14000019 },
+  { 0x0981d5a0, 0x24000019 },
+  { 0x0981d5ba, 0x14000019 },
+  { 0x0981d5d4, 0x24000019 },
+  { 0x0981d5ee, 0x14000019 },
+  { 0x0981d608, 0x24000019 },
+  { 0x0981d622, 0x14000019 },
+  { 0x0981d63c, 0x24000019 },
+  { 0x0981d656, 0x14000019 },
+  { 0x0981d670, 0x24000019 },
+  { 0x0981d68a, 0x1400001b },
+  { 0x0981d6a8, 0x24000018 },
+  { 0x0901d6c1, 0x64000000 },
+  { 0x0981d6c2, 0x14000018 },
+  { 0x0901d6db, 0x64000000 },
+  { 0x0981d6dc, 0x14000005 },
+  { 0x0981d6e2, 0x24000018 },
+  { 0x0901d6fb, 0x64000000 },
+  { 0x0981d6fc, 0x14000018 },
+  { 0x0901d715, 0x64000000 },
+  { 0x0981d716, 0x14000005 },
+  { 0x0981d71c, 0x24000018 },
+  { 0x0901d735, 0x64000000 },
+  { 0x0981d736, 0x14000018 },
+  { 0x0901d74f, 0x64000000 },
+  { 0x0981d750, 0x14000005 },
+  { 0x0981d756, 0x24000018 },
+  { 0x0901d76f, 0x64000000 },
+  { 0x0981d770, 0x14000018 },
+  { 0x0901d789, 0x64000000 },
+  { 0x0981d78a, 0x14000005 },
+  { 0x0981d790, 0x24000018 },
+  { 0x0901d7a9, 0x64000000 },
+  { 0x0981d7aa, 0x14000018 },
+  { 0x0901d7c3, 0x64000000 },
+  { 0x0981d7c4, 0x14000005 },
+  { 0x0981d7ce, 0x34000031 },
+  { 0x16820000, 0x1c00a6d6 },
+  { 0x1682f800, 0x1c00021d },
+  { 0x090e0001, 0x04000000 },
+  { 0x098e0020, 0x0400005f },
+  { 0x1b8e0100, 0x300000ef },
+  { 0x098f0000, 0x0c00fffd },
+  { 0x09900000, 0x0c00fffd },
+};
diff --git a/regexp2000/src/token.cc b/regexp2000/src/token.cc
new file mode 100644 (file)
index 0000000..3f92707
--- /dev/null
@@ -0,0 +1,162 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "token.h"
+
+namespace v8 { namespace internal {
+
+#ifdef DEBUG
+#define T(name, string, precedence) #name,
+const char* Token::name_[NUM_TOKENS] = {
+  TOKEN_LIST(T, T, IGNORE_TOKEN)
+};
+#undef T
+#endif
+
+
+#define T(name, string, precedence) string,
+const char* Token::string_[NUM_TOKENS] = {
+  TOKEN_LIST(T, T, IGNORE_TOKEN)
+};
+#undef T
+
+
+#define T(name, string, precedence) precedence,
+int8_t Token::precedence_[NUM_TOKENS] = {
+  TOKEN_LIST(T, T, IGNORE_TOKEN)
+};
+#undef T
+
+
+// A perfect (0 collision) hash table of keyword token values.
+
+// larger N will reduce the number of collisions (power of 2 for fast %)
+const unsigned int N = 128;
+// make this small since we have <= 256 tokens
+static uint8_t Hashtable[N];
+static bool IsInitialized = false;
+
+
+static unsigned int Hash(const char* s) {
+  // The following constants have been found using trial-and-error. If the
+  // keyword set changes, they may have to be recomputed (make them flags
+  // and play with the flag values). Increasing N is the simplest way to
+  // reduce the number of collisions.
+
+  // we must use at least 4 or more chars ('const' and 'continue' share
+  // 'con')
+  const unsigned int L = 5;
+  // smaller S tend to reduce the number of collisions
+  const unsigned int S = 4;
+  // make this a prime, or at least an odd number
+  const unsigned int M = 3;
+
+  unsigned int h = 0;
+  for (unsigned int i = 0; s[i] != '\0' && i < L; i++) {
+    h += (h << S) + s[i];
+  }
+  // unsigned int % by a power of 2 (otherwise this will not be a bit mask)
+  return h * M % N;
+}
+
+
+Token::Value Token::Lookup(const char* str) {
+  ASSERT(IsInitialized);
+  Value k = static_cast<Value>(Hashtable[Hash(str)]);
+  const char* s = string_[k];
+  ASSERT(s != NULL || k == IDENTIFIER);
+  if (s == NULL || strcmp(s, str) == 0) {
+    return k;
+  }
+  return IDENTIFIER;
+}
+
+
+#ifdef DEBUG
+// We need this function because C++ doesn't allow the expression
+// NULL == NULL, which is a result of macro expansion below. What
+// the hell?
+static bool IsNull(const char* s) {
+  return s == NULL;
+}
+#endif
+
+
+void Token::Initialize() {
+  if (IsInitialized) return;
+
+  // A list of all keywords, terminated by ILLEGAL.
+#define T(name, string, precedence) name,
+  static Value keyword[] = {
+    TOKEN_LIST(IGNORE_TOKEN, T, IGNORE_TOKEN)
+    ILLEGAL
+  };
+#undef T
+
+  // Assert that the keyword array contains the 25 keywords, 3 future
+  // reserved words (const, debugger, and native), and the 3 named literals
+  // defined by ECMA-262 standard.
+  ASSERT(ARRAY_SIZE(keyword) == 25 + 3 + 3 + 1);  // +1 for ILLEGAL sentinel
+
+  // Initialize Hashtable.
+  ASSERT(NUM_TOKENS <= 256);  // Hashtable contains uint8_t elements
+  for (unsigned int i = 0; i < N; i++) {
+    Hashtable[i] = IDENTIFIER;
+  }
+
+  // Insert all keywords into Hashtable.
+  int collisions = 0;
+  for (int i = 0; keyword[i] != ILLEGAL; i++) {
+    Value k = keyword[i];
+    unsigned int h = Hash(string_[k]);
+    if (Hashtable[h] != IDENTIFIER) collisions++;
+    Hashtable[h] = k;
+  }
+
+  if (collisions > 0) {
+    PrintF("%d collisions in keyword hashtable\n", collisions);
+    FATAL("Fix keyword lookup!");
+  }
+
+  IsInitialized = true;
+
+  // Verify hash table.
+#define T(name, string, precedence) \
+  ASSERT(IsNull(string) || Lookup(string) == IDENTIFIER);
+
+#define K(name, string, precedence) \
+  ASSERT(Lookup(string) == name);
+
+  TOKEN_LIST(T, K, IGNORE_TOKEN)
+
+#undef K
+#undef T
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/token.h b/regexp2000/src/token.h
new file mode 100644 (file)
index 0000000..0f194a3
--- /dev/null
@@ -0,0 +1,281 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_TOKEN_H_
+#define V8_TOKEN_H_
+
+namespace v8 { namespace internal {
+
+// TOKEN_LIST takes a list of 3 macros M, all of which satisfy the
+// same signature M(name, string, precedence), where name is the
+// symbolic token name, string is the corresponding syntactic symbol
+// (or NULL, for literals), and precedence is the precedence (or 0).
+// The parameters are invoked for token categories as follows:
+//
+//   T: Non-keyword tokens
+//   K: Keyword tokens
+//   F: Future (reserved) keyword tokens
+
+// IGNORE_TOKEN is a convenience macro that can be supplied as
+// an argument (at any position) for a TOKEN_LIST call. It does
+// nothing with tokens belonging to the respective category.
+
+#define IGNORE_TOKEN(name, string, precedence)
+
+#define TOKEN_LIST(T, K, F)                                             \
+  /* End of source indicator. */                                        \
+  T(EOS, "EOS", 0)                                                      \
+                                                                        \
+  /* Punctuators (ECMA-262, section 7.7, page 15). */                   \
+  T(LPAREN, "(", 0)                                                     \
+  T(RPAREN, ")", 0)                                                     \
+  T(LBRACK, "[", 0)                                                     \
+  T(RBRACK, "]", 0)                                                     \
+  T(LBRACE, "{", 0)                                                     \
+  T(RBRACE, "}", 0)                                                     \
+  T(COLON, ":", 0)                                                      \
+  T(SEMICOLON, ";", 0)                                                  \
+  T(PERIOD, ".", 0)                                                     \
+  T(CONDITIONAL, "?", 3)                                                \
+  T(INC, "++", 0)                                                       \
+  T(DEC, "--", 0)                                                       \
+                                                                        \
+  /* Assignment operators. */                                           \
+  /* IsAssignmentOp() relies on this block of enum values */            \
+  /* being contiguous and sorted in the same order! */                  \
+  T(INIT_VAR, "=init_var", 2)  /* AST-use only. */                      \
+  T(INIT_CONST, "=init_const", 2)  /* AST-use only. */                  \
+  T(ASSIGN, "=", 2)                                                     \
+  T(ASSIGN_BIT_OR, "|=", 2)                                             \
+  T(ASSIGN_BIT_XOR, "^=", 2)                                            \
+  T(ASSIGN_BIT_AND, "&=", 2)                                            \
+  T(ASSIGN_SHL, "<<=", 2)                                               \
+  T(ASSIGN_SAR, ">>=", 2)                                               \
+  T(ASSIGN_SHR, ">>>=", 2)                                              \
+  T(ASSIGN_ADD, "+=", 2)                                                \
+  T(ASSIGN_SUB, "-=", 2)                                                \
+  T(ASSIGN_MUL, "*=", 2)                                                \
+  T(ASSIGN_DIV, "/=", 2)                                                \
+  T(ASSIGN_MOD, "%=", 2)                                                \
+                                                                        \
+  /* Binary operators sorted by precedence. */                          \
+  /* IsBinaryOp() relies on this block of enum values */                \
+  /* being contiguous and sorted in the same order! */                  \
+  T(COMMA, ",", 1)                                                      \
+  T(OR, "||", 4)                                                        \
+  T(AND, "&&", 5)                                                       \
+  T(BIT_OR, "|", 6)                                                     \
+  T(BIT_XOR, "^", 7)                                                    \
+  T(BIT_AND, "&", 8)                                                    \
+  T(SHL, "<<", 11)                                                      \
+  T(SAR, ">>", 11)                                                      \
+  T(SHR, ">>>", 11)                                                     \
+  T(ADD, "+", 12)                                                       \
+  T(SUB, "-", 12)                                                       \
+  T(MUL, "*", 13)                                                       \
+  T(DIV, "/", 13)                                                       \
+  T(MOD, "%", 13)                                                       \
+                                                                        \
+  /* Compare operators sorted by precedence. */                         \
+  /* IsCompareOp() relies on this block of enum values */               \
+  /* being contiguous and sorted in the same order! */                  \
+  T(EQ, "==", 9)                                                        \
+  T(NE, "!=", 9)                                                        \
+  T(EQ_STRICT, "===", 9)                                                \
+  T(NE_STRICT, "!==", 9)                                                \
+  T(LT, "<", 10)                                                        \
+  T(GT, ">", 10)                                                        \
+  T(LTE, "<=", 10)                                                      \
+  T(GTE, ">=", 10)                                                      \
+  K(INSTANCEOF, "instanceof", 10)                                       \
+  K(IN, "in", 10)                                                       \
+                                                                        \
+  /* Unary operators. */                                                \
+  /* IsUnaryOp() relies on this block of enum values */                 \
+  /* being contiguous and sorted in the same order! */                  \
+  T(NOT, "!", 0)                                                        \
+  T(BIT_NOT, "~", 0)                                                    \
+  K(DELETE, "delete", 0)                                                \
+  K(TYPEOF, "typeof", 0)                                                \
+  K(VOID, "void", 0)                                                    \
+                                                                        \
+  /* Keywords (ECMA-262, section 7.5.2, page 13). */                    \
+  K(BREAK, "break", 0)                                                  \
+  K(CASE, "case", 0)                                                    \
+  K(CATCH, "catch", 0)                                                  \
+  K(CONTINUE, "continue", 0)                                            \
+  K(DEBUGGER, "debugger", 0)                                            \
+  K(DEFAULT, "default", 0)                                              \
+  /* DELETE */                                                          \
+  K(DO, "do", 0)                                                        \
+  K(ELSE, "else", 0)                                                    \
+  K(FINALLY, "finally", 0)                                              \
+  K(FOR, "for", 0)                                                      \
+  K(FUNCTION, "function", 0)                                            \
+  K(IF, "if", 0)                                                        \
+  /* IN */                                                              \
+  /* INSTANCEOF */                                                      \
+  K(NEW, "new", 0)                                                      \
+  K(RETURN, "return", 0)                                                \
+  K(SWITCH, "switch", 0)                                                \
+  K(THIS, "this", 0)                                                    \
+  K(THROW, "throw", 0)                                                  \
+  K(TRY, "try", 0)                                                      \
+  /* TYPEOF */                                                          \
+  K(VAR, "var", 0)                                                      \
+  /* VOID */                                                            \
+  K(WHILE, "while", 0)                                                  \
+  K(WITH, "with", 0)                                                    \
+                                                                        \
+  /* Future reserved words (ECMA-262, section 7.5.3, page 14). */       \
+  F(ABSTRACT, "abstract", 0)                                            \
+  F(BOOLEAN, "boolean", 0)                                              \
+  F(BYTE, "byte", 0)                                                    \
+  F(CHAR, "char", 0)                                                    \
+  F(CLASS, "class", 0)                                                  \
+  K(CONST, "const", 0)                                                  \
+  F(DOUBLE, "double", 0)                                                \
+  F(ENUM, "enum", 0)                                                    \
+  F(EXPORT, "export", 0)                                                \
+  F(EXTENDS, "extends", 0)                                              \
+  F(FINAL, "final", 0)                                                  \
+  F(FLOAT, "float", 0)                                                  \
+  F(GOTO, "goto", 0)                                                    \
+  F(IMPLEMENTS, "implements", 0)                                        \
+  F(IMPORT, "import", 0)                                                \
+  F(INT, "int", 0)                                                      \
+  F(INTERFACE, "interface", 0)                                          \
+  F(LONG, "long", 0)                                                    \
+  K(NATIVE, "native", 0)                                                \
+  F(PACKAGE, "package", 0)                                              \
+  F(PRIVATE, "private", 0)                                              \
+  F(PROTECTED, "protected", 0)                                          \
+  F(PUBLIC, "public", 0)                                                \
+  F(SHORT, "short", 0)                                                  \
+  F(STATIC, "static", 0)                                                \
+  F(SUPER, "super", 0)                                                  \
+  F(SYNCHRONIZED, "synchronized", 0)                                    \
+  F(THROWS, "throws", 0)                                                \
+  F(TRANSIENT, "transient", 0)                                          \
+  F(VOLATILE, "volatile", 0)                                            \
+                                                                        \
+  /* Literals (ECMA-262, section 7.8, page 16). */                      \
+  K(NULL_LITERAL, "null", 0)                                            \
+  K(TRUE_LITERAL, "true", 0)                                            \
+  K(FALSE_LITERAL, "false", 0)                                          \
+  T(NUMBER, NULL, 0)                                                    \
+  T(STRING, NULL, 0)                                                    \
+                                                                        \
+  /* Identifiers (not keywords or future reserved words). */            \
+  T(IDENTIFIER, NULL, 0)                                                \
+                                                                        \
+  /* Illegal token - not able to scan. */                               \
+  T(ILLEGAL, "ILLEGAL", 0)                                              \
+                                                                        \
+  /* Scanner-internal use only. */                                      \
+  T(COMMENT, NULL, 0)
+
+
+class Token {
+ public:
+  // All token values.
+#define T(name, string, precedence) name,
+  enum Value {
+    TOKEN_LIST(T, T, IGNORE_TOKEN)
+    NUM_TOKENS
+  };
+#undef T
+
+#ifdef DEBUG
+  // Returns a string corresponding to the C++ token name
+  // (e.g. "LT" for the token LT).
+  static const char* Name(Value tok) {
+    ASSERT(0 <= tok && tok < NUM_TOKENS);
+    return name_[tok];
+  }
+#endif
+
+  // Predicates
+  static bool IsAssignmentOp(Value tok) {
+    return INIT_VAR <= tok && tok <= ASSIGN_MOD;
+  }
+
+  static bool IsBinaryOp(Value op) {
+    return COMMA <= op && op <= MOD;
+  }
+
+  static bool IsCompareOp(Value op) {
+    return EQ <= op && op <= IN;
+  }
+
+  static bool IsBitOp(Value op) {
+    return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
+  }
+
+  static bool IsUnaryOp(Value op) {
+    return (NOT <= op && op <= VOID) || op == ADD || op == SUB;
+  }
+
+  static bool IsCountOp(Value op) {
+    return op == INC || op == DEC;
+  }
+
+  // Returns a string corresponding to the JS token string
+  // (.e., "<" for the token LT) or NULL if the token doesn't
+  // have a (unique) string (e.g. an IDENTIFIER).
+  static const char* String(Value tok) {
+    ASSERT(0 <= tok && tok < NUM_TOKENS);
+    return string_[tok];
+  }
+
+  // Returns the precedence > 0 for binary and compare
+  // operators; returns 0 otherwise.
+  static int Precedence(Value tok) {
+    ASSERT(0 <= tok && tok < NUM_TOKENS);
+    return precedence_[tok];
+  }
+
+  // Returns the keyword value if str is a keyword;
+  // returns IDENTIFIER otherwise. The class must
+  // have been initialized.
+  static Value Lookup(const char* str);
+
+  // Must be called once to initialize the class.
+  // Multiple calls are ignored.
+  static void Initialize();
+
+ private:
+#ifdef DEBUG
+  static const char* name_[NUM_TOKENS];
+#endif
+  static const char* string_[NUM_TOKENS];
+  static int8_t precedence_[NUM_TOKENS];
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_TOKEN_H_
diff --git a/regexp2000/src/top.cc b/regexp2000/src/top.cc
new file mode 100644 (file)
index 0000000..8df808e
--- /dev/null
@@ -0,0 +1,901 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "bootstrapper.h"
+#include "debug.h"
+#include "execution.h"
+#include "string-stream.h"
+#include "platform.h"
+
+namespace v8 { namespace internal {
+
+ThreadLocalTop Top::thread_local_;
+Mutex* Top::break_access_;
+StackFrame::Id Top::break_frame_id_;
+int Top::break_count_;
+int Top::break_id_;
+
+NoAllocationStringAllocator* preallocated_message_space = NULL;
+
+Address top_addresses[] = {
+#define C(name) reinterpret_cast<Address>(Top::name()),
+    TOP_ADDRESS_LIST(C)
+#undef C
+    NULL
+};
+
+Address Top::get_address_from_id(Top::AddressId id) {
+  return top_addresses[id];
+}
+
+char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
+  ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
+  Iterate(v, thread);
+  return thread_storage + sizeof(ThreadLocalTop);
+}
+
+
+#define VISIT(field) v->VisitPointer(reinterpret_cast<Object**>(&(field)));
+
+void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
+  v->VisitPointer(&(thread->pending_exception_));
+  v->VisitPointer(bit_cast<Object**, Context**>(&(thread->context_)));
+  v->VisitPointer(&(thread->scheduled_exception_));
+
+  for (v8::TryCatch* block = thread->try_catch_handler_;
+       block != NULL;
+       block = block->next_) {
+    v->VisitPointer(bit_cast<Object**, void**>(&(block->exception_)));
+    v->VisitPointer(bit_cast<Object**, void**>(&(block->message_)));
+  }
+
+  // Iterate over pointers on native execution stack.
+  for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
+    it.frame()->Iterate(v);
+  }
+}
+#undef VISIT
+
+
+void Top::Iterate(ObjectVisitor* v) {
+  ThreadLocalTop* current_t = &thread_local_;
+  Iterate(v, current_t);
+}
+
+
+void Top::InitializeThreadLocal() {
+  thread_local_.c_entry_fp_ = 0;
+  thread_local_.handler_ = 0;
+  thread_local_.stack_is_cooked_ = false;
+  thread_local_.try_catch_handler_ = NULL;
+  thread_local_.context_ = NULL;
+  thread_local_.external_caught_exception_ = false;
+  thread_local_.failed_access_check_callback_ = NULL;
+  clear_pending_exception();
+  clear_scheduled_exception();
+  thread_local_.save_context_ = NULL;
+  thread_local_.pending_external_caught_exception_ = false;
+}
+
+
+// Create a dummy thread that will wait forever on a semaphore. The only
+// purpose for this thread is to have some stack area to save essential data
+// into for use by a stacks only core dump (aka minidump).
+class PreallocatedMemoryThread: public Thread {
+ public:
+  PreallocatedMemoryThread() : keep_running_(true) {
+    wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
+    data_ready_semaphore_ = OS::CreateSemaphore(0);
+  }
+
+  // When the thread starts running it will allocate a fixed number of bytes
+  // on the stack and publish the location of this memory for others to use.
+  void Run() {
+    EmbeddedVector<char, 32 * 1024> local_buffer;
+
+    // Initialize the buffer with a known good value.
+    OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
+                local_buffer.length());
+
+    // Publish the local buffer and signal its availability.
+    data_ = &local_buffer[0];
+    length_ = sizeof(local_buffer);
+    data_ready_semaphore_->Signal();
+
+    while (keep_running_) {
+      // This thread will wait here until the end of time.
+      wait_for_ever_semaphore_->Wait();
+    }
+
+    // Make sure we access the buffer after the wait to remove all possibility
+    // of it being optimized away.
+    OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
+                local_buffer.length());
+  }
+
+  static char* data() {
+    if (data_ready_semaphore_ != NULL) {
+      // Initial access is guarded until the data has been published.
+      data_ready_semaphore_->Wait();
+      delete data_ready_semaphore_;
+      data_ready_semaphore_ = NULL;
+    }
+    return data_;
+  }
+
+  static unsigned length() {
+    if (data_ready_semaphore_ != NULL) {
+      // Initial access is guarded until the data has been published.
+      data_ready_semaphore_->Wait();
+      delete data_ready_semaphore_;
+      data_ready_semaphore_ = NULL;
+    }
+    return length_;
+  }
+
+  static void StartThread() {
+    if (the_thread_ != NULL) return;
+
+    the_thread_ = new PreallocatedMemoryThread();
+    the_thread_->Start();
+  }
+
+  // Stop the PreallocatedMemoryThread and release its resources.
+  static void StopThread() {
+    if (the_thread_ == NULL) return;
+
+    the_thread_->keep_running_ = false;
+    wait_for_ever_semaphore_->Signal();
+
+    // Wait for the thread to terminate.
+    the_thread_->Join();
+
+    if (data_ready_semaphore_ != NULL) {
+      delete data_ready_semaphore_;
+      data_ready_semaphore_ = NULL;
+    }
+
+    delete wait_for_ever_semaphore_;
+    wait_for_ever_semaphore_ = NULL;
+
+    // Done with the thread entirely.
+    delete the_thread_;
+    the_thread_ = NULL;
+  }
+
+ private:
+  // Used to make sure that the thread keeps looping even for spurious wakeups.
+  bool keep_running_;
+
+  // The preallocated memory thread singleton.
+  static PreallocatedMemoryThread* the_thread_;
+  // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
+  static Semaphore* wait_for_ever_semaphore_;
+  // Semaphore to signal that the data has been initialized.
+  static Semaphore* data_ready_semaphore_;
+
+  // Location and size of the preallocated memory block.
+  static char* data_;
+  static unsigned length_;
+
+  DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
+};
+
+PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL;
+Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL;
+Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL;
+char* PreallocatedMemoryThread::data_ = NULL;
+unsigned PreallocatedMemoryThread::length_ = 0;
+
+static bool initialized = false;
+
+void Top::Initialize() {
+  CHECK(!initialized);
+
+  InitializeThreadLocal();
+
+  break_access_ = OS::CreateMutex();
+  break_frame_id_ = StackFrame::NO_ID;
+  break_count_ = 0;
+  break_id_ = 0;
+
+  // Only preallocate on the first initialization.
+  if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) {
+    // Start the thread which will set aside some memory.
+    PreallocatedMemoryThread::StartThread();
+    preallocated_message_space =
+        new NoAllocationStringAllocator(PreallocatedMemoryThread::data(),
+                                        PreallocatedMemoryThread::length());
+    PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4);
+  }
+  initialized = true;
+}
+
+
+void Top::TearDown() {
+  if (initialized) {
+    // Remove the external reference to the preallocated stack memory.
+    if (preallocated_message_space != NULL) {
+      delete preallocated_message_space;
+      preallocated_message_space = NULL;
+    }
+
+    PreallocatedMemoryThread::StopThread();
+    initialized = false;
+  }
+}
+
+
+void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
+  thread_local_.try_catch_handler_ = that;
+}
+
+
+void Top::UnregisterTryCatchHandler(v8::TryCatch* that) {
+  ASSERT(thread_local_.try_catch_handler_ == that);
+  thread_local_.try_catch_handler_ = that->next_;
+}
+
+
+void Top::new_break(StackFrame::Id break_frame_id) {
+  ExecutionAccess access;
+  break_frame_id_ = break_frame_id;
+  break_id_ = ++break_count_;
+}
+
+
+void Top::set_break(StackFrame::Id break_frame_id, int break_id) {
+  ExecutionAccess access;
+  break_frame_id_ = break_frame_id;
+  break_id_ = break_id;
+}
+
+
+bool Top::check_break(int break_id) {
+  ExecutionAccess access;
+  return break_id == break_id_;
+}
+
+
+bool Top::is_break() {
+  ExecutionAccess access;
+  return break_id_ != 0;
+}
+
+
+StackFrame::Id Top::break_frame_id() {
+  ExecutionAccess access;
+  return break_frame_id_;
+}
+
+
+int Top::break_id() {
+  ExecutionAccess access;
+  return break_id_;
+}
+
+
+void Top::MarkCompactPrologue() {
+  MarkCompactPrologue(&thread_local_);
+}
+
+
+void Top::MarkCompactPrologue(char* data) {
+  MarkCompactPrologue(reinterpret_cast<ThreadLocalTop*>(data));
+}
+
+
+void Top::MarkCompactPrologue(ThreadLocalTop* thread) {
+  StackFrame::CookFramesForThread(thread);
+}
+
+
+void Top::MarkCompactEpilogue(char* data) {
+  MarkCompactEpilogue(reinterpret_cast<ThreadLocalTop*>(data));
+}
+
+
+void Top::MarkCompactEpilogue() {
+  MarkCompactEpilogue(&thread_local_);
+}
+
+
+void Top::MarkCompactEpilogue(ThreadLocalTop* thread) {
+  StackFrame::UncookFramesForThread(thread);
+}
+
+
+static int stack_trace_nesting_level = 0;
+static StringStream* incomplete_message = NULL;
+
+
+Handle<String> Top::StackTrace() {
+  if (stack_trace_nesting_level == 0) {
+    stack_trace_nesting_level++;
+    HeapStringAllocator allocator;
+    StringStream::ClearMentionedObjectCache();
+    StringStream accumulator(&allocator);
+    incomplete_message = &accumulator;
+    PrintStack(&accumulator);
+    Handle<String> stack_trace = accumulator.ToString();
+    incomplete_message = NULL;
+    stack_trace_nesting_level = 0;
+    return stack_trace;
+  } else if (stack_trace_nesting_level == 1) {
+    stack_trace_nesting_level++;
+    OS::PrintError(
+      "\n\nAttempt to print stack while printing stack (double fault)\n");
+    OS::PrintError(
+      "If you are lucky you may find a partial stack dump on stdout.\n\n");
+    incomplete_message->OutputToStdOut();
+    return Factory::empty_symbol();
+  } else {
+    OS::Abort();
+    // Unreachable
+    return Factory::empty_symbol();
+  }
+}
+
+
+void Top::PrintStack() {
+  if (stack_trace_nesting_level == 0) {
+    stack_trace_nesting_level++;
+
+    StringAllocator* allocator;
+    if (preallocated_message_space == NULL) {
+      allocator = new HeapStringAllocator();
+    } else {
+      allocator = preallocated_message_space;
+    }
+
+    NativeAllocationChecker allocation_checker(
+      !FLAG_preallocate_message_memory ?
+      NativeAllocationChecker::ALLOW :
+      NativeAllocationChecker::DISALLOW);
+
+    StringStream::ClearMentionedObjectCache();
+    StringStream accumulator(allocator);
+    incomplete_message = &accumulator;
+    PrintStack(&accumulator);
+    accumulator.OutputToStdOut();
+    accumulator.Log();
+    incomplete_message = NULL;
+    stack_trace_nesting_level = 0;
+    if (preallocated_message_space == NULL) {
+      // Remove the HeapStringAllocator created above.
+      delete allocator;
+    }
+  } else if (stack_trace_nesting_level == 1) {
+    stack_trace_nesting_level++;
+    OS::PrintError(
+      "\n\nAttempt to print stack while printing stack (double fault)\n");
+    OS::PrintError(
+      "If you are lucky you may find a partial stack dump on stdout.\n\n");
+    incomplete_message->OutputToStdOut();
+  }
+}
+
+
+static void PrintFrames(StringStream* accumulator,
+                        StackFrame::PrintMode mode) {
+  StackFrameIterator it;
+  for (int i = 0; !it.done(); it.Advance()) {
+    it.frame()->Print(accumulator, mode, i++);
+  }
+}
+
+
+void Top::PrintStack(StringStream* accumulator) {
+  // The MentionedObjectCache is not GC-proof at the moment.
+  AssertNoAllocation nogc;
+  ASSERT(StringStream::IsMentionedObjectCacheClear());
+
+  // Avoid printing anything if there are no frames.
+  if (c_entry_fp(GetCurrentThread()) == 0) return;
+
+  accumulator->Add(
+      "\n==== Stack trace ============================================\n\n");
+  PrintFrames(accumulator, StackFrame::OVERVIEW);
+
+  accumulator->Add(
+      "\n==== Details ================================================\n\n");
+  PrintFrames(accumulator, StackFrame::DETAILS);
+
+  accumulator->PrintMentionedObjectCache();
+  accumulator->Add("=====================\n\n");
+}
+
+
+void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
+  ASSERT(thread_local_.failed_access_check_callback_ == NULL);
+  thread_local_.failed_access_check_callback_ = callback;
+}
+
+
+void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
+  if (!thread_local_.failed_access_check_callback_) return;
+
+  ASSERT(receiver->IsAccessCheckNeeded());
+  ASSERT(Top::context());
+  // The callers of this method are not expecting a GC.
+  AssertNoAllocation no_gc;
+
+  // Get the data object from access check info.
+  JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
+  Object* info = constructor->shared()->function_data();
+  if (info == Heap::undefined_value()) return;
+
+  Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
+  if (data_obj == Heap::undefined_value()) return;
+
+  HandleScope scope;
+  Handle<JSObject> receiver_handle(receiver);
+  Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
+  thread_local_.failed_access_check_callback_(
+    v8::Utils::ToLocal(receiver_handle),
+    type,
+    v8::Utils::ToLocal(data));
+}
+
+
+enum MayAccessDecision {
+  YES, NO, UNKNOWN
+};
+
+
+static MayAccessDecision MayAccessPreCheck(JSObject* receiver,
+                                           v8::AccessType type) {
+  // During bootstrapping, callback functions are not enabled yet.
+  if (Bootstrapper::IsActive()) return YES;
+
+  if (receiver->IsJSGlobalProxy()) {
+    Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
+    if (!receiver_context->IsContext()) return NO;
+
+    // Get the global context of current top context.
+    // avoid using Top::global_context() because it uses Handle.
+    Context* global_context = Top::context()->global()->global_context();
+    if (receiver_context == global_context) return YES;
+
+    if (Context::cast(receiver_context)->security_token() ==
+        global_context->security_token())
+      return YES;
+  }
+
+  return UNKNOWN;
+}
+
+
+bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
+  ASSERT(receiver->IsAccessCheckNeeded());
+  // Check for compatibility between the security tokens in the
+  // current lexical context and the accessed object.
+  ASSERT(Top::context());
+  // The callers of this method are not expecting a GC.
+  AssertNoAllocation no_gc;
+
+  MayAccessDecision decision = MayAccessPreCheck(receiver, type);
+  if (decision != UNKNOWN) return decision == YES;
+
+  // Get named access check callback
+  JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
+  Object* info = constructor->shared()->function_data();
+  if (info == Heap::undefined_value()) return false;
+
+  Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
+  if (data_obj == Heap::undefined_value()) return false;
+
+  Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
+  v8::NamedSecurityCallback callback =
+      v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
+
+  if (!callback) return false;
+
+  HandleScope scope;
+  Handle<JSObject> receiver_handle(receiver);
+  Handle<Object> key_handle(key);
+  Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
+  LOG(ApiNamedSecurityCheck(key));
+  bool result = false;
+  {
+    // Leaving JavaScript.
+    VMState state(OTHER);
+    result = callback(v8::Utils::ToLocal(receiver_handle),
+                      v8::Utils::ToLocal(key_handle),
+                      type,
+                      v8::Utils::ToLocal(data));
+  }
+  return result;
+}
+
+
+bool Top::MayIndexedAccess(JSObject* receiver,
+                           uint32_t index,
+                           v8::AccessType type) {
+  ASSERT(receiver->IsAccessCheckNeeded());
+  // Check for compatibility between the security tokens in the
+  // current lexical context and the accessed object.
+  ASSERT(Top::context());
+  // The callers of this method are not expecting a GC.
+  AssertNoAllocation no_gc;
+
+  MayAccessDecision decision = MayAccessPreCheck(receiver, type);
+  if (decision != UNKNOWN) return decision == YES;
+
+  // Get indexed access check callback
+  JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
+  Object* info = constructor->shared()->function_data();
+  if (info == Heap::undefined_value()) return false;
+
+  Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
+  if (data_obj == Heap::undefined_value()) return false;
+
+  Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
+  v8::IndexedSecurityCallback callback =
+      v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
+
+  if (!callback) return false;
+
+  HandleScope scope;
+  Handle<JSObject> receiver_handle(receiver);
+  Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
+  LOG(ApiIndexedSecurityCheck(index));
+  bool result = false;
+  {
+    // Leaving JavaScript.
+    VMState state(OTHER);
+    result = callback(v8::Utils::ToLocal(receiver_handle),
+                      index,
+                      type,
+                      v8::Utils::ToLocal(data));
+  }
+  return result;
+}
+
+
+Failure* Top::StackOverflow() {
+  HandleScope scope;
+  Handle<String> key = Factory::stack_overflow_symbol();
+  Handle<JSObject> boilerplate =
+      Handle<JSObject>::cast(GetProperty(Top::builtins(), key));
+  Handle<Object> exception = Copy(boilerplate);
+  // TODO(1240995): To avoid having to call JavaScript code to compute
+  // the message for stack overflow exceptions which is very likely to
+  // double fault with another stack overflow exception, we use a
+  // precomputed message. This is somewhat problematic in that it
+  // doesn't use ReportUncaughtException to determine the location
+  // from where the exception occurred. It should probably be
+  // reworked.
+  static const char* kMessage =
+      "Uncaught RangeError: Maximum call stack size exceeded";
+  DoThrow(*exception, NULL, kMessage);
+  return Failure::Exception();
+}
+
+
+Failure* Top::Throw(Object* exception, MessageLocation* location) {
+  DoThrow(exception, location, NULL);
+  return Failure::Exception();
+}
+
+
+Failure* Top::ReThrow(Object* exception, MessageLocation* location) {
+  // Set the exception being re-thrown.
+  set_pending_exception(exception);
+  return Failure::Exception();
+}
+
+
+void Top::ScheduleThrow(Object* exception) {
+  // When scheduling a throw we first throw the exception to get the
+  // error reporting if it is uncaught before rescheduling it.
+  Throw(exception);
+  thread_local_.scheduled_exception_ = pending_exception();
+  thread_local_.external_caught_exception_ = false;
+  clear_pending_exception();
+}
+
+
+Object* Top::PromoteScheduledException() {
+  Object* thrown = scheduled_exception();
+  clear_scheduled_exception();
+  // Re-throw the exception to avoid getting repeated error reporting.
+  return ReThrow(thrown);
+}
+
+
+// NOTE: The stack trace frame iterator is an iterator that only
+// traverse proper JavaScript frames; that is JavaScript frames that
+// have proper JavaScript functions. This excludes the problematic
+// functions in runtime.js.
+class StackTraceFrameIterator: public JavaScriptFrameIterator {
+ public:
+  StackTraceFrameIterator() {
+    if (!done() && !frame()->function()->IsJSFunction()) Advance();
+  }
+
+  void Advance() {
+    while (true) {
+      JavaScriptFrameIterator::Advance();
+      if (done()) return;
+      if (frame()->function()->IsJSFunction()) return;
+    }
+  }
+};
+
+
+void Top::PrintCurrentStackTrace(FILE* out) {
+  StackTraceFrameIterator it;
+  while (!it.done()) {
+    HandleScope scope;
+    // Find code position if recorded in relocation info.
+    JavaScriptFrame* frame = it.frame();
+    int pos = frame->FindCode()->SourcePosition(frame->pc());
+    Handle<Object> pos_obj(Smi::FromInt(pos));
+    // Fetch function and receiver.
+    Handle<JSFunction> fun(JSFunction::cast(frame->function()));
+    Handle<Object> recv(frame->receiver());
+    // Advance to the next JavaScript frame and determine if the
+    // current frame is the top-level frame.
+    it.Advance();
+    Handle<Object> is_top_level = it.done()
+        ? Factory::true_value()
+        : Factory::false_value();
+    // Generate and print strack trace line.
+    Handle<String> line =
+        Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
+    if (line->length() > 0) {
+      line->PrintOn(out);
+      fprintf(out, "\n");
+    }
+  }
+}
+
+
+void Top::ComputeLocation(MessageLocation* target) {
+  *target = MessageLocation(empty_script(), -1, -1);
+  StackTraceFrameIterator it;
+  if (!it.done()) {
+    JavaScriptFrame* frame = it.frame();
+    JSFunction* fun = JSFunction::cast(frame->function());
+    Object* script = fun->shared()->script();
+    if (script->IsScript() &&
+        !(Script::cast(script)->source()->IsUndefined())) {
+      int pos = frame->FindCode()->SourcePosition(frame->pc());
+      // Compute the location from the function and the reloc info.
+      Handle<Script> casted_script(Script::cast(script));
+      *target = MessageLocation(casted_script, pos, pos + 1);
+    }
+  }
+}
+
+
+void Top::ReportUncaughtException(Handle<Object> exception,
+                                  MessageLocation* location,
+                                  Handle<String> stack_trace) {
+  Handle<Object> message =
+    MessageHandler::MakeMessageObject("uncaught_exception",
+                                      location,
+                                      HandleVector<Object>(&exception, 1),
+                                      stack_trace);
+
+  // Report the uncaught exception.
+  MessageHandler::ReportMessage(location, message);
+}
+
+
+bool Top::ShouldReportException(bool* is_caught_externally) {
+  StackHandler* handler =
+      StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
+
+  // Determine if we have an external exception handler and get the
+  // address of the external handler so we can compare the address to
+  // determine which one is closer to the top of the stack.
+  bool has_external_handler = (thread_local_.try_catch_handler_ != NULL);
+  Address external_handler_address =
+      reinterpret_cast<Address>(thread_local_.try_catch_handler_);
+
+  // NOTE: The stack is assumed to grown towards lower addresses. If
+  // the handler is at a higher address than the external address it
+  // means that it is below it on the stack.
+
+  // Find the top-most try-catch handler.
+  while (handler != NULL && !handler->is_try_catch()) {
+    handler = handler->next();
+  }
+
+  // The exception has been externally caught if and only if there is
+  // an external handler which is above any JavaScript try-catch but NOT
+  // try-finally handlers.
+  *is_caught_externally = has_external_handler &&
+      (handler == NULL || handler->address() > external_handler_address);
+
+  // If we have a try-catch handler then the exception is caught in
+  // JavaScript code.
+  bool is_uncaught_by_js = (handler == NULL);
+
+  // If there is no external try-catch handler, we report the
+  // exception if it isn't caught by JavaScript code.
+  if (!has_external_handler) return is_uncaught_by_js;
+
+  if (is_uncaught_by_js || handler->address() > external_handler_address) {
+    // Only report the exception if the external handler is verbose.
+    return thread_local_.try_catch_handler_->is_verbose_;
+  } else {
+    // Report the exception if it isn't caught by JavaScript code.
+    return is_uncaught_by_js;
+  }
+}
+
+
+void Top::DoThrow(Object* exception,
+                  MessageLocation* location,
+                  const char* message) {
+  ASSERT(!has_pending_exception());
+
+  HandleScope scope;
+  Handle<Object> exception_handle(exception);
+
+  // Determine reporting and whether the exception is caught externally.
+  bool is_caught_externally = false;
+  bool report_exception = (exception != Failure::OutOfMemoryException()) &&
+      ShouldReportException(&is_caught_externally);
+
+  // Generate the message.
+  Handle<Object> message_obj;
+  MessageLocation potential_computed_location;
+  bool try_catch_needs_message =
+      is_caught_externally &&
+      thread_local_.try_catch_handler_->capture_message_;
+  if (report_exception || try_catch_needs_message) {
+    if (location == NULL) {
+      // If no location was specified we use a computed one instead
+      ComputeLocation(&potential_computed_location);
+      location = &potential_computed_location;
+    }
+    Handle<String> stack_trace;
+    if (FLAG_trace_exception) stack_trace = StackTrace();
+    message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
+        location, HandleVector<Object>(&exception_handle, 1), stack_trace);
+  }
+
+  // If the exception is caught externally, we store it in the
+  // try/catch handler. The C code can find it later and process it if
+  // necessary.
+  thread_local_.pending_external_caught_exception_ = is_caught_externally;
+  if (is_caught_externally) {
+    thread_local_.try_catch_handler_->exception_ =
+      reinterpret_cast<void*>(*exception_handle);
+    if (!message_obj.is_null()) {
+      thread_local_.try_catch_handler_->message_ =
+        reinterpret_cast<void*>(*message_obj);
+    }
+  }
+
+  // Notify debugger of exception.
+  Debugger::OnException(exception_handle, report_exception);
+
+  if (report_exception) {
+    if (message != NULL) {
+      MessageHandler::ReportMessage(message);
+    } else {
+      MessageHandler::ReportMessage(location, message_obj);
+    }
+  }
+
+  // NOTE: Notifying the debugger or reporting the exception may have caused
+  // new exceptions. For now, we just ignore that and set the pending exception
+  // to the original one.
+  set_pending_exception(*exception_handle);
+}
+
+
+void Top::TraceException(bool flag) {
+  FLAG_trace_exception = flag;
+}
+
+
+bool Top::optional_reschedule_exception(bool is_bottom_call) {
+  if (!is_out_of_memory() &&
+      (thread_local_.external_caught_exception_ || is_bottom_call)) {
+    thread_local_.external_caught_exception_ = false;
+    clear_pending_exception();
+    return false;
+  } else {
+    thread_local_.scheduled_exception_ = pending_exception();
+    clear_pending_exception();
+    return true;
+  }
+}
+
+
+bool Top::is_out_of_memory() {
+  if (has_pending_exception()) {
+    Object* e = pending_exception();
+    if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
+      return true;
+    }
+  }
+  if (has_scheduled_exception()) {
+    Object* e = scheduled_exception();
+    if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+Handle<Context> Top::global_context() {
+  GlobalObject* global = thread_local_.context_->global();
+  return Handle<Context>(global->global_context());
+}
+
+
+Object* Top::LookupSpecialFunction(JSObject* receiver,
+                                   JSObject* prototype,
+                                   JSFunction* function) {
+  if (receiver->IsJSArray()) {
+    FixedArray* table = context()->global_context()->special_function_table();
+    for (int index = 0; index < table->length(); index +=3) {
+      if ((prototype == table->get(index)) &&
+          (function == table->get(index+1))) {
+        return table->get(index+2);
+      }
+    }
+  }
+  return Heap::undefined_value();
+}
+
+
+char* Top::ArchiveThread(char* to) {
+  memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
+  InitializeThreadLocal();
+  return to + sizeof(thread_local_);
+}
+
+
+char* Top::RestoreThread(char* from) {
+  memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_));
+  return from + sizeof(thread_local_);
+}
+
+
+ExecutionAccess::ExecutionAccess() {
+  Top::break_access_->Lock();
+}
+
+
+ExecutionAccess::~ExecutionAccess() {
+  Top::break_access_->Unlock();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/top.h b/regexp2000/src/top.h
new file mode 100644 (file)
index 0000000..69fb7fa
--- /dev/null
@@ -0,0 +1,371 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_TOP_H_
+#define V8_TOP_H_
+
+#include "frames-inl.h"
+
+namespace v8 { namespace internal {
+
+
+#define RETURN_IF_SCHEDULED_EXCEPTION() \
+  if (Top::has_scheduled_exception()) return Top::PromoteScheduledException()
+
+// Top has static variables used for JavaScript execution.
+
+class SaveContext;  // Forward decleration.
+
+class ThreadLocalTop BASE_EMBEDDED {
+ public:
+  // The context where the current execution method is created and for variable
+  // lookups.
+  Context* context_;
+  Object* pending_exception_;
+  // Use a separate value for scheduled exceptions to preserve the
+  // invariants that hold about pending_exception.  We may want to
+  // unify them later.
+  Object* scheduled_exception_;
+  bool external_caught_exception_;
+  v8::TryCatch* try_catch_handler_;
+  SaveContext* save_context_;
+  // Flag indicating that the try_catch_handler_ contains an exception to be
+  // caught.
+  bool pending_external_caught_exception_;
+
+  // Stack.
+  Address c_entry_fp_;  // the frame pointer of the top c entry frame
+  Address handler_;   // try-blocks are chained through the stack
+  bool stack_is_cooked_;
+  inline bool stack_is_cooked() { return stack_is_cooked_; }
+  inline void set_stack_is_cooked(bool value) { stack_is_cooked_ = value; }
+
+  // Generated code scratch locations.
+  int32_t formal_count_;
+
+  // Call back function to report unsafe JS accesses.
+  v8::FailedAccessCheckCallback failed_access_check_callback_;
+};
+
+#define TOP_ADDRESS_LIST(C) \
+  C(handler_address)                   \
+  C(c_entry_fp_address)                \
+  C(context_address)                   \
+  C(pending_exception_address)         \
+  C(external_caught_exception_address)
+
+class Top {
+ public:
+  enum AddressId {
+#define C(name) k_##name,
+    TOP_ADDRESS_LIST(C)
+#undef C
+    k_top_address_count
+  };
+
+  static Address get_address_from_id(AddressId id);
+
+  // Access to top context (where the current function object was created).
+  static Context* context() { return thread_local_.context_; }
+  static void set_context(Context* context) {
+    thread_local_.context_ = context;
+  }
+  static Context** context_address() { return &thread_local_.context_; }
+
+  static SaveContext* save_context() {return thread_local_.save_context_; }
+  static void set_save_context(SaveContext* save) {
+    thread_local_.save_context_ = save;
+  }
+
+  // Interface to pending exception.
+  static Object* pending_exception() {
+    ASSERT(has_pending_exception());
+    return thread_local_.pending_exception_;
+  }
+  static bool external_caught_exception() {
+    return thread_local_.external_caught_exception_;
+  }
+  static void set_pending_exception(Object* exception) {
+    thread_local_.pending_exception_ = exception;
+  }
+  static void clear_pending_exception() {
+    thread_local_.pending_exception_ = Heap::the_hole_value();
+  }
+
+  static Object** pending_exception_address() {
+    return &thread_local_.pending_exception_;
+  }
+  static bool has_pending_exception() {
+    return !thread_local_.pending_exception_->IsTheHole();
+  }
+  static v8::TryCatch* try_catch_handler() {
+    return thread_local_.try_catch_handler_;
+  }
+  // This method is called by the api after operations that may throw
+  // exceptions.  If an exception was thrown and not handled by an external
+  // handler the exception is scheduled to be rethrown when we return to running
+  // JavaScript code.  If an exception is scheduled true is returned.
+  static bool optional_reschedule_exception(bool is_bottom_call);
+
+  static bool* external_caught_exception_address() {
+    return &thread_local_.external_caught_exception_;
+  }
+
+  static Object* scheduled_exception() {
+    ASSERT(has_scheduled_exception());
+    return thread_local_.scheduled_exception_;
+  }
+  static bool has_scheduled_exception() {
+    return !thread_local_.scheduled_exception_->IsTheHole();
+  }
+  static void clear_scheduled_exception() {
+    thread_local_.scheduled_exception_ = Heap::the_hole_value();
+  }
+
+  // Propagate the external caught exception flag. If there is no external
+  // caught exception always clear the TryCatch handler as it might contain
+  // an exception object from a throw which was bypassed by a finally block
+  // doing an explicit return/break/continue.
+  static void propagate_external_caught() {
+    if (has_pending_exception()) {
+      thread_local_.external_caught_exception_ =
+          thread_local_.pending_external_caught_exception_;
+    }
+    thread_local_.pending_external_caught_exception_ = false;
+  }
+
+  // Tells whether the current context has experienced an out of memory
+  // exception.
+  static bool is_out_of_memory();
+
+  // JS execution stack (see frames.h).
+  static Address c_entry_fp(ThreadLocalTop* thread) {
+    return thread->c_entry_fp_;
+  }
+  static Address handler(ThreadLocalTop* thread) { return thread->handler_; }
+
+  static inline Address* c_entry_fp_address() {
+    return &thread_local_.c_entry_fp_;
+  }
+  static inline Address* handler_address() { return &thread_local_.handler_; }
+
+  // Generated code scratch locations.
+  static void* formal_count_address() { return &thread_local_.formal_count_; }
+
+  static void new_break(StackFrame::Id break_frame_id);
+  static void set_break(StackFrame::Id break_frame_id, int break_id);
+  static bool check_break(int break_id);
+  static bool is_break();
+  static StackFrame::Id break_frame_id();
+  static int break_id();
+
+  static void MarkCompactPrologue();
+  static void MarkCompactEpilogue();
+  static void MarkCompactPrologue(char* archived_thread_data);
+  static void MarkCompactEpilogue(char* archived_thread_data);
+  static void PrintCurrentStackTrace(FILE* out);
+  static void PrintStackTrace(FILE* out, char* thread_data);
+  static void PrintStack(StringStream* accumulator);
+  static void PrintStack();
+  static Handle<String> StackTrace();
+
+  // Returns if the top context may access the given global object. If
+  // the result is false, the pending exception is guaranteed to be
+  // set.
+  static bool MayNamedAccess(JSObject* receiver,
+                             Object* key,
+                             v8::AccessType type);
+  static bool MayIndexedAccess(JSObject* receiver,
+                               uint32_t index,
+                               v8::AccessType type);
+
+  static void SetFailedAccessCheckCallback(
+      v8::FailedAccessCheckCallback callback);
+  static void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
+
+  // Exception throwing support. The caller should use the result
+  // of Throw() as its return value.
+  static Failure* Throw(Object* exception, MessageLocation* location = NULL);
+  // Re-throw an exception.  This involves no error reporting since
+  // error reporting was handled when the exception was thrown
+  // originally.
+  static Failure* ReThrow(Object* exception, MessageLocation* location = NULL);
+  static void ScheduleThrow(Object* exception);
+
+  // Promote a scheduled exception to pending. Asserts has_scheduled_exception.
+  static Object* PromoteScheduledException();
+  static void DoThrow(Object* exception,
+                      MessageLocation* location,
+                      const char* message);
+  static bool ShouldReportException(bool* is_caught_externally);
+  static void ReportUncaughtException(Handle<Object> exception,
+                                      MessageLocation* location,
+                                      Handle<String> stack_trace);
+
+  // Attempts to compute the current source location, storing the
+  // result in the target out parameter.
+  static void ComputeLocation(MessageLocation* target);
+
+  // Override command line flag.
+  static void TraceException(bool flag);
+
+  // Out of resource exception helpers.
+  static Failure* StackOverflow();
+
+  // Administration
+  static void Initialize();
+  static void TearDown();
+  static void Iterate(ObjectVisitor* v);
+  static void Iterate(ObjectVisitor* v, ThreadLocalTop* t);
+  static char* Iterate(ObjectVisitor* v, char* t);
+
+  // Returns the global object of the current context. It could be
+  // a builtin object, or a js global object.
+  static Handle<GlobalObject> global() {
+    return Handle<GlobalObject>(context()->global());
+  }
+
+  // Returns the global proxy object of the current context.
+  static Object* global_proxy() {
+    return context()->global_proxy();
+  }
+
+  static Handle<Context> global_context();
+
+  static Handle<JSBuiltinsObject> builtins() {
+    return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
+  }
+
+  static Object* LookupSpecialFunction(JSObject* receiver,
+                                       JSObject* prototype,
+                                       JSFunction* value);
+
+  static void RegisterTryCatchHandler(v8::TryCatch* that);
+  static void UnregisterTryCatchHandler(v8::TryCatch* that);
+
+#define TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR(index, type, name)  \
+  static Handle<type> name() {                                \
+    return Handle<type>(context()->global_context()->name()); \
+  }
+  GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR)
+#undef TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR
+
+  static inline ThreadLocalTop* GetCurrentThread() { return &thread_local_; }
+  static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); }
+  static char* ArchiveThread(char* to);
+  static char* RestoreThread(char* from);
+
+ private:
+  // The context that initiated this JS execution.
+  static ThreadLocalTop thread_local_;
+  static void InitializeThreadLocal();
+  static void PrintStackTrace(FILE* out, ThreadLocalTop* thread);
+  static void MarkCompactPrologue(ThreadLocalTop* archived_thread_data);
+  static void MarkCompactEpilogue(ThreadLocalTop* archived_thread_data);
+
+  // Debug.
+  // Mutex for serializing access to break control structures.
+  static Mutex* break_access_;
+
+  // ID of the frame where execution is stopped by debugger.
+  static StackFrame::Id break_frame_id_;
+
+  // Counter to create unique id for each debug break.
+  static int break_count_;
+
+  // Current debug break, 0 if running.
+  static int break_id_;
+
+  friend class SaveContext;
+  friend class AssertNoContextChange;
+  friend class ExecutionAccess;
+
+  static void FillCache();
+};
+
+
+// If the GCC version is 4.1.x or 4.2.x an additional field is added to the
+// class as a workarround for a bug in the generated code found with these
+// versions of GCC. See V8 issue 122 for details.
+class SaveContext BASE_EMBEDDED {
+ public:
+  SaveContext() :
+      context_(Top::context()),
+#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
+      dummy_(Top::context()),
+#endif
+      prev_(Top::save_context()) {
+    Top::set_save_context(this);
+  }
+
+  ~SaveContext() {
+    Top::set_context(*context_);
+    Top::set_save_context(prev_);
+  }
+
+  Handle<Context> context() { return context_; }
+  SaveContext* prev() { return prev_; }
+
+ private:
+  Handle<Context> context_;
+#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
+  Handle<Context> dummy_;
+#endif
+  SaveContext* prev_;
+};
+
+
+class AssertNoContextChange BASE_EMBEDDED {
+#ifdef DEBUG
+ public:
+  AssertNoContextChange() :
+      context_(Top::context()) {
+  }
+
+  ~AssertNoContextChange() {
+    ASSERT(Top::context() == *context_);
+  }
+
+ private:
+  HandleScope scope_;
+  Handle<Context> context_;
+#else
+ public:
+  AssertNoContextChange() { }
+#endif
+};
+
+
+class ExecutionAccess BASE_EMBEDDED {
+ public:
+  ExecutionAccess();
+  ~ExecutionAccess();
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_TOP_H_
diff --git a/regexp2000/src/unicode-inl.h b/regexp2000/src/unicode-inl.h
new file mode 100644 (file)
index 0000000..9737c27
--- /dev/null
@@ -0,0 +1,238 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef __UNIBROW_INL_H__
+#define __UNIBROW_INL_H__
+
+#include "unicode.h"
+
+namespace unibrow {
+
+template <class T, int s> bool Predicate<T, s>::get(uchar code_point) {
+  CacheEntry entry = entries_[code_point & kMask];
+  if (entry.code_point_ == code_point) return entry.value_;
+  return CalculateValue(code_point);
+}
+
+template <class T, int s> bool Predicate<T, s>::CalculateValue(
+    uchar code_point) {
+  bool result = T::Is(code_point);
+  entries_[code_point & kMask] = CacheEntry(code_point, result);
+  return result;
+}
+
+template <class T, int s> int Mapping<T, s>::get(uchar c, uchar n,
+    uchar* result) {
+  CacheEntry entry = entries_[c & kMask];
+  if (entry.code_point_ == c) {
+    if (entry.offset_ == 0) {
+      return 0;
+    } else {
+      result[0] = c + entry.offset_;
+      return 1;
+    }
+  } else {
+    return CalculateValue(c, n, result);
+  }
+}
+
+template <class T, int s> int Mapping<T, s>::CalculateValue(uchar c, uchar n,
+    uchar* result) {
+  bool allow_caching = true;
+  int length = T::Convert(c, n, result, &allow_caching);
+  if (allow_caching) {
+    if (length == 1) {
+      entries_[c & kMask] = CacheEntry(c, result[0] - c);
+      return 1;
+    } else {
+      entries_[c & kMask] = CacheEntry(c, 0);
+      return 0;
+    }
+  } else {
+    return length;
+  }
+}
+
+
+unsigned Utf8::Encode(char* str, uchar c) {
+  static const int kMask = ~(1 << 6);
+  if (c <= kMaxOneByteChar) {
+    str[0] = c;
+    return 1;
+  } else if (c <= kMaxTwoByteChar) {
+    str[0] = 0xC0 | (c >> 6);
+    str[1] = 0x80 | (c & kMask);
+    return 2;
+  } else if (c <= kMaxThreeByteChar) {
+    str[0] = 0xE0 | (c >> 12);
+    str[1] = 0x80 | ((c >> 6) & kMask);
+    str[2] = 0x80 | (c & kMask);
+    return 3;
+  } else {
+    str[0] = 0xF0 | (c >> 18);
+    str[1] = 0x80 | ((c >> 12) & kMask);
+    str[2] = 0x80 | ((c >> 6) & kMask);
+    str[3] = 0x80 | (c & kMask);
+    return 4;
+  }
+}
+
+
+uchar Utf8::ValueOf(const byte* bytes, unsigned length, unsigned* cursor) {
+  if (length <= 0) return kBadChar;
+  byte first = bytes[0];
+  // Characters between 0000 and 0007F are encoded as a single character
+  if (first <= kMaxOneByteChar) {
+    *cursor += 1;
+    return first;
+  }
+  return CalculateValue(bytes, length, cursor);
+}
+
+unsigned Utf8::Length(uchar c) {
+  if (c <= kMaxOneByteChar) {
+    return 1;
+  } else if (c <= kMaxTwoByteChar) {
+    return 2;
+  } else if (c <= kMaxThreeByteChar) {
+    return 3;
+  } else {
+    return 4;
+  }
+}
+
+uchar CharacterStream::GetNext() {
+  uchar result = DecodeCharacter(buffer_, &cursor_);
+  if (remaining_ == 1) {
+    cursor_ = 0;
+    FillBuffer();
+  } else {
+    remaining_--;
+  }
+  return result;
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define IF_LITTLE(expr) expr
+#define IF_BIG(expr)    ((void) 0)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define IF_LITTLE(expr) ((void) 0)
+#define IF_BIG(expr)    expr
+#else
+#warning Unknown byte ordering
+#endif
+
+bool CharacterStream::EncodeAsciiCharacter(uchar c, byte* buffer,
+    unsigned capacity, unsigned& offset) {
+  if (offset >= capacity) return false;
+  buffer[offset] = c;
+  offset += 1;
+  return true;
+}
+
+bool CharacterStream::EncodeNonAsciiCharacter(uchar c, byte* buffer,
+    unsigned capacity, unsigned& offset) {
+  unsigned aligned = (offset + 0x3) & ~0x3;
+  if ((aligned + sizeof(uchar)) > capacity)
+    return false;
+  if (offset == aligned) {
+    IF_LITTLE(*reinterpret_cast<uchar*>(buffer + aligned) = (c << 8) | 0x80);
+    IF_BIG(*reinterpret_cast<uchar*>(buffer + aligned) = c | (1 << 31));
+  } else {
+    buffer[offset] = 0x80;
+    IF_LITTLE(*reinterpret_cast<uchar*>(buffer + aligned) = c << 8);
+    IF_BIG(*reinterpret_cast<uchar*>(buffer + aligned) = c);
+  }
+  offset = aligned + sizeof(uchar);
+  return true;
+}
+
+bool CharacterStream::EncodeCharacter(uchar c, byte* buffer, unsigned capacity,
+    unsigned& offset) {
+  if (c <= Utf8::kMaxOneByteChar) {
+    return EncodeAsciiCharacter(c, buffer, capacity, offset);
+  } else {
+    return EncodeNonAsciiCharacter(c, buffer, capacity, offset);
+  }
+}
+
+uchar CharacterStream::DecodeCharacter(const byte* buffer, unsigned* offset) {
+  byte b = buffer[*offset];
+  if (b <= Utf8::kMaxOneByteChar) {
+    (*offset)++;
+    return b;
+  } else {
+    unsigned aligned = (*offset + 0x3) & ~0x3;
+    *offset = aligned + sizeof(uchar);
+    IF_LITTLE(return *reinterpret_cast<const uchar*>(buffer + aligned) >> 8);
+    IF_BIG(return *reinterpret_cast<const uchar*>(buffer + aligned) &
+                    ~(1 << 31));
+  }
+}
+
+#undef IF_LITTLE
+#undef IF_BIG
+
+template <class R, class I, unsigned s>
+void InputBuffer<R, I, s>::FillBuffer() {
+  buffer_ = R::ReadBlock(input_, util_buffer_, s, &remaining_, &offset_);
+}
+
+template <class R, class I, unsigned s>
+void InputBuffer<R, I, s>::Rewind() {
+  Reset(input_);
+}
+
+template <class R, class I, unsigned s>
+void InputBuffer<R, I, s>::Reset(unsigned position, I input) {
+  input_ = input;
+  remaining_ = 0;
+  cursor_ = 0;
+  offset_ = position;
+  buffer_ = R::ReadBlock(input_, util_buffer_, s, &remaining_, &offset_);
+}
+
+template <class R, class I, unsigned s>
+void InputBuffer<R, I, s>::Reset(I input) {
+  Reset(0, input);
+}
+
+template <class R, class I, unsigned s>
+void InputBuffer<R, I, s>::Seek(unsigned position) {
+  offset_ = position;
+  buffer_ = R::ReadBlock(input_, util_buffer_, s, &remaining_, &offset_);
+}
+
+template <unsigned s>
+Utf8InputBuffer<s>::Utf8InputBuffer(const char* data, unsigned length)
+    : InputBuffer<Utf8, Buffer<const char*>, s>(Buffer<const char*>(data,
+                                                                    length)) {
+}
+
+}  // namespace unibrow
+
+#endif  // __UNIBROW_INL_H__
diff --git a/regexp2000/src/unicode.cc b/regexp2000/src/unicode.cc
new file mode 100644 (file)
index 0000000..2f70bd3
--- /dev/null
@@ -0,0 +1,816 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file was generated at 2008-10-01 18:05:45.480436
+
+#include "unicode-inl.h"
+#include <cstdlib>
+#include <cstdio>
+
+namespace unibrow {
+
+/**
+ * \file
+ * Implementations of functions for working with unicode.
+ */
+
+typedef signed short int16_t;  // NOLINT
+typedef unsigned short uint16_t;  // NOLINT
+
+// All access to the character table should go through this function.
+template <int D>
+static inline uchar TableGet(const uint16_t* table, int index) {
+  return table[D * index];
+}
+
+static inline uchar GetEntry(uint16_t entry) {
+  return entry & 0x7fff;
+}
+
+static inline bool IsStart(uint16_t entry) {
+  return (entry & (1 << 15)) != 0;
+}
+
+/**
+ * Look up a character in the unicode table using a mix of binary and
+ * interpolation search.  For a uniformly distributed array
+ * interpolation search beats binary search by a wide margin.  However,
+ * in this case interpolation search degenerates because of some very
+ * high values in the lower end of the table so this function uses a
+ * combination.  The average number of steps to look up the information
+ * about a character is around 10, slightly higher if there is no
+ * information available about the character.
+ */
+static bool LookupPredicate(const uint16_t* table, uint16_t size, uchar chr) {
+  static const int kEntryDist = 1;
+  uint16_t value = chr & 0x7fff;
+  unsigned int low = 0;
+  unsigned int high = size - 1;
+  while (high != low) {
+    unsigned int mid = low + ((high - low) >> 1);
+    uchar current_value = GetEntry(TableGet<kEntryDist>(table, mid));
+    // If we've found an entry less than or equal to this one, and the
+    // next one is not also less than this one, we've arrived.
+    if ((current_value <= value) &&
+        (mid + 1 == size ||
+         GetEntry(TableGet<kEntryDist>(table, mid + 1)) > value)) {
+      low = mid;
+      break;
+    } else if (current_value < value) {
+      low = mid + 1;
+    } else if (current_value > value) {
+      // If we've just checked the bottom-most value and it's not
+      // the one we're looking for, we're done.
+      if (mid == 0) break;
+      high = mid - 1;
+    }
+  }
+  uint16_t field = TableGet<kEntryDist>(table, low);
+  return (GetEntry(field) == value) ||
+          (GetEntry(field) < value && IsStart(field));
+}
+
+struct MultiCharacterSpecialCase {
+  uint16_t length;
+  uchar chars[kMaxCaseConvertedSize];
+};
+
+// Look up the mapping for the given character in the specified table,
+// which is of the specified length and uses the specified special case
+// mapping for multi-char mappings.  The next parameter is the character
+// following the one to map.  The result will be written in to the result
+// buffer and the number of characters written will be returned.  Finally,
+// if the allow_caching_ptr is non-null then false will be stored in
+// it if the result contains multiple characters or depends on the
+// context.
+static int LookupMapping(const uint16_t* table, uint16_t size,
+    const MultiCharacterSpecialCase* multi_chars, uchar chr, uchar next,
+    uchar* result, bool* allow_caching_ptr) {
+  static const int kEntryDist = 2;
+  uint16_t value = chr & 0x7fff;
+  unsigned int low = 0;
+  unsigned int high = size - 1;
+  while (high != low) {
+    unsigned int mid = low + ((high - low) >> 1);
+    uchar current_value = GetEntry(TableGet<kEntryDist>(table, mid));
+    // If we've found an entry less than or equal to this one, and the next one
+    // is not also less than this one, we've arrived.
+    if ((current_value <= value) &&
+        (mid + 1 == size ||
+         GetEntry(TableGet<kEntryDist>(table, mid + 1)) > value)) {
+      low = mid;
+      break;
+    } else if (current_value < value) {
+      low = mid + 1;
+    } else if (current_value > value) {
+      // If we've just checked the bottom-most value and it's not
+      // the one we're looking for, we're done.
+      if (mid == 0) break;
+      high = mid - 1;
+    }
+  }
+  uint16_t field = TableGet<kEntryDist>(table, low);
+  bool found = (GetEntry(field) == value) ||
+               (GetEntry(field) < value && IsStart(field));
+  if (found) {
+    int16_t value = table[2 * low + 1];
+    if (value == 0) {
+      // 0 means not present
+      return 0;
+    } else if ((value & 3) == 0) {
+      // Low bits 0 means a constant offset from the given character.
+      result[0] = chr + (value >> 2);
+      return 1;
+    } else if ((value & 3) == 1) {
+      // Low bits 1 means a special case mapping
+      if (allow_caching_ptr) *allow_caching_ptr = false;
+      const MultiCharacterSpecialCase& mapping = multi_chars[value >> 2];
+      for (int i = 0; i < mapping.length; i++)
+        result[i] = mapping.chars[i];
+      return mapping.length;
+    } else {
+      // Low bits 2 means a really really special case
+      if (allow_caching_ptr) *allow_caching_ptr = false;
+      // The cases of this switch are defined in unicode.py in the
+      // really_special_cases mapping.
+      switch (value >> 2) {
+        case 1:
+          // Really special case 1: upper case sigma.  This letter
+          // converts to two different lower case sigmas depending on
+          // whether or not it occurs at the end of a word.
+          if (next != 0 && Letter::Is(next)) {
+            result[0] = 0x03C3;
+          } else {
+            result[0] = 0x03C2;
+          }
+          return 1;
+        default:
+          return 0;
+      }
+      return -1;
+    }
+  } else {
+    return 0;
+  }
+}
+
+uchar Utf8::CalculateValue(const byte* str,
+                           unsigned length,
+                           unsigned* cursor) {
+  static const uchar kMaxOneByteChar = 0x7F;
+  static const uchar kMaxTwoByteChar = 0x7FF;
+  static const uchar kMaxThreeByteChar = 0xFFFF;
+  static const uchar kMaxFourByteChar = 0x1FFFFF;
+
+  // We only get called for non-ascii characters.
+  if (length == 1) {
+    *cursor += 1;
+    return kBadChar;
+  }
+  int first = str[0];
+  int second = str[1] ^ 0x80;
+  if (second & 0xC0) {
+    *cursor += 1;
+    return kBadChar;
+  }
+  if (first < 0xE0) {
+    if (first < 0xC0) {
+      *cursor += 1;
+      return kBadChar;
+    }
+    uchar l = ((first << 6) | second) & kMaxTwoByteChar;
+    if (l <= kMaxOneByteChar) {
+      *cursor += 1;
+      return kBadChar;
+    }
+    *cursor += 2;
+    return l;
+  }
+  if (length == 2) {
+    *cursor += 1;
+    return kBadChar;
+  }
+  int third = str[2] ^ 0x80;
+  if (third & 0xC0) {
+    *cursor += 1;
+    return kBadChar;
+  }
+  if (first < 0xF0) {
+    uchar l = ((((first << 6) | second) << 6) | third) & kMaxThreeByteChar;
+    if (l <= kMaxTwoByteChar) {
+      *cursor += 1;
+      return kBadChar;
+    }
+    *cursor += 3;
+    return l;
+  }
+  if (length == 3) {
+    *cursor += 1;
+    return kBadChar;
+  }
+  int fourth = str[3] ^ 0x80;
+  if (fourth & 0xC0) {
+    *cursor += 1;
+    return kBadChar;
+  }
+  if (first < 0xF8) {
+    uchar l = (((((first << 6 | second) << 6) | third) << 6) | fourth) &
+              kMaxFourByteChar;
+    if (l <= kMaxThreeByteChar) {
+      *cursor += 1;
+      return kBadChar;
+    }
+    *cursor += 4;
+    return l;
+  }
+  *cursor += 1;
+  return kBadChar;
+}
+
+const byte* Utf8::ReadBlock(Buffer<const char*> str, byte* buffer,
+    unsigned capacity, unsigned* chars_read_ptr, unsigned* offset_ptr) {
+  unsigned offset = *offset_ptr;
+  // Bail out early if we've reached the end of the string.
+  if (offset == str.length()) {
+    *chars_read_ptr = 0;
+    return NULL;
+  }
+  const byte* data = reinterpret_cast<const byte*>(str.data());
+  if (data[offset] <= kMaxOneByteChar) {
+    // The next character is an ascii char so we scan forward over
+    // the following ascii characters and return the next pure ascii
+    // substring
+    const byte* result = data + offset;
+    offset++;
+    while ((offset < str.length()) && (data[offset] <= kMaxOneByteChar))
+      offset++;
+    *chars_read_ptr = offset - *offset_ptr;
+    *offset_ptr = offset;
+    return result;
+  } else {
+    // The next character is non-ascii so we just fill the buffer
+    unsigned cursor = 0;
+    unsigned chars_read = 0;
+    while (offset < str.length()) {
+      uchar c = data[offset];
+      if (c <= kMaxOneByteChar) {
+        // Fast case for ascii characters
+        if (!CharacterStream::EncodeAsciiCharacter(c,
+                                                   buffer,
+                                                   capacity,
+                                                   cursor))
+          break;
+        offset += 1;
+      } else {
+        unsigned chars = 0;
+        c = Utf8::ValueOf(data + offset, str.length() - offset, &chars);
+        if (!CharacterStream::EncodeNonAsciiCharacter(c,
+                                                      buffer,
+                                                      capacity,
+                                                      cursor))
+          break;
+        offset += chars;
+      }
+      chars_read++;
+    }
+    *offset_ptr = offset;
+    *chars_read_ptr = chars_read;
+    return buffer;
+  }
+}
+
+unsigned CharacterStream::Length() {
+  unsigned result = 0;
+  while (has_more()) {
+    result++;
+    GetNext();
+  }
+  Rewind();
+  return result;
+}
+
+void CharacterStream::Seek(unsigned position) {
+  Rewind();
+  for (unsigned i = 0; i < position; i++) {
+    GetNext();
+  }
+}
+
+// Uppercase:            point.category == 'Lu'
+
+static const uint16_t kUppercaseTable0Size = 509;
+static const uint16_t kUppercaseTable0[509] = { 32833, 90, 32960, 214, 32984, 222, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 313, 315, 317, 319, 321, 323, 325, 327, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 33144, 377, 379, 381, 33153, 386, 388, 33158, 391, 33161, 395, 33166, 401, 33171, 404, 33174, 408, 33180, 413, 33183, 416, 418, 420, 33190, 423, 425, 428, 33198, 431, 33201, 435, 437, 33207, 440, 444, 452, 455, 458, 461, 463, 465, 467, 469, 471, 473, 475, 478, 480, 482, 484, 486, 488, 490, 492, 494, 497, 500, 33270, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 33338, 571, 33341, 574, 577, 33347, 582, 584, 586, 588, 590, 902, 33672, 906, 908, 33678, 911, 33681, 929, 33699, 939, 33746, 980, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1012, 1015, 33785, 1018, 33789, 1071, 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, 1152, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210, 1212, 1214, 33984, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1232, 1234, 1236, 1238, 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 34097, 1366, 37024, 4293, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 7824, 7826, 7828, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928, 40712, 7951, 40728, 7965, 40744, 7983, 40760, 7999, 40776, 8013, 8025, 8027, 8029, 8031, 40808, 8047, 40888, 8123, 40904, 8139, 40920, 8155, 40936, 8172, 40952, 8187, 8450, 8455, 41227, 8461, 41232, 8466, 8469, 41241, 8477, 8484, 8486, 8488, 41258, 8493, 41264, 8499, 41278, 8511, 8517, 8579, 44032, 11310, 11360, 44130, 11364, 11367, 11369, 11371, 11381, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 11486, 11488, 11490 }; // NOLINT
+static const uint16_t kUppercaseTable1Size = 2;
+static const uint16_t kUppercaseTable1[2] = { 65313, 32570 }; // NOLINT
+static const uint16_t kUppercaseTable2Size = 2;
+static const uint16_t kUppercaseTable2[2] = { 33792, 1063 }; // NOLINT
+static const uint16_t kUppercaseTable3Size = 58;
+static const uint16_t kUppercaseTable3[58] = { 54272, 21529, 54324, 21581, 54376, 21633, 21660, 54430, 21663, 21666, 54437, 21670, 54441, 21676, 54446, 21685, 54480, 21737, 54532, 21765, 54535, 21770, 54541, 21780, 54550, 21788, 54584, 21817, 54587, 21822, 54592, 21828, 21830, 54602, 21840, 54636, 21893, 54688, 21945, 54740, 21997, 54792, 22049, 54844, 22101, 54896, 22153, 54952, 22208, 55010, 22266, 55068, 22324, 55126, 22382, 55184, 22440, 22474 }; // NOLINT
+bool Uppercase::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kUppercaseTable0,
+                                       kUppercaseTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kUppercaseTable1,
+                                       kUppercaseTable1Size,
+                                       c);
+    case 2: return LookupPredicate(kUppercaseTable2,
+                                       kUppercaseTable2Size,
+                                       c);
+    case 3: return LookupPredicate(kUppercaseTable3,
+                                       kUppercaseTable3Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Lowercase:            point.category == 'Ll'
+
+static const uint16_t kLowercaseTable0Size = 528;
+static const uint16_t kLowercaseTable0[528] = { 32865, 122, 170, 181, 186, 32991, 246, 33016, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 33079, 312, 314, 316, 318, 320, 322, 324, 326, 33096, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 378, 380, 33150, 384, 387, 389, 392, 33164, 397, 402, 405, 33177, 411, 414, 417, 419, 421, 424, 33194, 427, 429, 432, 436, 438, 33209, 442, 33213, 447, 454, 457, 460, 462, 464, 466, 468, 470, 472, 474, 33244, 477, 479, 481, 483, 485, 487, 489, 491, 493, 33263, 496, 499, 501, 505, 507, 509, 511, 513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 33331, 569, 572, 33343, 576, 578, 583, 585, 587, 589, 33359, 659, 33429, 687, 33659, 893, 912, 33708, 974, 33744, 977, 33749, 983, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005, 33775, 1011, 1013, 1016, 33787, 1020, 33840, 1119, 1121, 1123, 1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, 1218, 1220, 1222, 1224, 1226, 1228, 33998, 1231, 1233, 1235, 1237, 1239, 1241, 1243, 1245, 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271, 1273, 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299, 34145, 1415, 40192, 7467, 40290, 7543, 40313, 7578, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 40597, 7835, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929, 40704, 7943, 40720, 7957, 40736, 7975, 40752, 7991, 40768, 8005, 40784, 8023, 40800, 8039, 40816, 8061, 40832, 8071, 40848, 8087, 40864, 8103, 40880, 8116, 40886, 8119, 8126, 40898, 8132, 40902, 8135, 40912, 8147, 40918, 8151, 40928, 8167, 40946, 8180, 40950, 8183, 8305, 8319, 8458, 41230, 8463, 8467, 8495, 8500, 8505, 41276, 8509, 41286, 8521, 8526, 8580, 44080, 11358, 11361, 44133, 11366, 11368, 11370, 11372, 11380, 44150, 11383, 11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487, 11489, 44259, 11492, 44288, 11557 }; // NOLINT
+static const uint16_t kLowercaseTable1Size = 6;
+static const uint16_t kLowercaseTable1[6] = { 64256, 31494, 64275, 31511, 65345, 32602 }; // NOLINT
+static const uint16_t kLowercaseTable2Size = 2;
+static const uint16_t kLowercaseTable2[2] = { 33832, 1103 }; // NOLINT
+static const uint16_t kLowercaseTable3Size = 54;
+static const uint16_t kLowercaseTable3[54] = { 54298, 21555, 54350, 21588, 54358, 21607, 54402, 21659, 54454, 21689, 21691, 54461, 21699, 54469, 21711, 54506, 21763, 54558, 21815, 54610, 21867, 54662, 21919, 54714, 21971, 54766, 22023, 54818, 22075, 54870, 22127, 54922, 22181, 54978, 22234, 55004, 22241, 55036, 22292, 55062, 22299, 55094, 22350, 55120, 22357, 55152, 22408, 55178, 22415, 55210, 22466, 55236, 22473, 22475 }; // NOLINT
+bool Lowercase::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kLowercaseTable0,
+                                       kLowercaseTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kLowercaseTable1,
+                                       kLowercaseTable1Size,
+                                       c);
+    case 2: return LookupPredicate(kLowercaseTable2,
+                                       kLowercaseTable2Size,
+                                       c);
+    case 3: return LookupPredicate(kLowercaseTable3,
+                                       kLowercaseTable3Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Letter:               point.category in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo' ]
+
+static const uint16_t kLetterTable0Size = 476;
+static const uint16_t kLetterTable0[476] = { 32833, 90, 32865, 122, 170, 181, 186, 32960, 214, 32984, 246, 33016, 705, 33478, 721, 33504, 740, 750, 33658, 893, 902, 33672, 906, 908, 33678, 929, 33699, 974, 33744, 1013, 33783, 1153, 33930, 1299, 34097, 1366, 1369, 34145, 1415, 34256, 1514, 34288, 1522, 34337, 1594, 34368, 1610, 34414, 1647, 34417, 1747, 1749, 34533, 1766, 34542, 1775, 34554, 1788, 1791, 1808, 34578, 1839, 34637, 1901, 34688, 1957, 1969, 34762, 2026, 34804, 2037, 2042, 35076, 2361, 2365, 2384, 35160, 2401, 35195, 2431, 35205, 2444, 35215, 2448, 35219, 2472, 35242, 2480, 2482, 35254, 2489, 2493, 2510, 35292, 2525, 35295, 2529, 35312, 2545, 35333, 2570, 35343, 2576, 35347, 2600, 35370, 2608, 35378, 2611, 35381, 2614, 35384, 2617, 35417, 2652, 2654, 35442, 2676, 35461, 2701, 35471, 2705, 35475, 2728, 35498, 2736, 35506, 2739, 35509, 2745, 2749, 2768, 35552, 2785, 35589, 2828, 35599, 2832, 35603, 2856, 35626, 2864, 35634, 2867, 35637, 2873, 2877, 35676, 2909, 35679, 2913, 2929, 2947, 35717, 2954, 35726, 2960, 35730, 2965, 35737, 2970, 2972, 35742, 2975, 35747, 2980, 35752, 2986, 35758, 3001, 35845, 3084, 35854, 3088, 35858, 3112, 35882, 3123, 35893, 3129, 35936, 3169, 35973, 3212, 35982, 3216, 35986, 3240, 36010, 3251, 36021, 3257, 3261, 3294, 36064, 3297, 36101, 3340, 36110, 3344, 36114, 3368, 36138, 3385, 36192, 3425, 36229, 3478, 36250, 3505, 36275, 3515, 3517, 36288, 3526, 36353, 3632, 36402, 3635, 36416, 3654, 36481, 3714, 3716, 36487, 3720, 3722, 3725, 36500, 3735, 36505, 3743, 36513, 3747, 3749, 3751, 36522, 3755, 36525, 3760, 36530, 3763, 3773, 36544, 3780, 3782, 36572, 3805, 3840, 36672, 3911, 36681, 3946, 36744, 3979, 36864, 4129, 36899, 4135, 36905, 4138, 36944, 4181, 37024, 4293, 37072, 4346, 4348, 37120, 4441, 37215, 4514, 37288, 4601, 37376, 4680, 37450, 4685, 37456, 4694, 4696, 37466, 4701, 37472, 4744, 37514, 4749, 37520, 4784, 37554, 4789, 37560, 4798, 4800, 37570, 4805, 37576, 4822, 37592, 4880, 37650, 4885, 37656, 4954, 37760, 5007, 37792, 5108, 37889, 5740, 38511, 5750, 38529, 5786, 38560, 5866, 38656, 5900, 38670, 5905, 38688, 5937, 38720, 5969, 38752, 5996, 38766, 6000, 38784, 6067, 6103, 6108, 38944, 6263, 39040, 6312, 39168, 6428, 39248, 6509, 39280, 6516, 39296, 6569, 39361, 6599, 39424, 6678, 39685, 6963, 39749, 6987, 40192, 7615, 40448, 7835, 40608, 7929, 40704, 7957, 40728, 7965, 40736, 8005, 40776, 8013, 40784, 8023, 8025, 8027, 8029, 40799, 8061, 40832, 8116, 40886, 8124, 8126, 40898, 8132, 40902, 8140, 40912, 8147, 40918, 8155, 40928, 8172, 40946, 8180, 40950, 8188, 8305, 8319, 41104, 8340, 8450, 8455, 41226, 8467, 8469, 41241, 8477, 8484, 8486, 8488, 41258, 8493, 41263, 8505, 41276, 8511, 41285, 8521, 8526, 41347, 8580, 44032, 11310, 44080, 11358, 44128, 11372, 44148, 11383, 44160, 11492, 44288, 11557, 44336, 11621, 11631, 44416, 11670, 44448, 11686, 44456, 11694, 44464, 11702, 44472, 11710, 44480, 11718, 44488, 11726, 44496, 11734, 44504, 11742, 45061, 12294, 45105, 12341, 45115, 12348, 45121, 12438, 45213, 12447, 45217, 12538, 45308, 12543, 45317, 12588, 45361, 12686, 45472, 12727, 45552, 12799, 46080, 19893, 52736, 32767 }; // NOLINT
+static const uint16_t kLetterTable1Size = 68;
+static const uint16_t kLetterTable1[68] = { 32768, 8123, 40960, 9356, 42775, 10010, 43008, 10241, 43011, 10245, 43015, 10250, 43020, 10274, 43072, 10355, 44032, 22435, 63744, 31277, 64048, 31338, 64112, 31449, 64256, 31494, 64275, 31511, 31517, 64287, 31528, 64298, 31542, 64312, 31548, 31550, 64320, 31553, 64323, 31556, 64326, 31665, 64467, 32061, 64848, 32143, 64914, 32199, 65008, 32251, 65136, 32372, 65142, 32508, 65313, 32570, 65345, 32602, 65382, 32702, 65474, 32711, 65482, 32719, 65490, 32727, 65498, 32732 }; // NOLINT
+static const uint16_t kLetterTable2Size = 48;
+static const uint16_t kLetterTable2[48] = { 32768, 11, 32781, 38, 32808, 58, 32828, 61, 32831, 77, 32848, 93, 32896, 250, 33536, 798, 33584, 832, 33602, 841, 33664, 925, 33696, 963, 33736, 975, 33792, 1181, 34816, 2053, 2056, 34826, 2101, 34871, 2104, 2108, 2111, 35072, 2325, 2560, 35344, 2579, 35349, 2583, 35353, 2611, 40960, 9070 }; // NOLINT
+static const uint16_t kLetterTable3Size = 57;
+static const uint16_t kLetterTable3[57] = { 54272, 21588, 54358, 21660, 54430, 21663, 21666, 54437, 21670, 54441, 21676, 54446, 21689, 21691, 54461, 21699, 54469, 21765, 54535, 21770, 54541, 21780, 54550, 21788, 54558, 21817, 54587, 21822, 54592, 21828, 21830, 54602, 21840, 54610, 22181, 54952, 22208, 54978, 22234, 55004, 22266, 55036, 22292, 55062, 22324, 55094, 22350, 55120, 22382, 55152, 22408, 55178, 22440, 55210, 22466, 55236, 22475 }; // NOLINT
+static const uint16_t kLetterTable4Size = 2;
+static const uint16_t kLetterTable4[2] = { 32768, 32767 }; // NOLINT
+static const uint16_t kLetterTable5Size = 4;
+static const uint16_t kLetterTable5[4] = { 32768, 9942, 63488, 31261 }; // NOLINT
+bool Letter::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kLetterTable0,
+                                       kLetterTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kLetterTable1,
+                                       kLetterTable1Size,
+                                       c);
+    case 2: return LookupPredicate(kLetterTable2,
+                                       kLetterTable2Size,
+                                       c);
+    case 3: return LookupPredicate(kLetterTable3,
+                                       kLetterTable3Size,
+                                       c);
+    case 4: return LookupPredicate(kLetterTable4,
+                                       kLetterTable4Size,
+                                       c);
+    case 5: return LookupPredicate(kLetterTable5,
+                                       kLetterTable5Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Space:                point.category == 'Zs'
+
+static const uint16_t kSpaceTable0Size = 9;
+static const uint16_t kSpaceTable0[9] = { 32, 160, 5760, 6158, 40960, 8202, 8239, 8287, 12288 }; // NOLINT
+bool Space::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kSpaceTable0,
+                                       kSpaceTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Titlecase:            point.category == 'Lt'
+
+static const uint16_t kTitlecaseTable0Size = 13;
+static const uint16_t kTitlecaseTable0[13] = { 453, 456, 459, 498, 40840, 8079, 40856, 8095, 40872, 8111, 8124, 8140, 8188 }; // NOLINT
+bool Titlecase::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kTitlecaseTable0,
+                                       kTitlecaseTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Number:               point.category in ['Nd', 'Nl', 'No' ]
+
+static const uint16_t kNumberTable0Size = 86;
+static const uint16_t kNumberTable0[86] = { 32816, 57, 32946, 179, 185, 32956, 190, 34400, 1641, 34544, 1785, 34752, 1993, 35174, 2415, 35302, 2543, 35316, 2553, 35430, 2671, 35558, 2799, 35686, 2927, 35814, 3058, 35942, 3183, 36070, 3311, 36198, 3439, 36432, 3673, 36560, 3801, 36640, 3891, 36928, 4169, 37737, 4988, 38638, 5872, 38880, 6121, 38896, 6137, 38928, 6169, 39238, 6479, 39376, 6617, 39760, 7001, 8304, 41076, 8313, 41088, 8329, 41299, 8578, 42080, 9371, 42218, 9471, 42870, 10131, 11517, 12295, 45089, 12329, 45112, 12346, 45458, 12693, 45600, 12841, 45649, 12895, 45696, 12937, 45745, 12991 }; // NOLINT
+static const uint16_t kNumberTable1Size = 2;
+static const uint16_t kNumberTable1[2] = { 65296, 32537 }; // NOLINT
+static const uint16_t kNumberTable2Size = 19;
+static const uint16_t kNumberTable2[19] = { 33031, 307, 33088, 376, 394, 33568, 803, 833, 842, 33745, 981, 33952, 1193, 35094, 2329, 35392, 2631, 41984, 9314 }; // NOLINT
+static const uint16_t kNumberTable3Size = 4;
+static const uint16_t kNumberTable3[4] = { 54112, 21361, 55246, 22527 }; // NOLINT
+bool Number::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kNumberTable0,
+                                       kNumberTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kNumberTable1,
+                                       kNumberTable1Size,
+                                       c);
+    case 2: return LookupPredicate(kNumberTable2,
+                                       kNumberTable2Size,
+                                       c);
+    case 3: return LookupPredicate(kNumberTable3,
+                                       kNumberTable3Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// DecimalDigit:         point.category == 'Nd'
+
+static const uint16_t kDecimalDigitTable0Size = 44;
+static const uint16_t kDecimalDigitTable0[44] = { 32816, 57, 34400, 1641, 34544, 1785, 34752, 1993, 35174, 2415, 35302, 2543, 35430, 2671, 35558, 2799, 35686, 2927, 35814, 3055, 35942, 3183, 36070, 3311, 36198, 3439, 36432, 3673, 36560, 3801, 36640, 3881, 36928, 4169, 38880, 6121, 38928, 6169, 39238, 6479, 39376, 6617, 39760, 7001 }; // NOLINT
+static const uint16_t kDecimalDigitTable1Size = 2;
+static const uint16_t kDecimalDigitTable1[2] = { 65296, 32537 }; // NOLINT
+static const uint16_t kDecimalDigitTable2Size = 2;
+static const uint16_t kDecimalDigitTable2[2] = { 33952, 1193 }; // NOLINT
+static const uint16_t kDecimalDigitTable3Size = 2;
+static const uint16_t kDecimalDigitTable3[2] = { 55246, 22527 }; // NOLINT
+bool DecimalDigit::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kDecimalDigitTable0,
+                                       kDecimalDigitTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kDecimalDigitTable1,
+                                       kDecimalDigitTable1Size,
+                                       c);
+    case 2: return LookupPredicate(kDecimalDigitTable2,
+                                       kDecimalDigitTable2Size,
+                                       c);
+    case 3: return LookupPredicate(kDecimalDigitTable3,
+                                       kDecimalDigitTable3Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Ideographic:          'Id' in point.properties
+
+static const uint16_t kIdeographicTable0Size = 10;
+static const uint16_t kIdeographicTable0[10] = { 45062, 12295, 45089, 12329, 45112, 12346, 46080, 19893, 52736, 32767 }; // NOLINT
+static const uint16_t kIdeographicTable1Size = 6;
+static const uint16_t kIdeographicTable1[6] = { 32768, 8123, 63744, 31277, 64112, 31449 }; // NOLINT
+static const uint16_t kIdeographicTable4Size = 2;
+static const uint16_t kIdeographicTable4[2] = { 32768, 32767 }; // NOLINT
+static const uint16_t kIdeographicTable5Size = 4;
+static const uint16_t kIdeographicTable5[4] = { 32768, 9942, 63488, 31261 }; // NOLINT
+bool Ideographic::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kIdeographicTable0,
+                                       kIdeographicTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kIdeographicTable1,
+                                       kIdeographicTable1Size,
+                                       c);
+    case 4: return LookupPredicate(kIdeographicTable4,
+                                       kIdeographicTable4Size,
+                                       c);
+    case 5: return LookupPredicate(kIdeographicTable5,
+                                       kIdeographicTable5Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// WhiteSpace:           'Ws' in point.properties
+
+static const uint16_t kWhiteSpaceTable0Size = 14;
+static const uint16_t kWhiteSpaceTable0[14] = { 32777, 13, 32, 133, 160, 5760, 6158, 40960, 8202, 41000, 8233, 8239, 8287, 12288 }; // NOLINT
+bool WhiteSpace::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kWhiteSpaceTable0,
+                                       kWhiteSpaceTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// HexDigit:             'Hd' in point.properties
+
+static const uint16_t kHexDigitTable0Size = 6;
+static const uint16_t kHexDigitTable0[6] = { 32816, 57, 32833, 70, 32865, 102 }; // NOLINT
+static const uint16_t kHexDigitTable1Size = 6;
+static const uint16_t kHexDigitTable1[6] = { 65296, 32537, 65313, 32550, 65345, 32582 }; // NOLINT
+bool HexDigit::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kHexDigitTable0,
+                                       kHexDigitTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kHexDigitTable1,
+                                       kHexDigitTable1Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// AsciiHexDigit:        'Ah' in point.properties
+
+static const uint16_t kAsciiHexDigitTable0Size = 6;
+static const uint16_t kAsciiHexDigitTable0[6] = { 32816, 57, 32833, 70, 32865, 102 }; // NOLINT
+bool AsciiHexDigit::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kAsciiHexDigitTable0,
+                                       kAsciiHexDigitTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// BidiControl:          'Bc' in point.properties
+
+static const uint16_t kBidiControlTable0Size = 4;
+static const uint16_t kBidiControlTable0[4] = { 40974, 8207, 41002, 8238 }; // NOLINT
+bool BidiControl::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kBidiControlTable0,
+                                       kBidiControlTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// JoinControl:          'Jc' in point.properties
+
+static const uint16_t kJoinControlTable0Size = 2;
+static const uint16_t kJoinControlTable0[2] = { 40972, 8205 }; // NOLINT
+bool JoinControl::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kJoinControlTable0,
+                                       kJoinControlTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Dash:                 'Dh' in point.properties
+
+static const uint16_t kDashTable0Size = 14;
+static const uint16_t kDashTable0[14] = { 45, 1418, 1470, 6150, 40976, 8213, 8275, 8315, 8331, 8722, 11799, 12316, 12336, 12448 }; // NOLINT
+static const uint16_t kDashTable1Size = 5;
+static const uint16_t kDashTable1[5] = { 65073, 32306, 32344, 32355, 32525 }; // NOLINT
+bool Dash::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kDashTable0,
+                                       kDashTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kDashTable1,
+                                       kDashTable1Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// Hyphen:               'Hp' in point.properties
+
+static const uint16_t kHyphenTable0Size = 8;
+static const uint16_t kHyphenTable0[8] = { 45, 173, 1418, 6150, 40976, 8209, 11799, 12539 }; // NOLINT
+static const uint16_t kHyphenTable1Size = 3;
+static const uint16_t kHyphenTable1[3] = { 32355, 32525, 32613 }; // NOLINT
+bool Hyphen::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kHyphenTable0,
+                                       kHyphenTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kHyphenTable1,
+                                       kHyphenTable1Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// LineTerminator:       'Lt' in point.properties
+
+static const uint16_t kLineTerminatorTable0Size = 4;
+static const uint16_t kLineTerminatorTable0[4] = { 10, 13, 41000, 8233 }; // NOLINT
+bool LineTerminator::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kLineTerminatorTable0,
+                                       kLineTerminatorTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// RegExpSpecialChar:    'Rx' in point.properties
+
+static const uint16_t kRegExpSpecialCharTable0Size = 9;
+static const uint16_t kRegExpSpecialCharTable0[9] = { 36, 32808, 43, 46, 63, 32859, 94, 32891, 125 }; // NOLINT
+bool RegExpSpecialChar::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kRegExpSpecialCharTable0,
+                                       kRegExpSpecialCharTable0Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// CombiningMark:        point.category in ['Mn', 'Mc']
+
+static const uint16_t kCombiningMarkTable0Size = 214;
+static const uint16_t kCombiningMarkTable0[214] = { 33536, 879, 33923, 1158, 34193, 1469, 1471, 34241, 1474, 34244, 1477, 1479, 34320, 1557, 34379, 1630, 1648, 34518, 1756, 34527, 1764, 34535, 1768, 34538, 1773, 1809, 34608, 1866, 34726, 1968, 34795, 2035, 35073, 2307, 2364, 35134, 2381, 35153, 2388, 35170, 2403, 35201, 2435, 2492, 35262, 2500, 35271, 2504, 35275, 2509, 2519, 35298, 2531, 35329, 2563, 2620, 35390, 2626, 35399, 2632, 35403, 2637, 35440, 2673, 35457, 2691, 2748, 35518, 2757, 35527, 2761, 35531, 2765, 35554, 2787, 35585, 2819, 2876, 35646, 2883, 35655, 2888, 35659, 2893, 35670, 2903, 2946, 35774, 3010, 35782, 3016, 35786, 3021, 3031, 35841, 3075, 35902, 3140, 35910, 3144, 35914, 3149, 35925, 3158, 35970, 3203, 3260, 36030, 3268, 36038, 3272, 36042, 3277, 36053, 3286, 36066, 3299, 36098, 3331, 36158, 3395, 36166, 3400, 36170, 3405, 3415, 36226, 3459, 3530, 36303, 3540, 3542, 36312, 3551, 36338, 3571, 3633, 36404, 3642, 36423, 3662, 3761, 36532, 3769, 36539, 3772, 36552, 3789, 36632, 3865, 3893, 3895, 3897, 36670, 3903, 36721, 3972, 36742, 3975, 36752, 3991, 36761, 4028, 4038, 36908, 4146, 36918, 4153, 36950, 4185, 4959, 38674, 5908, 38706, 5940, 38738, 5971, 38770, 6003, 38838, 6099, 6109, 38923, 6157, 6313, 39200, 6443, 39216, 6459, 39344, 6592, 39368, 6601, 39447, 6683, 39680, 6916, 39732, 6980, 39787, 7027, 40384, 7626, 40446, 7679, 41168, 8412, 8417, 41189, 8431, 45098, 12335, 45209, 12442 }; // NOLINT
+static const uint16_t kCombiningMarkTable1Size = 10;
+static const uint16_t kCombiningMarkTable1[10] = { 10242, 10246, 10251, 43043, 10279, 31518, 65024, 32271, 65056, 32291 }; // NOLINT
+static const uint16_t kCombiningMarkTable2Size = 9;
+static const uint16_t kCombiningMarkTable2[9] = { 35329, 2563, 35333, 2566, 35340, 2575, 35384, 2618, 2623 }; // NOLINT
+static const uint16_t kCombiningMarkTable3Size = 12;
+static const uint16_t kCombiningMarkTable3[12] = { 53605, 20841, 53613, 20850, 53627, 20866, 53637, 20875, 53674, 20909, 53826, 21060 }; // NOLINT
+static const uint16_t kCombiningMarkTable28Size = 2;
+static const uint16_t kCombiningMarkTable28[2] = { 33024, 495 }; // NOLINT
+bool CombiningMark::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kCombiningMarkTable0,
+                                       kCombiningMarkTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kCombiningMarkTable1,
+                                       kCombiningMarkTable1Size,
+                                       c);
+    case 2: return LookupPredicate(kCombiningMarkTable2,
+                                       kCombiningMarkTable2Size,
+                                       c);
+    case 3: return LookupPredicate(kCombiningMarkTable3,
+                                       kCombiningMarkTable3Size,
+                                       c);
+    case 28: return LookupPredicate(kCombiningMarkTable28,
+                                       kCombiningMarkTable28Size,
+                                       c);
+    default: return false;
+  }
+}
+
+// ConnectorPunctuation: point.category == 'Pc'
+
+static const uint16_t kConnectorPunctuationTable0Size = 4;
+static const uint16_t kConnectorPunctuationTable0[4] = { 95, 41023, 8256, 8276 }; // NOLINT
+static const uint16_t kConnectorPunctuationTable1Size = 5;
+static const uint16_t kConnectorPunctuationTable1[5] = { 65075, 32308, 65101, 32335, 32575 }; // NOLINT
+bool ConnectorPunctuation::Is(uchar c) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupPredicate(kConnectorPunctuationTable0,
+                                       kConnectorPunctuationTable0Size,
+                                       c);
+    case 1: return LookupPredicate(kConnectorPunctuationTable1,
+                                       kConnectorPunctuationTable1Size,
+                                       c);
+    default: return false;
+  }
+}
+
+static const MultiCharacterSpecialCase kToLowercaseMultiStrings0[] = { {2, {105, 775}}, {0, {0}} }; // NOLINT
+static const uint16_t kToLowercaseTable0Size = 531;
+static const uint16_t kToLowercaseTable0[1062] = { 32833, 128, 90, 128, 32960, 128, 214, 128, 32984, 128, 222, 128, 256, 4, 258, 4, 260, 4, 262, 4, 264, 4, 266, 4, 268, 4, 270, 4, 272, 4, 274, 4, 276, 4, 278, 4, 280, 4, 282, 4, 284, 4, 286, 4, 288, 4, 290, 4, 292, 4, 294, 4, 296, 4, 298, 4, 300, 4, 302, 4, 304, 1, 306, 4, 308, 4, 310, 4, 313, 4, 315, 4, 317, 4, 319, 4, 321, 4, 323, 4, 325, 4, 327, 4, 330, 4, 332, 4, 334, 4, 336, 4, 338, 4, 340, 4, 342, 4, 344, 4, 346, 4, 348, 4, 350, 4, 352, 4, 354, 4, 356, 4, 358, 4, 360, 4, 362, 4, 364, 4, 366, 4, 368, 4, 370, 4, 372, 4, 374, 4, 376, static_cast<uint16_t>(-484), 377, 4, 379, 4, 381, 4, 385, 840, 386, 4, 388, 4, 390, 824, 391, 4, 33161, 820, 394, 820, 395, 4, 398, 316, 399, 808, 400, 812, 401, 4, 403, 820, 404, 828, 406, 844, 407, 836, 408, 4, 412, 844, 413, 852, 415, 856, 416, 4, 418, 4, 420, 4, 422, 872, 423, 4, 425, 872, 428, 4, 430, 872, 431, 4, 33201, 868, 434, 868, 435, 4, 437, 4, 439, 876, 440, 4, 444, 4, 452, 8, 453, 4, 455, 8, 456, 4, 458, 8, 459, 4, 461, 4, 463, 4, 465, 4, 467, 4, 469, 4, 471, 4, 473, 4, 475, 4, 478, 4, 480, 4, 482, 4, 484, 4, 486, 4, 488, 4, 490, 4, 492, 4, 494, 4, 497, 8, 498, 4, 500, 4, 502, static_cast<uint16_t>(-388), 503, static_cast<uint16_t>(-224), 504, 4, 506, 4, 508, 4, 510, 4, 512, 4, 514, 4, 516, 4, 518, 4, 520, 4, 522, 4, 524, 4, 526, 4, 528, 4, 530, 4, 532, 4, 534, 4, 536, 4, 538, 4, 540, 4, 542, 4, 544, static_cast<uint16_t>(-520), 546, 4, 548, 4, 550, 4, 552, 4, 554, 4, 556, 4, 558, 4, 560, 4, 562, 4, 570, 43180, 571, 4, 573, static_cast<uint16_t>(-652), 574, 43168, 577, 4, 579, static_cast<uint16_t>(-780), 580, 276, 581, 284, 582, 4, 584, 4, 586, 4, 588, 4, 590, 4, 902, 152, 33672, 148, 906, 148, 908, 256, 33678, 252, 911, 252, 33681, 128, 929, 128, 33699, 6, 939, 128, 984, 4, 986, 4, 988, 4, 990, 4, 992, 4, 994, 4, 996, 4, 998, 4, 1000, 4, 1002, 4, 1004, 4, 1006, 4, 1012, static_cast<uint16_t>(-240), 1015, 4, 1017, static_cast<uint16_t>(-28), 1018, 4, 33789, static_cast<uint16_t>(-520), 1023, static_cast<uint16_t>(-520), 33792, 320, 1039, 320, 33808, 128, 1071, 128, 1120, 4, 1122, 4, 1124, 4, 1126, 4, 1128, 4, 1130, 4, 1132, 4, 1134, 4, 1136, 4, 1138, 4, 1140, 4, 1142, 4, 1144, 4, 1146, 4, 1148, 4, 1150, 4, 1152, 4, 1162, 4, 1164, 4, 1166, 4, 1168, 4, 1170, 4, 1172, 4, 1174, 4, 1176, 4, 1178, 4, 1180, 4, 1182, 4, 1184, 4, 1186, 4, 1188, 4, 1190, 4, 1192, 4, 1194, 4, 1196, 4, 1198, 4, 1200, 4, 1202, 4, 1204, 4, 1206, 4, 1208, 4, 1210, 4, 1212, 4, 1214, 4, 1216, 60, 1217, 4, 1219, 4, 1221, 4, 1223, 4, 1225, 4, 1227, 4, 1229, 4, 1232, 4, 1234, 4, 1236, 4, 1238, 4, 1240, 4, 1242, 4, 1244, 4, 1246, 4, 1248, 4, 1250, 4, 1252, 4, 1254, 4, 1256, 4, 1258, 4, 1260, 4, 1262, 4, 1264, 4, 1266, 4, 1268, 4, 1270, 4, 1272, 4, 1274, 4, 1276, 4, 1278, 4, 1280, 4, 1282, 4, 1284, 4, 1286, 4, 1288, 4, 1290, 4, 1292, 4, 1294, 4, 1296, 4, 1298, 4, 34097, 192, 1366, 192, 37024, 29056, 4293, 29056, 7680, 4, 7682, 4, 7684, 4, 7686, 4, 7688, 4, 7690, 4, 7692, 4, 7694, 4, 7696, 4, 7698, 4, 7700, 4, 7702, 4, 7704, 4, 7706, 4, 7708, 4, 7710, 4, 7712, 4, 7714, 4, 7716, 4, 7718, 4, 7720, 4, 7722, 4, 7724, 4, 7726, 4, 7728, 4, 7730, 4, 7732, 4, 7734, 4, 7736, 4, 7738, 4, 7740, 4, 7742, 4, 7744, 4, 7746, 4, 7748, 4, 7750, 4, 7752, 4, 7754, 4, 7756, 4, 7758, 4, 7760, 4, 7762, 4, 7764, 4, 7766, 4, 7768, 4, 7770, 4, 7772, 4, 7774, 4, 7776, 4, 7778, 4, 7780, 4, 7782, 4, 7784, 4, 7786, 4, 7788, 4, 7790, 4, 7792, 4, 7794, 4, 7796, 4, 7798, 4, 7800, 4, 7802, 4, 7804, 4, 7806, 4, 7808, 4, 7810, 4, 7812, 4, 7814, 4, 7816, 4, 7818, 4, 7820, 4, 7822, 4, 7824, 4, 7826, 4, 7828, 4, 7840, 4, 7842, 4, 7844, 4, 7846, 4, 7848, 4, 7850, 4, 7852, 4, 7854, 4, 7856, 4, 7858, 4, 7860, 4, 7862, 4, 7864, 4, 7866, 4, 7868, 4, 7870, 4, 7872, 4, 7874, 4, 7876, 4, 7878, 4, 7880, 4, 7882, 4, 7884, 4, 7886, 4, 7888, 4, 7890, 4, 7892, 4, 7894, 4, 7896, 4, 7898, 4, 7900, 4, 7902, 4, 7904, 4, 7906, 4, 7908, 4, 7910, 4, 7912, 4, 7914, 4, 7916, 4, 7918, 4, 7920, 4, 7922, 4, 7924, 4, 7926, 4, 7928, 4, 40712, static_cast<uint16_t>(-32), 7951, static_cast<uint16_t>(-32), 40728, static_cast<uint16_t>(-32), 7965, static_cast<uint16_t>(-32), 40744, static_cast<uint16_t>(-32), 7983, static_cast<uint16_t>(-32), 40760, static_cast<uint16_t>(-32), 7999, static_cast<uint16_t>(-32), 40776, static_cast<uint16_t>(-32), 8013, static_cast<uint16_t>(-32), 8025, static_cast<uint16_t>(-32), 8027, static_cast<uint16_t>(-32), 8029, static_cast<uint16_t>(-32), 8031, static_cast<uint16_t>(-32), 40808, static_cast<uint16_t>(-32), 8047, static_cast<uint16_t>(-32), 40840, static_cast<uint16_t>(-32), 8079, static_cast<uint16_t>(-32), 40856, static_cast<uint16_t>(-32), 8095, static_cast<uint16_t>(-32), 40872, static_cast<uint16_t>(-32), 8111, static_cast<uint16_t>(-32), 40888, static_cast<uint16_t>(-32), 8121, static_cast<uint16_t>(-32), 40890, static_cast<uint16_t>(-296), 8123, static_cast<uint16_t>(-296), 8124, static_cast<uint16_t>(-36), 40904, static_cast<uint16_t>(-344), 8139, static_cast<uint16_t>(-344), 8140, static_cast<uint16_t>(-36), 40920, static_cast<uint16_t>(-32), 8153, static_cast<uint16_t>(-32), 40922, static_cast<uint16_t>(-400), 8155, static_cast<uint16_t>(-400), 40936, static_cast<uint16_t>(-32), 8169, static_cast<uint16_t>(-32), 40938, static_cast<uint16_t>(-448), 8171, static_cast<uint16_t>(-448), 8172, static_cast<uint16_t>(-28), 40952, static_cast<uint16_t>(-512), 8185, static_cast<uint16_t>(-512), 40954, static_cast<uint16_t>(-504), 8187, static_cast<uint16_t>(-504), 8188, static_cast<uint16_t>(-36), 8486, static_cast<uint16_t>(-30068), 8490, static_cast<uint16_t>(-33532), 8491, static_cast<uint16_t>(-33048), 8498, 112, 41312, 64, 8559, 64, 8579, 4, 42166, 104, 9423, 104, 44032, 192, 11310, 192, 11360, 4, 11362, static_cast<uint16_t>(-42972), 11363, static_cast<uint16_t>(-15256), 11364, static_cast<uint16_t>(-42908), 11367, 4, 11369, 4, 11371, 4, 11381, 4, 11392, 4, 11394, 4, 11396, 4, 11398, 4, 11400, 4, 11402, 4, 11404, 4, 11406, 4, 11408, 4, 11410, 4, 11412, 4, 11414, 4, 11416, 4, 11418, 4, 11420, 4, 11422, 4, 11424, 4, 11426, 4, 11428, 4, 11430, 4, 11432, 4, 11434, 4, 11436, 4, 11438, 4, 11440, 4, 11442, 4, 11444, 4, 11446, 4, 11448, 4, 11450, 4, 11452, 4, 11454, 4, 11456, 4, 11458, 4, 11460, 4, 11462, 4, 11464, 4, 11466, 4, 11468, 4, 11470, 4, 11472, 4, 11474, 4, 11476, 4, 11478, 4, 11480, 4, 11482, 4, 11484, 4, 11486, 4, 11488, 4, 11490, 4 }; // NOLINT
+static const MultiCharacterSpecialCase kToLowercaseMultiStrings1[] = { {0, {0}} }; // NOLINT
+static const uint16_t kToLowercaseTable1Size = 2;
+static const uint16_t kToLowercaseTable1[4] = { 65313, 128, 32570, 128 }; // NOLINT
+static const MultiCharacterSpecialCase kToLowercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const uint16_t kToLowercaseTable2Size = 2;
+static const uint16_t kToLowercaseTable2[4] = { 33792, 160, 1063, 160 }; // NOLINT
+int ToLowercase::Convert(uchar c,
+                      uchar n,
+                      uchar* result,
+                      bool* allow_caching_ptr) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupMapping(kToLowercaseTable0,
+                                     kToLowercaseTable0Size,
+                                     kToLowercaseMultiStrings0,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 1: return LookupMapping(kToLowercaseTable1,
+                                     kToLowercaseTable1Size,
+                                     kToLowercaseMultiStrings1,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 2: return LookupMapping(kToLowercaseTable2,
+                                     kToLowercaseTable2Size,
+                                     kToLowercaseMultiStrings2,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    default: return 0;
+  }
+}
+
+static const MultiCharacterSpecialCase kToUppercaseMultiStrings0[] = { {2, {83, 83}}, {2, {700, 78}}, {2, {74, 780}}, {3, {921, 776, 769}}, {3, {933, 776, 769}}, {2, {1333, 1362}}, {2, {72, 817}}, {2, {84, 776}}, {2, {87, 778}}, {2, {89, 778}}, {2, {65, 702}}, {2, {933, 787}}, {3, {933, 787, 768}}, {3, {933, 787, 769}}, {3, {933, 787, 834}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8122, 921}}, {2, {913, 921}}, {2, {902, 921}}, {2, {913, 834}}, {3, {913, 834, 921}}, {2, {913, 921}}, {2, {8138, 921}}, {2, {919, 921}}, {2, {905, 921}}, {2, {919, 834}}, {3, {919, 834, 921}}, {2, {919, 921}}, {3, {921, 776, 768}}, {3, {921, 776, 769}}, {2, {921, 834}}, {3, {921, 776, 834}}, {3, {933, 776, 768}}, {3, {933, 776, 769}}, {2, {929, 787}}, {2, {933, 834}}, {3, {933, 776, 834}}, {2, {8186, 921}}, {2, {937, 921}}, {2, {911, 921}}, {2, {937, 834}}, {3, {937, 834, 921}}, {2, {937, 921}}, {0, {0}} }; // NOLINT
+static const uint16_t kToUppercaseTable0Size = 621;
+static const uint16_t kToUppercaseTable0[1242] = { 32865, static_cast<uint16_t>(-128), 122, static_cast<uint16_t>(-128), 181, 2972, 223, 1, 32992, static_cast<uint16_t>(-128), 246, static_cast<uint16_t>(-128), 33016, static_cast<uint16_t>(-128), 254, static_cast<uint16_t>(-128), 255, 484, 257, static_cast<uint16_t>(-4), 259, static_cast<uint16_t>(-4), 261, static_cast<uint16_t>(-4), 263, static_cast<uint16_t>(-4), 265, static_cast<uint16_t>(-4), 267, static_cast<uint16_t>(-4), 269, static_cast<uint16_t>(-4), 271, static_cast<uint16_t>(-4), 273, static_cast<uint16_t>(-4), 275, static_cast<uint16_t>(-4), 277, static_cast<uint16_t>(-4), 279, static_cast<uint16_t>(-4), 281, static_cast<uint16_t>(-4), 283, static_cast<uint16_t>(-4), 285, static_cast<uint16_t>(-4), 287, static_cast<uint16_t>(-4), 289, static_cast<uint16_t>(-4), 291, static_cast<uint16_t>(-4), 293, static_cast<uint16_t>(-4), 295, static_cast<uint16_t>(-4), 297, static_cast<uint16_t>(-4), 299, static_cast<uint16_t>(-4), 301, static_cast<uint16_t>(-4), 303, static_cast<uint16_t>(-4), 305, static_cast<uint16_t>(-928), 307, static_cast<uint16_t>(-4), 309, static_cast<uint16_t>(-4), 311, static_cast<uint16_t>(-4), 314, static_cast<uint16_t>(-4), 316, static_cast<uint16_t>(-4), 318, static_cast<uint16_t>(-4), 320, static_cast<uint16_t>(-4), 322, static_cast<uint16_t>(-4), 324, static_cast<uint16_t>(-4), 326, static_cast<uint16_t>(-4), 328, static_cast<uint16_t>(-4), 329, 5, 331, static_cast<uint16_t>(-4), 333, static_cast<uint16_t>(-4), 335, static_cast<uint16_t>(-4), 337, static_cast<uint16_t>(-4), 339, static_cast<uint16_t>(-4), 341, static_cast<uint16_t>(-4), 343, static_cast<uint16_t>(-4), 345, static_cast<uint16_t>(-4), 347, static_cast<uint16_t>(-4), 349, static_cast<uint16_t>(-4), 351, static_cast<uint16_t>(-4), 353, static_cast<uint16_t>(-4), 355, static_cast<uint16_t>(-4), 357, static_cast<uint16_t>(-4), 359, static_cast<uint16_t>(-4), 361, static_cast<uint16_t>(-4), 363, static_cast<uint16_t>(-4), 365, static_cast<uint16_t>(-4), 367, static_cast<uint16_t>(-4), 369, static_cast<uint16_t>(-4), 371, static_cast<uint16_t>(-4), 373, static_cast<uint16_t>(-4), 375, static_cast<uint16_t>(-4), 378, static_cast<uint16_t>(-4), 380, static_cast<uint16_t>(-4), 382, static_cast<uint16_t>(-4), 383, static_cast<uint16_t>(-1200), 384, 780, 387, static_cast<uint16_t>(-4), 389, static_cast<uint16_t>(-4), 392, static_cast<uint16_t>(-4), 396, static_cast<uint16_t>(-4), 402, static_cast<uint16_t>(-4), 405, 388, 409, static_cast<uint16_t>(-4), 410, 652, 414, 520, 417, static_cast<uint16_t>(-4), 419, static_cast<uint16_t>(-4), 421, static_cast<uint16_t>(-4), 424, static_cast<uint16_t>(-4), 429, static_cast<uint16_t>(-4), 432, static_cast<uint16_t>(-4), 436, static_cast<uint16_t>(-4), 438, static_cast<uint16_t>(-4), 441, static_cast<uint16_t>(-4), 445, static_cast<uint16_t>(-4), 447, 224, 453, static_cast<uint16_t>(-4), 454, static_cast<uint16_t>(-8), 456, static_cast<uint16_t>(-4), 457, static_cast<uint16_t>(-8), 459, static_cast<uint16_t>(-4), 460, static_cast<uint16_t>(-8), 462, static_cast<uint16_t>(-4), 464, static_cast<uint16_t>(-4), 466, static_cast<uint16_t>(-4), 468, static_cast<uint16_t>(-4), 470, static_cast<uint16_t>(-4), 472, static_cast<uint16_t>(-4), 474, static_cast<uint16_t>(-4), 476, static_cast<uint16_t>(-4), 477, static_cast<uint16_t>(-316), 479, static_cast<uint16_t>(-4), 481, static_cast<uint16_t>(-4), 483, static_cast<uint16_t>(-4), 485, static_cast<uint16_t>(-4), 487, static_cast<uint16_t>(-4), 489, static_cast<uint16_t>(-4), 491, static_cast<uint16_t>(-4), 493, static_cast<uint16_t>(-4), 495, static_cast<uint16_t>(-4), 496, 9, 498, static_cast<uint16_t>(-4), 499, static_cast<uint16_t>(-8), 501, static_cast<uint16_t>(-4), 505, static_cast<uint16_t>(-4), 507, static_cast<uint16_t>(-4), 509, static_cast<uint16_t>(-4), 511, static_cast<uint16_t>(-4), 513, static_cast<uint16_t>(-4), 515, static_cast<uint16_t>(-4), 517, static_cast<uint16_t>(-4), 519, static_cast<uint16_t>(-4), 521, static_cast<uint16_t>(-4), 523, static_cast<uint16_t>(-4), 525, static_cast<uint16_t>(-4), 527, static_cast<uint16_t>(-4), 529, static_cast<uint16_t>(-4), 531, static_cast<uint16_t>(-4), 533, static_cast<uint16_t>(-4), 535, static_cast<uint16_t>(-4), 537, static_cast<uint16_t>(-4), 539, static_cast<uint16_t>(-4), 541, static_cast<uint16_t>(-4), 543, static_cast<uint16_t>(-4), 547, static_cast<uint16_t>(-4), 549, static_cast<uint16_t>(-4), 551, static_cast<uint16_t>(-4), 553, static_cast<uint16_t>(-4), 555, static_cast<uint16_t>(-4), 557, static_cast<uint16_t>(-4), 559, static_cast<uint16_t>(-4), 561, static_cast<uint16_t>(-4), 563, static_cast<uint16_t>(-4), 572, static_cast<uint16_t>(-4), 578, static_cast<uint16_t>(-4), 583, static_cast<uint16_t>(-4), 585, static_cast<uint16_t>(-4), 587, static_cast<uint16_t>(-4), 589, static_cast<uint16_t>(-4), 591, static_cast<uint16_t>(-4), 595, static_cast<uint16_t>(-840), 596, static_cast<uint16_t>(-824), 33366, static_cast<uint16_t>(-820), 599, static_cast<uint16_t>(-820), 601, static_cast<uint16_t>(-808), 603, static_cast<uint16_t>(-812), 608, static_cast<uint16_t>(-820), 611, static_cast<uint16_t>(-828), 616, static_cast<uint16_t>(-836), 617, static_cast<uint16_t>(-844), 619, 42972, 623, static_cast<uint16_t>(-844), 626, static_cast<uint16_t>(-852), 629, static_cast<uint16_t>(-856), 637, 42908, 640, static_cast<uint16_t>(-872), 643, static_cast<uint16_t>(-872), 648, static_cast<uint16_t>(-872), 649, static_cast<uint16_t>(-276), 33418, static_cast<uint16_t>(-868), 651, static_cast<uint16_t>(-868), 652, static_cast<uint16_t>(-284), 658, static_cast<uint16_t>(-876), 837, 336, 33659, 520, 893, 520, 912, 13, 940, static_cast<uint16_t>(-152), 33709, static_cast<uint16_t>(-148), 943, static_cast<uint16_t>(-148), 944, 17, 33713, static_cast<uint16_t>(-128), 961, static_cast<uint16_t>(-128), 962, static_cast<uint16_t>(-124), 33731, static_cast<uint16_t>(-128), 971, static_cast<uint16_t>(-128), 972, static_cast<uint16_t>(-256), 33741, static_cast<uint16_t>(-252), 974, static_cast<uint16_t>(-252), 976, static_cast<uint16_t>(-248), 977, static_cast<uint16_t>(-228), 981, static_cast<uint16_t>(-188), 982, static_cast<uint16_t>(-216), 985, static_cast<uint16_t>(-4), 987, static_cast<uint16_t>(-4), 989, static_cast<uint16_t>(-4), 991, static_cast<uint16_t>(-4), 993, static_cast<uint16_t>(-4), 995, static_cast<uint16_t>(-4), 997, static_cast<uint16_t>(-4), 999, static_cast<uint16_t>(-4), 1001, static_cast<uint16_t>(-4), 1003, static_cast<uint16_t>(-4), 1005, static_cast<uint16_t>(-4), 1007, static_cast<uint16_t>(-4), 1008, static_cast<uint16_t>(-344), 1009, static_cast<uint16_t>(-320), 1010, 28, 1013, static_cast<uint16_t>(-384), 1016, static_cast<uint16_t>(-4), 1019, static_cast<uint16_t>(-4), 33840, static_cast<uint16_t>(-128), 1103, static_cast<uint16_t>(-128), 33872, static_cast<uint16_t>(-320), 1119, static_cast<uint16_t>(-320), 1121, static_cast<uint16_t>(-4), 1123, static_cast<uint16_t>(-4), 1125, static_cast<uint16_t>(-4), 1127, static_cast<uint16_t>(-4), 1129, static_cast<uint16_t>(-4), 1131, static_cast<uint16_t>(-4), 1133, static_cast<uint16_t>(-4), 1135, static_cast<uint16_t>(-4), 1137, static_cast<uint16_t>(-4), 1139, static_cast<uint16_t>(-4), 1141, static_cast<uint16_t>(-4), 1143, static_cast<uint16_t>(-4), 1145, static_cast<uint16_t>(-4), 1147, static_cast<uint16_t>(-4), 1149, static_cast<uint16_t>(-4), 1151, static_cast<uint16_t>(-4), 1153, static_cast<uint16_t>(-4), 1163, static_cast<uint16_t>(-4), 1165, static_cast<uint16_t>(-4), 1167, static_cast<uint16_t>(-4), 1169, static_cast<uint16_t>(-4), 1171, static_cast<uint16_t>(-4), 1173, static_cast<uint16_t>(-4), 1175, static_cast<uint16_t>(-4), 1177, static_cast<uint16_t>(-4), 1179, static_cast<uint16_t>(-4), 1181, static_cast<uint16_t>(-4), 1183, static_cast<uint16_t>(-4), 1185, static_cast<uint16_t>(-4), 1187, static_cast<uint16_t>(-4), 1189, static_cast<uint16_t>(-4), 1191, static_cast<uint16_t>(-4), 1193, static_cast<uint16_t>(-4), 1195, static_cast<uint16_t>(-4), 1197, static_cast<uint16_t>(-4), 1199, static_cast<uint16_t>(-4), 1201, static_cast<uint16_t>(-4), 1203, static_cast<uint16_t>(-4), 1205, static_cast<uint16_t>(-4), 1207, static_cast<uint16_t>(-4), 1209, static_cast<uint16_t>(-4), 1211, static_cast<uint16_t>(-4), 1213, static_cast<uint16_t>(-4), 1215, static_cast<uint16_t>(-4), 1218, static_cast<uint16_t>(-4), 1220, static_cast<uint16_t>(-4), 1222, static_cast<uint16_t>(-4), 1224, static_cast<uint16_t>(-4), 1226, static_cast<uint16_t>(-4), 1228, static_cast<uint16_t>(-4), 1230, static_cast<uint16_t>(-4), 1231, static_cast<uint16_t>(-60), 1233, static_cast<uint16_t>(-4), 1235, static_cast<uint16_t>(-4), 1237, static_cast<uint16_t>(-4), 1239, static_cast<uint16_t>(-4), 1241, static_cast<uint16_t>(-4), 1243, static_cast<uint16_t>(-4), 1245, static_cast<uint16_t>(-4), 1247, static_cast<uint16_t>(-4), 1249, static_cast<uint16_t>(-4), 1251, static_cast<uint16_t>(-4), 1253, static_cast<uint16_t>(-4), 1255, static_cast<uint16_t>(-4), 1257, static_cast<uint16_t>(-4), 1259, static_cast<uint16_t>(-4), 1261, static_cast<uint16_t>(-4), 1263, static_cast<uint16_t>(-4), 1265, static_cast<uint16_t>(-4), 1267, static_cast<uint16_t>(-4), 1269, static_cast<uint16_t>(-4), 1271, static_cast<uint16_t>(-4), 1273, static_cast<uint16_t>(-4), 1275, static_cast<uint16_t>(-4), 1277, static_cast<uint16_t>(-4), 1279, static_cast<uint16_t>(-4), 1281, static_cast<uint16_t>(-4), 1283, static_cast<uint16_t>(-4), 1285, static_cast<uint16_t>(-4), 1287, static_cast<uint16_t>(-4), 1289, static_cast<uint16_t>(-4), 1291, static_cast<uint16_t>(-4), 1293, static_cast<uint16_t>(-4), 1295, static_cast<uint16_t>(-4), 1297, static_cast<uint16_t>(-4), 1299, static_cast<uint16_t>(-4), 34145, static_cast<uint16_t>(-192), 1414, static_cast<uint16_t>(-192), 1415, 21, 7549, 15256, 7681, static_cast<uint16_t>(-4), 7683, static_cast<uint16_t>(-4), 7685, static_cast<uint16_t>(-4), 7687, static_cast<uint16_t>(-4), 7689, static_cast<uint16_t>(-4), 7691, static_cast<uint16_t>(-4), 7693, static_cast<uint16_t>(-4), 7695, static_cast<uint16_t>(-4), 7697, static_cast<uint16_t>(-4), 7699, static_cast<uint16_t>(-4), 7701, static_cast<uint16_t>(-4), 7703, static_cast<uint16_t>(-4), 7705, static_cast<uint16_t>(-4), 7707, static_cast<uint16_t>(-4), 7709, static_cast<uint16_t>(-4), 7711, static_cast<uint16_t>(-4), 7713, static_cast<uint16_t>(-4), 7715, static_cast<uint16_t>(-4), 7717, static_cast<uint16_t>(-4), 7719, static_cast<uint16_t>(-4), 7721, static_cast<uint16_t>(-4), 7723, static_cast<uint16_t>(-4), 7725, static_cast<uint16_t>(-4), 7727, static_cast<uint16_t>(-4), 7729, static_cast<uint16_t>(-4), 7731, static_cast<uint16_t>(-4), 7733, static_cast<uint16_t>(-4), 7735, static_cast<uint16_t>(-4), 7737, static_cast<uint16_t>(-4), 7739, static_cast<uint16_t>(-4), 7741, static_cast<uint16_t>(-4), 7743, static_cast<uint16_t>(-4), 7745, static_cast<uint16_t>(-4), 7747, static_cast<uint16_t>(-4), 7749, static_cast<uint16_t>(-4), 7751, static_cast<uint16_t>(-4), 7753, static_cast<uint16_t>(-4), 7755, static_cast<uint16_t>(-4), 7757, static_cast<uint16_t>(-4), 7759, static_cast<uint16_t>(-4), 7761, static_cast<uint16_t>(-4), 7763, static_cast<uint16_t>(-4), 7765, static_cast<uint16_t>(-4), 7767, static_cast<uint16_t>(-4), 7769, static_cast<uint16_t>(-4), 7771, static_cast<uint16_t>(-4), 7773, static_cast<uint16_t>(-4), 7775, static_cast<uint16_t>(-4), 7777, static_cast<uint16_t>(-4), 7779, static_cast<uint16_t>(-4), 7781, static_cast<uint16_t>(-4), 7783, static_cast<uint16_t>(-4), 7785, static_cast<uint16_t>(-4), 7787, static_cast<uint16_t>(-4), 7789, static_cast<uint16_t>(-4), 7791, static_cast<uint16_t>(-4), 7793, static_cast<uint16_t>(-4), 7795, static_cast<uint16_t>(-4), 7797, static_cast<uint16_t>(-4), 7799, static_cast<uint16_t>(-4), 7801, static_cast<uint16_t>(-4), 7803, static_cast<uint16_t>(-4), 7805, static_cast<uint16_t>(-4), 7807, static_cast<uint16_t>(-4), 7809, static_cast<uint16_t>(-4), 7811, static_cast<uint16_t>(-4), 7813, static_cast<uint16_t>(-4), 7815, static_cast<uint16_t>(-4), 7817, static_cast<uint16_t>(-4), 7819, static_cast<uint16_t>(-4), 7821, static_cast<uint16_t>(-4), 7823, static_cast<uint16_t>(-4), 7825, static_cast<uint16_t>(-4), 7827, static_cast<uint16_t>(-4), 7829, static_cast<uint16_t>(-4), 7830, 25, 7831, 29, 7832, 33, 7833, 37, 7834, 41, 7835, static_cast<uint16_t>(-236), 7841, static_cast<uint16_t>(-4), 7843, static_cast<uint16_t>(-4), 7845, static_cast<uint16_t>(-4), 7847, static_cast<uint16_t>(-4), 7849, static_cast<uint16_t>(-4), 7851, static_cast<uint16_t>(-4), 7853, static_cast<uint16_t>(-4), 7855, static_cast<uint16_t>(-4), 7857, static_cast<uint16_t>(-4), 7859, static_cast<uint16_t>(-4), 7861, static_cast<uint16_t>(-4), 7863, static_cast<uint16_t>(-4), 7865, static_cast<uint16_t>(-4), 7867, static_cast<uint16_t>(-4), 7869, static_cast<uint16_t>(-4), 7871, static_cast<uint16_t>(-4), 7873, static_cast<uint16_t>(-4), 7875, static_cast<uint16_t>(-4), 7877, static_cast<uint16_t>(-4), 7879, static_cast<uint16_t>(-4), 7881, static_cast<uint16_t>(-4), 7883, static_cast<uint16_t>(-4), 7885, static_cast<uint16_t>(-4), 7887, static_cast<uint16_t>(-4), 7889, static_cast<uint16_t>(-4), 7891, static_cast<uint16_t>(-4), 7893, static_cast<uint16_t>(-4), 7895, static_cast<uint16_t>(-4), 7897, static_cast<uint16_t>(-4), 7899, static_cast<uint16_t>(-4), 7901, static_cast<uint16_t>(-4), 7903, static_cast<uint16_t>(-4), 7905, static_cast<uint16_t>(-4), 7907, static_cast<uint16_t>(-4), 7909, static_cast<uint16_t>(-4), 7911, static_cast<uint16_t>(-4), 7913, static_cast<uint16_t>(-4), 7915, static_cast<uint16_t>(-4), 7917, static_cast<uint16_t>(-4), 7919, static_cast<uint16_t>(-4), 7921, static_cast<uint16_t>(-4), 7923, static_cast<uint16_t>(-4), 7925, static_cast<uint16_t>(-4), 7927, static_cast<uint16_t>(-4), 7929, static_cast<uint16_t>(-4), 40704, 32, 7943, 32, 40720, 32, 7957, 32, 40736, 32, 7975, 32, 40752, 32, 7991, 32, 40768, 32, 8005, 32, 8016, 45, 8017, 32, 8018, 49, 8019, 32, 8020, 53, 8021, 32, 8022, 57, 8023, 32, 40800, 32, 8039, 32, 40816, 296, 8049, 296, 40818, 344, 8053, 344, 40822, 400, 8055, 400, 40824, 512, 8057, 512, 40826, 448, 8059, 448, 40828, 504, 8061, 504, 8064, 61, 8065, 65, 8066, 69, 8067, 73, 8068, 77, 8069, 81, 8070, 85, 8071, 89, 8072, 93, 8073, 97, 8074, 101, 8075, 105, 8076, 109, 8077, 113, 8078, 117, 8079, 121, 8080, 125, 8081, 129, 8082, 133, 8083, 137, 8084, 141, 8085, 145, 8086, 149, 8087, 153, 8088, 157, 8089, 161, 8090, 165, 8091, 169, 8092, 173, 8093, 177, 8094, 181, 8095, 185, 8096, 189, 8097, 193, 8098, 197, 8099, 201, 8100, 205, 8101, 209, 8102, 213, 8103, 217, 8104, 221, 8105, 225, 8106, 229, 8107, 233, 8108, 237, 8109, 241, 8110, 245, 8111, 249, 40880, 32, 8113, 32, 8114, 253, 8115, 257, 8116, 261, 8118, 265, 8119, 269, 8124, 273, 8126, static_cast<uint16_t>(-28820), 8130, 277, 8131, 281, 8132, 285, 8134, 289, 8135, 293, 8140, 297, 40912, 32, 8145, 32, 8146, 301, 8147, 305, 8150, 309, 8151, 313, 40928, 32, 8161, 32, 8162, 317, 8163, 321, 8164, 325, 8165, 28, 8166, 329, 8167, 333, 8178, 337, 8179, 341, 8180, 345, 8182, 349, 8183, 353, 8188, 357, 8526, static_cast<uint16_t>(-112), 41328, static_cast<uint16_t>(-64), 8575, static_cast<uint16_t>(-64), 8580, static_cast<uint16_t>(-4), 42192, static_cast<uint16_t>(-104), 9449, static_cast<uint16_t>(-104), 44080, static_cast<uint16_t>(-192), 11358, static_cast<uint16_t>(-192), 11361, static_cast<uint16_t>(-4), 11365, static_cast<uint16_t>(-43180), 11366, static_cast<uint16_t>(-43168), 11368, static_cast<uint16_t>(-4), 11370, static_cast<uint16_t>(-4), 11372, static_cast<uint16_t>(-4), 11382, static_cast<uint16_t>(-4), 11393, static_cast<uint16_t>(-4), 11395, static_cast<uint16_t>(-4), 11397, static_cast<uint16_t>(-4), 11399, static_cast<uint16_t>(-4), 11401, static_cast<uint16_t>(-4), 11403, static_cast<uint16_t>(-4), 11405, static_cast<uint16_t>(-4), 11407, static_cast<uint16_t>(-4), 11409, static_cast<uint16_t>(-4), 11411, static_cast<uint16_t>(-4), 11413, static_cast<uint16_t>(-4), 11415, static_cast<uint16_t>(-4), 11417, static_cast<uint16_t>(-4), 11419, static_cast<uint16_t>(-4), 11421, static_cast<uint16_t>(-4), 11423, static_cast<uint16_t>(-4), 11425, static_cast<uint16_t>(-4), 11427, static_cast<uint16_t>(-4), 11429, static_cast<uint16_t>(-4), 11431, static_cast<uint16_t>(-4), 11433, static_cast<uint16_t>(-4), 11435, static_cast<uint16_t>(-4), 11437, static_cast<uint16_t>(-4), 11439, static_cast<uint16_t>(-4), 11441, static_cast<uint16_t>(-4), 11443, static_cast<uint16_t>(-4), 11445, static_cast<uint16_t>(-4), 11447, static_cast<uint16_t>(-4), 11449, static_cast<uint16_t>(-4), 11451, static_cast<uint16_t>(-4), 11453, static_cast<uint16_t>(-4), 11455, static_cast<uint16_t>(-4), 11457, static_cast<uint16_t>(-4), 11459, static_cast<uint16_t>(-4), 11461, static_cast<uint16_t>(-4), 11463, static_cast<uint16_t>(-4), 11465, static_cast<uint16_t>(-4), 11467, static_cast<uint16_t>(-4), 11469, static_cast<uint16_t>(-4), 11471, static_cast<uint16_t>(-4), 11473, static_cast<uint16_t>(-4), 11475, static_cast<uint16_t>(-4), 11477, static_cast<uint16_t>(-4), 11479, static_cast<uint16_t>(-4), 11481, static_cast<uint16_t>(-4), 11483, static_cast<uint16_t>(-4), 11485, static_cast<uint16_t>(-4), 11487, static_cast<uint16_t>(-4), 11489, static_cast<uint16_t>(-4), 11491, static_cast<uint16_t>(-4), 44288, static_cast<uint16_t>(-29056), 11557, static_cast<uint16_t>(-29056) }; // NOLINT
+static const MultiCharacterSpecialCase kToUppercaseMultiStrings1[] = { {2, {70, 70}}, {2, {70, 73}}, {2, {70, 76}}, {3, {70, 70, 73}}, {3, {70, 70, 76}}, {2, {83, 84}}, {2, {83, 84}}, {2, {1348, 1350}}, {2, {1348, 1333}}, {2, {1348, 1339}}, {2, {1358, 1350}}, {2, {1348, 1341}}, {0, {0}} }; // NOLINT
+static const uint16_t kToUppercaseTable1Size = 14;
+static const uint16_t kToUppercaseTable1[28] = { 31488, 1, 31489, 5, 31490, 9, 31491, 13, 31492, 17, 31493, 21, 31494, 25, 31507, 29, 31508, 33, 31509, 37, 31510, 41, 31511, 45, 65345, static_cast<uint16_t>(-128), 32602, static_cast<uint16_t>(-128) }; // NOLINT
+static const MultiCharacterSpecialCase kToUppercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const uint16_t kToUppercaseTable2Size = 2;
+static const uint16_t kToUppercaseTable2[4] = { 33832, static_cast<uint16_t>(-160), 1103, static_cast<uint16_t>(-160) }; // NOLINT
+int ToUppercase::Convert(uchar c,
+                      uchar n,
+                      uchar* result,
+                      bool* allow_caching_ptr) {
+  int chunk_index = c >> 15;
+  switch (chunk_index) {
+    case 0: return LookupMapping(kToUppercaseTable0,
+                                     kToUppercaseTable0Size,
+                                     kToUppercaseMultiStrings0,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 1: return LookupMapping(kToUppercaseTable1,
+                                     kToUppercaseTable1Size,
+                                     kToUppercaseMultiStrings1,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    case 2: return LookupMapping(kToUppercaseTable2,
+                                     kToUppercaseTable2Size,
+                                     kToUppercaseMultiStrings2,
+                                     c,
+                                     n,
+                                     result,
+                                     allow_caching_ptr);
+    default: return 0;
+  }
+}
+
+
+uchar UnicodeData::kMaxCodePoint = 1114109;
+
+int UnicodeData::GetByteCount() {
+  return 0 + (sizeof(uint16_t) * kUppercaseTable0Size) + (sizeof(uint16_t) * kUppercaseTable1Size) + (sizeof(uint16_t) * kUppercaseTable2Size) + (sizeof(uint16_t) * kUppercaseTable3Size) + (sizeof(uint16_t) * kLowercaseTable0Size) + (sizeof(uint16_t) * kLowercaseTable1Size) + (sizeof(uint16_t) * kLowercaseTable2Size) + (sizeof(uint16_t) * kLowercaseTable3Size) + (sizeof(uint16_t) * kLetterTable0Size) + (sizeof(uint16_t) * kLetterTable1Size) + (sizeof(uint16_t) * kLetterTable2Size) + (sizeof(uint16_t) * kLetterTable3Size) + (sizeof(uint16_t) * kLetterTable4Size) + (sizeof(uint16_t) * kLetterTable5Size) + (sizeof(uint16_t) * kSpaceTable0Size) + (sizeof(uint16_t) * kTitlecaseTable0Size) + (sizeof(uint16_t) * kNumberTable0Size) + (sizeof(uint16_t) * kNumberTable1Size) + (sizeof(uint16_t) * kNumberTable2Size) + (sizeof(uint16_t) * kNumberTable3Size) + (sizeof(uint16_t) * kDecimalDigitTable0Size) + (sizeof(uint16_t) * kDecimalDigitTable1Size) + (sizeof(uint16_t) * kDecimalDigitTable2Size) + (sizeof(uint16_t) * kDecimalDigitTable3Size) + (sizeof(uint16_t) * kIdeographicTable0Size) + (sizeof(uint16_t) * kIdeographicTable1Size) + (sizeof(uint16_t) * kIdeographicTable4Size) + (sizeof(uint16_t) * kIdeographicTable5Size) + (sizeof(uint16_t) * kWhiteSpaceTable0Size) + (sizeof(uint16_t) * kHexDigitTable0Size) + (sizeof(uint16_t) * kHexDigitTable1Size) + (sizeof(uint16_t) * kAsciiHexDigitTable0Size) + (sizeof(uint16_t) * kBidiControlTable0Size) + (sizeof(uint16_t) * kJoinControlTable0Size) + (sizeof(uint16_t) * kDashTable0Size) + (sizeof(uint16_t) * kDashTable1Size) + (sizeof(uint16_t) * kHyphenTable0Size) + (sizeof(uint16_t) * kHyphenTable1Size) + (sizeof(uint16_t) * kLineTerminatorTable0Size) + (sizeof(uint16_t) * kRegExpSpecialCharTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable1Size) + (sizeof(uint16_t) * kCombiningMarkTable2Size) + (sizeof(uint16_t) * kCombiningMarkTable3Size) + (sizeof(uint16_t) * kCombiningMarkTable28Size) + (sizeof(uint16_t) * kConnectorPunctuationTable0Size) + (sizeof(uint16_t) * kConnectorPunctuationTable1Size) + (sizeof(uint16_t) * kToLowercaseTable0Size) + (sizeof(uint16_t) * kToLowercaseTable1Size) + (sizeof(uint16_t) * kToLowercaseTable2Size) + (sizeof(uint16_t) * kToUppercaseTable0Size) + (sizeof(uint16_t) * kToUppercaseTable1Size) + (sizeof(uint16_t) * kToUppercaseTable2Size); // NOLINT
+}
+
+}  // namespace unicode
diff --git a/regexp2000/src/unicode.h b/regexp2000/src/unicode.h
new file mode 100644 (file)
index 0000000..fd7dfbc
--- /dev/null
@@ -0,0 +1,285 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef __UNIBROW_H__
+#define __UNIBROW_H__
+
+#include <sys/types.h>
+
+/**
+ * \file
+ * Definitions and convenience functions for working with unicode.
+ */
+
+namespace unibrow {
+
+typedef unsigned int uchar;
+typedef unsigned char byte;
+
+/**
+ * The max length of the result of converting the case of a single
+ * character.
+ */
+static const int kMaxCaseConvertedSize = 3;
+
+template <class T, int size = 256>
+class Predicate {
+ public:
+  inline Predicate() { }
+  inline bool get(uchar c);
+ private:
+  friend class Test;
+  bool CalculateValue(uchar c);
+  struct CacheEntry {
+    inline CacheEntry() : code_point_(0), value_(0) { }
+    inline CacheEntry(uchar code_point, bool value)
+      : code_point_(code_point),
+        value_(value) { }
+    uchar code_point_ : 21;
+    bool value_ : 1;
+  };
+  static const int kSize = size;
+  static const int kMask = kSize - 1;
+  CacheEntry entries_[kSize];
+};
+
+// A cache used in case conversion.  It caches the value for characters
+// that either have no mapping or map to a single character independent
+// of context.  Characters that map to more than one character or that
+// map differently depending on context are always looked up.
+template <class T, int size = 256>
+class Mapping {
+ public:
+  inline Mapping() { }
+  inline int get(uchar c, uchar n, uchar* result);
+ private:
+  friend class Test;
+  int CalculateValue(uchar c, uchar n, uchar* result);
+  struct CacheEntry {
+    inline CacheEntry() : code_point_(0), offset_(0) { }
+    inline CacheEntry(uchar code_point, signed offset)
+      : code_point_(code_point),
+        offset_(offset) { }
+    uchar code_point_ : 21;
+    signed offset_ : 11;
+  };
+  static const int kSize = size;
+  static const int kMask = kSize - 1;
+  CacheEntry entries_[kSize];
+};
+
+class UnicodeData {
+ private:
+  friend class Test;
+  static int GetByteCount();
+  static uchar kMaxCodePoint;
+};
+
+// --- U t f   8 ---
+
+template <typename Data>
+class Buffer {
+ public:
+  inline Buffer(Data data, unsigned length) : data_(data), length_(length) { }
+  inline Buffer() : data_(0), length_(0) { }
+  Data data() { return data_; }
+  unsigned length() { return length_; }
+ private:
+  Data data_;
+  unsigned length_;
+};
+
+class Utf8 {
+ public:
+  static inline uchar Length(uchar chr);
+  static inline unsigned Encode(char* out, uchar c);
+  static const byte* ReadBlock(Buffer<const char*> str, byte* buffer,
+      unsigned capacity, unsigned* chars_read, unsigned* offset);
+  static const uchar kBadChar = 0xFFFD;
+  static const unsigned kMaxEncodedSize   = 4;
+  static const unsigned kMaxOneByteChar   = 0x7f;
+  static const unsigned kMaxTwoByteChar   = 0x7ff;
+  static const unsigned kMaxThreeByteChar = 0xffff;
+  static const unsigned kMaxFourByteChar  = 0x1fffff;
+
+ private:
+  template <unsigned s> friend class Utf8InputBuffer;
+  friend class Test;
+  static inline uchar ValueOf(const byte* str,
+                              unsigned length,
+                              unsigned* cursor);
+  static uchar CalculateValue(const byte* str,
+                              unsigned length,
+                              unsigned* cursor);
+};
+
+// --- C h a r a c t e r   S t r e a m ---
+
+class CharacterStream {
+ public:
+  inline uchar GetNext();
+  inline bool has_more() { return remaining_ != 0; }
+  // Note that default implementation is not efficient.
+  virtual void Seek(unsigned);
+  unsigned Length();
+  virtual ~CharacterStream() { }
+  static inline bool EncodeCharacter(uchar c, byte* buffer, unsigned capacity,
+      unsigned& offset);
+  static inline bool EncodeAsciiCharacter(uchar c, byte* buffer,
+      unsigned capacity, unsigned& offset);
+  static inline bool EncodeNonAsciiCharacter(uchar c, byte* buffer,
+      unsigned capacity, unsigned& offset);
+  static inline uchar DecodeCharacter(const byte* buffer, unsigned* offset);
+  virtual void Rewind() = 0;
+ protected:
+  virtual void FillBuffer() = 0;
+  // The number of characters left in the current buffer
+  unsigned remaining_;
+  // The current offset within the buffer
+  unsigned cursor_;
+  // The buffer containing the decoded characters.
+  const byte* buffer_;
+};
+
+// --- I n p u t   B u f f e r ---
+
+/**
+ * Provides efficient access to encoded characters in strings.  It
+ * does so by reading characters one block at a time, rather than one
+ * character at a time, which gives string implementations an
+ * opportunity to optimize the decoding.
+ */
+template <class Reader, class Input = Reader*, unsigned kSize = 256>
+class InputBuffer : public CharacterStream {
+ public:
+  virtual void Rewind();
+  inline void Reset(Input input);
+  void Seek(unsigned position);
+  inline void Reset(unsigned position, Input input);
+ protected:
+  InputBuffer() { }
+  explicit InputBuffer(Input input) { Reset(input); }
+  virtual void FillBuffer();
+
+  // A custom offset that can be used by the string implementation to
+  // mark progress within the encoded string.
+  unsigned offset_;
+  // The input string
+  Input input_;
+  // To avoid heap allocation, we keep an internal buffer to which
+  // the encoded string can write its characters.  The string
+  // implementation is free to decide whether it wants to use this
+  // buffer or not.
+  byte util_buffer_[kSize];
+};
+
+// --- U t f 8   I n p u t   B u f f e r ---
+
+template <unsigned s = 256>
+class Utf8InputBuffer : public InputBuffer<Utf8, Buffer<const char*>, s> {
+ public:
+  inline Utf8InputBuffer() { }
+  inline Utf8InputBuffer(const char* data, unsigned length);
+  inline void Reset(const char* data, unsigned length) {
+    InputBuffer<Utf8, Buffer<const char*>, s>::Reset(
+        Buffer<const char*>(data, length));
+  }
+};
+
+struct Uppercase {
+  static bool Is(uchar c);
+};
+struct Lowercase {
+  static bool Is(uchar c);
+};
+struct Letter {
+  static bool Is(uchar c);
+};
+struct Space {
+  static bool Is(uchar c);
+};
+struct Titlecase {
+  static bool Is(uchar c);
+};
+struct Number {
+  static bool Is(uchar c);
+};
+struct DecimalDigit {
+  static bool Is(uchar c);
+};
+struct Ideographic {
+  static bool Is(uchar c);
+};
+struct WhiteSpace {
+  static bool Is(uchar c);
+};
+struct HexDigit {
+  static bool Is(uchar c);
+};
+struct AsciiHexDigit {
+  static bool Is(uchar c);
+};
+struct BidiControl {
+  static bool Is(uchar c);
+};
+struct JoinControl {
+  static bool Is(uchar c);
+};
+struct Dash {
+  static bool Is(uchar c);
+};
+struct Hyphen {
+  static bool Is(uchar c);
+};
+struct LineTerminator {
+  static bool Is(uchar c);
+};
+struct RegExpSpecialChar {
+  static bool Is(uchar c);
+};
+struct CombiningMark {
+  static bool Is(uchar c);
+};
+struct ConnectorPunctuation {
+  static bool Is(uchar c);
+};
+struct ToLowercase {
+  static int Convert(uchar c,
+                     uchar n,
+                     uchar* result,
+                     bool* allow_caching_ptr);
+};
+struct ToUppercase {
+  static int Convert(uchar c,
+                     uchar n,
+                     uchar* result,
+                     bool* allow_caching_ptr);
+};
+
+}  // namespace unibrow
+
+#endif  // __UNIBROW_H__
diff --git a/regexp2000/src/uri.js b/regexp2000/src/uri.js
new file mode 100644 (file)
index 0000000..e47c284
--- /dev/null
@@ -0,0 +1,371 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file contains support for URI manipulations written in
+// JavaScript.
+
+// Expect $String = global.String;
+
+function URIAddEncodedOctetToBuffer(octet, result, index) {
+  result[index++] = 37; // Char code of '%'.
+  result[index++] = hexCharCodeArray[octet >> 4];
+  result[index++] = hexCharCodeArray[octet & 0x0F];
+  return index;
+}
+
+
+function URIEncodeOctets(octets, result, index) {
+  index = URIAddEncodedOctetToBuffer(octets[0], result, index);
+  if (octets[1]) index = URIAddEncodedOctetToBuffer(octets[1], result, index);
+  if (octets[2]) index = URIAddEncodedOctetToBuffer(octets[2], result, index);
+  if (octets[3]) index = URIAddEncodedOctetToBuffer(octets[3], result, index);
+  return index;
+}
+
+
+function URIEncodeSingle(cc, result, index) {
+  var x = (cc >> 12) & 0xF;
+  var y = (cc >> 6) & 63;
+  var z = cc & 63;
+  var octets = new $Array(3);
+  if (cc <= 0x007F) {
+    octets[0] = cc;
+  } else if (cc <= 0x07FF) {
+    octets[0] = y + 192;
+    octets[1] = z + 128;
+  } else {
+    octets[0] = x + 224;
+    octets[1] = y + 128;
+    octets[2] = z + 128;
+  }
+  return URIEncodeOctets(octets, result, index);
+}
+
+
+function URIEncodePair(cc1 , cc2, result, index) {
+  var u = ((cc1 >> 6) & 0xF) + 1;
+  var w = (cc1 >> 2) & 0xF;
+  var x = cc1 & 3;
+  var y = (cc2 >> 6) & 0xF;
+  var z = cc2 & 63;
+  var octets = new $Array(4);
+  octets[0] = (u >> 2) + 240;
+  octets[1] = (((u & 3) << 4) | w) + 128;
+  octets[2] = ((x << 4) | y) + 128;
+  octets[3] = z + 128;
+  return URIEncodeOctets(octets, result, index);
+}
+
+
+function URIHexCharsToCharCode(ch1, ch2) {
+  if (HexValueOf(ch1) == -1 || HexValueOf(ch2) == -1) {
+    throw new $URIError("URI malformed");
+  }
+  return HexStrToCharCode(ch1 + ch2);
+}
+
+
+function URIDecodeOctets(octets, result, index) {
+  if (octets[3]) {
+    var x = (octets[2] >> 4) & 3;
+    var y = octets[2] & 0xF;
+    var z = octets[3] & 63;
+    var v = (((octets[0] & 7) << 2) | ((octets[1] >> 4) & 3)) - 1;
+    var w = octets[1] & 0xF;
+    result[index++] = 55296 | (v << 6) | (w << 2) | x;
+    result[index++] = 56320 | (y << 6) | z;
+    return index;
+  }
+  if (octets[2]) {
+    var x = octets[0] & 0xF;
+    var y = octets[1] & 63;
+    var z = octets[2] & 63;
+    result[index++] = (x << 12) | (y << 6) | z;
+    return index;
+  }
+  var z = octets[1] & 63;
+  var y = octets[0] & 31;
+  result[index++] = (y << 6) | z;
+  return index;
+}
+
+
+// ECMA-262, section 15.1.3
+function Encode(uri, unescape) {
+  var uriLength = uri.length;
+  var result = new $Array(uriLength);
+  var index = 0;
+  for (var k = 0; k < uriLength; k++) {
+    var cc1 = uri.charCodeAt(k);
+    if (unescape(cc1)) {
+      result[index++] = cc1;
+    } else {
+      if (cc1 >= 0xDC00 && cc1 <= 0xDFFF) throw new $URIError("URI malformed");
+      if (cc1 < 0xD800 || cc1 > 0xDBFF) {
+        index = URIEncodeSingle(cc1, result, index);
+      } else {
+        k++;
+        if (k == uriLength) throw new $URIError("URI malformed");
+        var cc2 = uri.charCodeAt(k);
+        if (cc2 < 0xDC00 || cc2 > 0xDFFF) throw new $URIError("URI malformed");
+        index = URIEncodePair(cc1, cc2, result, index);
+      }
+    }
+  }
+  return %StringFromCharCodeArray(result);
+}
+
+
+// ECMA-262, section 15.1.3
+function Decode(uri, reserved) {
+  var uriLength = uri.length;
+  var result = new $Array(uriLength);
+  var index = 0;
+  for (var k = 0; k < uriLength; k++) {
+    var ch = uri.charAt(k);
+    if (ch == '%') {
+      if (k + 2 >= uriLength) throw new $URIError("URI malformed");
+      var cc = URIHexCharsToCharCode(uri.charAt(++k), uri.charAt(++k));
+      if (cc >> 7) {
+        var n = 0;
+        while (((cc << ++n) & 0x80) != 0) ;
+        if (n == 1 || n > 4) throw new $URIError("URI malformed");
+        var octets = new $Array(n);
+        octets[0] = cc;
+        if (k + 3 * (n - 1) >= uriLength) throw new $URIError("URI malformed");
+        for (var i = 1; i < n; i++) {
+          k++;
+          octets[i] = URIHexCharsToCharCode(uri.charAt(++k), uri.charAt(++k));
+        }
+        index = URIDecodeOctets(octets, result, index);
+      } else {
+        if (reserved(cc)) {
+          result[index++] = 37; // Char code of '%'.
+          result[index++] = uri.charCodeAt(k - 1);
+          result[index++] = uri.charCodeAt(k);
+        } else {
+          result[index++] = cc;
+        }
+      }
+    } else {
+      result[index++] = ch.charCodeAt(0);
+    }
+  }
+  result.length = index;
+  return %StringFromCharCodeArray(result);
+}
+
+
+// ECMA-262 - 15.1.3.1.
+function URIDecode(uri) {
+  function reservedPredicate(cc) {
+    // #$
+    if (35 <= cc && cc <= 36) return true;
+    // &
+    if (cc == 38) return true;
+    // +,
+    if (43 <= cc && cc <= 44) return true;
+    // /
+    if (cc == 47) return true;
+    // :;
+    if (58 <= cc && cc <= 59) return true;
+    // =
+    if (cc == 61) return true;
+    // ?@
+    if (63 <= cc && cc <= 64) return true;
+    
+    return false;
+  };
+  var string = ToString(uri);
+  return Decode(string, reservedPredicate);
+}
+
+
+// ECMA-262 - 15.1.3.2.
+function URIDecodeComponent(component) {
+  function reservedPredicate(cc) { return false; };
+  var string = ToString(component);
+  return Decode(string, reservedPredicate);
+}
+
+
+// Does the char code correspond to an alpha-numeric char.
+function isAlphaNumeric(cc) {
+  // a - z
+  if (97 <= cc && cc <= 122) return true;
+  // A - Z
+  if (65 <= cc && cc <= 90) return true;
+  // 0 - 9
+  if (48 <= cc && cc <= 57) return true;
+  
+  return false;
+}
+
+
+// ECMA-262 - 15.1.3.3.
+function URIEncode(uri) {
+  function unescapePredicate(cc) {
+    if (isAlphaNumeric(cc)) return true;
+    // !
+    if (cc == 33) return true;
+    // #$
+    if (35 <= cc && cc <= 36) return true;
+    // &'()*+,-./
+    if (38 <= cc && cc <= 47) return true;
+    // :;
+    if (58 <= cc && cc <= 59) return true;
+    // =
+    if (cc == 61) return true;
+    // ?@
+    if (63 <= cc && cc <= 64) return true;
+    // _
+    if (cc == 95) return true;
+    // ~
+    if (cc == 126) return true;
+    
+    return false;
+  };
+
+  var string = ToString(uri);
+  return Encode(string, unescapePredicate);
+}
+
+
+// ECMA-262 - 15.1.3.4
+function URIEncodeComponent(component) {
+  function unescapePredicate(cc) {
+    if (isAlphaNumeric(cc)) return true;
+    // !
+    if (cc == 33) return true;
+    // '()*
+    if (39 <= cc && cc <= 42) return true;
+    // -.
+    if (45 <= cc && cc <= 46) return true;
+    // _
+    if (cc == 95) return true;
+    // ~
+    if (cc == 126) return true;
+    
+    return false;
+  };
+
+  var string = ToString(component);
+  return Encode(string, unescapePredicate);
+}
+
+
+const hexCharArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+                      "A", "B", "C", "D", "E", "F"];
+
+const hexCharCodeArray = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+                          65, 66, 67, 68, 69, 70];
+
+
+function HexValueOf(c) {
+  var code = c.charCodeAt(0);
+  
+  // 0-9
+  if (code >= 48 && code <= 57) return code - 48;
+  // A-F
+  if (code >= 65 && code <= 70) return code - 55;
+  // a-f
+  if (code >= 97 && code <= 102) return code - 87;
+  
+  return -1;
+}
+
+
+// Convert a character code to 4-digit hex string representation
+// 64 -> 0040, 62234 -> F31A.
+function CharCodeToHex4Str(cc) {
+  var r = "";
+  for (var i = 0; i < 4; ++i) {
+    var c = hexCharArray[cc & 0x0F];
+    r = c + r;
+    cc = cc >>> 4;
+  }
+  return r;
+}
+
+
+// Converts hex string to char code. Not efficient.
+function HexStrToCharCode(s) {
+  var m = 0;
+  var r = 0;
+  for (var i = s.length - 1; i >= 0; --i) {
+    r = r + (HexValueOf(s.charAt(i)) << m);
+    m = m + 4;
+  }
+  return r;
+}
+
+
+// Returns true if all digits in string s are valid hex numbers
+function IsValidHex(s) {
+  for (var i = 0; i < s.length; ++i) {
+    var cc = s.charCodeAt(i);
+    if ((48 <= cc && cc <= 57) || (65 <= cc && cc <= 70) || (97 <= cc && cc <= 102)) {
+      // '0'..'9', 'A'..'F' and 'a' .. 'f'.
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+// ECMA-262 - B.2.1.
+function URIEscape(str) {
+  var s = ToString(str);
+  return %URIEscape(s);
+}
+
+
+// ECMA-262 - B.2.2.
+function URIUnescape(str) {
+  var s = ToString(str);
+  return %URIUnescape(s);
+}
+
+
+// -------------------------------------------------------------------
+
+function SetupURI() {
+  // Setup non-enumerable URI functions on the global object and set
+  // their names.
+  InstallFunctions(global, DONT_ENUM, $Array(
+    "escape", URIEscape,
+    "unescape", URIUnescape,
+    "decodeURI", URIDecode,
+    "decodeURIComponent", URIDecodeComponent,
+    "encodeURI", URIEncode,
+    "encodeURIComponent", URIEncodeComponent
+  ));
+}
+
+SetupURI();
+
diff --git a/regexp2000/src/usage-analyzer.cc b/regexp2000/src/usage-analyzer.cc
new file mode 100644 (file)
index 0000000..43f29a1
--- /dev/null
@@ -0,0 +1,438 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+#include "scopes.h"
+#include "usage-analyzer.h"
+
+namespace v8 { namespace internal {
+
+// Weight boundaries
+static const int MinWeight = 1;
+static const int MaxWeight = 1000000;
+static const int InitialWeight = 100;
+
+
+class UsageComputer: public Visitor {
+ public:
+  static bool Traverse(Node* node);
+
+  void VisitBlock(Block* node);
+  void VisitDeclaration(Declaration* node);
+  void VisitExpressionStatement(ExpressionStatement* node);
+  void VisitEmptyStatement(EmptyStatement* node);
+  void VisitIfStatement(IfStatement* node);
+  void VisitContinueStatement(ContinueStatement* node);
+  void VisitBreakStatement(BreakStatement* node);
+  void VisitReturnStatement(ReturnStatement* node);
+  void VisitWithEnterStatement(WithEnterStatement* node);
+  void VisitWithExitStatement(WithExitStatement* node);
+  void VisitSwitchStatement(SwitchStatement* node);
+  void VisitLoopStatement(LoopStatement* node);
+  void VisitForInStatement(ForInStatement* node);
+  void VisitTryCatch(TryCatch* node);
+  void VisitTryFinally(TryFinally* node);
+  void VisitDebuggerStatement(DebuggerStatement* node);
+  void VisitFunctionLiteral(FunctionLiteral* node);
+  void VisitFunctionBoilerplateLiteral(FunctionBoilerplateLiteral* node);
+  void VisitConditional(Conditional* node);
+  void VisitSlot(Slot* node);
+  void VisitVariable(Variable* node);
+  void VisitVariableProxy(VariableProxy* node);
+  void VisitLiteral(Literal* node);
+  void VisitRegExpLiteral(RegExpLiteral* node);
+  void VisitObjectLiteral(ObjectLiteral* node);
+  void VisitArrayLiteral(ArrayLiteral* node);
+  void VisitAssignment(Assignment* node);
+  void VisitThrow(Throw* node);
+  void VisitProperty(Property* node);
+  void VisitCall(Call* node);
+  void VisitCallNew(CallNew* node);
+  void VisitCallRuntime(CallRuntime* node);
+  void VisitUnaryOperation(UnaryOperation* node);
+  void VisitCountOperation(CountOperation* node);
+  void VisitBinaryOperation(BinaryOperation* node);
+  void VisitCompareOperation(CompareOperation* node);
+  void VisitThisFunction(ThisFunction* node);
+
+ private:
+  int weight_;
+  bool is_write_;
+
+  UsageComputer(int weight, bool is_write);
+  virtual ~UsageComputer();
+
+  // Helper functions
+  void RecordUses(UseCount* uses);
+  void Read(Expression* x);
+  void Write(Expression* x);
+  void ReadList(ZoneList<Expression*>* list);
+  void ReadList(ZoneList<ObjectLiteral::Property*>* list);
+
+  friend class WeightScaler;
+};
+
+
+class WeightScaler BASE_EMBEDDED {
+ public:
+  WeightScaler(UsageComputer* uc, float scale);
+  ~WeightScaler();
+
+ private:
+  UsageComputer* uc_;
+  int old_weight_;
+};
+
+
+// ----------------------------------------------------------------------------
+// Implementation of UsageComputer
+
+bool UsageComputer::Traverse(Node* node) {
+  UsageComputer uc(InitialWeight, false);
+  uc.Visit(node);
+  return !uc.HasStackOverflow();
+}
+
+
+void UsageComputer::VisitBlock(Block* node) {
+  VisitStatements(node->statements());
+}
+
+
+void UsageComputer::VisitDeclaration(Declaration* node) {
+  Write(node->proxy());
+  if (node->fun() != NULL)
+    VisitFunctionLiteral(node->fun());
+}
+
+
+void UsageComputer::VisitExpressionStatement(ExpressionStatement* node) {
+  Visit(node->expression());
+}
+
+
+void UsageComputer::VisitEmptyStatement(EmptyStatement* node) {
+  // nothing to do
+}
+
+
+void UsageComputer::VisitIfStatement(IfStatement* node) {
+  Read(node->condition());
+  { WeightScaler ws(this, 0.5);  // executed 50% of the time
+    Visit(node->then_statement());
+    Visit(node->else_statement());
+  }
+}
+
+
+void UsageComputer::VisitContinueStatement(ContinueStatement* node) {
+  // nothing to do
+}
+
+
+void UsageComputer::VisitBreakStatement(BreakStatement* node) {
+  // nothing to do
+}
+
+
+void UsageComputer::VisitReturnStatement(ReturnStatement* node) {
+  Read(node->expression());
+}
+
+
+void UsageComputer::VisitWithEnterStatement(WithEnterStatement* node) {
+  Read(node->expression());
+}
+
+
+void UsageComputer::VisitWithExitStatement(WithExitStatement* node) {
+  // nothing to do
+}
+
+
+void UsageComputer::VisitSwitchStatement(SwitchStatement* node) {
+  Read(node->tag());
+  ZoneList<CaseClause*>* cases = node->cases();
+  for (int i = cases->length(); i-- > 0;) {
+    WeightScaler ws(this, static_cast<float>(1.0 / cases->length()));
+    CaseClause* clause = cases->at(i);
+    if (!clause->is_default())
+      Read(clause->label());
+    VisitStatements(clause->statements());
+  }
+}
+
+
+void UsageComputer::VisitLoopStatement(LoopStatement* node) {
+  if (node->init() != NULL)
+    Visit(node->init());
+  { WeightScaler ws(this, 10.0);  // executed in each iteration
+    if (node->cond() != NULL)
+      Read(node->cond());
+    if (node->next() != NULL)
+      Visit(node->next());
+    Visit(node->body());
+  }
+}
+
+
+void UsageComputer::VisitForInStatement(ForInStatement* node) {
+  WeightScaler ws(this, 10.0);
+  Write(node->each());
+  Read(node->enumerable());
+  Visit(node->body());
+}
+
+
+void UsageComputer::VisitTryCatch(TryCatch* node) {
+  Visit(node->try_block());
+  { WeightScaler ws(this, 0.25);
+    Write(node->catch_var());
+    Visit(node->catch_block());
+  }
+}
+
+
+void UsageComputer::VisitTryFinally(TryFinally* node) {
+  Visit(node->try_block());
+  Visit(node->finally_block());
+}
+
+
+void UsageComputer::VisitDebuggerStatement(DebuggerStatement* node) {
+}
+
+
+void UsageComputer::VisitFunctionLiteral(FunctionLiteral* node) {
+  ZoneList<Declaration*>* decls = node->scope()->declarations();
+  for (int i = 0; i < decls->length(); i++) VisitDeclaration(decls->at(i));
+  VisitStatements(node->body());
+}
+
+
+void UsageComputer::VisitFunctionBoilerplateLiteral(
+    FunctionBoilerplateLiteral* node) {
+  // Do nothing.
+}
+
+
+void UsageComputer::VisitConditional(Conditional* node) {
+  Read(node->condition());
+  { WeightScaler ws(this, 0.5);
+    Read(node->then_expression());
+    Read(node->else_expression());
+  }
+}
+
+
+void UsageComputer::VisitSlot(Slot* node) {
+  UNREACHABLE();
+}
+
+
+void UsageComputer::VisitVariable(Variable* node) {
+  RecordUses(node->var_uses());
+}
+
+
+void UsageComputer::VisitVariableProxy(VariableProxy* node) {
+  // The proxy may refer to a variable in which case it was bound via
+  // VariableProxy::BindTo.
+  RecordUses(node->var_uses());
+}
+
+
+void UsageComputer::VisitLiteral(Literal* node) {
+  // nothing to do
+}
+
+void UsageComputer::VisitRegExpLiteral(RegExpLiteral* node) {
+  // nothing to do
+}
+
+
+void UsageComputer::VisitObjectLiteral(ObjectLiteral* node) {
+  ReadList(node->properties());
+}
+
+
+void UsageComputer::VisitArrayLiteral(ArrayLiteral* node) {
+  ReadList(node->values());
+}
+
+
+void UsageComputer::VisitAssignment(Assignment* node) {
+  if (node->op() != Token::ASSIGN)
+    Read(node->target());
+  Write(node->target());
+  Read(node->value());
+}
+
+
+void UsageComputer::VisitThrow(Throw* node) {
+  Read(node->exception());
+}
+
+
+void UsageComputer::VisitProperty(Property* node) {
+  // In any case (read or write) we read both the
+  // node's object and the key.
+  Read(node->obj());
+  Read(node->key());
+  // If the node's object is a variable proxy,
+  // we have a 'simple' object property access. We count
+  // the access via the variable or proxy's object uses.
+  VariableProxy* proxy = node->obj()->AsVariableProxy();
+  if (proxy != NULL) {
+    RecordUses(proxy->obj_uses());
+  }
+}
+
+
+void UsageComputer::VisitCall(Call* node) {
+  Read(node->expression());
+  ReadList(node->arguments());
+}
+
+
+void UsageComputer::VisitCallNew(CallNew* node) {
+  VisitCall(node);
+}
+
+
+void UsageComputer::VisitCallRuntime(CallRuntime* node) {
+  ReadList(node->arguments());
+}
+
+
+void UsageComputer::VisitUnaryOperation(UnaryOperation* node) {
+  Read(node->expression());
+}
+
+
+void UsageComputer::VisitCountOperation(CountOperation* node) {
+  Read(node->expression());
+  Write(node->expression());
+}
+
+
+void UsageComputer::VisitBinaryOperation(BinaryOperation* node) {
+  Read(node->left());
+  Read(node->right());
+}
+
+
+void UsageComputer::VisitCompareOperation(CompareOperation* node) {
+  Read(node->left());
+  Read(node->right());
+}
+
+
+void UsageComputer::VisitThisFunction(ThisFunction* node) {
+}
+
+
+UsageComputer::UsageComputer(int weight, bool is_write) {
+  weight_ = weight;
+  is_write_ = is_write;
+}
+
+
+UsageComputer::~UsageComputer() {
+  // nothing to do
+}
+
+
+void UsageComputer::RecordUses(UseCount* uses) {
+  if (is_write_)
+    uses->RecordWrite(weight_);
+  else
+    uses->RecordRead(weight_);
+}
+
+
+void UsageComputer::Read(Expression* x) {
+  if (is_write_) {
+    UsageComputer uc(weight_, false);
+    uc.Visit(x);
+  } else {
+    Visit(x);
+  }
+}
+
+
+void UsageComputer::Write(Expression* x) {
+  if (!is_write_) {
+    UsageComputer uc(weight_, true);
+    uc.Visit(x);
+  } else {
+    Visit(x);
+  }
+}
+
+
+void UsageComputer::ReadList(ZoneList<Expression*>* list) {
+  for (int i = list->length(); i-- > 0; )
+    Read(list->at(i));
+}
+
+
+void UsageComputer::ReadList(ZoneList<ObjectLiteral::Property*>* list) {
+  for (int i = list->length(); i-- > 0; )
+    Read(list->at(i)->value());
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of WeightScaler
+
+WeightScaler::WeightScaler(UsageComputer* uc, float scale) {
+  uc_ = uc;
+  old_weight_ = uc->weight_;
+  int new_weight = static_cast<int>(uc->weight_ * scale);
+  if (new_weight <= 0) new_weight = MinWeight;
+  else if (new_weight > MaxWeight) new_weight = MaxWeight;
+  uc->weight_ = new_weight;
+}
+
+
+WeightScaler::~WeightScaler() {
+  uc_->weight_ = old_weight_;
+}
+
+
+// ----------------------------------------------------------------------------
+// Interface to variable usage analysis
+
+bool AnalyzeVariableUsage(FunctionLiteral* lit) {
+  if (!FLAG_usage_computation) return true;
+  return UsageComputer::Traverse(lit);
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/usage-analyzer.h b/regexp2000/src/usage-analyzer.h
new file mode 100644 (file)
index 0000000..2732dd5
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_USAGE_ANALYSER_H_
+#define V8_USAGE_ANALYSER_H_
+
+namespace v8 { namespace internal {
+
+// Compute usage counts for all variables.
+// Used for variable allocation.
+bool AnalyzeVariableUsage(FunctionLiteral* lit);
+
+} }  // namespace v8::internal
+
+#endif  // V8_USAGE_ANALYSER_H_
diff --git a/regexp2000/src/utils.cc b/regexp2000/src/utils.cc
new file mode 100644 (file)
index 0000000..9310301
--- /dev/null
@@ -0,0 +1,287 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdarg.h>
+
+#include "v8.h"
+
+#include "platform.h"
+
+#include "sys/stat.h"
+
+namespace v8 { namespace internal {
+
+
+// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
+// figure 3-3, page 48, where the function is called clp2.
+uint32_t RoundUpToPowerOf2(uint32_t x) {
+  x = x - 1;
+  x = x | (x >> 1);
+  x = x | (x >> 2);
+  x = x | (x >> 4);
+  x = x | (x >> 8);
+  x = x | (x >> 16);
+  return x + 1;
+}
+
+
+byte* EncodeInt(byte* p, int x) {
+  while (x < -64 || x >= 64) {
+    *p++ = static_cast<byte>(x & 127);
+    x = ArithmeticShiftRight(x, 7);
+  }
+  // -64 <= x && x < 64
+  *p++ = static_cast<byte>(x + 192);
+  return p;
+}
+
+
+byte* DecodeInt(byte* p, int* x) {
+  int r = 0;
+  unsigned int s = 0;
+  byte b = *p++;
+  while (b < 128) {
+    r |= static_cast<int>(b) << s;
+    s += 7;
+    b = *p++;
+  }
+  // b >= 128
+  *x = r | ((static_cast<int>(b) - 192) << s);
+  return p;
+}
+
+
+byte* EncodeUnsignedIntBackward(byte* p, unsigned int x) {
+  while (x >= 128) {
+    *--p = static_cast<byte>(x & 127);
+    x = x >> 7;
+  }
+  // x < 128
+  *--p = static_cast<byte>(x + 128);
+  return p;
+}
+
+
+void PrintF(const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  OS::VPrint(format, arguments);
+  va_end(arguments);
+}
+
+
+void Flush() {
+  fflush(stdout);
+}
+
+
+char* ReadLine(const char* prompt) {
+  char* result = NULL;
+  char line_buf[256];
+  int offset = 0;
+  bool keep_going = true;
+  fprintf(stdout, "%s", prompt);
+  fflush(stdout);
+  while (keep_going) {
+    if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) {
+      // fgets got an error. Just give up.
+      if (result != NULL) {
+        DeleteArray(result);
+      }
+      return NULL;
+    }
+    int len = strlen(line_buf);
+    if (len > 1 &&
+        line_buf[len - 2] == '\\' &&
+        line_buf[len - 1] == '\n') {
+      // When we read a line that ends with a "\" we remove the escape and
+      // append the remainder.
+      line_buf[len - 2] = '\n';
+      line_buf[len - 1] = 0;
+      len -= 1;
+    } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
+      // Since we read a new line we are done reading the line. This
+      // will exit the loop after copying this buffer into the result.
+      keep_going = false;
+    }
+    if (result == NULL) {
+      // Allocate the initial result and make room for the terminating '\0'
+      result = NewArray<char>(len + 1);
+    } else {
+      // Allocate a new result with enough room for the new addition.
+      int new_len = offset + len + 1;
+      char* new_result = NewArray<char>(new_len);
+      // Copy the existing input into the new array and set the new
+      // array as the result.
+      memcpy(new_result, result, offset * kCharSize);
+      DeleteArray(result);
+      result = new_result;
+    }
+    // Copy the newly read line into the result.
+    memcpy(result + offset, line_buf, len * kCharSize);
+    offset += len;
+  }
+  ASSERT(result != NULL);
+  result[offset] = '\0';
+  return result;
+}
+
+
+char* ReadCharsFromFile(const char* filename,
+                        int* size,
+                        int extra_space,
+                        bool verbose) {
+  FILE* file = OS::FOpen(filename, "rb");
+  if (file == NULL || fseek(file, 0, SEEK_END) != 0) {
+    if (verbose) {
+      OS::PrintError("Cannot read from file %s.\n", filename);
+    }
+    return NULL;
+  }
+
+  // Get the size of the file and rewind it.
+  *size = ftell(file);
+  rewind(file);
+
+  char* result = NewArray<char>(*size + extra_space);
+  for (int i = 0; i < *size;) {
+    int read = fread(&result[i], 1, *size - i, file);
+    if (read <= 0) {
+      fclose(file);
+      DeleteArray(result);
+      return NULL;
+    }
+    i += read;
+  }
+  fclose(file);
+  return result;
+}
+
+
+char* ReadChars(const char* filename, int* size, bool verbose) {
+  return ReadCharsFromFile(filename, size, 0, verbose);
+}
+
+
+Vector<const char> ReadFile(const char* filename,
+                            bool* exists,
+                            bool verbose) {
+  int size;
+  char* result = ReadCharsFromFile(filename, &size, 1, verbose);
+  if (!result) {
+    *exists = false;
+    return Vector<const char>::empty();
+  }
+  result[size] = '\0';
+  *exists = true;
+  return Vector<const char>(result, size);
+}
+
+
+int WriteCharsToFile(const char* str, int size, FILE* f) {
+  int total = 0;
+  while (total < size) {
+    int write = fwrite(str, 1, size - total, f);
+    if (write == 0) {
+      return total;
+    }
+    total += write;
+    str += write;
+  }
+  return total;
+}
+
+
+int WriteChars(const char* filename,
+               const char* str,
+               int size,
+               bool verbose) {
+  FILE* f = OS::FOpen(filename, "wb");
+  if (f == NULL) {
+    if (verbose) {
+      OS::PrintError("Cannot open file %s for reading.\n", filename);
+    }
+    return 0;
+  }
+  int written = WriteCharsToFile(str, size, f);
+  fclose(f);
+  return written;
+}
+
+
+StringBuilder::StringBuilder(int size) {
+  buffer_ = Vector<char>::New(size);
+  position_ = 0;
+}
+
+
+void StringBuilder::AddString(const char* s) {
+  AddSubstring(s, strlen(s));
+}
+
+
+void StringBuilder::AddSubstring(const char* s, int n) {
+  ASSERT(!is_finalized() && position_ + n < buffer_.length());
+  ASSERT(static_cast<size_t>(n) <= strlen(s));
+  memcpy(&buffer_[position_], s, n * kCharSize);
+  position_ += n;
+}
+
+
+void StringBuilder::AddFormatted(const char* format, ...) {
+  ASSERT(!is_finalized() && position_ < buffer_.length());
+  va_list args;
+  va_start(args, format);
+  int n = OS::VSNPrintF(buffer_ + position_, format, args);
+  va_end(args);
+  if (n < 0 || n >= (buffer_.length() - position_)) {
+    position_ = buffer_.length();
+  } else {
+    position_ += n;
+  }
+}
+
+
+void StringBuilder::AddPadding(char c, int count) {
+  for (int i = 0; i < count; i++) {
+    AddCharacter(c);
+  }
+}
+
+
+char* StringBuilder::Finalize() {
+  ASSERT(!is_finalized() && position_ < buffer_.length());
+  buffer_[position_] = '\0';
+  // Make sure nobody managed to add a 0-character to the
+  // buffer while building the string.
+  ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
+  position_ = -1;
+  ASSERT(is_finalized());
+  return buffer_.start();
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/utils.h b/regexp2000/src/utils.h
new file mode 100644 (file)
index 0000000..9f24079
--- /dev/null
@@ -0,0 +1,470 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_UTILS_H_
+#define V8_UTILS_H_
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// General helper functions
+
+// Returns true iff x is a power of 2.  Does not work for zero.
+template <typename T>
+static inline bool IsPowerOf2(T x) {
+  return (x & (x - 1)) == 0;
+}
+
+
+
+
+// The C++ standard leaves the semantics of '>>' undefined for
+// negative signed operands. Most implementations do the right thing,
+// though.
+static inline int ArithmeticShiftRight(int x, int s) {
+  return x >> s;
+}
+
+
+// Compute the 0-relative offset of some absolute value x of type T.
+// This allows conversion of Addresses and integral types into
+// 0-relative int offsets.
+template <typename T>
+static inline int OffsetFrom(T x) {
+  return x - static_cast<T>(0);
+}
+
+
+// Compute the absolute value of type T for some 0-relative offset x.
+// This allows conversion of 0-relative int offsets into Addresses and
+// integral types.
+template <typename T>
+static inline T AddressFrom(int x) {
+  return static_cast<T>(0) + x;
+}
+
+
+// Return the largest multiple of m which is <= x.
+template <typename T>
+static inline T RoundDown(T x, int m) {
+  ASSERT(IsPowerOf2(m));
+  return AddressFrom<T>(OffsetFrom(x) & -m);
+}
+
+
+// Return the smallest multiple of m which is >= x.
+template <typename T>
+static inline T RoundUp(T x, int m) {
+  return RoundDown(x + m - 1, m);
+}
+
+
+// Returns the smallest power of two which is >= x. If you pass in a
+// number that is already a power of two, it is returned as is.
+uint32_t RoundUpToPowerOf2(uint32_t x);
+
+
+template <typename T>
+static inline bool IsAligned(T value, T alignment) {
+  ASSERT(IsPowerOf2(alignment));
+  return (value & (alignment - 1)) == 0;
+}
+
+
+// Returns true if (addr + offset) is aligned.
+static inline bool IsAddressAligned(Address addr, int alignment, int offset) {
+  int offs = OffsetFrom(addr + offset);
+  return IsAligned(offs, alignment);
+}
+
+
+// Returns the maximum of the two parameters.
+template <typename T>
+static T Max(T a, T b) {
+  return a < b ? b : a;
+}
+
+
+// Returns the minimum of the two parameters.
+template <typename T>
+static T Min(T a, T b) {
+  return a < b ? a : b;
+}
+
+
+// ----------------------------------------------------------------------------
+// BitField is a help template for encoding and decode bitfield with
+// unsigned content.
+template<class T, int shift, int size>
+class BitField {
+ public:
+  // 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() {
+    return (1U << (size + shift)) - (1U << shift);
+  }
+
+  // Returns a uint32_t with the bit field value encoded.
+  static uint32_t encode(T value) {
+    ASSERT(is_valid(value));
+    return static_cast<uint32_t>(value) << shift;
+  }
+
+  // Extracts the bit field from the value.
+  static T decode(uint32_t value) {
+    return static_cast<T>((value >> shift) & ((1U << (size)) - 1));
+  }
+};
+
+
+// ----------------------------------------------------------------------------
+// Support for compressed, machine-independent encoding
+// and decoding of integer values of arbitrary size.
+
+// Encoding and decoding from/to a buffer at position p;
+// the result is the position after the encoded integer.
+// Small signed integers in the range -64 <= x && x < 64
+// are encoded in 1 byte; larger values are encoded in 2
+// or more bytes. At most sizeof(int) + 1 bytes are used
+// in the worst case.
+byte* EncodeInt(byte* p, int x);
+byte* DecodeInt(byte* p, int* x);
+
+
+// Encoding and decoding from/to a buffer at position p - 1
+// moving backward; the result is the position of the last
+// byte written. These routines are useful to read/write
+// into a buffer starting at the end of the buffer.
+byte* EncodeUnsignedIntBackward(byte* p, unsigned int x);
+
+// The decoding function is inlined since its performance is
+// important to mark-sweep garbage collection.
+inline byte* DecodeUnsignedIntBackward(byte* p, unsigned int* x) {
+  byte b = *--p;
+  if (b >= 128) {
+    *x = static_cast<unsigned int>(b) - 128;
+    return p;
+  }
+  unsigned int r = static_cast<unsigned int>(b);
+  unsigned int s = 7;
+  b = *--p;
+  while (b < 128) {
+    r |= static_cast<unsigned int>(b) << s;
+    s += 7;
+    b = *--p;
+  }
+  // b >= 128
+  *x = r | ((static_cast<unsigned int>(b) - 128) << s);
+  return p;
+}
+
+
+// ----------------------------------------------------------------------------
+// I/O support.
+
+// Our version of printf(). Avoids compilation errors that we get
+// with standard printf when attempting to print pointers, etc.
+// (the errors are due to the extra compilation flags, which we
+// want elsewhere).
+void PrintF(const char* format, ...);
+
+// Our version of fflush.
+void Flush();
+
+
+// Read a line of characters after printing the prompt to stdout. The resulting
+// char* needs to be disposed off with DeleteArray by the caller.
+char* ReadLine(const char* prompt);
+
+
+// Read and return the raw chars in a file. the size of the buffer is returned
+// in size.
+// The returned buffer is not 0-terminated. It must be freed by the caller.
+char* ReadChars(const char* filename, int* size, bool verbose = true);
+
+
+// Write size chars from str to the file given by filename.
+// The file is overwritten. Returns the number of chars written.
+int WriteChars(const char* filename,
+               const char* str,
+               int size,
+               bool verbose = true);
+
+
+// Write the C code
+// const char* <varname> = "<str>";
+// const int <varname>_len = <len>;
+// to the file given by filename. Only the first len chars are written.
+int WriteAsCFile(const char* filename, const char* varname,
+                 const char* str, int size, bool verbose = true);
+
+
+// ----------------------------------------------------------------------------
+// Miscellaneous
+
+// A static resource holds a static instance that can be reserved in
+// a local scope using an instance of Access.  Attempts to re-reserve
+// the instance will cause an error.
+template <typename T>
+class StaticResource {
+ public:
+  StaticResource() : is_reserved_(false)  {}
+
+ private:
+  template <typename S> friend class Access;
+  T instance_;
+  bool is_reserved_;
+};
+
+
+// Locally scoped access to a static resource.
+template <typename T>
+class Access {
+ public:
+  explicit Access(StaticResource<T>* resource)
+    : resource_(resource)
+    , instance_(&resource->instance_) {
+    ASSERT(!resource->is_reserved_);
+    resource->is_reserved_ = true;
+  }
+
+  ~Access() {
+    resource_->is_reserved_ = false;
+    resource_ = NULL;
+    instance_ = NULL;
+  }
+
+  T* value()  { return instance_; }
+  T* operator -> ()  { return instance_; }
+
+ private:
+  StaticResource<T>* resource_;
+  T* instance_;
+};
+
+
+template <typename T>
+class Vector {
+ public:
+  Vector() : start_(NULL), length_(0) {}
+  Vector(T* data, int length) : start_(data), length_(length) {
+    ASSERT(length == 0 || (length > 0 && data != NULL));
+  }
+
+  static Vector<T> New(int length) {
+    return Vector<T>(NewArray<T>(length), length);
+  }
+
+  // Returns the length of the vector.
+  int length() const { return length_; }
+
+  // Returns whether or not the vector is empty.
+  bool is_empty() const { return length_ == 0; }
+
+  // Returns the pointer to the start of the data in the vector.
+  T* start() const { return start_; }
+
+  // Access individual vector elements - checks bounds in debug mode.
+  T& operator[](int index) const {
+    ASSERT(0 <= index && index < length_);
+    return start_[index];
+  }
+
+  // Returns a clone of this vector with a new backing store.
+  Vector<T> Clone() const {
+    T* result = NewArray<T>(length_);
+    for (int i = 0; i < length_; i++) result[i] = start_[i];
+    return Vector<T>(result, length_);
+  }
+
+  // Releases the array underlying this vector. Once disposed the
+  // vector is empty.
+  void Dispose() {
+    if (is_empty()) return;
+    DeleteArray(start_);
+    start_ = NULL;
+    length_ = 0;
+  }
+
+  inline Vector<T> operator+(int offset) {
+    ASSERT(offset < length_);
+    return Vector<T>(start_ + offset, length_ - offset);
+  }
+
+  // Factory method for creating empty vectors.
+  static Vector<T> empty() { return Vector<T>(NULL, 0); }
+
+ private:
+  T* start_;
+  int length_;
+};
+
+
+template <typename T, int kSize>
+class EmbeddedVector : public Vector<T> {
+ public:
+  EmbeddedVector() : Vector<T>(buffer_, kSize) { }
+ private:
+  T buffer_[kSize];
+};
+
+
+inline Vector<const char> CStrVector(const char* data) {
+  return Vector<const char>(data, strlen(data));
+}
+
+inline Vector<char> MutableCStrVector(char* data) {
+  return Vector<char>(data, strlen(data));
+}
+
+inline Vector<char> MutableCStrVector(char* data, int max) {
+  int length = strlen(data);
+  return Vector<char>(data, (length < max) ? length : max);
+}
+
+template <typename T>
+inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
+                                             int length) {
+  return Vector< Handle<Object> >(
+      reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
+}
+
+
+// Simple support to read a file into a 0-terminated C-string.
+// The returned buffer must be freed by the caller.
+// On return, *exits tells whether the file exisited.
+Vector<const char> ReadFile(const char* filename,
+                            bool* exists,
+                            bool verbose = true);
+
+
+// Simple wrapper that allows an ExternalString to refer to a
+// Vector<const char>. Doesn't assume ownership of the data.
+class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
+ public:
+  explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
+
+  virtual const char* data() const { return data_.start(); }
+
+  virtual size_t length() const { return data_.length(); }
+
+ private:
+  Vector<const char> data_;
+};
+
+
+// Helper class for building result strings in a character buffer. The
+// purpose of the class is to use safe operations that checks the
+// buffer bounds on all operations in debug mode.
+class StringBuilder {
+ public:
+  // Create a string builder with a buffer of the given size. The
+  // buffer is allocated through NewArray<char> and must be
+  // deallocated by the caller of Finalize().
+  explicit StringBuilder(int size);
+
+  StringBuilder(char* buffer, int size)
+      : buffer_(buffer, size), position_(0) { }
+
+  ~StringBuilder() { if (!is_finalized()) Finalize(); }
+
+  int size() const { return buffer_.length(); }
+
+  // Get the current position in the builder.
+  int position() const {
+    ASSERT(!is_finalized());
+    return position_;
+  }
+
+  // Reset the position.
+  void Reset() { position_ = 0; }
+
+  // Add a single character to the builder. It is not allowed to add
+  // 0-characters; use the Finalize() method to terminate the string
+  // instead.
+  void AddCharacter(char c) {
+    ASSERT(c != '\0');
+    ASSERT(!is_finalized() && position_ < buffer_.length());
+    buffer_[position_++] = c;
+  }
+
+  // Add an entire string to the builder. Uses strlen() internally to
+  // compute the length of the input string.
+  void AddString(const char* s);
+
+  // Add the first 'n' characters of the given string 's' to the
+  // builder. The input string must have enough characters.
+  void AddSubstring(const char* s, int n);
+
+  // Add formatted contents to the builder just like printf().
+  void AddFormatted(const char* format, ...);
+
+  // Add character padding to the builder. If count is non-positive,
+  // nothing is added to the builder.
+  void AddPadding(char c, int count);
+
+  // Finalize the string by 0-terminating it and returning the buffer.
+  char* Finalize();
+
+ private:
+  Vector<char> buffer_;
+  int position_;
+
+  bool is_finalized() const { return position_ < 0; }
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
+};
+
+
+// Copy from ASCII/16bit chars to ASCII/16bit chars.
+template <typename sourcechar, typename sinkchar>
+static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
+  sinkchar* limit = dest + chars;
+#ifdef CAN_READ_UNALIGNED
+  if (sizeof(*dest) == sizeof(*src)) {
+    // Number of characters in a uint32_t.
+    static const int kStepSize = sizeof(uint32_t) / sizeof(*dest);  // NOLINT
+    while (dest <= limit - kStepSize) {
+      *reinterpret_cast<uint32_t*>(dest) =
+          *reinterpret_cast<const uint32_t*>(src);
+      dest += kStepSize;
+      src += kStepSize;
+    }
+  }
+#endif
+  while (dest < limit) {
+    *dest++ = static_cast<sinkchar>(*src++);
+  }
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_UTILS_H_
diff --git a/regexp2000/src/v8-counters.cc b/regexp2000/src/v8-counters.cc
new file mode 100644 (file)
index 0000000..95847f6
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "v8-counters.h"
+
+namespace v8 { namespace internal {
+
+#define SR(name, caption) \
+  StatsRate Counters::name = { \
+  { { L"t:" L###caption, NULL, false }, 0, 0 }, \
+  { L"c:" L###caption, NULL, false } };
+
+  STATS_RATE_LIST(SR)
+#undef SR
+
+#define SC(name, caption) \
+  StatsCounter Counters::name = { L"c:" L###caption, NULL, false };
+
+  STATS_COUNTER_LIST_1(SC)
+  STATS_COUNTER_LIST_2(SC)
+#undef SC
+
+StatsCounter Counters::state_counters[] = {
+#define COUNTER_NAME(name) \
+  { L"c:V8.State" L###name, NULL, false },
+  STATE_TAG_LIST(COUNTER_NAME)
+#undef COUNTER_NAME
+};
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/v8-counters.h b/regexp2000/src/v8-counters.h
new file mode 100644 (file)
index 0000000..6eb7426
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_V8_COUNTERS_H_
+#define V8_V8_COUNTERS_H_
+
+#include "counters.h"
+
+namespace v8 { namespace internal {
+
+#define STATS_RATE_LIST(SR)                                \
+  SR(gc_compactor, V8.GCCompactor) /* GC Compactor time */ \
+  SR(gc_scavenger, V8.GCScavenger) /* GC Scavenger time */ \
+  SR(compile, V8.Compile)          /* Compile time*/       \
+  SR(compile_eval, V8.CompileEval) /* Eval compile time */ \
+  SR(compile_lazy, V8.CompileLazy) /* Lazy compile time */ \
+  SR(parse, V8.Parse)              /* Parse time */        \
+  SR(parse_lazy, V8.ParseLazy)     /* Lazy parse time */   \
+  SR(pre_parse, V8.PreParse)       /* Pre-parse time */
+
+// WARNING: STATS_COUNTER_LIST_* is a very large macro that is causing MSVC
+// Intellisense to crash.  It was broken into two macros (each of length 40
+// lines) rather than one macro (of length about 80 lines) to work around
+// this problem.  Please avoid using recursive macros of this length when
+// possible.
+#define STATS_COUNTER_LIST_1(SC)                                 \
+  /* Global Handle Count*/                                       \
+  SC(global_handles, V8.GlobalHandles)                           \
+  /* Global Object Count */                                      \
+  SC(global_objects, V8.GlobalObjects)                           \
+  /* Mallocs from PCRE */                                        \
+  SC(pcre_mallocs, V8.PcreMallocCount)                           \
+  /* OS Memory allocated */                                      \
+  SC(memory_allocated, V8.OsMemoryAllocated)                     \
+  SC(props_to_dictionary, V8.ObjectPropertiesToDictionary)       \
+  SC(elements_to_dictionary, V8.ObjectElementsToDictionary)      \
+  SC(alive_after_last_gc, V8.AliveAfterLastGC)                   \
+  SC(objs_since_last_young, V8.ObjsSinceLastYoung)               \
+  SC(objs_since_last_full, V8.ObjsSinceLastFull)                 \
+  SC(symbol_table_capacity, V8.SymbolTableCapacity)              \
+  SC(number_of_symbols, V8.NumberOfSymbols)                      \
+  /* Current amount of memory in external string buffers. */     \
+  SC(total_external_string_memory, V8.TotalExternalStringMemory) \
+  SC(script_wrappers, V8.ScriptWrappers)                         \
+  SC(call_initialize_stubs, V8.CallInitializeStubs)              \
+  SC(call_premonomorphic_stubs, V8.CallPreMonomorphicStubs)      \
+  SC(call_normal_stubs, V8.CallNormalStubs)                      \
+  SC(call_megamorphic_stubs, V8.CallMegamorphicStubs)            \
+  SC(arguments_adaptors, V8.ArgumentsAdaptors)                   \
+  SC(compilation_cache_hits, V8.CompilationCacheHits)            \
+  SC(compilation_cache_misses, V8.CompilationCacheMisses)        \
+  SC(regexp_cache_hits, V8.RegExpCacheHits)                      \
+  SC(regexp_cache_misses, V8.RegExpCacheMisses)                  \
+  /* Amount of evaled source code. */                            \
+  SC(total_eval_size, V8.TotalEvalSize)                          \
+  /* Amount of loaded source code. */                            \
+  SC(total_load_size, V8.TotalLoadSize)                          \
+  /* Amount of parsed source code. */                            \
+  SC(total_parse_size, V8.TotalParseSize)                        \
+  /* Amount of source code skipped over using preparsing. */     \
+  SC(total_preparse_skipped, V8.TotalPreparseSkipped)            \
+  /* Amount of compiled source code. */                          \
+  SC(total_compile_size, V8.TotalCompileSize)
+
+
+#define STATS_COUNTER_LIST_2(SC)                                    \
+  /* Number of code stubs. */                                       \
+  SC(code_stubs, V8.CodeStubs)                                      \
+  /* Amount of stub code. */                                        \
+  SC(total_stubs_code_size, V8.TotalStubsCodeSize)                  \
+  /* Amount of (JS) compiled code. */                               \
+  SC(total_compiled_code_size, V8.TotalCompiledCodeSize)            \
+  SC(gc_compactor_caused_by_request, V8.GCCompactorCausedByRequest) \
+  SC(gc_compactor_caused_by_promoted_data,                          \
+     V8.GCCompactorCausedByPromotedData)                            \
+  SC(gc_compactor_caused_by_oldspace_exhaustion,                    \
+     V8.GCCompactorCausedByOldspaceExhaustion)                      \
+  SC(gc_compactor_caused_by_weak_handles,                           \
+     V8.GCCompactorCausedByWeakHandles)                             \
+  /* How is the generic keyed-load stub used? */                    \
+  SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi)                \
+  SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol)          \
+  SC(keyed_load_generic_slow, V8.KeyedLoadGenericSlow)              \
+  /* Count how much the monomorphic keyed-load stubs are hit. */    \
+  SC(keyed_load_function_prototype, V8.KeyedLoadFunctionPrototype)  \
+  SC(keyed_load_string_length, V8.KeyedLoadStringLength)            \
+  SC(keyed_load_array_length, V8.KeyedLoadArrayLength)              \
+  SC(keyed_load_constant_function, V8.KeyedLoadConstantFunction)    \
+  SC(keyed_load_field, V8.KeyedLoadField)                           \
+  SC(keyed_load_callback, V8.KeyedLoadCallback)                     \
+  SC(keyed_load_interceptor, V8.KeyedLoadInterceptor)               \
+  SC(keyed_store_field, V8.KeyedStoreField)                         \
+  SC(for_in, V8.ForIn)                                              \
+  SC(enum_cache_hits, V8.EnumCacheHits)                             \
+  SC(enum_cache_misses, V8.EnumCacheMisses)                         \
+  SC(reloc_info_count, V8.RelocInfoCount)                           \
+  SC(reloc_info_size, V8.RelocInfoSize)
+
+
+// This file contains all the v8 counters that are in use.
+class Counters : AllStatic {
+ public:
+#define SR(name, caption) \
+  static StatsRate name;
+  STATS_RATE_LIST(SR)
+#undef SR
+
+#define SC(name, caption) \
+  static StatsCounter name;
+  STATS_COUNTER_LIST_1(SC)
+  STATS_COUNTER_LIST_2(SC)
+#undef SC
+
+  enum Id {
+#define RATE_ID(name, caption) k_##name,
+    STATS_RATE_LIST(RATE_ID)
+#undef RATE_ID
+#define COUNTER_ID(name, caption) k_##name,
+  STATS_COUNTER_LIST_1(COUNTER_ID)
+  STATS_COUNTER_LIST_2(COUNTER_ID)
+#undef COUNTER_ID
+#define COUNTER_ID(name) k_##name,
+  STATE_TAG_LIST(COUNTER_ID)
+#undef COUNTER_ID
+    stats_counter_count
+  };
+
+  // Sliding state window counters.
+  static StatsCounter state_counters[];
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_COUNTERS_H_
diff --git a/regexp2000/src/v8.cc b/regexp2000/src/v8.cc
new file mode 100644 (file)
index 0000000..29013fd
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bootstrapper.h"
+#include "debug.h"
+#include "serialize.h"
+#include "stub-cache.h"
+
+namespace v8 { namespace internal {
+
+bool V8::has_been_setup_ = false;
+bool V8::has_been_disposed_ = false;
+
+bool V8::Initialize(Deserializer *des) {
+  bool create_heap_objects = des == NULL;
+  if (HasBeenDisposed()) return false;
+  if (HasBeenSetup()) return true;
+  has_been_setup_ = true;
+#ifdef DEBUG
+  // The initialization process does not handle memory exhaustion.
+  DisallowAllocationFailure disallow_allocation_failure;
+#endif
+
+  // Enable logging before setting up the heap
+  Logger::Setup();
+  if (des) des->GetLog();
+
+  // Setup the CPU support.
+  CPU::Setup();
+
+  // Setup the platform OS support.
+  OS::Setup();
+
+  // Setup the object heap
+  ASSERT(!Heap::HasBeenSetup());
+  if (!Heap::Setup(create_heap_objects)) {
+    has_been_setup_ = false;
+    return false;
+  }
+
+  // Initialize other runtime facilities
+  Bootstrapper::Initialize(create_heap_objects);
+  Builtins::Setup(create_heap_objects);
+  Top::Initialize();
+
+  if (FLAG_preemption) {
+    v8::Locker locker;
+    v8::Locker::StartPreemption(100);
+  }
+
+  Debug::Setup(create_heap_objects);
+  StubCache::Initialize(create_heap_objects);
+
+  // If we are deserializing, read the state into the now-empty heap.
+  if (des != NULL) {
+    des->Deserialize();
+    StubCache::Clear();
+  }
+
+  return true;
+}
+
+
+void V8::TearDown() {
+  if (HasBeenDisposed()) return;
+  if (!HasBeenSetup()) return;
+
+  if (FLAG_preemption) {
+    v8::Locker locker;
+    v8::Locker::StopPreemption();
+  }
+
+  Builtins::TearDown();
+  Bootstrapper::TearDown();
+
+  Top::TearDown();
+
+  Heap::TearDown();
+  Logger::TearDown();
+
+  has_been_setup_ = false;
+  has_been_disposed_ = true;
+}
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/v8.h b/regexp2000/src/v8.h
new file mode 100644 (file)
index 0000000..328c88c
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Top include for all V8 .cc files.
+//
+
+#ifndef V8_V8_H_
+#define V8_V8_H_
+
+#if defined(GOOGLE3)
+// Google3 special flag handling.
+#if defined(DEBUG) && defined(NDEBUG)
+// If both are defined in Google3, then we are building an optimized v8 with
+// assertions enabled.
+#undef NDEBUG
+#endif
+#endif  // defined(GOOGLE3)
+
+// V8 only uses DEBUG, but included external files
+// may use NDEBUG - make sure they are consistent.
+#if defined(DEBUG) && defined(NDEBUG)
+#error both DEBUG and NDEBUG are set
+#endif
+
+// Basic includes
+#include "../include/v8.h"
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "utils.h"
+#include "flags.h"
+
+// Objects & heap
+#include "objects.h"
+#include "spaces.h"
+#include "heap.h"
+#include "objects-inl.h"
+#include "spaces-inl.h"
+#include "heap-inl.h"
+#include "messages.h"
+
+namespace v8 { namespace internal {
+
+class V8 : public AllStatic {
+ public:
+  // Global actions.
+
+  // If Initialize is called with des == NULL, the
+  // initial state is created from scratch. If a non-null Deserializer
+  // is given, the initial state is created by reading the
+  // deserialized data into an empty heap.
+  static bool Initialize(Deserializer* des);
+  static void TearDown();
+  static bool HasBeenSetup() { return has_been_setup_; }
+  static bool HasBeenDisposed() { return has_been_disposed_; }
+
+  // Report process out of memory. Implementation found in api.cc.
+  static void FatalProcessOutOfMemory(const char* location);
+ private:
+  static bool has_been_setup_;
+  static bool has_been_disposed_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_V8_H_
diff --git a/regexp2000/src/v8natives.js b/regexp2000/src/v8natives.js
new file mode 100644 (file)
index 0000000..094d5ea
--- /dev/null
@@ -0,0 +1,535 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file relies on the fact that the following declarations have been made
+//
+// in runtime.js:
+// const $Object = global.Object;
+// const $Boolean = global.Boolean;
+// const $Number = global.Number;
+// const $Function = global.Function;
+// const $Array = global.Array;
+// const $NaN = 0/0;
+//
+// in math.js:
+// const $floor = MathFloor
+
+const $isNaN = GlobalIsNaN;
+const $isFinite = GlobalIsFinite;
+
+// ----------------------------------------------------------------------------
+
+
+// Helper function used to install functions on objects.
+function InstallFunctions(object, attributes, functions) {
+  for (var i = 0; i < functions.length; i += 2) {
+    var key = functions[i];
+    var f = functions[i + 1];
+    %FunctionSetName(f, key);
+    %SetProperty(object, key, f, attributes);
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+// ECMA 262 - 15.1.4
+function GlobalIsNaN(number) {
+  var n = ToNumber(number);
+  return NUMBER_IS_NAN(n);
+}
+
+
+// ECMA 262 - 15.1.5
+function GlobalIsFinite(number) {
+  return %NumberIsFinite(ToNumber(number));
+}
+
+
+// ECMA-262 - 15.1.2.2
+function GlobalParseInt(string, radix) {
+  if (radix === void 0) {
+    radix = 0;
+    // Some people use parseInt instead of Math.floor.  This
+    // optimization makes parseInt on a Smi 12 times faster (60ns
+    // vs 800ns).  The following optimization makes parseInt on a
+    // non-Smi number 9 times faster (230ns vs 2070ns).  Together
+    // they make parseInt on a string 1.4% slower (274ns vs 270ns).
+    if (%_IsSmi(string)) return string;
+    if (IS_NUMBER(string)) {
+      if (string >= 0.01 && string < 1e9)
+        return $floor(string);
+      if (string <= -0.01 && string > -1e9)
+        return - $floor(-string);
+    }
+  } else {
+    radix = TO_INT32(radix);
+    if (!(radix == 0 || (2 <= radix && radix <= 36)))
+      return $NaN;
+  }
+  return %StringParseInt(ToString(string), radix);
+}
+
+
+// ECMA-262 - 15.1.2.3
+function GlobalParseFloat(string) {
+  return %StringParseFloat(ToString(string));
+}
+
+
+function GlobalEval(x) {
+  if (!IS_STRING(x)) return x;
+
+  var f = %CompileString(x, 0, true);
+  if (!IS_FUNCTION(f)) return f;
+
+  return f.call(%EvalReceiver(this));
+}
+
+
+// execScript for IE compatibility.
+function GlobalExecScript(expr, lang) {
+  // NOTE: We don't care about the character casing.
+  if (!lang || /javascript/i.test(lang)) {
+    var f = %CompileString(ToString(expr), 0, false);
+    f.call(%GlobalReceiver(global));
+  }
+  return null;
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+function SetupGlobal() {
+  // ECMA 262 - 15.1.1.1.
+  %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
+
+  // ECMA-262 - 15.1.1.2.
+  %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
+
+  // ECMA-262 - 15.1.1.3.
+  %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
+
+  // Setup non-enumerable function on the global object.
+  InstallFunctions(global, DONT_ENUM, $Array(
+    "isNaN", GlobalIsNaN,
+    "isFinite", GlobalIsFinite,
+    "parseInt", GlobalParseInt,
+    "parseFloat", GlobalParseFloat,
+    "eval", GlobalEval,
+    "execScript", GlobalExecScript
+  ));
+}
+
+SetupGlobal();
+
+
+// ----------------------------------------------------------------------------
+// Boolean (first part of definition)
+
+
+%SetCode($Boolean, function(x) {
+  if (%IsConstructCall()) {
+    %_SetValueOf(this, ToBoolean(x));
+  } else {
+    return ToBoolean(x);
+  }
+});
+
+%FunctionSetPrototype($Boolean, new $Boolean(false));
+
+%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
+
+// ----------------------------------------------------------------------------
+// Object
+
+$Object.prototype.constructor = $Object;
+
+// ECMA-262 - 15.2.4.2
+function ObjectToString() {
+  var c = %ClassOf(this);
+  // Hide Arguments from the outside.
+  if (c === 'Arguments') c  = 'Object';
+  return "[object " + c + "]";
+}
+
+
+// ECMA-262 - 15.2.4.3
+function ObjectToLocaleString() {
+  return this.toString();
+}
+
+
+// ECMA-262 - 15.2.4.4
+function ObjectValueOf() {
+  return this;
+}
+
+
+// ECMA-262 - 15.2.4.5
+function ObjectHasOwnProperty(V) {
+  return %HasLocalProperty(ToObject(this), ToString(V));
+}
+
+
+// ECMA-262 - 15.2.4.6
+function ObjectIsPrototypeOf(V) {
+  if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
+  return %IsInPrototypeChain(this, V);
+}
+
+
+// ECMA-262 - 15.2.4.6
+function ObjectPropertyIsEnumerable(V) {
+  if (this == null) return false;
+  if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false;
+  return %IsPropertyEnumerable(this, ToString(V));
+}
+
+
+// Extensions for providing property getters and setters.
+function ObjectDefineGetter(name, fun) {
+  if (this == null) {
+    throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
+  }
+  if (!IS_FUNCTION(fun)) {
+    throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
+  }
+  return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
+}
+
+
+function ObjectLookupGetter(name) {
+  if (this == null) {
+    throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
+  }
+  return %LookupAccessor(ToObject(this), ToString(name), GETTER);
+}
+
+
+function ObjectDefineSetter(name, fun) {
+  if (this == null) {
+    throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
+  }
+  if (!IS_FUNCTION(fun)) {
+    throw new $TypeError(
+        'Object.prototype.__defineSetter__: Expecting function');
+  }
+  return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
+}
+
+
+function ObjectLookupSetter(name) {
+  if (this == null) {
+    throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
+  }
+  return %LookupAccessor(ToObject(this), ToString(name), SETTER);
+}
+
+
+%SetCode($Object, function(x) {
+  if (%IsConstructCall()) {
+    if (x == null) return this;
+    return ToObject(x);
+  } else {
+    if (x == null) return { };
+    return ToObject(x);
+  }
+});
+
+
+// ----------------------------------------------------------------------------
+
+
+function SetupObject() {
+  // Setup non-enumerable functions on the Object.prototype object.
+  InstallFunctions($Object.prototype, DONT_ENUM, $Array(
+    "toString", ObjectToString,
+    "toLocaleString", ObjectToLocaleString,
+    "valueOf", ObjectValueOf,
+    "hasOwnProperty", ObjectHasOwnProperty,
+    "isPrototypeOf", ObjectIsPrototypeOf,
+    "propertyIsEnumerable", ObjectPropertyIsEnumerable,
+    "__defineGetter__", ObjectDefineGetter,
+    "__lookupGetter__", ObjectLookupGetter,
+    "__defineSetter__", ObjectDefineSetter,
+    "__lookupSetter__", ObjectLookupSetter
+  ));
+}
+
+SetupObject();
+
+
+// ----------------------------------------------------------------------------
+// Boolean
+
+function BooleanToString() {
+  // NOTE: Both Boolean objects and values can enter here as
+  // 'this'. This is not as dictated by ECMA-262.
+  if (!IS_BOOLEAN(this) && !%HasBooleanClass(this))
+    throw new $TypeError('Boolean.prototype.toString is not generic');
+  return ToString(%_ValueOf(this));
+}
+
+
+function BooleanValueOf() {
+  // NOTE: Both Boolean objects and values can enter here as
+  // 'this'. This is not as dictated by ECMA-262.
+  if (!IS_BOOLEAN(this) && !%HasBooleanClass(this))
+    throw new $TypeError('Boolean.prototype.valueOf is not generic');
+  return %_ValueOf(this);
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+function SetupBoolean() {
+  InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
+    "toString", BooleanToString,
+    "valueOf", BooleanValueOf
+  ));
+}
+
+SetupBoolean();
+
+// ----------------------------------------------------------------------------
+// Number
+
+// Set the Number function and constructor.
+%SetCode($Number, function(x) {
+  var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
+  if (%IsConstructCall()) {
+    %_SetValueOf(this, value);
+  } else {
+    return value;
+  }
+});
+
+%FunctionSetPrototype($Number, new $Number(0));
+
+// ECMA-262 section 15.7.4.2.
+function NumberToString(radix) {
+  // NOTE: Both Number objects and values can enter here as
+  // 'this'. This is not as dictated by ECMA-262.
+  var number = this;
+  if (!IS_NUMBER(this)) {
+    if (!%HasNumberClass(this))
+      throw new $TypeError('Number.prototype.toString is not generic');
+    // Get the value of this number in case it's an object.
+    number = %_ValueOf(this);
+  }
+  // Fast case: Convert number in radix 10.
+  if (IS_UNDEFINED(radix) || radix === 10) {
+    return ToString(number);
+  }
+
+  // Convert the radix to an integer and check the range.
+  radix = TO_INTEGER(radix);
+  if (radix < 2 || radix > 36) {
+    throw new $RangeError('toString() radix argument must be between 2 and 36');
+  }
+  // Convert the number to a string in the given radix.
+  return %NumberToRadixString(number, radix);
+}
+
+
+// ECMA-262 section 15.7.4.3
+function NumberToLocaleString() {
+  return this.toString();
+}
+
+
+// ECMA-262 section 15.7.4.4
+function NumberValueOf() {
+  // NOTE: Both Number objects and values can enter here as
+  // 'this'. This is not as dictated by ECMA-262.
+  if (!IS_NUMBER(this) && !%HasNumberClass(this))
+    throw new $TypeError('Number.prototype.valueOf is not generic');
+  return %_ValueOf(this);
+}
+
+
+// ECMA-262 section 15.7.4.5
+function NumberToFixed(fractionDigits) {
+  var f = TO_INTEGER(fractionDigits);
+  if (f < 0 || f > 20) {
+    throw new $RangeError("toFixed() digits argument must be between 0 and 20");
+  }
+  var x = ToNumber(this);
+  return %NumberToFixed(x, f);
+}
+
+
+// ECMA-262 section 15.7.4.6
+function NumberToExponential(fractionDigits) {
+  var f = -1;
+  if (!IS_UNDEFINED(fractionDigits)) {
+    f = TO_INTEGER(fractionDigits);
+    if (f < 0 || f > 20) {
+      throw new $RangeError("toExponential() argument must be between 0 and 20");
+    }
+  }
+  var x = ToNumber(this);
+  return %NumberToExponential(x, f);
+}
+
+
+// ECMA-262 section 15.7.4.7
+function NumberToPrecision(precision) {
+  if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
+  var p = TO_INTEGER(precision);
+  if (p < 1 || p > 21) {
+    throw new $RangeError("toPrecision() argument must be between 1 and 21");
+  }
+  var x = ToNumber(this);
+  return %NumberToPrecision(x, p);
+}
+
+
+// ----------------------------------------------------------------------------
+
+function SetupNumber() {
+  // Setup the constructor property on the Number prototype object.
+  %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
+
+  // ECMA-262 section 15.7.3.1.
+  %SetProperty($Number,
+               "MAX_VALUE",
+               1.7976931348623157e+308,
+               DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+  // ECMA-262 section 15.7.3.2.
+  %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+  // ECMA-262 section 15.7.3.3.
+  %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+  // ECMA-262 section 15.7.3.4.
+  %SetProperty($Number,
+               "NEGATIVE_INFINITY",
+               -1/0,
+               DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+  // ECMA-262 section 15.7.3.5.
+  %SetProperty($Number,
+               "POSITIVE_INFINITY",
+               1/0,
+               DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+  // Setup non-enumerable functions on the Number prototype object.
+  InstallFunctions($Number.prototype, DONT_ENUM, $Array(
+    "toString", NumberToString,
+    "toLocaleString", NumberToLocaleString,
+    "valueOf", NumberValueOf,
+    "toFixed", NumberToFixed,
+    "toExponential", NumberToExponential,
+    "toPrecision", NumberToPrecision
+  ));
+}
+
+SetupNumber();
+
+
+
+// ----------------------------------------------------------------------------
+// Function
+
+$Function.prototype.constructor = $Function;
+
+function FunctionSourceString(func) {
+  // NOTE: Both Function objects and values can enter here as
+  // 'func'. This is not as dictated by ECMA-262.
+  if (!IS_FUNCTION(func) && !%HasFunctionClass(func))
+    throw new $TypeError('Function.prototype.toString is not generic');
+
+  var source = %FunctionGetSourceCode(func);
+  if (!IS_STRING(source)) {
+    var name = %FunctionGetName(func);
+    if (name) {
+      // Mimic what KJS does.
+      return 'function ' + name + '() { [native code] }';
+    } else {
+      return 'function () { [native code] }';
+    }
+  }
+
+  // Censor occurrences of internal calls.  We do that for all
+  // functions and don't cache under the assumption that people rarly
+  // convert functions to strings.  Note that we (apparently) can't
+  // use regular expression literals in natives files.
+  var regexp = ORIGINAL_REGEXP("%(\\w+\\()", "gm");
+  if (source.match(regexp)) source = source.replace(regexp, "$1");
+  var name = %FunctionGetName(func);
+  return 'function ' + name + source;
+}
+
+
+function FunctionToString() {
+  return FunctionSourceString(this);
+}
+
+
+function NewFunction(arg1) {  // length == 1
+  var n = %_ArgumentsLength();
+  var p = '';
+  if (n > 1) {
+    p = new $Array(n - 1);
+    // Explicitly convert all parameters to strings.
+    // Array.prototype.join replaces null with empty strings which is
+    // not appropriate.
+    for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
+    p = p.join(',');
+    // If the formal parameters string include ) - an illegal
+    // character - it may make the combined function expression
+    // compile. We avoid this problem by checking for this early on.
+    if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
+  }
+  var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
+  var source = '(function(' + p + ') {\n' + body + '\n})';
+
+  // The call to SetNewFunctionAttributes will ensure the prototype
+  // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
+  var f = %CompileString(source, -1, false)();
+  %FunctionSetName(f, "anonymous");
+  return %SetNewFunctionAttributes(f);
+}
+
+%SetCode($Function, NewFunction);
+
+// ----------------------------------------------------------------------------
+
+function SetupFunction() {
+  InstallFunctions($Function.prototype, DONT_ENUM, $Array(
+    "toString", FunctionToString
+  ));
+}
+
+SetupFunction();
+
diff --git a/regexp2000/src/v8threads.cc b/regexp2000/src/v8threads.cc
new file mode 100644 (file)
index 0000000..2b4a027
--- /dev/null
@@ -0,0 +1,332 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "debug.h"
+#include "execution.h"
+#include "v8threads.h"
+
+namespace v8 {
+
+static internal::Thread::LocalStorageKey thread_state_key =
+    internal::Thread::CreateThreadLocalKey();
+
+// Constructor for the Locker object.  Once the Locker is constructed the
+// current thread will be guaranteed to have the big V8 lock.
+Locker::Locker() : has_lock_(false), top_level_(true) {
+  // Get the big lock if necessary.
+  if (!internal::ThreadManager::IsLockedByCurrentThread()) {
+    internal::ThreadManager::Lock();
+    has_lock_ = true;
+    // This may be a locker within an unlocker in which case we have to
+    // get the saved state for this thread and restore it.
+    if (internal::ThreadManager::RestoreThread()) {
+      top_level_ = false;
+    }
+  }
+  ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
+}
+
+
+bool Locker::IsLocked() {
+  return internal::ThreadManager::IsLockedByCurrentThread();
+}
+
+
+Locker::~Locker() {
+  ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
+  if (has_lock_) {
+    if (!top_level_) {
+      internal::ThreadManager::ArchiveThread();
+    }
+    internal::ThreadManager::Unlock();
+  }
+}
+
+
+Unlocker::Unlocker() {
+  ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
+  internal::ThreadManager::ArchiveThread();
+  internal::ThreadManager::Unlock();
+}
+
+
+Unlocker::~Unlocker() {
+  ASSERT(!internal::ThreadManager::IsLockedByCurrentThread());
+  internal::ThreadManager::Lock();
+  internal::ThreadManager::RestoreThread();
+}
+
+
+void Locker::StartPreemption(int every_n_ms) {
+  v8::internal::ContextSwitcher::StartPreemption(every_n_ms);
+}
+
+
+void Locker::StopPreemption() {
+  v8::internal::ContextSwitcher::StopPreemption();
+}
+
+
+namespace internal {
+
+
+bool ThreadManager::RestoreThread() {
+  // First check whether the current thread has been 'lazily archived', ie
+  // not archived at all.  If that is the case we put the state storage we
+  // had prepared back in the free list, since we didn't need it after all.
+  if (lazily_archived_thread_.IsSelf()) {
+    lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
+    ASSERT(Thread::GetThreadLocal(thread_state_key) ==
+           lazily_archived_thread_state_);
+    lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
+    lazily_archived_thread_state_ = NULL;
+    Thread::SetThreadLocal(thread_state_key, NULL);
+    return true;
+  }
+  // If there is another thread that was lazily archived then we have to really
+  // archive it now.
+  if (lazily_archived_thread_.IsValid()) {
+    EagerlyArchiveThread();
+  }
+  ThreadState* state =
+      reinterpret_cast<ThreadState*>(Thread::GetThreadLocal(thread_state_key));
+  if (state == NULL) {
+    return false;
+  }
+  char* from = state->data();
+  from = HandleScopeImplementer::RestoreThread(from);
+  from = Top::RestoreThread(from);
+  from = Debug::RestoreDebug(from);
+  from = StackGuard::RestoreStackGuard(from);
+  Thread::SetThreadLocal(thread_state_key, NULL);
+  state->Unlink();
+  state->LinkInto(ThreadState::FREE_LIST);
+  return true;
+}
+
+
+void ThreadManager::Lock() {
+  mutex_->Lock();
+  mutex_owner_.Initialize(ThreadHandle::SELF);
+  ASSERT(IsLockedByCurrentThread());
+}
+
+
+void ThreadManager::Unlock() {
+  mutex_owner_.Initialize(ThreadHandle::INVALID);
+  mutex_->Unlock();
+}
+
+
+static int ArchiveSpacePerThread() {
+  return HandleScopeImplementer::ArchiveSpacePerThread() +
+                            Top::ArchiveSpacePerThread() +
+                          Debug::ArchiveSpacePerThread() +
+                     StackGuard::ArchiveSpacePerThread();
+}
+
+
+ThreadState* ThreadState::free_anchor_ = new ThreadState();
+ThreadState* ThreadState::in_use_anchor_ = new ThreadState();
+
+
+ThreadState::ThreadState() : next_(this), previous_(this) {
+}
+
+
+void ThreadState::AllocateSpace() {
+  data_ = NewArray<char>(ArchiveSpacePerThread());
+}
+
+
+void ThreadState::Unlink() {
+  next_->previous_ = previous_;
+  previous_->next_ = next_;
+}
+
+
+void ThreadState::LinkInto(List list) {
+  ThreadState* flying_anchor =
+      list == FREE_LIST ? free_anchor_ : in_use_anchor_;
+  next_ = flying_anchor->next_;
+  previous_ = flying_anchor;
+  flying_anchor->next_ = this;
+  next_->previous_ = this;
+}
+
+
+ThreadState* ThreadState::GetFree() {
+  ThreadState* gotten = free_anchor_->next_;
+  if (gotten == free_anchor_) {
+    ThreadState* new_thread_state = new ThreadState();
+    new_thread_state->AllocateSpace();
+    return new_thread_state;
+  }
+  return gotten;
+}
+
+
+// Gets the first in the list of archived threads.
+ThreadState* ThreadState::FirstInUse() {
+  return in_use_anchor_->Next();
+}
+
+
+ThreadState* ThreadState::Next() {
+  if (next_ == in_use_anchor_) return NULL;
+  return next_;
+}
+
+
+Mutex* ThreadManager::mutex_ = OS::CreateMutex();
+ThreadHandle ThreadManager::mutex_owner_(ThreadHandle::INVALID);
+ThreadHandle ThreadManager::lazily_archived_thread_(ThreadHandle::INVALID);
+ThreadState* ThreadManager::lazily_archived_thread_state_ = NULL;
+
+
+void ThreadManager::ArchiveThread() {
+  ASSERT(!lazily_archived_thread_.IsValid());
+  ASSERT(Thread::GetThreadLocal(thread_state_key) == NULL);
+  ThreadState* state = ThreadState::GetFree();
+  state->Unlink();
+  Thread::SetThreadLocal(thread_state_key, reinterpret_cast<void*>(state));
+  lazily_archived_thread_.Initialize(ThreadHandle::SELF);
+  lazily_archived_thread_state_ = state;
+}
+
+
+void ThreadManager::EagerlyArchiveThread() {
+  ThreadState* state = lazily_archived_thread_state_;
+  state->LinkInto(ThreadState::IN_USE_LIST);
+  char* to = state->data();
+  to = HandleScopeImplementer::ArchiveThread(to);
+  to = Top::ArchiveThread(to);
+  to = Debug::ArchiveDebug(to);
+  to = StackGuard::ArchiveStackGuard(to);
+  lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
+  lazily_archived_thread_state_ = NULL;
+}
+
+
+void ThreadManager::Iterate(ObjectVisitor* v) {
+  // Expecting no threads during serialization/deserialization
+  for (ThreadState* state = ThreadState::FirstInUse();
+       state != NULL;
+       state = state->Next()) {
+    char* data = state->data();
+    data = HandleScopeImplementer::Iterate(v, data);
+    data = Top::Iterate(v, data);
+  }
+}
+
+
+void ThreadManager::MarkCompactPrologue() {
+  for (ThreadState* state = ThreadState::FirstInUse();
+       state != NULL;
+       state = state->Next()) {
+    char* data = state->data();
+    data += HandleScopeImplementer::ArchiveSpacePerThread();
+    Top::MarkCompactPrologue(data);
+  }
+}
+
+
+void ThreadManager::MarkCompactEpilogue() {
+  for (ThreadState* state = ThreadState::FirstInUse();
+       state != NULL;
+       state = state->Next()) {
+    char* data = state->data();
+    data += HandleScopeImplementer::ArchiveSpacePerThread();
+    Top::MarkCompactEpilogue(data);
+  }
+}
+
+
+ContextSwitcher::ContextSwitcher(int every_n_ms)
+  : preemption_semaphore_(OS::CreateSemaphore(0)),
+    keep_going_(true),
+    sleep_ms_(every_n_ms) {
+}
+
+
+static v8::internal::ContextSwitcher* switcher;
+
+
+void ContextSwitcher::StartPreemption(int every_n_ms) {
+  ASSERT(Locker::IsLocked());
+  if (switcher == NULL) {
+    switcher = new ContextSwitcher(every_n_ms);
+    switcher->Start();
+  } else {
+    switcher->sleep_ms_ = every_n_ms;
+  }
+}
+
+
+void ContextSwitcher::StopPreemption() {
+  ASSERT(Locker::IsLocked());
+  if (switcher != NULL) {
+    switcher->Stop();
+    delete(switcher);
+    switcher = NULL;
+  }
+}
+
+
+void ContextSwitcher::Run() {
+  while (keep_going_) {
+    OS::Sleep(sleep_ms_);
+    StackGuard::Preempt();
+    WaitForPreemption();
+  }
+}
+
+
+void ContextSwitcher::Stop() {
+  ASSERT(Locker::IsLocked());
+  keep_going_ = false;
+  preemption_semaphore_->Signal();
+  Join();
+}
+
+
+void ContextSwitcher::WaitForPreemption() {
+  preemption_semaphore_->Wait();
+}
+
+
+void ContextSwitcher::PreemptionReceived() {
+  ASSERT(Locker::IsLocked());
+  switcher->preemption_semaphore_->Signal();
+}
+
+
+}  // namespace internal
+}  // namespace v8
diff --git a/regexp2000/src/v8threads.h b/regexp2000/src/v8threads.h
new file mode 100644 (file)
index 0000000..f5c844d
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_V8THREADS_H_
+#define V8_V8THREADS_H_
+
+namespace v8 { namespace internal {
+
+
+class ThreadState {
+ public:
+  // Iterate over in-use states.
+  static ThreadState* FirstInUse();
+  // Returns NULL after the last one.
+  ThreadState* Next();
+
+  enum List {FREE_LIST, IN_USE_LIST};
+
+  void LinkInto(List list);
+  void Unlink();
+
+  static ThreadState* GetFree();
+
+  // Get data area for archiving a thread.
+  char* data() { return data_; }
+ private:
+  ThreadState();
+
+  void AllocateSpace();
+
+  char* data_;
+  ThreadState* next_;
+  ThreadState* previous_;
+  // In the following two lists there is always at least one object on the list.
+  // The first object is a flying anchor that is only there to simplify linking
+  // and unlinking.
+  // Head of linked list of free states.
+  static ThreadState* free_anchor_;
+  // Head of linked list of states in use.
+  static ThreadState* in_use_anchor_;
+};
+
+
+class ThreadManager : public AllStatic {
+ public:
+  static void Lock();
+  static void Unlock();
+
+  static void ArchiveThread();
+  static bool RestoreThread();
+
+  static void Iterate(ObjectVisitor* v);
+  static void MarkCompactPrologue();
+  static void MarkCompactEpilogue();
+  static bool IsLockedByCurrentThread() { return mutex_owner_.IsSelf(); }
+ private:
+  static void EagerlyArchiveThread();
+
+  static Mutex* mutex_;
+  static ThreadHandle mutex_owner_;
+  static ThreadHandle lazily_archived_thread_;
+  static ThreadState* lazily_archived_thread_state_;
+};
+
+
+class ContextSwitcher: public Thread {
+ public:
+  void Run();
+  static void StartPreemption(int every_n_ms);
+  static void StopPreemption();
+  static void PreemptionReceived();
+ private:
+  explicit ContextSwitcher(int every_n_ms);
+  void WaitForPreemption();
+  void Stop();
+  Semaphore* preemption_semaphore_;
+  bool keep_going_;
+  int sleep_ms_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_V8THREADS_H_
diff --git a/regexp2000/src/variables.cc b/regexp2000/src/variables.cc
new file mode 100644 (file)
index 0000000..d57ec1b
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "ast.h"
+#include "scopes.h"
+#include "variables.h"
+
+namespace v8 { namespace internal {
+
+// ----------------------------------------------------------------------------
+// Implementation UseCount.
+
+UseCount::UseCount()
+  : nreads_(0),
+    nwrites_(0) {
+}
+
+
+void UseCount::RecordRead(int weight) {
+  ASSERT(weight > 0);
+  nreads_ += weight;
+  // We must have a positive nreads_ here. Handle
+  // any kind of overflow by setting nreads_ to
+  // some large-ish value.
+  if (nreads_ <= 0) nreads_ = 1000000;
+  ASSERT(is_read() & is_used());
+}
+
+
+void UseCount::RecordWrite(int weight) {
+  ASSERT(weight > 0);
+  nwrites_ += weight;
+  // We must have a positive nwrites_ here. Handle
+  // any kind of overflow by setting nwrites_ to
+  // some large-ish value.
+  if (nwrites_ <= 0) nwrites_ = 1000000;
+  ASSERT(is_written() && is_used());
+}
+
+
+void UseCount::RecordAccess(int weight) {
+  RecordRead(weight);
+  RecordWrite(weight);
+}
+
+
+void UseCount::RecordUses(UseCount* uses) {
+  if (uses->nreads() > 0) RecordRead(uses->nreads());
+  if (uses->nwrites() > 0) RecordWrite(uses->nwrites());
+}
+
+
+#ifdef DEBUG
+void UseCount::Print() {
+  // PrintF("r = %d, w = %d", nreads_, nwrites_);
+  PrintF("%du = %dr + %dw", nuses(), nreads(), nwrites());
+}
+#endif
+
+
+// ----------------------------------------------------------------------------
+// Implementation Variable.
+
+
+const char* Variable::Mode2String(Mode mode) {
+  switch (mode) {
+    case VAR: return "VAR";
+    case CONST: return "CONST";
+    case DYNAMIC: return "DYNAMIC";
+    case INTERNAL: return "INTERNAL";
+    case TEMPORARY: return "TEMPORARY";
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+Property* Variable::AsProperty() {
+  return rewrite_ == NULL ? NULL : rewrite_->AsProperty();
+}
+
+
+Variable* Variable::AsVariable()  {
+  return rewrite_ == NULL || rewrite_->AsSlot() != NULL ? this : NULL;
+}
+
+
+Slot* Variable::slot() const {
+  return rewrite_ != NULL ? rewrite_->AsSlot() : NULL;
+}
+
+
+Variable::Variable(Scope* scope,
+                   Handle<String> name,
+                   Mode mode,
+                   bool is_valid_LHS,
+                   bool is_this)
+  : scope_(scope),
+    name_(name),
+    mode_(mode),
+    is_valid_LHS_(is_valid_LHS),
+    is_this_(is_this),
+    is_accessed_from_inner_scope_(false),
+    rewrite_(NULL) {
+  // names must be canonicalized for fast equality checks
+  ASSERT(name->IsSymbol());
+}
+
+
+bool Variable::is_global() const {
+  // Temporaries are never global, they must always be allocated in the
+  // activation frame.
+  return mode_ != TEMPORARY && scope_ != NULL && scope_->is_global_scope();
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/variables.h b/regexp2000/src/variables.h
new file mode 100644 (file)
index 0000000..6a4b3c5
--- /dev/null
@@ -0,0 +1,145 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_VARIABLES_H_
+#define V8_VARIABLES_H_
+
+#include "zone.h"
+
+namespace v8 { namespace internal {
+
+class UseCount BASE_EMBEDDED {
+ public:
+  UseCount();
+
+  // Inform the node of a "use". The weight can be used to indicate
+  // heavier use, for instance if the variable is accessed inside a loop.
+  void RecordRead(int weight);
+  void RecordWrite(int weight);
+  void RecordAccess(int weight);  // records a read & write
+  void RecordUses(UseCount* uses);
+
+  int nreads() const  { return nreads_; }
+  int nwrites() const  { return nwrites_; }
+  int nuses() const  { return nreads_ + nwrites_; }
+
+  bool is_read() const  { return nreads() > 0; }
+  bool is_written() const  { return nwrites() > 0; }
+  bool is_used() const  { return nuses() > 0; }
+
+#ifdef DEBUG
+  void Print();
+#endif
+
+ private:
+  int nreads_;
+  int nwrites_;
+};
+
+
+// The AST refers to variables via VariableProxies - placeholders for the actual
+// variables. Variables themselves are never directly referred to from the AST,
+// they are maintained by scopes, and referred to from VariableProxies and Slots
+// after binding and variable allocation.
+
+class Variable: public ZoneObject {
+ public:
+  enum Mode {
+    // User declared variables:
+    VAR,       // declared via 'var', and 'function' declarations
+    CONST,     // declared via 'const' declarations
+
+    // Variables introduced by the compiler:
+    DYNAMIC,   // always require dynamic lookup (we don't know the declaration)
+    INTERNAL,  // like VAR, but not user-visible (may or may not be in a
+               // context)
+    TEMPORARY  // temporary variables (not user-visible), never in a context
+  };
+
+  // Printing support
+  static const char* Mode2String(Mode mode);
+
+  // Type testing & conversion
+  Property* AsProperty();
+  Variable* AsVariable();
+  bool IsValidLeftHandSide() { return is_valid_LHS_; }
+
+  // The source code for an eval() call may refer to a variable that is
+  // in an outer scope about which we don't know anything (it may not
+  // be the global scope). scope() is NULL in that case. Currently the
+  // scope is only used to follow the context chain length.
+  Scope* scope() const  { return scope_; }
+  // If this assertion fails it means that some code has tried to
+  // treat the special this variable as an ordinary variable with
+  // the name "this".
+  Handle<String> name() const  { return name_; }
+  Mode mode() const  { return mode_; }
+  bool is_accessed_from_inner_scope() const  {
+    return is_accessed_from_inner_scope_;
+  }
+  UseCount* var_uses()  { return &var_uses_; }
+  UseCount* obj_uses()  { return &obj_uses_; }
+
+  bool IsVariable(Handle<String> n) {
+    return !is_this() && name().is_identical_to(n);
+  }
+
+  bool is_global() const;
+  bool is_this() const { return is_this_; }
+
+  Expression* rewrite() const  { return rewrite_; }
+  Slot* slot() const;
+
+ private:
+  Variable(Scope* scope, Handle<String> name, Mode mode, bool is_valid_LHS,
+      bool is_this);
+
+  Scope* scope_;
+  Handle<String> name_;
+  Mode mode_;
+  bool is_valid_LHS_;
+  bool is_this_;
+
+  // Usage info.
+  bool is_accessed_from_inner_scope_;  // set by variable resolver
+  UseCount var_uses_;  // uses of the variable value
+  UseCount obj_uses_;  // uses of the object the variable points to
+
+  // Code generation.
+  // rewrite_ is usually a Slot or a Property, but maybe any expression.
+  Expression* rewrite_;
+
+  friend class VariableProxy;
+  friend class Scope;
+  friend class LocalsMap;
+  friend class AstBuildingParser;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_VARIABLES_H_
diff --git a/regexp2000/src/zone-inl.h b/regexp2000/src/zone-inl.h
new file mode 100644 (file)
index 0000000..7ed4e6b
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ZONE_INL_H_
+#define V8_ZONE_INL_H_
+
+#include "zone.h"
+
+namespace v8 { namespace internal {
+
+
+inline void* Zone::New(int size) {
+  ASSERT(AssertNoZoneAllocation::allow_allocation());
+  // Round up the requested size to fit the alignment.
+  size = RoundUp(size, kAlignment);
+
+  // Check if the requested size is available without expanding.
+  Address result = position_;
+  if ((position_ += size) > limit_) result = NewExpand(size);
+
+  // Check that the result has the proper alignment and return it.
+  ASSERT(IsAddressAligned(result, kAlignment, 0));
+  return reinterpret_cast<void*>(result);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ZONE_INL_H_
diff --git a/regexp2000/src/zone.cc b/regexp2000/src/zone.cc
new file mode 100644 (file)
index 0000000..d37f4f7
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "zone-inl.h"
+
+namespace v8 { namespace internal {
+
+
+Address Zone::position_ = 0;
+Address Zone::limit_ = 0;
+
+bool AssertNoZoneAllocation::allow_allocation_ = true;
+
+int ZoneScope::nesting_ = 0;
+
+// Segments represent chunks of memory: They have starting address
+// (encoded in the this pointer) and a size in bytes. Segments are
+// chained together forming a LIFO structure with the newest segment
+// available as Segment::head(). Segments are allocated using malloc()
+// and de-allocated using free().
+
+class Segment {
+ public:
+  Segment* next() const { return next_; }
+  void clear_next() { next_ = NULL; }
+
+  int size() const { return size_; }
+  int capacity() const { return size_ - sizeof(Segment); }
+
+  Address start() const { return address(sizeof(Segment)); }
+  Address end() const { return address(size_); }
+
+  static Segment* head() { return head_; }
+  static void set_head(Segment* head) { head_ = head; }
+
+  // Creates a new segment, sets it size, and pushes it to the front
+  // of the segment chain. Returns the new segment.
+  static Segment* New(int size) {
+    Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
+    if (result != NULL) {
+      result->next_ = head_;
+      result->size_ = size;
+      head_ = result;
+    }
+    return result;
+  }
+
+  // Deletes the given segment. Does not touch the segment chain.
+  static void Delete(Segment* segment) {
+    Malloced::Delete(segment);
+  }
+
+ private:
+  // Computes the address of the nth byte in this segment.
+  Address address(int n) const {
+    return Address(this) + n;
+  }
+
+  static Segment* head_;
+  Segment* next_;
+  int size_;
+};
+
+
+Segment* Segment::head_ = NULL;
+
+
+void Zone::DeleteAll() {
+#ifdef DEBUG
+  // Constant byte value used for zapping dead memory in debug mode.
+  static const unsigned char kZapDeadByte = 0xcd;
+#endif
+
+  // Find a segment with a suitable size to keep around.
+  Segment* keep = Segment::head();
+  while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) {
+    keep = keep->next();
+  }
+
+  // Traverse the chained list of segments, zapping (in debug mode)
+  // and freeing every segment except the one we wish to keep.
+  Segment* current = Segment::head();
+  while (current != NULL) {
+    Segment* next = current->next();
+    if (current == keep) {
+      // Unlink the segment we wish to keep from the list.
+      current->clear_next();
+    } else {
+#ifdef DEBUG
+      // Zap the entire current segment (including the header).
+      memset(current, kZapDeadByte, current->size());
+#endif
+      Segment::Delete(current);
+    }
+    current = next;
+  }
+
+  // If we have found a segment we want to keep, we must recompute the
+  // variables 'position' and 'limit' to prepare for future allocate
+  // attempts. Otherwise, we must clear the position and limit to
+  // force a new segment to be allocated on demand.
+  if (keep != NULL) {
+    Address start = keep->start();
+    position_ = RoundUp(start, kAlignment);
+    limit_ = keep->end();
+#ifdef DEBUG
+    // Zap the contents of the kept segment (but not the header).
+    memset(start, kZapDeadByte, keep->capacity());
+#endif
+  } else {
+    position_ = limit_ = 0;
+  }
+
+  // Update the head segment to be the kept segment (if any).
+  Segment::set_head(keep);
+}
+
+
+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_);
+
+  // Compute the new segment size. We use a 'high water mark'
+  // strategy, where we increase the segment size every time we expand
+  // except that we employ a maximum segment size when we delete. This
+  // is to avoid excessive malloc() and free() overhead.
+  Segment* head = Segment::head();
+  int old_size = (head == NULL) ? 0 : head->size();
+  int new_size = sizeof(Segment) + kAlignment + size + (old_size << 1);
+  if (new_size < kMinimumSegmentSize) new_size = kMinimumSegmentSize;
+  Segment* segment = Segment::New(new_size);
+  if (segment == NULL) V8::FatalProcessOutOfMemory("Zone");
+
+  // Recompute 'top' and 'limit' based on the new segment.
+  Address result = RoundUp(segment->start(), kAlignment);
+  position_ = result + size;
+  limit_ = segment->end();
+  ASSERT(position_ <= limit_);
+  return result;
+}
+
+
+} }  // namespace v8::internal
diff --git a/regexp2000/src/zone.h b/regexp2000/src/zone.h
new file mode 100644 (file)
index 0000000..c7129ec
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ZONE_H_
+#define V8_ZONE_H_
+
+namespace v8 { namespace internal {
+
+
+// Zone scopes are in one of two modes.  Either they delete the zone
+// on exit or they do not.
+enum ZoneScopeMode {
+  DELETE_ON_EXIT,
+  DONT_DELETE_ON_EXIT
+};
+
+
+// The Zone supports very fast allocation of small chunks of
+// memory. The chunks cannot be deallocated individually, but instead
+// the Zone supports deallocating all chunks in one fast
+// operation. The Zone is used to hold temporary data structures like
+// the abstract syntax tree, which is deallocated after compilation.
+
+// Note: There is no need to initialize the Zone; the first time an
+// allocation is attempted, a segment of memory will be requested
+// through a call to malloc().
+
+// Note: The implementation is inherently not thread safe. Do not use
+// from multi-threaded code.
+
+class Zone {
+ public:
+  // Allocate 'size' bytes of memory in the Zone; expands the Zone by
+  // allocating new segments of memory on demand using malloc().
+  static inline void* New(int size);
+
+  // Delete all objects and free all memory allocated in the Zone.
+  static void DeleteAll();
+
+ private:
+  // All pointers returned from New() have this alignment.
+  static const int kAlignment = kPointerSize;
+
+  // Never allocate segments smaller than this size in bytes.
+  static const int kMinimumSegmentSize = 8 * KB;
+
+  // Never keep segments larger than this size in bytes around.
+  static const int kMaximumKeptSegmentSize = 64 * KB;
+
+
+  // The Zone is intentionally a singleton; you should not try to
+  // allocate instances of the class.
+  Zone() { UNREACHABLE(); }
+
+
+  // Expand the Zone to hold at least 'size' more bytes and allocate
+  // the bytes. Returns the address of the newly allocated chunk of
+  // memory in the Zone. Should only be called if there isn't enough
+  // room in the Zone already.
+  static Address NewExpand(int size);
+
+
+  // The free region in the current (front) segment is represented as
+  // the half-open interval [position, limit). The 'position' variable
+  // is guaranteed to be aligned as dictated by kAlignment.
+  static Address position_;
+  static Address limit_;
+};
+
+
+// ZoneObject is an abstraction that helps define classes of objects
+// allocated in the Zone. Use it as a base class; see ast.h.
+class ZoneObject {
+ public:
+  // Allocate a new ZoneObject of 'size' bytes in the Zone.
+  void* operator new(size_t size) { return Zone::New(size); }
+
+  // Ideally, the delete operator should be private instead of
+  // public, but unfortuately the compiler sometimes synthesizes
+  // (unused) destructors for classes derived from ZoneObject, which
+  // require the operator to be visible. MSVC requires the delete
+  // operator to be public.
+
+  // ZoneObjects should never be deleted individually; use
+  // Zone::DeleteAll() to delete all zone objects in one go.
+  void operator delete(void*, size_t) { UNREACHABLE(); }
+};
+
+
+class AssertNoZoneAllocation {
+ public:
+  AssertNoZoneAllocation() : prev_(allow_allocation_) {
+    allow_allocation_ = false;
+  }
+  ~AssertNoZoneAllocation() { allow_allocation_ = prev_; }
+  static bool allow_allocation() { return allow_allocation_; }
+ private:
+  bool prev_;
+  static bool allow_allocation_;
+};
+
+
+// The ZoneListAllocationPolicy is used to specialize the GenericList
+// implementation to allocate ZoneLists and their elements in the
+// Zone.
+class ZoneListAllocationPolicy {
+ public:
+  // Allocate 'size' bytes of memory in the zone.
+  static void* New(int size) {  return Zone::New(size); }
+
+  // De-allocation attempts are silently ignored.
+  static void Delete(void* p) { }
+};
+
+
+// ZoneLists are growable lists with constant-time access to the
+// elements. The list itself and all its elements are allocated in the
+// Zone. ZoneLists cannot be deleted individually; you can delete all
+// objects in the Zone by calling Zone::DeleteAll().
+template<typename T>
+class ZoneList: public List<T, ZoneListAllocationPolicy> {
+ public:
+  // Construct a new ZoneList with the given capacity; the length is
+  // always zero. The capacity must be non-negative.
+  explicit ZoneList(int capacity)
+      : List<T, ZoneListAllocationPolicy>(capacity) { }
+};
+
+
+// ZoneScopes keep track of the current parsing and compilation
+// nesting and cleans up generated ASTs in the Zone when exiting the
+// outer-most scope.
+class ZoneScope BASE_EMBEDDED {
+ public:
+  explicit ZoneScope(ZoneScopeMode mode) : mode_(mode) {
+    nesting_++;
+  }
+
+  ~ZoneScope() {
+    if (--nesting_ == 0 && mode_ == DELETE_ON_EXIT) Zone::DeleteAll();
+  }
+
+  // For ZoneScopes that do not delete on exit by default, call this
+  // method to request deletion on exit.
+  void DeleteOnExit() {
+    mode_ = DELETE_ON_EXIT;
+  }
+
+ private:
+  ZoneScopeMode mode_;
+  static int nesting_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ZONE_H_
diff --git a/regexp2000/test/cctest/SConscript b/regexp2000/test/cctest/SConscript
new file mode 100644 (file)
index 0000000..78ad579
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+from os.path import join, dirname, abspath
+root_dir = dirname(File('SConstruct').rfile().abspath)
+sys.path.append(join(root_dir, 'tools'))
+Import('context object_files')
+
+
+SOURCES = {
+  'all': [
+    'test-hashmap.cc', 'test-debug.cc', 'test-api.cc', 'test-flags.cc',
+    'test-ast.cc', 'test-heap.cc', 'test-utils.cc', 'test-compiler.cc',
+    'test-spaces.cc', 'test-mark-compact.cc', 'test-lock.cc',
+    'test-conversions.cc', 'test-strings.cc', 'test-serialize.cc',
+    'test-decls.cc', 'test-regexp.cc'
+  ],
+  'arch:arm':  ['test-assembler-arm.cc', 'test-disasm-arm.cc'],
+  'arch:ia32': ['test-assembler-ia32.cc', 'test-disasm-ia32.cc'],
+  'os:linux':  ['test-platform-linux.cc'],
+  'os:macos':  ['test-platform-macos.cc'],
+  'os:nullos': ['test-platform-nullos.cc'],
+  'os:win32':  ['test-platform-win32.cc']
+}
+
+
+def Build():
+  cctest_files = context.GetRelevantSources(SOURCES)
+  env = Environment()
+  env.Replace(**context.flags['cctest'])
+  context.ApplyEnvOverrides(env)
+  # There seems to be a glitch in the way scons decides where to put
+  # PDB files when compiling using MSVC so we specify it manually.
+  # This should not affect any other platforms.
+  return env.Program('cctest', ['cctest.cc', cctest_files, object_files],
+      PDB='cctest.exe.pdb')
+
+
+program = Build()
+Return('program')
diff --git a/regexp2000/test/cctest/cctest.cc b/regexp2000/test/cctest/cctest.cc
new file mode 100644 (file)
index 0000000..e9c8f0d
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <v8.h>
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+#include "cctest.h"
+
+
+CcTest* CcTest::last_ = NULL;
+
+
+CcTest::CcTest(TestFunction* callback, const char* file,
+               const char* name, bool enabled)
+    : callback_(callback), name_(name), prev_(last_) {
+  // Find the base name of this test (const_cast required on Windows).
+  char *basename = strrchr(const_cast<char *>(file), '/');
+  if (!basename) {
+    basename = strrchr(const_cast<char *>(file), '\\');
+  }
+  if (!basename) {
+    basename = v8::internal::OS::StrDup(file);
+  } else {
+    basename = v8::internal::OS::StrDup(basename + 1);
+  }
+  // Drop the extension, if there is one.
+  char *extension = strrchr(basename, '.');
+  if (extension) *extension = 0;
+  // Install this test in the list of tests
+  file_ = basename;
+  enabled_ = enabled;
+  prev_ = last_;
+  last_ = this;
+}
+
+
+static void PrintTestList(CcTest* current) {
+  if (current == NULL) return;
+  PrintTestList(current->prev());
+  printf("%s/%s\n", current->file(), current->name());
+}
+
+
+int main(int argc, char* argv[]) {
+  v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
+  int tests_run = 0;
+  bool print_run_count = true;
+  for (int i = 1; i < argc; i++) {
+    char* arg = argv[i];
+    if (strcmp(arg, "--list") == 0) {
+      PrintTestList(CcTest::last());
+      print_run_count = false;
+
+    } else {
+      char* arg_copy = v8::internal::OS::StrDup(arg);
+      char* testname = strchr(arg_copy, '/');
+      if (testname) {
+        // Split the string in two by nulling the slash and then run
+        // exact matches.
+        *testname = 0;
+        char* file = arg_copy;
+        char* name = testname + 1;
+        CcTest* test = CcTest::last();
+        while (test != NULL) {
+          if (test->enabled()
+              && strcmp(test->file(), file) == 0
+              && strcmp(test->name(), name) == 0) {
+            test->Run();
+            tests_run++;
+          }
+          test = test->prev();
+        }
+
+      } else {
+        // Run all tests with the specified file or test name.
+        char* file_or_name = arg_copy;
+        CcTest* test = CcTest::last();
+        while (test != NULL) {
+          if (test->enabled()
+              && (strcmp(test->file(), file_or_name) == 0
+                  || strcmp(test->name(), file_or_name) == 0)) {
+            test->Run();
+            tests_run++;
+          }
+          test = test->prev();
+        }
+      }
+      free(arg_copy);
+    }
+  }
+  if (print_run_count && tests_run != 1)
+    printf("Ran %i tests.\n", tests_run);
+  return 0;
+}
diff --git a/regexp2000/test/cctest/cctest.h b/regexp2000/test/cctest/cctest.h
new file mode 100644 (file)
index 0000000..8646479
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CCTEST_H_
+#define CCTEST_H_
+
+#ifndef TEST
+#define TEST(Name)                                                   \
+  static void Test##Name();                                          \
+  CcTest register_test_##Name(Test##Name, __FILE__, #Name, true);    \
+  static void Test##Name()
+#endif
+
+#ifndef DISABLED_TEST
+#define DISABLED_TEST(Name)                                          \
+  static void Test##Name();                                          \
+  CcTest register_test_##Name(Test##Name, __FILE__, #Name, false);   \
+  static void Test##Name()
+#endif
+
+
+class CcTest {
+ public:
+  typedef void (TestFunction)();
+  CcTest(TestFunction* callback, const char* file, const char* name,
+         bool enabled);
+  void Run() { callback_(); }
+  static int test_count();
+  static CcTest* last() { return last_; }
+  CcTest* prev() { return prev_; }
+  const char* file() { return file_; }
+  const char* name() { return name_; }
+  bool enabled() { return enabled_; }
+ private:
+  TestFunction* callback_;
+  const char* file_;
+  const char* name_;
+  bool enabled_;
+  static CcTest* last_;
+  CcTest* prev_;
+};
+
+#endif  // ifndef CCTEST_H_
diff --git a/regexp2000/test/cctest/cctest.status b/regexp2000/test/cctest/cctest.status
new file mode 100644 (file)
index 0000000..b3f71d9
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+prefix cctest
+
+# BUG(96): Fix this flaky test.
+test-debug/ThreadedDebugging: PASS || FAIL
+
+[ $arch == arm ]
+
+test-debug: SKIP
+test-serialize: SKIP
+test-api: SKIP
+
+# BUG(113): Test seems flaky on ARM.
+test-spaces/LargeObjectSpace: PASS || FAIL
diff --git a/regexp2000/test/cctest/test-api.cc b/regexp2000/test/cctest/test-api.cc
new file mode 100644 (file)
index 0000000..0b4f6e5
--- /dev/null
@@ -0,0 +1,5077 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include <map>
+#include <string>
+
+#include "v8.h"
+
+#include "api.h"
+#include "snapshot.h"
+#include "platform.h"
+#include "top.h"
+#include "cctest.h"
+
+static bool IsNaN(double x) {
+#ifdef WIN32
+  return _isnan(x);
+#else
+  return isnan(x);
+#endif
+}
+
+using ::v8::ObjectTemplate;
+using ::v8::Value;
+using ::v8::Context;
+using ::v8::Local;
+using ::v8::String;
+using ::v8::Script;
+using ::v8::Function;
+using ::v8::AccessorInfo;
+using ::v8::Extension;
+
+namespace i = ::v8::internal;
+
+static Local<Value> v8_num(double x) {
+  return v8::Number::New(x);
+}
+
+
+static Local<String> v8_str(const char* x) {
+  return String::New(x);
+}
+
+
+static Local<Script> v8_compile(const char* x) {
+  return Script::Compile(v8_str(x));
+}
+
+
+// A LocalContext holds a reference to a v8::Context.
+class LocalContext {
+ public:
+  LocalContext(v8::ExtensionConfiguration* extensions = 0,
+               v8::Handle<ObjectTemplate> global_template =
+                   v8::Handle<ObjectTemplate>(),
+               v8::Handle<Value> global_object = v8::Handle<Value>())
+    : context_(Context::New(extensions, global_template, global_object)) {
+    context_->Enter();
+  }
+
+  virtual ~LocalContext() {
+    context_->Exit();
+    context_.Dispose();
+  }
+
+  Context* operator->() { return *context_; }
+  Context* operator*() { return *context_; }
+  Local<Context> local() { return Local<Context>::New(context_); }
+  bool IsReady() { return !context_.IsEmpty(); }
+
+ private:
+  v8::Persistent<Context> context_;
+};
+
+
+// Switches between all the Api tests using the threading support.
+// In order to get a surprising but repeatable pattern of thread
+// switching it has extra semaphores to control the order in which
+// the tests alternate, not relying solely on the big V8 lock.
+//
+// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
+// callbacks.  This will have no effect when we are not running the
+// thread fuzzing test.  In the thread fuzzing test it will
+// pseudorandomly select a successor thread and switch execution
+// to that thread, suspending the current test.
+class ApiTestFuzzer: public v8::internal::Thread {
+ public:
+  void CallTest();
+  explicit ApiTestFuzzer(int num)
+      : test_number_(num),
+        gate_(v8::internal::OS::CreateSemaphore(0)),
+        active_(true) {
+  }
+
+  // The ApiTestFuzzer is also a Thread, so it has a Run method.
+  virtual void Run();
+
+  enum PartOfTest { FIRST_PART, SECOND_PART };
+
+  static void Setup(PartOfTest part);
+  static void RunAllTests();
+  static void TearDown();
+  // This method switches threads if we are running the Threading test.
+  // Otherwise it does nothing.
+  static void Fuzz();
+ private:
+  static bool fuzzing_;
+  static int tests_being_run_;
+  static int current_;
+  static int active_tests_;
+  static bool NextThread();
+  int test_number_;
+  v8::internal::Semaphore* gate_;
+  bool active_;
+  void ContextSwitch();
+  static int GetNextTestNumber();
+  static v8::internal::Semaphore* all_tests_done_;
+};
+
+
+#define THREADED_TEST(Name)                                          \
+  static void Test##Name();                                          \
+  RegisterThreadedTest register_##Name(Test##Name);                  \
+  /* */ TEST(Name)
+
+
+class RegisterThreadedTest {
+ public:
+  explicit RegisterThreadedTest(CcTest::TestFunction* callback)
+      : callback_(callback) {
+    prev_ = first_;
+    first_ = this;
+    count_++;
+  }
+  static int count() { return count_; }
+  static RegisterThreadedTest* nth(int i) {
+    ASSERT(i < count());
+    RegisterThreadedTest* current = first_;
+    while (i > 0) {
+      i--;
+      current = current->prev_;
+    }
+    return current;
+  }
+  CcTest::TestFunction* callback() { return callback_; }
+  ApiTestFuzzer* fuzzer_;
+
+ private:
+  static RegisterThreadedTest* first_;
+  static int count_;
+  CcTest::TestFunction* callback_;
+  RegisterThreadedTest* prev_;
+};
+
+
+RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
+int RegisterThreadedTest::count_ = 0;
+
+
+static int signature_callback_count;
+static v8::Handle<Value> IncrementingSignatureCallback(
+    const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  signature_callback_count++;
+  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
+  for (int i = 0; i < args.Length(); i++)
+    result->Set(v8::Integer::New(i), args[i]);
+  return result;
+}
+
+
+static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
+  for (int i = 0; i < args.Length(); i++) {
+    result->Set(v8::Integer::New(i), args[i]);
+  }
+  return result;
+}
+
+
+THREADED_TEST(Handles) {
+  v8::HandleScope scope;
+  Local<Context> local_env;
+  {
+    LocalContext env;
+    local_env = env.local();
+  }
+
+  // Local context should still be live.
+  CHECK(!local_env.IsEmpty());
+  local_env->Enter();
+
+  v8::Handle<v8::Primitive> undef = v8::Undefined();
+  CHECK(!undef.IsEmpty());
+  CHECK(undef->IsUndefined());
+
+  const char* c_source = "1 + 2 + 3";
+  Local<String> source = String::New(c_source);
+  Local<Script> script = Script::Compile(source);
+  CHECK_EQ(6, script->Run()->Int32Value());
+
+  local_env->Exit();
+}
+
+
+// Helper function that compiles and runs the source.
+static Local<Value> CompileRun(const char* source) {
+  return Script::Compile(String::New(source))->Run();
+}
+
+THREADED_TEST(ReceiverSignature) {
+  v8::HandleScope scope;
+  LocalContext env;
+  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
+  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
+  fun->PrototypeTemplate()->Set(
+      v8_str("m"),
+      v8::FunctionTemplate::New(IncrementingSignatureCallback,
+                                v8::Handle<Value>(),
+                                sig));
+  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
+  signature_callback_count = 0;
+  CompileRun(
+      "var o = new Fun();"
+      "o.m();");
+  CHECK_EQ(1, signature_callback_count);
+  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
+  sub_fun->Inherit(fun);
+  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
+  CompileRun(
+      "var o = new SubFun();"
+      "o.m();");
+  CHECK_EQ(2, signature_callback_count);
+
+  v8::TryCatch try_catch;
+  CompileRun(
+      "var o = { };"
+      "o.m = Fun.prototype.m;"
+      "o.m();");
+  CHECK_EQ(2, signature_callback_count);
+  CHECK(try_catch.HasCaught());
+  try_catch.Reset();
+  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
+  sub_fun->Inherit(fun);
+  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
+  CompileRun(
+      "var o = new UnrelFun();"
+      "o.m = Fun.prototype.m;"
+      "o.m();");
+  CHECK_EQ(2, signature_callback_count);
+  CHECK(try_catch.HasCaught());
+}
+
+
+
+
+THREADED_TEST(ArgumentSignature) {
+  v8::HandleScope scope;
+  LocalContext env;
+  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
+  cons->SetClassName(v8_str("Cons"));
+  v8::Handle<v8::Signature> sig =
+      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
+  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
+  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
+
+  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
+  ASSERT(value1->IsTrue());
+
+  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
+  ASSERT(value2->IsTrue());
+
+  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
+  ASSERT(value3->IsTrue());
+
+  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
+  cons1->SetClassName(v8_str("Cons1"));
+  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
+  cons2->SetClassName(v8_str("Cons2"));
+  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
+  cons3->SetClassName(v8_str("Cons3"));
+
+  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
+  v8::Handle<v8::Signature> wsig =
+      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
+  v8::Handle<v8::FunctionTemplate> fun2 =
+      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
+
+  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
+  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
+  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
+  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
+  v8::Handle<Value> value4 = CompileRun(
+      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
+      "'[object Cons1],[object Cons2],[object Cons3]'");
+  ASSERT(value4->IsTrue());
+
+  v8::Handle<Value> value5 = CompileRun(
+      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
+  ASSERT(value5->IsTrue());
+
+  v8::Handle<Value> value6 = CompileRun(
+      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
+  ASSERT(value6->IsTrue());
+
+  v8::Handle<Value> value7 = CompileRun(
+      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
+      "'[object Cons1],[object Cons2],[object Cons3],d';");
+  ASSERT(value7->IsTrue());
+
+  v8::Handle<Value> value8 = CompileRun(
+      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
+  ASSERT(value8->IsTrue());
+}
+
+
+THREADED_TEST(HulIgennem) {
+  v8::HandleScope scope;
+  LocalContext env;
+  v8::Handle<v8::Primitive> undef = v8::Undefined();
+  Local<String> undef_str = undef->ToString();
+  char* value = i::NewArray<char>(undef_str->Length() + 1);
+  undef_str->WriteAscii(value);
+  CHECK_EQ(0, strcmp(value, "undefined"));
+  i::DeleteArray(value);
+}
+
+
+THREADED_TEST(Access) {
+  v8::HandleScope scope;
+  LocalContext env;
+  Local<v8::Object> obj = v8::Object::New();
+  Local<Value> foo_before = obj->Get(v8_str("foo"));
+  CHECK(foo_before->IsUndefined());
+  Local<String> bar_str = v8_str("bar");
+  obj->Set(v8_str("foo"), bar_str);
+  Local<Value> foo_after = obj->Get(v8_str("foo"));
+  CHECK(!foo_after->IsUndefined());
+  CHECK(foo_after->IsString());
+  CHECK_EQ(bar_str, foo_after);
+}
+
+
+THREADED_TEST(Script) {
+  v8::HandleScope scope;
+  LocalContext env;
+  const char* c_source = "1 + 2 + 3";
+  Local<String> source = String::New(c_source);
+  Local<Script> script = Script::Compile(source);
+  CHECK_EQ(6, script->Run()->Int32Value());
+}
+
+
+static uint16_t* AsciiToTwoByteString(const char* source) {
+  size_t array_length = strlen(source) + 1;
+  uint16_t* converted = i::NewArray<uint16_t>(array_length);
+  for (size_t i = 0; i < array_length; i++) converted[i] = source[i];
+  return converted;
+}
+
+
+class TestResource: public String::ExternalStringResource {
+ public:
+  static int dispose_count;
+
+  explicit TestResource(uint16_t* data)
+      : data_(data), length_(0) {
+    while (data[length_]) ++length_;
+  }
+
+  ~TestResource() {
+    i::DeleteArray(data_);
+    ++dispose_count;
+  }
+
+  const uint16_t* data() const {
+    return data_;
+  }
+
+  size_t length() const {
+    return length_;
+  }
+ private:
+  uint16_t* data_;
+  size_t length_;
+};
+
+
+int TestResource::dispose_count = 0;
+
+
+class TestAsciiResource: public String::ExternalAsciiStringResource {
+ public:
+  static int dispose_count;
+
+  explicit TestAsciiResource(char* data)
+      : data_(data),
+        length_(strlen(data)) { }
+
+  ~TestAsciiResource() {
+    i::DeleteArray(data_);
+    ++dispose_count;
+  }
+
+  const char* data() const {
+    return data_;
+  }
+
+  size_t length() const {
+    return length_;
+  }
+ private:
+  char* data_;
+  size_t length_;
+};
+
+
+int TestAsciiResource::dispose_count = 0;
+
+
+THREADED_TEST(ScriptUsingStringResource) {
+  TestResource::dispose_count = 0;
+  const char* c_source = "1 + 2 * 3";
+  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
+  {
+    v8::HandleScope scope;
+    LocalContext env;
+    TestResource* resource = new TestResource(two_byte_source);
+    Local<String> source = String::NewExternal(resource);
+    Local<Script> script = Script::Compile(source);
+    Local<Value> value = script->Run();
+    CHECK(value->IsNumber());
+    CHECK_EQ(7, value->Int32Value());
+    CHECK(source->IsExternal());
+    CHECK_EQ(resource,
+             static_cast<TestResource*>(source->GetExternalStringResource()));
+    v8::internal::Heap::CollectAllGarbage();
+    CHECK_EQ(0, TestResource::dispose_count);
+  }
+  v8::internal::Heap::CollectAllGarbage();
+  CHECK_EQ(1, TestResource::dispose_count);
+}
+
+
+THREADED_TEST(ScriptUsingAsciiStringResource) {
+  TestAsciiResource::dispose_count = 0;
+  const char* c_source = "1 + 2 * 3";
+  {
+    v8::HandleScope scope;
+    LocalContext env;
+    Local<String> source =
+        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
+    Local<Script> script = Script::Compile(source);
+    Local<Value> value = script->Run();
+    CHECK(value->IsNumber());
+    CHECK_EQ(7, value->Int32Value());
+    v8::internal::Heap::CollectAllGarbage();
+    CHECK_EQ(0, TestAsciiResource::dispose_count);
+  }
+  v8::internal::Heap::CollectAllGarbage();
+  CHECK_EQ(1, TestAsciiResource::dispose_count);
+}
+
+
+THREADED_TEST(GlobalProperties) {
+  v8::HandleScope scope;
+  LocalContext env;
+  v8::Handle<v8::Object> global = env->Global();
+  global->Set(v8_str("pi"), v8_num(3.1415926));
+  Local<Value> pi = global->Get(v8_str("pi"));
+  CHECK_EQ(3.1415926, pi->NumberValue());
+}
+
+
+static v8::Handle<Value> handle_call(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(102);
+}
+
+
+static v8::Handle<Value> construct_call(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  args.This()->Set(v8_str("x"), v8_num(1));
+  args.This()->Set(v8_str("y"), v8_num(2));
+  return args.This();
+}
+
+THREADED_TEST(FunctionTemplate) {
+  v8::HandleScope scope;
+  LocalContext env;
+  {
+    Local<v8::FunctionTemplate> fun_templ =
+        v8::FunctionTemplate::New(handle_call);
+    Local<Function> fun = fun_templ->GetFunction();
+    env->Global()->Set(v8_str("obj"), fun);
+    Local<Script> script = v8_compile("obj()");
+    CHECK_EQ(102, script->Run()->Int32Value());
+  }
+  // Use SetCallHandler to initialize a function template, should work like the
+  // previous one.
+  {
+    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+    fun_templ->SetCallHandler(handle_call);
+    Local<Function> fun = fun_templ->GetFunction();
+    env->Global()->Set(v8_str("obj"), fun);
+    Local<Script> script = v8_compile("obj()");
+    CHECK_EQ(102, script->Run()->Int32Value());
+  }
+  // Test constructor calls.
+  {
+    Local<v8::FunctionTemplate> fun_templ =
+        v8::FunctionTemplate::New(construct_call);
+    fun_templ->SetClassName(v8_str("funky"));
+    Local<Function> fun = fun_templ->GetFunction();
+    env->Global()->Set(v8_str("obj"), fun);
+    Local<Script> script = v8_compile("var s = new obj(); s.x");
+    CHECK_EQ(1, script->Run()->Int32Value());
+
+    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
+    CHECK_EQ(v8_str("[object funky]"), result);
+  }
+}
+
+
+static v8::Handle<Value> handle_property(Local<String> name,
+                                         const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(900);
+}
+
+
+THREADED_TEST(PropertyHandler) {
+  v8::HandleScope scope;
+  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+  fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
+  LocalContext env;
+  Local<Function> fun = fun_templ->GetFunction();
+  env->Global()->Set(v8_str("Fun"), fun);
+  Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
+  CHECK_EQ(900, getter->Run()->Int32Value());
+  Local<Script> setter = v8_compile("obj.foo = 901;");
+  CHECK_EQ(901, setter->Run()->Int32Value());
+}
+
+
+THREADED_TEST(Number) {
+  v8::HandleScope scope;
+  LocalContext env;
+  double PI = 3.1415926;
+  Local<v8::Number> pi_obj = v8::Number::New(PI);
+  CHECK_EQ(PI, pi_obj->NumberValue());
+}
+
+
+THREADED_TEST(ToNumber) {
+  v8::HandleScope scope;
+  LocalContext env;
+  Local<String> str = v8_str("3.1415926");
+  CHECK_EQ(3.1415926, str->NumberValue());
+  v8::Handle<v8::Boolean> t = v8::True();
+  CHECK_EQ(1.0, t->NumberValue());
+  v8::Handle<v8::Boolean> f = v8::False();
+  CHECK_EQ(0.0, f->NumberValue());
+}
+
+
+THREADED_TEST(Date) {
+  v8::HandleScope scope;
+  LocalContext env;
+  double PI = 3.1415926;
+  Local<Value> date_obj = v8::Date::New(PI);
+  CHECK_EQ(3.0, date_obj->NumberValue());
+}
+
+
+THREADED_TEST(Boolean) {
+  v8::HandleScope scope;
+  LocalContext env;
+  v8::Handle<v8::Boolean> t = v8::True();
+  CHECK(t->Value());
+  v8::Handle<v8::Boolean> f = v8::False();
+  CHECK(!f->Value());
+  v8::Handle<v8::Primitive> u = v8::Undefined();
+  CHECK(!u->BooleanValue());
+  v8::Handle<v8::Primitive> n = v8::Null();
+  CHECK(!n->BooleanValue());
+  v8::Handle<String> str1 = v8_str("");
+  CHECK(!str1->BooleanValue());
+  v8::Handle<String> str2 = v8_str("x");
+  CHECK(str2->BooleanValue());
+  CHECK(!v8::Number::New(0)->BooleanValue());
+  CHECK(v8::Number::New(-1)->BooleanValue());
+  CHECK(v8::Number::New(1)->BooleanValue());
+  CHECK(v8::Number::New(42)->BooleanValue());
+  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
+}
+
+
+static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(13.4);
+}
+
+
+static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(876);
+}
+
+
+THREADED_TEST(GlobalPrototype) {
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
+  func_templ->PrototypeTemplate()->Set(
+      "dummy",
+      v8::FunctionTemplate::New(DummyCallHandler));
+  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
+  templ->Set("x", v8_num(200));
+  templ->SetAccessor(v8_str("m"), GetM);
+  LocalContext env(0, templ);
+  v8::Handle<v8::Object> obj = env->Global();
+  v8::Handle<Script> script = v8_compile("dummy()");
+  v8::Handle<Value> result = script->Run();
+  CHECK_EQ(13.4, result->NumberValue());
+  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
+  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
+}
+
+
+static v8::Handle<Value> GetIntValue(Local<String> property,
+                                     const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  int* value =
+      static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
+  return v8_num(*value);
+}
+
+static void SetIntValue(Local<String> property,
+                        Local<Value> value,
+                        const AccessorInfo& info) {
+  int* field =
+      static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
+  *field = value->Int32Value();
+}
+
+int foo, bar, baz;
+
+THREADED_TEST(GlobalVariableAccess) {
+  foo = 0;
+  bar = -4;
+  baz = 10;
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
+                                         GetIntValue,
+                                         SetIntValue,
+                                         v8::External::New(&foo));
+  templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
+                                         GetIntValue,
+                                         SetIntValue,
+                                         v8::External::New(&bar));
+  templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
+                                         GetIntValue,
+                                         SetIntValue,
+                                         v8::External::New(&baz));
+  LocalContext env(0, templ->InstanceTemplate());
+  v8_compile("foo = (++bar) + baz")->Run();
+  CHECK_EQ(bar, -3);
+  CHECK_EQ(foo, 7);
+}
+
+
+THREADED_TEST(ObjectTemplate) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
+  templ1->Set("x", v8_num(10));
+  templ1->Set("y", v8_num(13));
+  LocalContext env;
+  Local<v8::Object> instance1 = templ1->NewInstance();
+  env->Global()->Set(v8_str("p"), instance1);
+  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
+  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
+  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
+  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
+  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
+  templ2->Set("a", v8_num(12));
+  templ2->Set("b", templ1);
+  Local<v8::Object> instance2 = templ2->NewInstance();
+  env->Global()->Set(v8_str("q"), instance2);
+  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
+  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
+  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
+  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
+}
+
+
+static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(17.2);
+}
+
+
+static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(15.2);
+}
+
+
+THREADED_TEST(DescriptorInheritance) {
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
+  super->PrototypeTemplate()->Set("flabby",
+                                  v8::FunctionTemplate::New(GetFlabby));
+  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
+
+  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
+
+  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
+  base1->Inherit(super);
+  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
+
+  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
+  base2->Inherit(super);
+  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
+
+  LocalContext env;
+
+  env->Global()->Set(v8_str("s"), super->GetFunction());
+  env->Global()->Set(v8_str("base1"), base1->GetFunction());
+  env->Global()->Set(v8_str("base2"), base2->GetFunction());
+
+  // Checks right __proto__ chain.
+  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
+  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
+
+  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
+
+  // Instance accessor should not be visible on function object or its prototype
+  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
+  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
+  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
+
+  env->Global()->Set(v8_str("obj"),
+                     base1->GetFunction()->NewInstance());
+  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
+  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
+  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
+  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
+  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
+
+  env->Global()->Set(v8_str("obj2"),
+                     base2->GetFunction()->NewInstance());
+  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
+  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
+  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
+  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
+  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
+
+  // base1 and base2 cannot cross reference to each's prototype
+  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
+  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
+}
+
+
+int echo_named_call_count;
+
+
+static v8::Handle<Value> EchoNamedProperty(Local<String> name,
+                                           const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(v8_str("data"), info.Data());
+  echo_named_call_count++;
+  return name;
+}
+
+
+THREADED_TEST(NamedPropertyHandlerGetter) {
+  echo_named_call_count = 0;
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
+                                                     0, 0, 0, 0,
+                                                     v8_str("data"));
+  LocalContext env;
+  env->Global()->Set(v8_str("obj"),
+                     templ->GetFunction()->NewInstance());
+  CHECK_EQ(echo_named_call_count, 0);
+  v8_compile("obj.x")->Run();
+  CHECK_EQ(echo_named_call_count, 1);
+  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
+  v8::Handle<Value> str = CompileRun(code);
+  String::AsciiValue value(str);
+  CHECK_EQ(*value, "oddlepoddle");
+  // Check default behavior
+  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
+  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
+  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
+}
+
+
+int echo_indexed_call_count = 0;
+
+
+static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
+                                             const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(v8_num(637), info.Data());
+  echo_indexed_call_count++;
+  return v8_num(index);
+}
+
+
+THREADED_TEST(IndexedPropertyHandlerGetter) {
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
+                                                       0, 0, 0, 0,
+                                                       v8_num(637));
+  LocalContext env;
+  env->Global()->Set(v8_str("obj"),
+                     templ->GetFunction()->NewInstance());
+  Local<Script> script = v8_compile("obj[900]");
+  CHECK_EQ(script->Run()->Int32Value(), 900);
+}
+
+
+v8::Handle<v8::Object> bottom;
+
+static v8::Handle<Value> CheckThisIndexedPropertyHandler(
+    uint32_t index,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<Value>();
+}
+
+static v8::Handle<Value> CheckThisNamedPropertyHandler(
+    Local<String> name,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<Value>();
+}
+
+
+v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
+                                                 Local<Value> value,
+                                                 const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<Value>();
+}
+
+
+v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
+                                               Local<Value> value,
+                                               const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<Value>();
+}
+
+v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
+    uint32_t index,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<v8::Boolean>();
+}
+
+
+v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
+                                                    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<v8::Boolean>();
+}
+
+
+v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
+    uint32_t index,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<v8::Boolean>();
+}
+
+
+v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
+    Local<String> property,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<v8::Boolean>();
+}
+
+
+v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<v8::Array>();
+}
+
+
+v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.This()->Equals(bottom));
+  return v8::Handle<v8::Array>();
+}
+
+
+THREADED_TEST(PropertyHandlerInPrototype) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  // Set up a prototype chain with three interceptors.
+  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->InstanceTemplate()->SetIndexedPropertyHandler(
+      CheckThisIndexedPropertyHandler,
+      CheckThisIndexedPropertySetter,
+      CheckThisIndexedPropertyQuery,
+      CheckThisIndexedPropertyDeleter,
+      CheckThisIndexedPropertyEnumerator);
+
+  templ->InstanceTemplate()->SetNamedPropertyHandler(
+      CheckThisNamedPropertyHandler,
+      CheckThisNamedPropertySetter,
+      CheckThisNamedPropertyQuery,
+      CheckThisNamedPropertyDeleter,
+      CheckThisNamedPropertyEnumerator);
+
+  bottom = templ->GetFunction()->NewInstance();
+  Local<v8::Object> top = templ->GetFunction()->NewInstance();
+  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
+
+  bottom->Set(v8_str("__proto__"), middle);
+  middle->Set(v8_str("__proto__"), top);
+  env->Global()->Set(v8_str("obj"), bottom);
+
+  // Indexed and named get.
+  Script::Compile(v8_str("obj[0]"))->Run();
+  Script::Compile(v8_str("obj.x"))->Run();
+
+  // Indexed and named set.
+  Script::Compile(v8_str("obj[1] = 42"))->Run();
+  Script::Compile(v8_str("obj.y = 42"))->Run();
+
+  // Indexed and named query.
+  Script::Compile(v8_str("0 in obj"))->Run();
+  Script::Compile(v8_str("'x' in obj"))->Run();
+
+  // Indexed and named deleter.
+  Script::Compile(v8_str("delete obj[0]"))->Run();
+  Script::Compile(v8_str("delete obj.x"))->Run();
+
+  // Enumerators.
+  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
+}
+
+
+static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
+                                               const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  if (v8_str("pre")->Equals(key)) {
+    return v8_str("PrePropertyHandler: pre");
+  }
+  return v8::Handle<String>();
+}
+
+
+static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
+                                                     const AccessorInfo&) {
+  if (v8_str("pre")->Equals(key)) {
+    return v8::True();
+  }
+
+  return v8::Handle<v8::Boolean>();  // do not intercept the call
+}
+
+
+THREADED_TEST(PrePropertyHandler) {
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
+  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
+                                                    0,
+                                                    PrePropertyHandlerHas);
+  LocalContext env(NULL, desc->InstanceTemplate());
+  Script::Compile(v8_str(
+      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
+  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
+  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
+  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
+  CHECK_EQ(v8_str("Object: on"), result_on);
+  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
+  CHECK(result_post.IsEmpty());
+}
+
+
+v8::Handle<Script> call_recursively_script;
+static const int kTargetRecursionDepth = 300;  // near maximum
+
+
+static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
+  if (depth == kTargetRecursionDepth) return v8::Undefined();
+  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
+  return call_recursively_script->Run();
+}
+
+
+static v8::Handle<Value> CallFunctionRecursivelyCall(
+    const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
+  if (depth == kTargetRecursionDepth) {
+    printf("[depth = %d]\n", depth);
+    return v8::Undefined();
+  }
+  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
+  v8::Handle<Value> function =
+      args.This()->Get(v8_str("callFunctionRecursively"));
+  return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
+}
+
+
+THREADED_TEST(DeepCrossLanguageRecursion) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
+  global->Set(v8_str("callScriptRecursively"),
+              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
+  global->Set(v8_str("callFunctionRecursively"),
+              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
+  LocalContext env(NULL, global);
+
+  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
+  call_recursively_script = v8_compile("callScriptRecursively()");
+  v8::Handle<Value> result = call_recursively_script->Run();
+  call_recursively_script = v8::Handle<Script>();
+
+  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
+  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
+}
+
+
+static v8::Handle<Value>
+    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  return v8::ThrowException(key);
+}
+
+
+static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
+                                                    Local<Value>,
+                                                    const AccessorInfo&) {
+  v8::ThrowException(key);
+  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
+}
+
+
+THREADED_TEST(CallbackExceptionRegression) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
+                               ThrowingPropertyHandlerSet);
+  LocalContext env;
+  env->Global()->Set(v8_str("obj"), obj->NewInstance());
+  v8::Handle<Value> otto = Script::Compile(v8_str(
+      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
+  CHECK_EQ(v8_str("otto"), otto);
+  v8::Handle<Value> netto = Script::Compile(v8_str(
+      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
+  CHECK_EQ(v8_str("netto"), netto);
+}
+
+
+static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
+                                             const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  return v8::ThrowException(v8_str("g"));
+}
+
+
+static void ThrowingSetAccessor(Local<String> name,
+                                Local<Value> value,
+                                const AccessorInfo& info) {
+  v8::ThrowException(value);
+}
+
+
+THREADED_TEST(Regress1054726) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetAccessor(v8_str("x"),
+                   ThrowingGetAccessor,
+                   ThrowingSetAccessor,
+                   Local<Value>());
+
+  LocalContext env;
+  env->Global()->Set(v8_str("obj"), obj->NewInstance());
+
+  // Use the throwing property setter/getter in a loop to force
+  // the accessor ICs to be initialized.
+  v8::Handle<Value> result;
+  result = Script::Compile(v8_str(
+      "var result = '';"
+      "for (var i = 0; i < 5; i++) {"
+      "  try { obj.x; } catch (e) { result += e; }"
+      "}; result"))->Run();
+  CHECK_EQ(v8_str("ggggg"), result);
+
+  result = Script::Compile(String::New(
+      "var result = '';"
+      "for (var i = 0; i < 5; i++) {"
+      "  try { obj.x = i; } catch (e) { result += e; }"
+      "}; result"))->Run();
+  CHECK_EQ(v8_str("01234"), result);
+}
+
+
+THREADED_TEST(FunctionPrototype) {
+  v8::HandleScope scope;
+  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
+  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
+  LocalContext env;
+  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
+  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
+  CHECK_EQ(script->Run()->Int32Value(), 321);
+}
+
+
+THREADED_TEST(InternalFields) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
+  instance_templ->SetInternalFieldCount(1);
+  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
+  CHECK_EQ(1, obj->InternalFieldCount());
+  CHECK(obj->GetInternalField(0)->IsUndefined());
+  obj->SetInternalField(0, v8_num(17));
+  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
+}
+
+
+THREADED_TEST(External) {
+  v8::HandleScope scope;
+  int x = 3;
+  Local<v8::External> ext = v8::External::New(&x);
+  LocalContext env;
+  env->Global()->Set(v8_str("ext"), ext);
+  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
+  v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
+  int* ptr = static_cast<int*>(reext->Value());
+  CHECK_EQ(x, 3);
+  *ptr = 10;
+  CHECK_EQ(x, 10);
+}
+
+
+THREADED_TEST(GlobalHandle) {
+  v8::Persistent<String> global;
+  {
+    v8::HandleScope scope;
+    Local<String> str = v8_str("str");
+    global = v8::Persistent<String>::New(str);
+  }
+  CHECK_EQ(global->Length(), 3);
+  global.Dispose();
+}
+
+
+THREADED_TEST(ScriptException) {
+  v8::HandleScope scope;
+  LocalContext env;
+  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
+  v8::TryCatch try_catch;
+  Local<Value> result = script->Run();
+  CHECK(result.IsEmpty());
+  CHECK(try_catch.HasCaught());
+  String::AsciiValue exception_value(try_catch.Exception());
+  CHECK_EQ(*exception_value, "panama!");
+}
+
+
+bool message_received;
+
+
+static void check_message(v8::Handle<v8::Message> message,
+                          v8::Handle<Value> data) {
+  CHECK_EQ(5.76, data->NumberValue());
+  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
+  message_received = true;
+}
+
+
+THREADED_TEST(MessageHandlerData) {
+  message_received = false;
+  v8::HandleScope scope;
+  CHECK(!message_received);
+  v8::V8::AddMessageListener(check_message, v8_num(5.76));
+  LocalContext context;
+  v8::ScriptOrigin origin =
+      v8::ScriptOrigin(v8_str("6.75"));
+  Script::Compile(v8_str("throw 'error'"), &origin)->Run();
+  CHECK(message_received);
+  // clear out the message listener
+  v8::V8::RemoveMessageListeners(check_message);
+}
+
+
+THREADED_TEST(GetSetProperty) {
+  v8::HandleScope scope;
+  LocalContext context;
+  context->Global()->Set(v8_str("foo"), v8_num(14));
+  context->Global()->Set(v8_str("12"), v8_num(92));
+  context->Global()->Set(v8::Integer::New(16), v8_num(32));
+  context->Global()->Set(v8_num(13), v8_num(56));
+  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
+  CHECK_EQ(14, foo->Int32Value());
+  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
+  CHECK_EQ(92, twelve->Int32Value());
+  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
+  CHECK_EQ(32, sixteen->Int32Value());
+  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
+  CHECK_EQ(56, thirteen->Int32Value());
+  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
+  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
+  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
+  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
+  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
+  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
+  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
+  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
+  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
+}
+
+
+THREADED_TEST(PropertyAttributes) {
+  v8::HandleScope scope;
+  LocalContext context;
+  // read-only
+  Local<String> prop = v8_str("read_only");
+  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
+  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
+  Script::Compile(v8_str("read_only = 9"))->Run();
+  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
+  context->Global()->Set(prop, v8_num(10));
+  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
+  // dont-delete
+  prop = v8_str("dont_delete");
+  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
+  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
+  Script::Compile(v8_str("delete dont_delete"))->Run();
+  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
+}
+
+
+THREADED_TEST(Array) {
+  v8::HandleScope scope;
+  LocalContext context;
+  Local<v8::Array> array = v8::Array::New();
+  CHECK_EQ(0, array->Length());
+  CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
+  CHECK(!array->Has(0));
+  CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
+  CHECK(!array->Has(100));
+  array->Set(v8::Integer::New(2), v8_num(7));
+  CHECK_EQ(3, array->Length());
+  CHECK(!array->Has(0));
+  CHECK(!array->Has(1));
+  CHECK(array->Has(2));
+  CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
+  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
+  Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
+  CHECK_EQ(3, arr->Length());
+  CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
+  CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
+  CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
+}
+
+
+v8::Handle<Value> HandleF(const v8::Arguments& args) {
+  v8::HandleScope scope;
+  ApiTestFuzzer::Fuzz();
+  Local<v8::Array> result = v8::Array::New(args.Length());
+  for (int i = 0; i < args.Length(); i++)
+    result->Set(v8::Integer::New(i), args[i]);
+  return scope.Close(result);
+}
+
+
+THREADED_TEST(Vector) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> global = ObjectTemplate::New();
+  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
+  LocalContext context(0, global);
+
+  const char* fun = "f()";
+  Local<v8::Array> a0 =
+      Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
+  CHECK_EQ(0, a0->Length());
+
+  const char* fun2 = "f(11)";
+  Local<v8::Array> a1 =
+      Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
+  CHECK_EQ(1, a1->Length());
+  CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
+
+  const char* fun3 = "f(12, 13)";
+  Local<v8::Array> a2 =
+      Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
+  CHECK_EQ(2, a2->Length());
+  CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
+  CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
+
+  const char* fun4 = "f(14, 15, 16)";
+  Local<v8::Array> a3 =
+      Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
+  CHECK_EQ(3, a3->Length());
+  CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
+  CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
+  CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
+
+  const char* fun5 = "f(17, 18, 19, 20)";
+  Local<v8::Array> a4 =
+      Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
+  CHECK_EQ(4, a4->Length());
+  CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
+  CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
+  CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
+  CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
+}
+
+
+THREADED_TEST(FunctionCall) {
+  v8::HandleScope scope;
+  LocalContext context;
+  CompileRun(
+    "function Foo() {"
+    "  var result = [];"
+    "  for (var i = 0; i < arguments.length; i++) {"
+    "    result.push(arguments[i]);"
+    "  }"
+    "  return result;"
+    "}");
+  Local<Function> Foo =
+      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
+
+  v8::Handle<Value>* args0 = NULL;
+  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
+  CHECK_EQ(0, a0->Length());
+
+  v8::Handle<Value> args1[] = { v8_num(1.1) };
+  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
+  CHECK_EQ(1, a1->Length());
+  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
+
+  v8::Handle<Value> args2[] = { v8_num(2.2),
+                                v8_num(3.3) };
+  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
+  CHECK_EQ(2, a2->Length());
+  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
+  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
+
+  v8::Handle<Value> args3[] = { v8_num(4.4),
+                                v8_num(5.5),
+                                v8_num(6.6) };
+  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
+  CHECK_EQ(3, a3->Length());
+  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
+  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
+  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
+
+  v8::Handle<Value> args4[] = { v8_num(7.7),
+                                v8_num(8.8),
+                                v8_num(9.9),
+                                v8_num(10.11) };
+  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
+  CHECK_EQ(4, a4->Length());
+  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
+  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
+  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
+  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
+}
+
+
+static const char* js_code_causing_out_of_memory =
+    "var a = new Array(); while(true) a.push(a);";
+
+
+// These tests run for a long time and prevent us from running tests
+// that come after them so they cannot run in parallel.
+TEST(OutOfMemory) {
+  // It's not possible to read a snapshot into a heap with different dimensions.
+  if (v8::internal::Snapshot::IsEnabled()) return;
+  // Set heap limits.
+  static const int K = 1024;
+  v8::ResourceConstraints constraints;
+  constraints.set_max_young_space_size(256 * K);
+  constraints.set_max_old_space_size(4 * K * K);
+  v8::SetResourceConstraints(&constraints);
+
+  // Execute a script that causes out of memory.
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::V8::IgnoreOutOfMemoryException();
+  Local<Script> script =
+      Script::Compile(String::New(js_code_causing_out_of_memory));
+  Local<Value> result = script->Run();
+
+  // Check for out of memory state.
+  CHECK(result.IsEmpty());
+  CHECK(context->HasOutOfMemoryException());
+}
+
+
+v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+
+  v8::HandleScope scope;
+  LocalContext context;
+  Local<Script> script =
+      Script::Compile(String::New(js_code_causing_out_of_memory));
+  Local<Value> result = script->Run();
+
+  // Check for out of memory state.
+  CHECK(result.IsEmpty());
+  CHECK(context->HasOutOfMemoryException());
+
+  return result;
+}
+
+
+TEST(OutOfMemoryNested) {
+  // It's not possible to read a snapshot into a heap with different dimensions.
+  if (v8::internal::Snapshot::IsEnabled()) return;
+  // Set heap limits.
+  static const int K = 1024;
+  v8::ResourceConstraints constraints;
+  constraints.set_max_young_space_size(256 * K);
+  constraints.set_max_old_space_size(4 * K * K);
+  v8::SetResourceConstraints(&constraints);
+
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->Set(v8_str("ProvokeOutOfMemory"),
+             v8::FunctionTemplate::New(ProvokeOutOfMemory));
+  LocalContext context(0, templ);
+  v8::V8::IgnoreOutOfMemoryException();
+  Local<Value> result = CompileRun(
+    "var thrown = false;"
+    "try {"
+    "  ProvokeOutOfMemory();"
+    "} catch (e) {"
+    "  thrown = true;"
+    "}");
+  // Check for out of memory state.
+  CHECK(result.IsEmpty());
+  CHECK(context->HasOutOfMemoryException());
+}
+
+
+TEST(HugeConsStringOutOfMemory) {
+  // It's not possible to read a snapshot into a heap with different dimensions.
+  if (v8::internal::Snapshot::IsEnabled()) return;
+  v8::HandleScope scope;
+  LocalContext context;
+  // Set heap limits.
+  static const int K = 1024;
+  v8::ResourceConstraints constraints;
+  constraints.set_max_young_space_size(256 * K);
+  constraints.set_max_old_space_size(2 * K * K);
+  v8::SetResourceConstraints(&constraints);
+
+  // Execute a script that causes out of memory.
+  v8::V8::IgnoreOutOfMemoryException();
+
+  // Build huge string. This should fail with out of memory exception.
+  Local<Value> result = CompileRun(
+    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
+    "for (var i = 0; i < 21; i++) { str = str + str; }");
+
+  // Check for out of memory state.
+  CHECK(result.IsEmpty());
+  CHECK(context->HasOutOfMemoryException());
+}
+
+
+THREADED_TEST(ConstructCall) {
+  v8::HandleScope scope;
+  LocalContext context;
+  CompileRun(
+    "function Foo() {"
+    "  var result = [];"
+    "  for (var i = 0; i < arguments.length; i++) {"
+    "    result.push(arguments[i]);"
+    "  }"
+    "  return result;"
+    "}");
+  Local<Function> Foo =
+      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
+
+  v8::Handle<Value>* args0 = NULL;
+  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
+  CHECK_EQ(0, a0->Length());
+
+  v8::Handle<Value> args1[] = { v8_num(1.1) };
+  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
+  CHECK_EQ(1, a1->Length());
+  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
+
+  v8::Handle<Value> args2[] = { v8_num(2.2),
+                                v8_num(3.3) };
+  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
+  CHECK_EQ(2, a2->Length());
+  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
+  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
+
+  v8::Handle<Value> args3[] = { v8_num(4.4),
+                                v8_num(5.5),
+                                v8_num(6.6) };
+  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
+  CHECK_EQ(3, a3->Length());
+  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
+  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
+  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
+
+  v8::Handle<Value> args4[] = { v8_num(7.7),
+                                v8_num(8.8),
+                                v8_num(9.9),
+                                v8_num(10.11) };
+  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
+  CHECK_EQ(4, a4->Length());
+  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
+  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
+  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
+  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
+}
+
+
+static void CheckUncle(v8::TryCatch* try_catch) {
+  CHECK(try_catch->HasCaught());
+  String::AsciiValue str_value(try_catch->Exception());
+  CHECK_EQ(*str_value, "uncle?");
+  try_catch->Reset();
+}
+
+
+THREADED_TEST(ConversionException) {
+  v8::HandleScope scope;
+  LocalContext env;
+  CompileRun(
+    "function TestClass() { };"
+    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
+    "var obj = new TestClass();");
+  Local<Value> obj = env->Global()->Get(v8_str("obj"));
+
+  v8::TryCatch try_catch;
+
+  Local<Value> to_string_result = obj->ToString();
+  CHECK(to_string_result.IsEmpty());
+  CheckUncle(&try_catch);
+
+  Local<Value> to_number_result = obj->ToNumber();
+  CHECK(to_number_result.IsEmpty());
+  CheckUncle(&try_catch);
+
+  Local<Value> to_integer_result = obj->ToInteger();
+  CHECK(to_integer_result.IsEmpty());
+  CheckUncle(&try_catch);
+
+  Local<Value> to_uint32_result = obj->ToUint32();
+  CHECK(to_uint32_result.IsEmpty());
+  CheckUncle(&try_catch);
+
+  Local<Value> to_int32_result = obj->ToInt32();
+  CHECK(to_int32_result.IsEmpty());
+  CheckUncle(&try_catch);
+
+  Local<Value> to_object_result = v8::Undefined()->ToObject();
+  CHECK(to_object_result.IsEmpty());
+  CHECK(try_catch.HasCaught());
+  try_catch.Reset();
+
+  int32_t int32_value = obj->Int32Value();
+  CHECK_EQ(0, int32_value);
+  CheckUncle(&try_catch);
+
+  uint32_t uint32_value = obj->Uint32Value();
+  CHECK_EQ(0, uint32_value);
+  CheckUncle(&try_catch);
+
+  double number_value = obj->NumberValue();
+  CHECK_NE(0, IsNaN(number_value));
+  CheckUncle(&try_catch);
+
+  int64_t integer_value = obj->IntegerValue();
+  CHECK_EQ(0.0, static_cast<double>(integer_value));
+  CheckUncle(&try_catch);
+}
+
+
+v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8::ThrowException(v8_str("konto"));
+}
+
+
+THREADED_TEST(APICatch) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->Set(v8_str("ThrowFromC"),
+             v8::FunctionTemplate::New(ThrowFromC));
+  LocalContext context(0, templ);
+  CompileRun(
+    "var thrown = false;"
+    "try {"
+    "  ThrowFromC();"
+    "} catch (e) {"
+    "  thrown = true;"
+    "}");
+  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
+  CHECK(thrown->BooleanValue());
+}
+
+
+THREADED_TEST(ExternalScriptException) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->Set(v8_str("ThrowFromC"),
+             v8::FunctionTemplate::New(ThrowFromC));
+  LocalContext context(0, templ);
+
+  v8::TryCatch try_catch;
+  Local<Script> script
+      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
+  Local<Value> result = script->Run();
+  CHECK(result.IsEmpty());
+  CHECK(try_catch.HasCaught());
+  String::AsciiValue exception_value(try_catch.Exception());
+  CHECK_EQ("konto", *exception_value);
+}
+
+
+
+v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(4, args.Length());
+  int count = args[0]->Int32Value();
+  int cInterval = args[2]->Int32Value();
+  if (count == 0) {
+    return v8::ThrowException(v8_str("FromC"));
+  } else {
+    Local<v8::Object> global = Context::GetCurrent()->Global();
+    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
+    v8::Handle<Value> argv[] = { v8_num(count - 1),
+                                 args[1],
+                                 args[2],
+                                 args[3] };
+    if (count % cInterval == 0) {
+      v8::TryCatch try_catch;
+      Local<Value> result =
+          v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
+      int expected = args[3]->Int32Value();
+      if (try_catch.HasCaught()) {
+        CHECK_EQ(expected, count);
+        CHECK(!i::Top::has_scheduled_exception());
+      } else {
+        CHECK_NE(expected, count);
+      }
+      return result;
+    } else {
+      return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
+    }
+  }
+}
+
+
+v8::Handle<Value> JSCheck(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(3, args.Length());
+  bool equality = args[0]->BooleanValue();
+  int count = args[1]->Int32Value();
+  int expected = args[2]->Int32Value();
+  if (equality) {
+    CHECK_EQ(count, expected);
+  } else {
+    CHECK_NE(count, expected);
+  }
+  return v8::Undefined();
+}
+
+
+// This test works by making a stack of alternating JavaScript and C
+// activations.  These activations set up exception handlers with regular
+// intervals, one interval for C activations and another for JavaScript
+// activations.  When enough activations have been created an exception is
+// thrown and we check that the right activation catches the exception and that
+// no other activations do.  The right activation is always the topmost one with
+// a handler, regardless of whether it is in JavaScript or C.
+//
+// The notation used to describe a test case looks like this:
+//
+//    *JS[4] *C[3] @JS[2] C[1] JS[0]
+//
+// Each entry is an activation, either JS or C.  The index is the count at that
+// level.  Stars identify activations with exception handlers, the @ identifies
+// the exception handler that should catch the exception.
+THREADED_TEST(ExceptionOrder) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
+  templ->Set(v8_str("CThrowCountDown"),
+             v8::FunctionTemplate::New(CThrowCountDown));
+  LocalContext context(0, templ);
+  CompileRun(
+    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
+    "  if (count == 0) throw 'FromJS';"
+    "  if (count % jsInterval == 0) {"
+    "    try {"
+    "      var value = CThrowCountDown(count - 1,"
+    "                                  jsInterval,"
+    "                                  cInterval,"
+    "                                  expected);"
+    "      check(false, count, expected);"
+    "      return value;"
+    "    } catch (e) {"
+    "      check(true, count, expected);"
+    "    }"
+    "  } else {"
+    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
+    "  }"
+    "}");
+  Local<Function> fun =
+      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
+
+  const int argc = 4;
+  //                             count      jsInterval cInterval  expected
+
+  // *JS[4] *C[3] @JS[2] C[1] JS[0]
+  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
+  fun->Call(fun, argc, a0);
+
+  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
+  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
+  fun->Call(fun, argc, a1);
+
+  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
+  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
+  fun->Call(fun, argc, a2);
+
+  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
+  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
+  fun->Call(fun, argc, a3);
+
+  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
+  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
+  fun->Call(fun, argc, a4);
+
+  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
+  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
+  fun->Call(fun, argc, a5);
+}
+
+
+v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(1, args.Length());
+  return v8::ThrowException(args[0]);
+}
+
+
+THREADED_TEST(ThrowValues) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
+  LocalContext context(0, templ);
+  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
+    "function Run(obj) {"
+    "  try {"
+    "    Throw(obj);"
+    "  } catch (e) {"
+    "    return e;"
+    "  }"
+    "  return 'no exception';"
+    "}"
+    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
+  CHECK_EQ(5, result->Length());
+  CHECK(result->Get(v8::Integer::New(0))->IsString());
+  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
+  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
+  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
+  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
+  CHECK(result->Get(v8::Integer::New(3))->IsNull());
+  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
+}
+
+
+THREADED_TEST(CatchZero) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::TryCatch try_catch;
+  CHECK(!try_catch.HasCaught());
+  Script::Compile(v8_str("throw 10"))->Run();
+  CHECK(try_catch.HasCaught());
+  CHECK_EQ(10, try_catch.Exception()->Int32Value());
+  try_catch.Reset();
+  CHECK(!try_catch.HasCaught());
+  Script::Compile(v8_str("throw 0"))->Run();
+  CHECK(try_catch.HasCaught());
+  CHECK_EQ(0, try_catch.Exception()->Int32Value());
+}
+
+
+THREADED_TEST(CatchExceptionFromWith) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::TryCatch try_catch;
+  CHECK(!try_catch.HasCaught());
+  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
+  CHECK(try_catch.HasCaught());
+}
+
+
+THREADED_TEST(Equality) {
+  v8::HandleScope scope;
+  LocalContext context;
+  // Check that equality works at all before relying on CHECK_EQ
+  CHECK(v8_str("a")->Equals(v8_str("a")));
+  CHECK(!v8_str("a")->Equals(v8_str("b")));
+
+  CHECK_EQ(v8_str("a"), v8_str("a"));
+  CHECK_NE(v8_str("a"), v8_str("b"));
+  CHECK_EQ(v8_num(1), v8_num(1));
+  CHECK_EQ(v8_num(1.00), v8_num(1));
+  CHECK_NE(v8_num(1), v8_num(2));
+
+  // Assume String is not symbol.
+  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
+  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
+  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
+  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
+  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
+  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
+  Local<Value> not_a_number = v8_num(i::OS::nan_value());
+  CHECK(!not_a_number->StrictEquals(not_a_number));
+  CHECK(v8::False()->StrictEquals(v8::False()));
+  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
+
+  v8::Handle<v8::Object> obj = v8::Object::New();
+  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
+  CHECK(alias->StrictEquals(obj));
+  alias.Dispose();
+}
+
+
+THREADED_TEST(MultiRun) {
+  v8::HandleScope scope;
+  LocalContext context;
+  Local<Script> script = Script::Compile(v8_str("x"));
+  for (int i = 0; i < 10; i++)
+    script->Run();
+}
+
+
+static v8::Handle<Value> GetXValue(Local<String> name,
+                                   const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(info.Data(), v8_str("donut"));
+  CHECK_EQ(name, v8_str("x"));
+  return name;
+}
+
+
+THREADED_TEST(SimplePropertyRead) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
+  LocalContext context;
+  context->Global()->Set(v8_str("obj"), templ->NewInstance());
+  Local<Script> script = Script::Compile(v8_str("obj.x"));
+  for (int i = 0; i < 10; i++) {
+    Local<Value> result = script->Run();
+    CHECK_EQ(result, v8_str("x"));
+  }
+}
+
+
+v8::Persistent<Value> xValue;
+
+
+static void SetXValue(Local<String> name,
+                      Local<Value> value,
+                      const AccessorInfo& info) {
+  CHECK_EQ(value, v8_num(4));
+  CHECK_EQ(info.Data(), v8_str("donut"));
+  CHECK_EQ(name, v8_str("x"));
+  CHECK(xValue.IsEmpty());
+  xValue = v8::Persistent<Value>::New(value);
+}
+
+
+THREADED_TEST(SimplePropertyWrite) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
+  LocalContext context;
+  context->Global()->Set(v8_str("obj"), templ->NewInstance());
+  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
+  for (int i = 0; i < 10; i++) {
+    CHECK(xValue.IsEmpty());
+    script->Run();
+    CHECK_EQ(v8_num(4), xValue);
+    xValue.Dispose();
+    xValue = v8::Persistent<Value>();
+  }
+}
+
+
+static v8::Handle<Value> XPropertyGetter(Local<String> property,
+                                         const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(info.Data()->IsUndefined());
+  return property;
+}
+
+
+THREADED_TEST(NamedInterceporPropertyRead) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(XPropertyGetter);
+  LocalContext context;
+  context->Global()->Set(v8_str("obj"), templ->NewInstance());
+  Local<Script> script = Script::Compile(v8_str("obj.x"));
+  for (int i = 0; i < 10; i++) {
+    Local<Value> result = script->Run();
+    CHECK_EQ(result, v8_str("x"));
+  }
+}
+
+THREADED_TEST(MultiContexts) {
+  v8::HandleScope scope;
+  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
+
+  Local<String> password = v8_str("Password");
+
+  // Create an environment
+  LocalContext context0(0, templ);
+  context0->SetSecurityToken(password);
+  v8::Handle<v8::Object> global0 = context0->Global();
+  global0->Set(v8_str("custom"), v8_num(1234));
+  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
+
+  // Create an independent environment
+  LocalContext context1(0, templ);
+  context1->SetSecurityToken(password);
+  v8::Handle<v8::Object> global1 = context1->Global();
+  global1->Set(v8_str("custom"), v8_num(1234));
+  CHECK_NE(global0, global1);
+  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
+  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
+
+  // Now create a new context with the old global
+  LocalContext context2(0, templ, global1);
+  context2->SetSecurityToken(password);
+  v8::Handle<v8::Object> global2 = context2->Global();
+  CHECK_EQ(global1, global2);
+  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
+  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
+}
+
+
+THREADED_TEST(FunctionPrototypeAcrossContexts) {
+  // Make sure that functions created by cloning boilerplates cannot
+  // communicate through their __proto__ field.
+
+  v8::HandleScope scope;
+
+  LocalContext env0;
+  v8::Handle<v8::Object> global0 =
+      env0->Global();
+  v8::Handle<v8::Object> object0 =
+      v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
+  v8::Handle<v8::Object> tostring0 =
+      v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
+  v8::Handle<v8::Object> proto0 =
+      v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
+  proto0->Set(v8_str("custom"), v8_num(1234));
+
+  LocalContext env1;
+  v8::Handle<v8::Object> global1 =
+      env1->Global();
+  v8::Handle<v8::Object> object1 =
+      v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
+  v8::Handle<v8::Object> tostring1 =
+      v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
+  v8::Handle<v8::Object> proto1 =
+      v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
+  CHECK(!proto1->Has(v8_str("custom")));
+}
+
+
+THREADED_TEST(Regress892105) {
+  // Make sure that object and array literals created by cloning
+  // boilerplates cannot communicate through their __proto__
+  // field. This is rather difficult to check, but we try to add stuff
+  // to Object.prototype and Array.prototype and create a new
+  // environment. This should succeed.
+
+  v8::HandleScope scope;
+
+  Local<String> source = v8_str("Object.prototype.obj = 1234;"
+                                "Array.prototype.arr = 4567;"
+                                "8901");
+
+  LocalContext env0;
+  Local<Script> script0 = Script::Compile(source);
+  CHECK_EQ(8901.0, script0->Run()->NumberValue());
+
+  LocalContext env1;
+  Local<Script> script1 = Script::Compile(source);
+  CHECK_EQ(8901.0, script1->Run()->NumberValue());
+}
+
+
+static void ExpectString(const char* code, const char* expected) {
+  Local<Value> result = CompileRun(code);
+  CHECK(result->IsString());
+  String::AsciiValue ascii(result);
+  CHECK_EQ(0, strcmp(*ascii, expected));
+}
+
+
+static void ExpectBoolean(const char* code, bool expected) {
+  Local<Value> result = CompileRun(code);
+  CHECK(result->IsBoolean());
+  CHECK_EQ(expected, result->BooleanValue());
+}
+
+
+static void ExpectObject(const char* code, Local<Value> expected) {
+  Local<Value> result = CompileRun(code);
+  CHECK(result->Equals(expected));
+}
+
+
+THREADED_TEST(UndetectableObject) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  Local<v8::FunctionTemplate> desc =
+      v8::FunctionTemplate::New(0, v8::Handle<Value>());
+  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
+
+  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
+  env->Global()->Set(v8_str("undetectable"), obj);
+
+  ExpectString("undetectable.toString()", "[object Object]");
+  ExpectString("typeof undetectable", "undefined");
+  ExpectString("typeof(undetectable)", "undefined");
+  ExpectBoolean("typeof undetectable == 'undefined'", true);
+  ExpectBoolean("typeof undetectable == 'object'", false);
+  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
+  ExpectBoolean("!undetectable", true);
+
+  ExpectObject("true&&undetectable", obj);
+  ExpectBoolean("false&&undetectable", false);
+  ExpectBoolean("true||undetectable", true);
+  ExpectObject("false||undetectable", obj);
+
+  ExpectObject("undetectable&&true", obj);
+  ExpectObject("undetectable&&false", obj);
+  ExpectBoolean("undetectable||true", true);
+  ExpectBoolean("undetectable||false", false);
+
+  ExpectBoolean("undetectable==null", true);
+  ExpectBoolean("undetectable==undefined", true);
+  ExpectBoolean("undetectable==undetectable", true);
+
+  ExpectBoolean("undetectable===null", false);
+  ExpectBoolean("undetectable===undefined", true);
+  ExpectBoolean("undetectable===undetectable", true);
+}
+
+
+THREADED_TEST(UndetectableString) {
+  v8::HandleScope scope;
+  LocalContext env;
+
+  Local<String> obj = String::NewUndetectable("foo");
+  env->Global()->Set(v8_str("undetectable"), obj);
+
+  ExpectString("undetectable", "foo");
+  ExpectString("typeof undetectable", "undefined");
+  ExpectString("typeof(undetectable)", "undefined");
+  ExpectBoolean("typeof undetectable == 'undefined'", true);
+  ExpectBoolean("typeof undetectable == 'string'", false);
+  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
+  ExpectBoolean("!undetectable", true);
+
+  ExpectObject("true&&undetectable", obj);
+  ExpectBoolean("false&&undetectable", false);
+  ExpectBoolean("true||undetectable", true);
+  ExpectObject("false||undetectable", obj);
+
+  ExpectObject("undetectable&&true", obj);
+  ExpectObject("undetectable&&false", obj);
+  ExpectBoolean("undetectable||true", true);
+  ExpectBoolean("undetectable||false", false);
+
+  ExpectBoolean("undetectable==null", true);
+  ExpectBoolean("undetectable==undefined", true);
+  ExpectBoolean("undetectable==undetectable", true);
+
+  ExpectBoolean("undetectable===null", false);
+  ExpectBoolean("undetectable===undefined", true);
+  ExpectBoolean("undetectable===undetectable", true);
+}
+
+
+template <typename T> static void USE(T) { }
+
+
+// This test is not intended to be run, just type checked.
+static void PersistentHandles() {
+  USE(PersistentHandles);
+  Local<String> str = v8_str("foo");
+  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
+  USE(p_str);
+  Local<Script> scr = Script::Compile(v8_str(""));
+  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
+  USE(p_scr);
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  v8::Persistent<ObjectTemplate> p_templ =
+    v8::Persistent<ObjectTemplate>::New(templ);
+  USE(p_templ);
+}
+
+
+static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8::Undefined();
+}
+
+
+THREADED_TEST(GlobalObjectTemplate) {
+  v8::HandleScope handle_scope;
+  Local<ObjectTemplate> global_template = ObjectTemplate::New();
+  global_template->Set(v8_str("JSNI_Log"),
+                       v8::FunctionTemplate::New(HandleLogDelegator));
+  v8::Persistent<Context> context = Context::New(0, global_template);
+  Context::Scope context_scope(context);
+  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
+  context.Dispose();
+}
+
+
+static const char* kSimpleExtensionSource =
+  "function Foo() {"
+  "  return 4;"
+  "}";
+
+
+THREADED_TEST(SimpleExtensions) {
+  v8::HandleScope handle_scope;
+  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
+  const char* extension_names[] = { "simpletest" };
+  v8::ExtensionConfiguration extensions(1, extension_names);
+  v8::Handle<Context> context = Context::New(&extensions);
+  Context::Scope lock(context);
+  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
+  CHECK_EQ(result, v8::Integer::New(4));
+}
+
+
+THREADED_TEST(AutoExtensions) {
+  v8::HandleScope handle_scope;
+  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
+  extension->set_auto_enable(true);
+  v8::RegisterExtension(extension);
+  v8::Handle<Context> context = Context::New();
+  Context::Scope lock(context);
+  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
+  CHECK_EQ(result, v8::Integer::New(4));
+}
+
+
+static void CheckDependencies(const char* name, const char* expected) {
+  v8::HandleScope handle_scope;
+  v8::ExtensionConfiguration config(1, &name);
+  LocalContext context(&config);
+  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
+}
+
+
+/*
+ * Configuration:
+ *
+ *     /-- B <--\
+ * A <-          -- D <-- E
+ *     \-- C <--/
+ */
+THREADED_TEST(ExtensionDependency) {
+  static const char* kEDeps[] = { "D" };
+  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
+  static const char* kDDeps[] = { "B", "C" };
+  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
+  static const char* kBCDeps[] = { "A" };
+  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
+  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
+  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
+  CheckDependencies("A", "undefinedA");
+  CheckDependencies("B", "undefinedAB");
+  CheckDependencies("C", "undefinedAC");
+  CheckDependencies("D", "undefinedABCD");
+  CheckDependencies("E", "undefinedABCDE");
+  v8::HandleScope handle_scope;
+  static const char* exts[2] = { "C", "E" };
+  v8::ExtensionConfiguration config(2, exts);
+  LocalContext context(&config);
+  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
+}
+
+
+static const char* kExtensionTestScript =
+  "native function A();"
+  "native function B();"
+  "native function C();"
+  "function Foo(i) {"
+  "  if (i == 0) return A();"
+  "  if (i == 1) return B();"
+  "  if (i == 2) return C();"
+  "}";
+
+
+static v8::Handle<Value> CallFun(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return args.Data();
+}
+
+
+class FunctionExtension : public Extension {
+ public:
+  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
+  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
+      v8::Handle<String> name);
+};
+
+
+static int lookup_count = 0;
+v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
+      v8::Handle<String> name) {
+  lookup_count++;
+  if (name->Equals(v8_str("A"))) {
+    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
+  } else if (name->Equals(v8_str("B"))) {
+    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
+  } else if (name->Equals(v8_str("C"))) {
+    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
+  } else {
+    return v8::Handle<v8::FunctionTemplate>();
+  }
+}
+
+
+THREADED_TEST(FunctionLookup) {
+  v8::RegisterExtension(new FunctionExtension());
+  v8::HandleScope handle_scope;
+  static const char* exts[1] = { "functiontest" };
+  v8::ExtensionConfiguration config(1, exts);
+  LocalContext context(&config);
+  CHECK_EQ(3, lookup_count);
+  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
+  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
+  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
+}
+
+
+static const char* last_location;
+static const char* last_message;
+void StoringErrorCallback(const char* location, const char* message) {
+  if (last_location == NULL) {
+    last_location = location;
+    last_message = message;
+  }
+}
+
+
+// ErrorReporting creates a circular extensions configuration and
+// tests that the fatal error handler gets called.  This renders V8
+// unusable and therefore this test cannot be run in parallel.
+TEST(ErrorReporting) {
+  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
+  static const char* aDeps[] = { "B" };
+  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
+  static const char* bDeps[] = { "A" };
+  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
+  last_location = NULL;
+  v8::ExtensionConfiguration config(1, bDeps);
+  v8::Handle<Context> context = Context::New(&config);
+  CHECK(context.IsEmpty());
+  CHECK_NE(last_location, NULL);
+}
+
+
+static const char* js_code_causing_huge_string_flattening =
+    "var str = 'X';"
+    "for (var i = 0; i < 29; i++) {"
+    "  str = str + str;"
+    "}"
+    "str.match(/X/);";
+
+
+void OOMCallback(const char* location, const char* message) {
+  exit(0);
+}
+
+
+TEST(RegexpOutOfMemory) {
+  // Execute a script that causes out of memory when flattening a string.
+  v8::HandleScope scope;
+  v8::V8::SetFatalErrorHandler(OOMCallback);
+  LocalContext context;
+  Local<Script> script =
+      Script::Compile(String::New(js_code_causing_huge_string_flattening));
+  last_location = NULL;
+  Local<Value> result = script->Run();
+
+  CHECK(false);  // Should not return.
+}
+
+
+static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
+                                             v8::Handle<Value> data) {
+  CHECK_EQ(v8::Undefined(), data);
+  CHECK(message->GetScriptResourceName()->IsUndefined());
+  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
+  message->GetLineNumber();
+  message->GetSourceLine();
+}
+
+
+THREADED_TEST(ErrorWithMissingScriptInfo) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
+  Script::Compile(v8_str("throw Error()"))->Run();
+  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
+}
+
+
+int global_index = 0;
+
+class Snorkel {
+ public:
+  Snorkel() { index_ = global_index++; }
+  int index_;
+};
+
+class Whammy {
+ public:
+  Whammy() {
+    cursor_ = 0;
+  }
+  ~Whammy() {
+    script_.Dispose();
+  }
+  v8::Handle<Script> getScript() {
+    if (script_.IsEmpty())
+      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
+    return Local<Script>(*script_);
+  }
+
+ public:
+  static const int kObjectCount = 256;
+  int cursor_;
+  v8::Persistent<v8::Object> objects_[kObjectCount];
+  v8::Persistent<Script> script_;
+};
+
+static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
+  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
+  delete snorkel;
+  obj.ClearWeak();
+}
+
+v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
+                                       const AccessorInfo& info) {
+  Whammy* whammy =
+    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
+
+  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
+
+  v8::Handle<v8::Object> obj = v8::Object::New();
+  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
+  if (!prev.IsEmpty()) {
+    prev->Set(v8_str("next"), obj);
+    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
+    whammy->objects_[whammy->cursor_].Clear();
+  }
+  whammy->objects_[whammy->cursor_] = global;
+  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
+  return whammy->getScript()->Run();
+}
+
+THREADED_TEST(WeakReference) {
+  v8::HandleScope handle_scope;
+  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
+                                 0, 0, 0, 0,
+                                 v8::External::New(new Whammy()));
+  const char* extension_list[] = { "v8/gc" };
+  v8::ExtensionConfiguration extensions(1, extension_list);
+  v8::Persistent<Context> context = Context::New(&extensions);
+  Context::Scope context_scope(context);
+
+  v8::Handle<v8::Object> interceptor = templ->NewInstance();
+  context->Global()->Set(v8_str("whammy"), interceptor);
+  const char* code =
+      "var last;"
+      "for (var i = 0; i < 10000; i++) {"
+      "  var obj = whammy.length;"
+      "  if (last) last.next = obj;"
+      "  last = obj;"
+      "}"
+      "gc();"
+      "4";
+  v8::Handle<Value> result = CompileRun(code);
+  CHECK_EQ(4.0, result->NumberValue());
+
+  context.Dispose();
+}
+
+
+v8::Handle<Function> args_fun;
+
+
+static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(args_fun, args.Callee());
+  CHECK_EQ(3, args.Length());
+  CHECK_EQ(v8::Integer::New(1), args[0]);
+  CHECK_EQ(v8::Integer::New(2), args[1]);
+  CHECK_EQ(v8::Integer::New(3), args[2]);
+  CHECK_EQ(v8::Undefined(), args[3]);
+  v8::HandleScope scope;
+  i::Heap::CollectAllGarbage();
+  return v8::Undefined();
+}
+
+
+THREADED_TEST(Arguments) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
+  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
+  LocalContext context(NULL, global);
+  args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
+  v8_compile("f(1, 2, 3)")->Run();
+}
+
+
+static int x_register = 0;
+static v8::Handle<v8::Object> x_receiver;
+static v8::Handle<v8::Object> x_holder;
+
+
+static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK_EQ(x_receiver, info.This());
+  CHECK_EQ(x_holder, info.Holder());
+  return v8_num(x_register);
+}
+
+
+static void XSetter(Local<String> name,
+                    Local<Value> value,
+                    const AccessorInfo& info) {
+  CHECK_EQ(x_holder, info.This());
+  CHECK_EQ(x_holder, info.Holder());
+  x_register = value->Int32Value();
+}
+
+
+THREADED_TEST(AccessorIC) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetAccessor(v8_str("x"), XGetter, XSetter);
+  LocalContext context;
+  x_holder = obj->NewInstance();
+  context->Global()->Set(v8_str("holder"), x_holder);
+  x_receiver = v8::Object::New();
+  context->Global()->Set(v8_str("obj"), x_receiver);
+  v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
+    "obj.__proto__ = holder;"
+    "var result = [];"
+    "for (var i = 0; i < 10; i++) {"
+    "  holder.x = i;"
+    "  result.push(obj.x);"
+    "}"
+    "result"));
+  CHECK_EQ(10, array->Length());
+  for (int i = 0; i < 10; i++) {
+    v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
+    CHECK_EQ(v8::Integer::New(i), entry);
+  }
+}
+
+
+static v8::Handle<Value> NoBlockGetterX(Local<String> name,
+                                        const AccessorInfo&) {
+  return v8::Handle<Value>();
+}
+
+
+static v8::Handle<Value> NoBlockGetterI(uint32_t index,
+                                        const AccessorInfo&) {
+  return v8::Handle<Value>();
+}
+
+
+static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
+                                        const AccessorInfo&) {
+  if (!name->Equals(v8_str("foo"))) {
+    return v8::Handle<v8::Boolean>();  // not intercepted
+  }
+
+  return v8::False();  // intercepted, and don't delete the property
+}
+
+
+static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
+  if (index != 2) {
+    return v8::Handle<v8::Boolean>();  // not intercepted
+  }
+
+  return v8::False();  // intercepted, and don't delete the property
+}
+
+
+THREADED_TEST(Deleter) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
+  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
+  LocalContext context;
+  context->Global()->Set(v8_str("k"), obj->NewInstance());
+  CompileRun(
+    "k.foo = 'foo';"
+    "k.bar = 'bar';"
+    "k[2] = 2;"
+    "k[4] = 4;");
+  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
+  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
+
+  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
+  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
+
+  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
+  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
+
+  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
+  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
+}
+
+
+static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  return v8::Undefined();
+}
+
+
+static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  v8::Handle<v8::Array> result = v8::Array::New(3);
+  result->Set(v8::Integer::New(0), v8_str("foo"));
+  result->Set(v8::Integer::New(1), v8_str("bar"));
+  result->Set(v8::Integer::New(2), v8_str("baz"));
+  return result;
+}
+
+
+static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  v8::Handle<v8::Array> result = v8::Array::New(2);
+  result->Set(v8::Integer::New(0), v8_str("hat"));
+  result->Set(v8::Integer::New(1), v8_str("gyt"));
+  return result;
+}
+
+
+THREADED_TEST(Enumerators) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
+  obj->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, IndexedEnum);
+  LocalContext context;
+  context->Global()->Set(v8_str("k"), obj->NewInstance());
+  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
+    "var result = [];"
+    "for (var prop in k) {"
+    "  result.push(prop);"
+    "}"
+    "result"));
+  CHECK_EQ(5, result->Length());
+  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(0)));
+  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(1)));
+  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(2)));
+  CHECK_EQ(v8_str("hat"), result->Get(v8::Integer::New(3)));
+  CHECK_EQ(v8_str("gyt"), result->Get(v8::Integer::New(4)));
+}
+
+
+int p_getter_count;
+int p_getter_count2;
+
+
+static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  p_getter_count++;
+  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
+  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
+  if (name->Equals(v8_str("p1"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
+  } else if (name->Equals(v8_str("p2"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
+  } else if (name->Equals(v8_str("p3"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
+  } else if (name->Equals(v8_str("p4"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
+  }
+  return v8::Undefined();
+}
+
+
+static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
+  ApiTestFuzzer::Fuzz();
+  LocalContext context;
+  context->Global()->Set(v8_str("o1"), obj->NewInstance());
+  CompileRun(
+    "o1.__proto__ = { };"
+    "var o2 = { __proto__: o1 };"
+    "var o3 = { __proto__: o2 };"
+    "var o4 = { __proto__: o3 };"
+    "for (var i = 0; i < 10; i++) o4.p4;"
+    "for (var i = 0; i < 10; i++) o3.p3;"
+    "for (var i = 0; i < 10; i++) o2.p2;"
+    "for (var i = 0; i < 10; i++) o1.p1;");
+}
+
+
+static v8::Handle<Value> PGetter2(Local<String> name,
+                                  const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  p_getter_count2++;
+  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
+  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
+  if (name->Equals(v8_str("p1"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
+  } else if (name->Equals(v8_str("p2"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
+  } else if (name->Equals(v8_str("p3"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
+  } else if (name->Equals(v8_str("p4"))) {
+    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
+  }
+  return v8::Undefined();
+}
+
+
+THREADED_TEST(GetterHolders) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetAccessor(v8_str("p1"), PGetter);
+  obj->SetAccessor(v8_str("p2"), PGetter);
+  obj->SetAccessor(v8_str("p3"), PGetter);
+  obj->SetAccessor(v8_str("p4"), PGetter);
+  p_getter_count = 0;
+  RunHolderTest(obj);
+  CHECK_EQ(40, p_getter_count);
+}
+
+
+THREADED_TEST(PreInterceptorHolders) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetNamedPropertyHandler(PGetter2);
+  p_getter_count2 = 0;
+  RunHolderTest(obj);
+  CHECK_EQ(40, p_getter_count2);
+}
+
+
+THREADED_TEST(ObjectInstantiation) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetAccessor(v8_str("t"), PGetter2);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  for (int i = 0; i < 100; i++) {
+    v8::HandleScope inner_scope;
+    v8::Handle<v8::Object> obj = templ->NewInstance();
+    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
+    context->Global()->Set(v8_str("o2"), obj);
+    v8::Handle<Value> value =
+        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
+    CHECK_EQ(v8::True(), value);
+    context->Global()->Set(v8_str("o"), obj);
+  }
+}
+
+
+THREADED_TEST(StringWrite) {
+  v8::HandleScope scope;
+  v8::Handle<String> str = v8_str("abcde");
+
+  char buf[100];
+  int len;
+
+  memset(buf, 0x1, sizeof(buf));
+  len = str->WriteAscii(buf);
+  CHECK_EQ(len, 5);
+  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
+
+  memset(buf, 0x1, sizeof(buf));
+  len = str->WriteAscii(buf, 0, 4);
+  CHECK_EQ(len, 4);
+  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
+
+  memset(buf, 0x1, sizeof(buf));
+  len = str->WriteAscii(buf, 0, 5);
+  CHECK_EQ(len, 5);
+  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
+
+  memset(buf, 0x1, sizeof(buf));
+  len = str->WriteAscii(buf, 0, 6);
+  CHECK_EQ(len, 5);
+  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
+
+  memset(buf, 0x1, sizeof(buf));
+  len = str->WriteAscii(buf, 4, -1);
+  CHECK_EQ(len, 1);
+  CHECK_EQ(strncmp("e\0", buf, 2), 0);
+
+  memset(buf, 0x1, sizeof(buf));
+  len = str->WriteAscii(buf, 4, 6);
+  CHECK_EQ(len, 1);
+  CHECK_EQ(strncmp("e\0", buf, 2), 0);
+
+  memset(buf, 0x1, sizeof(buf));
+  len = str->WriteAscii(buf, 4, 1);
+  CHECK_EQ(len, 1);
+  CHECK_EQ(strncmp("e\1", buf, 2), 0);
+}
+
+
+THREADED_TEST(ToArrayIndex) {
+  v8::HandleScope scope;
+  LocalContext context;
+
+  v8::Handle<String> str = v8_str("42");
+  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
+  CHECK(!index.IsEmpty());
+  CHECK_EQ(42.0, index->Uint32Value());
+  str = v8_str("42asdf");
+  index = str->ToArrayIndex();
+  CHECK(index.IsEmpty());
+  str = v8_str("-42");
+  index = str->ToArrayIndex();
+  CHECK(index.IsEmpty());
+  str = v8_str("4294967295");
+  index = str->ToArrayIndex();
+  CHECK(!index.IsEmpty());
+  CHECK_EQ(4294967295.0, index->Uint32Value());
+  v8::Handle<v8::Number> num = v8::Number::New(1);
+  index = num->ToArrayIndex();
+  CHECK(!index.IsEmpty());
+  CHECK_EQ(1.0, index->Uint32Value());
+  num = v8::Number::New(-1);
+  index = num->ToArrayIndex();
+  CHECK(index.IsEmpty());
+  v8::Handle<v8::Object> obj = v8::Object::New();
+  index = obj->ToArrayIndex();
+  CHECK(index.IsEmpty());
+}
+
+
+THREADED_TEST(ErrorConstruction) {
+  v8::HandleScope scope;
+  LocalContext context;
+
+  v8::Handle<String> foo = v8_str("foo");
+  v8::Handle<String> message = v8_str("message");
+  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
+  CHECK(range_error->IsObject());
+  v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
+  CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
+  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
+  CHECK(reference_error->IsObject());
+  CHECK(
+      v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
+  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
+  CHECK(syntax_error->IsObject());
+  CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
+  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
+  CHECK(type_error->IsObject());
+  CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
+  v8::Handle<Value> error = v8::Exception::Error(foo);
+  CHECK(error->IsObject());
+  CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
+}
+
+
+static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(10);
+}
+
+
+static void YSetter(Local<String> name,
+                    Local<Value> value,
+                    const AccessorInfo& info) {
+  if (info.This()->Has(name)) {
+    info.This()->Delete(name);
+  }
+  info.This()->Set(name, value);
+}
+
+
+THREADED_TEST(DeleteAccessor) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
+  LocalContext context;
+  v8::Handle<v8::Object> holder = obj->NewInstance();
+  context->Global()->Set(v8_str("holder"), holder);
+  v8::Handle<Value> result = CompileRun(
+      "holder.y = 11; holder.y = 12; holder.y");
+  CHECK_EQ(12, result->Uint32Value());
+}
+
+
+THREADED_TEST(TypeSwitch) {
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
+  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
+  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
+  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
+  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
+  LocalContext context;
+  v8::Handle<v8::Object> obj0 = v8::Object::New();
+  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
+  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
+  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
+  for (int i = 0; i < 10; i++) {
+    CHECK_EQ(0, type_switch->match(obj0));
+    CHECK_EQ(1, type_switch->match(obj1));
+    CHECK_EQ(2, type_switch->match(obj2));
+    CHECK_EQ(3, type_switch->match(obj3));
+    CHECK_EQ(3, type_switch->match(obj3));
+    CHECK_EQ(2, type_switch->match(obj2));
+    CHECK_EQ(1, type_switch->match(obj1));
+    CHECK_EQ(0, type_switch->match(obj0));
+  }
+}
+
+
+// For use within the TestSecurityHandler() test.
+static bool g_security_callback_result = false;
+static bool NamedSecurityTestCallback(Local<v8::Object> global,
+                                      Local<Value> name,
+                                      v8::AccessType type,
+                                      Local<Value> data) {
+  // Always allow read access.
+  if (type == v8::ACCESS_GET)
+    return true;
+
+  // Sometimes allow other access.
+  return g_security_callback_result;
+}
+
+
+static bool IndexedSecurityTestCallback(Local<v8::Object> global,
+                                        uint32_t key,
+                                        v8::AccessType type,
+                                        Local<Value> data) {
+  // Always allow read access.
+  if (type == v8::ACCESS_GET)
+    return true;
+
+  // Sometimes allow other access.
+  return g_security_callback_result;
+}
+
+
+static int trouble_nesting = 0;
+static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  trouble_nesting++;
+
+  // Call a JS function that throws an uncaught exception.
+  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
+  Local<Value> trouble_callee = (trouble_nesting == 3) ?
+    arg_this->Get(v8_str("trouble_callee")) :
+    arg_this->Get(v8_str("trouble_caller"));
+  CHECK(trouble_callee->IsFunction());
+  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
+}
+
+
+static int report_count = 0;
+static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
+                                             v8::Handle<Value>) {
+  report_count++;
+}
+
+
+// Counts uncaught exceptions, but other tests running in parallel
+// also have uncaught exceptions.
+TEST(ApiUncaughtException) {
+  v8::HandleScope scope;
+  LocalContext env;
+  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
+
+  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
+  v8::Local<v8::Object> global = env->Global();
+  global->Set(v8_str("trouble"), fun->GetFunction());
+
+  Script::Compile(v8_str("function trouble_callee() {"
+                         "  var x = null;"
+                         "  return x.foo;"
+                         "};"
+                         "function trouble_caller() {"
+                         "  trouble();"
+                         "};"))->Run();
+  Local<Value> trouble = global->Get(v8_str("trouble"));
+  CHECK(trouble->IsFunction());
+  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
+  CHECK(trouble_callee->IsFunction());
+  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
+  CHECK(trouble_caller->IsFunction());
+  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
+  CHECK_EQ(1, report_count);
+}
+
+
+// SecurityHandler can't be run twice
+TEST(SecurityHandler) {
+  v8::HandleScope scope0;
+  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
+                                           IndexedSecurityTestCallback);
+  // Create an environment
+  v8::Persistent<Context> context0 =
+    Context::New(NULL, global_template);
+  context0->Enter();
+
+  v8::Handle<v8::Object> global0 = context0->Global();
+  v8::Handle<Script> script0 = v8_compile("foo = 111");
+  script0->Run();
+  global0->Set(v8_str("0"), v8_num(999));
+  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
+  CHECK_EQ(111, foo0->Int32Value());
+  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
+  CHECK_EQ(999, z0->Int32Value());
+
+  // Create another environment, should fail security checks.
+  v8::HandleScope scope1;
+
+  v8::Persistent<Context> context1 =
+    Context::New(NULL, global_template);
+  context1->Enter();
+
+  v8::Handle<v8::Object> global1 = context1->Global();
+  global1->Set(v8_str("othercontext"), global0);
+  // This set will fail the security check.
+  v8::Handle<Script> script1 =
+    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
+  script1->Run();
+  // This read will pass the security check.
+  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
+  CHECK_EQ(111, foo1->Int32Value());
+  // This read will pass the security check.
+  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
+  CHECK_EQ(999, z1->Int32Value());
+
+  // Create another environment, should pass security checks.
+  { g_security_callback_result = true;  // allow security handler to pass.
+    v8::HandleScope scope2;
+    LocalContext context2;
+    v8::Handle<v8::Object> global2 = context2->Global();
+    global2->Set(v8_str("othercontext"), global0);
+    v8::Handle<Script> script2 =
+        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
+    script2->Run();
+    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
+    CHECK_EQ(333, foo2->Int32Value());
+    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
+    CHECK_EQ(888, z2->Int32Value());
+  }
+
+  context1->Exit();
+  context1.Dispose();
+
+  context0->Exit();
+  context0.Dispose();
+}
+
+
+THREADED_TEST(SecurityChecks) {
+  v8::HandleScope handle_scope;
+  LocalContext env1;
+  v8::Persistent<Context> env2 = Context::New();
+
+  Local<Value> foo = v8_str("foo");
+  Local<Value> bar = v8_str("bar");
+
+  // Set to the same domain.
+  env1->SetSecurityToken(foo);
+
+  // Create a function in env1.
+  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
+  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
+  CHECK(spy->IsFunction());
+
+  // Create another function accessing global objects.
+  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
+  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
+  CHECK(spy2->IsFunction());
+
+  // Switch to env2 in the same domain and invoke spy on env2.
+  {
+    env2->SetSecurityToken(foo);
+    // Enter env2
+    Context::Scope scope_env2(env2);
+    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
+    CHECK(result->IsFunction());
+  }
+
+  {
+    env2->SetSecurityToken(bar);
+    Context::Scope scope_env2(env2);
+
+    // Call cross_domain_call, it should throw an exception
+    v8::TryCatch try_catch;
+    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
+    CHECK(try_catch.HasCaught());
+  }
+
+  env2.Dispose();
+}
+
+
+// Regression test case for issue 1183439.
+THREADED_TEST(SecurityChecksForPrototypeChain) {
+  v8::HandleScope scope;
+  LocalContext current;
+  v8::Persistent<Context> other = Context::New();
+
+  // Change context to be able to get to the Object function in the
+  // other context without hitting the security checks.
+  v8::Local<Value> other_object;
+  { Context::Scope scope(other);
+    other_object = other->Global()->Get(v8_str("Object"));
+    other->Global()->Set(v8_num(42), v8_num(87));
+  }
+
+  current->Global()->Set(v8_str("other"), other->Global());
+  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
+
+  // Make sure the security check fails here and we get an undefined
+  // result instead of getting the Object function. Repeat in a loop
+  // to make sure to exercise the IC code.
+  v8::Local<Script> access_other0 = v8_compile("other.Object");
+  v8::Local<Script> access_other1 = v8_compile("other[42]");
+  for (int i = 0; i < 5; i++) {
+    CHECK(!access_other0->Run()->Equals(other_object));
+    CHECK(access_other0->Run()->IsUndefined());
+    CHECK(!access_other1->Run()->Equals(v8_num(87)));
+    CHECK(access_other1->Run()->IsUndefined());
+  }
+
+  // Create an object that has 'other' in its prototype chain and make
+  // sure we cannot access the Object function indirectly through
+  // that. Repeat in a loop to make sure to exercise the IC code.
+  v8_compile("function F() { };"
+             "F.prototype = other;"
+             "var f = new F();")->Run();
+  v8::Local<Script> access_f0 = v8_compile("f.Object");
+  v8::Local<Script> access_f1 = v8_compile("f[42]");
+  for (int j = 0; j < 5; j++) {
+    CHECK(!access_f0->Run()->Equals(other_object));
+    CHECK(access_f0->Run()->IsUndefined());
+    CHECK(!access_f1->Run()->Equals(v8_num(87)));
+    CHECK(access_f1->Run()->IsUndefined());
+  }
+
+  // Now it gets hairy: Set the prototype for the other global object
+  // to be the current global object. The prototype chain for 'f' now
+  // goes through 'other' but ends up in the current global object.
+  { Context::Scope scope(other);
+    other->Global()->Set(v8_str("__proto__"), current->Global());
+  }
+  // Set a named and an index property on the current global
+  // object. To force the lookup to go through the other global object,
+  // the properties must not exist in the other global object.
+  current->Global()->Set(v8_str("foo"), v8_num(100));
+  current->Global()->Set(v8_num(99), v8_num(101));
+  // Try to read the properties from f and make sure that the access
+  // gets stopped by the security checks on the other global object.
+  Local<Script> access_f2 = v8_compile("f.foo");
+  Local<Script> access_f3 = v8_compile("f[99]");
+  for (int k = 0; k < 5; k++) {
+    CHECK(!access_f2->Run()->Equals(v8_num(100)));
+    CHECK(access_f2->Run()->IsUndefined());
+    CHECK(!access_f3->Run()->Equals(v8_num(101)));
+    CHECK(access_f3->Run()->IsUndefined());
+  }
+  other.Dispose();
+}
+
+
+THREADED_TEST(CrossDomainDelete) {
+  v8::HandleScope handle_scope;
+  LocalContext env1;
+  v8::Persistent<Context> env2 = Context::New();
+
+  Local<Value> foo = v8_str("foo");
+  Local<Value> bar = v8_str("bar");
+
+  // Set to the same domain.
+  env1->SetSecurityToken(foo);
+  env2->SetSecurityToken(foo);
+
+  env1->Global()->Set(v8_str("prop"), v8_num(3));
+  env2->Global()->Set(v8_str("env1"), env1->Global());
+
+  // Change env2 to a different domain and delete env1.prop.
+  env2->SetSecurityToken(bar);
+  {
+    Context::Scope scope_env2(env2);
+    Local<Value> result =
+        Script::Compile(v8_str("delete env1.prop"))->Run();
+    CHECK(result->IsFalse());
+  }
+
+  // Check that env1.prop still exists.
+  Local<Value> v = env1->Global()->Get(v8_str("prop"));
+  CHECK(v->IsNumber());
+  CHECK_EQ(3, v->Int32Value());
+
+  env2.Dispose();
+}
+
+
+THREADED_TEST(CrossDomainForIn) {
+  v8::HandleScope handle_scope;
+  LocalContext env1;
+  v8::Persistent<Context> env2 = Context::New();
+
+  Local<Value> foo = v8_str("foo");
+  Local<Value> bar = v8_str("bar");
+
+  // Set to the same domain.
+  env1->SetSecurityToken(foo);
+  env2->SetSecurityToken(foo);
+
+  env1->Global()->Set(v8_str("prop"), v8_num(3));
+  env2->Global()->Set(v8_str("env1"), env1->Global());
+
+  // Change env2 to a different domain and set env1's global object
+  // as the __proto__ of an object in env2 and enumerate properties
+  // in for-in. It shouldn't enumerate properties on env1's global
+  // object.
+  env2->SetSecurityToken(bar);
+  {
+    Context::Scope scope_env2(env2);
+    Local<Value> result =
+        CompileRun("(function(){var obj = {'__proto__':env1};"
+                   "for (var p in obj)"
+                   "   if (p == 'prop') return false;"
+                   "return true;})()");
+    CHECK(result->IsTrue());
+  }
+  env2.Dispose();
+}
+
+
+TEST(ContextDetachGlobal) {
+  v8::HandleScope handle_scope;
+  LocalContext env1;
+  v8::Persistent<Context> env2 = Context::New();
+
+  Local<v8::Object> global1 = env1->Global();
+
+  Local<Value> foo = v8_str("foo");
+
+  // Set to the same domain.
+  env1->SetSecurityToken(foo);
+  env2->SetSecurityToken(foo);
+
+  // Enter env2
+  env2->Enter();
+
+  // Create a function in env1
+  Local<v8::Object> global2 = env2->Global();
+  global2->Set(v8_str("prop"), v8::Integer::New(1));
+  CompileRun("function getProp() {return prop;}");
+
+  env1->Global()->Set(v8_str("getProp"),
+                      global2->Get(v8_str("getProp")));
+
+  // Detach env1's global, and reuse the global object of env1
+  env2->Exit();
+  env2->DetachGlobal();
+  // env2 has a new global object.
+  CHECK(!env2->Global()->Equals(global2));
+
+  v8::Persistent<Context> env3 =
+      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
+  env3->SetSecurityToken(v8_str("bar"));
+  env3->Enter();
+
+  Local<v8::Object> global3 = env3->Global();
+  CHECK_EQ(global2, global3);
+  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
+  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
+  global3->Set(v8_str("prop"), v8::Integer::New(-1));
+  global3->Set(v8_str("prop2"), v8::Integer::New(2));
+  env3->Exit();
+
+  // Call getProp in env1, and it should return the value 1
+  {
+    Local<Value> get_prop = global1->Get(v8_str("getProp"));
+    CHECK(get_prop->IsFunction());
+    v8::TryCatch try_catch;
+    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
+    CHECK(!try_catch.HasCaught());
+    CHECK_EQ(1, r->Int32Value());
+  }
+
+  // Check that env3 is not accessible from env1
+  {
+    Local<Value> r = global3->Get(v8_str("prop2"));
+    CHECK(r->IsUndefined());
+  }
+
+  env2.Dispose();
+  env3.Dispose();
+}
+
+
+static bool NamedAccessBlocker(Local<v8::Object> global,
+                               Local<Value> name,
+                               v8::AccessType type,
+                               Local<Value> data) {
+  return Context::GetCurrent()->Global()->Equals(global);
+}
+
+
+static bool IndexedAccessBlocker(Local<v8::Object> global,
+                                 uint32_t key,
+                                 v8::AccessType type,
+                                 Local<Value> data) {
+  return Context::GetCurrent()->Global()->Equals(global);
+}
+
+
+static int g_echo_value = -1;
+static v8::Handle<Value> EchoGetter(Local<String> name,
+                                    const AccessorInfo& info) {
+  return v8_num(g_echo_value);
+}
+
+
+static void EchoSetter(Local<String> name,
+                       Local<Value> value,
+                       const AccessorInfo&) {
+  if (value->IsNumber())
+    g_echo_value = value->Int32Value();
+}
+
+
+static v8::Handle<Value> UnreachableGetter(Local<String> name,
+                                           const AccessorInfo& info) {
+  CHECK(false);  // This function should not be called..
+  return v8::Undefined();
+}
+
+
+static void UnreachableSetter(Local<String>, Local<Value>,
+                              const AccessorInfo&) {
+  CHECK(false);  // This function should nto be called.
+}
+
+
+THREADED_TEST(AccessControl) {
+  v8::HandleScope handle_scope;
+  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+
+  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
+                                           IndexedAccessBlocker);
+
+  // Add an accessor accessible by cross-domain JS code.
+  global_template->SetAccessor(
+      v8_str("accessible_prop"),
+      EchoGetter, EchoSetter,
+      v8::Handle<Value>(),
+      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
+
+  // Add an accessor that is not accessible by cross-domain JS code.
+  global_template->SetAccessor(v8_str("blocked_access_prop"),
+                               UnreachableGetter, UnreachableSetter,
+                               v8::Handle<Value>(),
+                               v8::DEFAULT);
+
+  // Create an environment
+  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
+  context0->Enter();
+
+  v8::Handle<v8::Object> global0 = context0->Global();
+
+  v8::HandleScope scope1;
+
+  v8::Persistent<Context> context1 = Context::New();
+  context1->Enter();
+
+  v8::Handle<v8::Object> global1 = context1->Global();
+  global1->Set(v8_str("other"), global0);
+
+  v8::Handle<Value> value;
+
+  // Access blocked property
+  value = v8_compile("other.blocked_prop = 1")->Run();
+  value = v8_compile("other.blocked_prop")->Run();
+  CHECK(value->IsUndefined());
+
+  // Access accessible property
+  value = v8_compile("other.accessible_prop = 3")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(3, value->Int32Value());
+
+  value = v8_compile("other.accessible_prop")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(3, value->Int32Value());
+
+  context1->Exit();
+  context0->Exit();
+  context1.Dispose();
+  context0.Dispose();
+}
+
+
+static v8::Handle<Value> ConstTenGetter(Local<String> name,
+                                        const AccessorInfo& info) {
+  return v8_num(10);
+}
+
+
+THREADED_TEST(CrossDomainAccessors) {
+  v8::HandleScope handle_scope;
+
+  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
+
+  v8::Handle<v8::ObjectTemplate> global_template =
+      func_template->InstanceTemplate();
+
+  v8::Handle<v8::ObjectTemplate> proto_template =
+      func_template->PrototypeTemplate();
+
+  // Add an accessor to proto that's accessible by cross-domain JS code.
+  proto_template->SetAccessor(v8_str("accessible"),
+                              ConstTenGetter, 0,
+                              v8::Handle<Value>(),
+                              v8::ALL_CAN_READ);
+
+  // Add an accessor that is not accessible by cross-domain JS code.
+  global_template->SetAccessor(v8_str("unreachable"),
+                               UnreachableGetter, 0,
+                               v8::Handle<Value>(),
+                               v8::DEFAULT);
+
+  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
+  context0->Enter();
+
+  Local<v8::Object> global = context0->Global();
+  // Add a normal property that shadows 'accessible'
+  global->Set(v8_str("accessible"), v8_num(11));
+
+  // Enter a new context.
+  v8::HandleScope scope1;
+  v8::Persistent<Context> context1 = Context::New();
+  context1->Enter();
+
+  v8::Handle<v8::Object> global1 = context1->Global();
+  global1->Set(v8_str("other"), global);
+
+  // Should return 10, instead of 11
+  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(10, value->Int32Value());
+
+  value = v8_compile("other.unreachable")->Run();
+  CHECK(value->IsUndefined());
+
+  context1->Exit();
+  context0->Exit();
+  context1.Dispose();
+  context0.Dispose();
+}
+
+
+static int named_access_count = 0;
+static int indexed_access_count = 0;
+
+static bool NamedAccessCounter(Local<v8::Object> global,
+                               Local<Value> name,
+                               v8::AccessType type,
+                               Local<Value> data) {
+  named_access_count++;
+  return true;
+}
+
+
+static bool IndexedAccessCounter(Local<v8::Object> global,
+                                 uint32_t key,
+                                 v8::AccessType type,
+                                 Local<Value> data) {
+  indexed_access_count++;
+  return true;
+}
+
+
+// This one is too easily disturbed by other tests.
+TEST(AccessControlIC) {
+  named_access_count = 0;
+  indexed_access_count = 0;
+
+  v8::HandleScope handle_scope;
+
+  // Create an environment.
+  v8::Persistent<Context> context0 = Context::New();
+  context0->Enter();
+
+  // Create an object that requires access-check functions to be
+  // called for cross-domain access.
+  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
+  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
+                                           IndexedAccessCounter);
+  Local<v8::Object> object = object_template->NewInstance();
+
+  v8::HandleScope scope1;
+
+  // Create another environment.
+  v8::Persistent<Context> context1 = Context::New();
+  context1->Enter();
+
+  // Make easy access to the object from the other environment.
+  v8::Handle<v8::Object> global1 = context1->Global();
+  global1->Set(v8_str("obj"), object);
+
+  v8::Handle<Value> value;
+
+  // Check that the named access-control function is called every time.
+  value = v8_compile("for (var i = 0; i < 10; i++)  obj.prop = 1;")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++)  obj.prop;"
+                     "obj.prop")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(1, value->Int32Value());
+  CHECK_EQ(21, named_access_count);
+
+  // Check that the named access-control function is called every time.
+  value = v8_compile("var p = 'prop';")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
+                     "obj[p]")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(1, value->Int32Value());
+  CHECK_EQ(42, named_access_count);
+
+  // Check that the indexed access-control function is called every time.
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
+                     "obj[0]")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(1, value->Int32Value());
+  CHECK_EQ(21, indexed_access_count);
+
+  context1->Exit();
+  context0->Exit();
+  context1.Dispose();
+  context0.Dispose();
+}
+
+
+static bool NamedAccessFlatten(Local<v8::Object> global,
+                               Local<Value> name,
+                               v8::AccessType type,
+                               Local<Value> data) {
+  char buf[100];
+  int len;
+
+  CHECK(name->IsString());
+
+  memset(buf, 0x1, sizeof(buf));
+  len = Local<String>::Cast(name)->WriteAscii(buf);
+  CHECK_EQ(4, len);
+
+  uint16_t buf2[100];
+
+  memset(buf, 0x1, sizeof(buf));
+  len = Local<String>::Cast(name)->Write(buf2);
+  CHECK_EQ(4, len);
+
+  return true;
+}
+
+
+static bool IndexedAccessFlatten(Local<v8::Object> global,
+                                 uint32_t key,
+                                 v8::AccessType type,
+                                 Local<Value> data) {
+  return true;
+}
+
+
+// Regression test.  In access checks, operations that may cause
+// garbage collection are not allowed.  It used to be the case that
+// using the Write operation on a string could cause a garbage
+// collection due to flattening of the string.  This is no longer the
+// case.
+THREADED_TEST(AccessControlFlatten) {
+  named_access_count = 0;
+  indexed_access_count = 0;
+
+  v8::HandleScope handle_scope;
+
+  // Create an environment.
+  v8::Persistent<Context> context0 = Context::New();
+  context0->Enter();
+
+  // Create an object that requires access-check functions to be
+  // called for cross-domain access.
+  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
+  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
+                                           IndexedAccessFlatten);
+  Local<v8::Object> object = object_template->NewInstance();
+
+  v8::HandleScope scope1;
+
+  // Create another environment.
+  v8::Persistent<Context> context1 = Context::New();
+  context1->Enter();
+
+  // Make easy access to the object from the other environment.
+  v8::Handle<v8::Object> global1 = context1->Global();
+  global1->Set(v8_str("obj"), object);
+
+  v8::Handle<Value> value;
+
+  value = v8_compile("var p = 'as' + 'df';")->Run();
+  value = v8_compile("obj[p];")->Run();
+
+  context1->Exit();
+  context0->Exit();
+  context1.Dispose();
+  context0.Dispose();
+}
+
+
+static v8::Handle<Value> AccessControlNamedGetter(
+    Local<String>, const AccessorInfo&) {
+  return v8::Integer::New(42);
+}
+
+
+static v8::Handle<Value> AccessControlNamedSetter(
+    Local<String>, Local<Value> value, const AccessorInfo&) {
+  return value;
+}
+
+
+static v8::Handle<Value> AccessControlIndexedGetter(
+      uint32_t index,
+      const AccessorInfo& info) {
+  return v8_num(42);
+}
+
+
+static v8::Handle<Value> AccessControlIndexedSetter(
+    uint32_t, Local<Value> value, const AccessorInfo&) {
+  return value;
+}
+
+
+THREADED_TEST(AccessControlInterceptorIC) {
+  named_access_count = 0;
+  indexed_access_count = 0;
+
+  v8::HandleScope handle_scope;
+
+  // Create an environment.
+  v8::Persistent<Context> context0 = Context::New();
+  context0->Enter();
+
+  // Create an object that requires access-check functions to be
+  // called for cross-domain access.  The object also has interceptors
+  // interceptor.
+  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
+  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
+                                           IndexedAccessCounter);
+  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
+                                           AccessControlNamedSetter);
+  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
+                                             AccessControlIndexedSetter);
+  Local<v8::Object> object = object_template->NewInstance();
+
+  v8::HandleScope scope1;
+
+  // Create another environment.
+  v8::Persistent<Context> context1 = Context::New();
+  context1->Enter();
+
+  // Make easy access to the object from the other environment.
+  v8::Handle<v8::Object> global1 = context1->Global();
+  global1->Set(v8_str("obj"), object);
+
+  v8::Handle<Value> value;
+
+  // Check that the named access-control function is called every time
+  // eventhough there is an interceptor on the object.
+  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
+                     "obj.x")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(42, value->Int32Value());
+  CHECK_EQ(21, named_access_count);
+
+  value = v8_compile("var p = 'x';")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
+                     "obj[p]")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(42, value->Int32Value());
+  CHECK_EQ(42, named_access_count);
+
+  // Check that the indexed access-control function is called every
+  // time eventhough there is an interceptor on the object.
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
+  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
+                     "obj[0]")->Run();
+  CHECK(value->IsNumber());
+  CHECK_EQ(42, value->Int32Value());
+  CHECK_EQ(21, indexed_access_count);
+
+  context1->Exit();
+  context0->Exit();
+  context1.Dispose();
+  context0.Dispose();
+}
+
+
+THREADED_TEST(Version) {
+  v8::V8::GetVersion();
+}
+
+
+static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(12);
+}
+
+
+THREADED_TEST(InstanceProperties) {
+  v8::HandleScope handle_scope;
+  LocalContext context;
+
+  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+  Local<ObjectTemplate> instance = t->InstanceTemplate();
+
+  instance->Set(v8_str("x"), v8_num(42));
+  instance->Set(v8_str("f"),
+                v8::FunctionTemplate::New(InstanceFunctionCallback));
+
+  Local<Value> o = t->GetFunction()->NewInstance();
+
+  context->Global()->Set(v8_str("i"), o);
+  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
+  CHECK_EQ(42, value->Int32Value());
+
+  value = Script::Compile(v8_str("i.f()"))->Run();
+  CHECK_EQ(12, value->Int32Value());
+}
+
+
+static v8::Handle<Value>
+GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  return v8::Handle<Value>();
+}
+
+
+THREADED_TEST(GlobalObjectInstanceProperties) {
+  v8::HandleScope handle_scope;
+
+  Local<Value> global_object;
+
+  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+  t->InstanceTemplate()->SetNamedPropertyHandler(
+      GlobalObjectInstancePropertiesGet);
+  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+  instance_template->Set(v8_str("x"), v8_num(42));
+  instance_template->Set(v8_str("f"),
+                         v8::FunctionTemplate::New(InstanceFunctionCallback));
+
+  {
+    LocalContext env(NULL, instance_template);
+    // Hold on to the global object so it can be used again in another
+    // environment initialization.
+    global_object = env->Global();
+
+    Local<Value> value = Script::Compile(v8_str("x"))->Run();
+    CHECK_EQ(42, value->Int32Value());
+    value = Script::Compile(v8_str("f()"))->Run();
+    CHECK_EQ(12, value->Int32Value());
+  }
+
+  {
+    // Create new environment reusing the global object.
+    LocalContext env(NULL, instance_template, global_object);
+    Local<Value> value = Script::Compile(v8_str("x"))->Run();
+    CHECK_EQ(42, value->Int32Value());
+    value = Script::Compile(v8_str("f()"))->Run();
+    CHECK_EQ(12, value->Int32Value());
+  }
+}
+
+
+static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(42);
+}
+
+
+static int shadow_y;
+static int shadow_y_setter_call_count;
+static int shadow_y_getter_call_count;
+
+
+static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
+  shadow_y_setter_call_count++;
+  shadow_y = 42;
+}
+
+
+static v8::Handle<Value> ShadowYGetter(Local<String> name,
+                                       const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  shadow_y_getter_call_count++;
+  return v8_num(shadow_y);
+}
+
+
+static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
+                                          const AccessorInfo& info) {
+  return v8::Handle<Value>();
+}
+
+
+static v8::Handle<Value> ShadowNamedGet(Local<String> key,
+                                        const AccessorInfo&) {
+  return v8::Handle<Value>();
+}
+
+
+THREADED_TEST(ShadowObject) {
+  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
+  v8::HandleScope handle_scope;
+
+  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
+  LocalContext context(NULL, global_template);
+
+  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
+  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
+  Local<ObjectTemplate> proto = t->PrototypeTemplate();
+  Local<ObjectTemplate> instance = t->InstanceTemplate();
+
+  // Only allow calls of f on instances of t.
+  Local<v8::Signature> signature = v8::Signature::New(t);
+  proto->Set(v8_str("f"),
+             v8::FunctionTemplate::New(ShadowFunctionCallback,
+                                       Local<Value>(),
+                                       signature));
+  proto->Set(v8_str("x"), v8_num(12));
+
+  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
+
+  Local<Value> o = t->GetFunction()->NewInstance();
+  context->Global()->Set(v8_str("__proto__"), o);
+
+  Local<Value> value =
+      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
+  CHECK(value->IsBoolean());
+  CHECK(!value->BooleanValue());
+
+  value = Script::Compile(v8_str("x"))->Run();
+  CHECK_EQ(12, value->Int32Value());
+
+  value = Script::Compile(v8_str("f()"))->Run();
+  CHECK_EQ(42, value->Int32Value());
+
+  Script::Compile(v8_str("y = 42"))->Run();
+  CHECK_EQ(1, shadow_y_setter_call_count);
+  value = Script::Compile(v8_str("y"))->Run();
+  CHECK_EQ(1, shadow_y_getter_call_count);
+  CHECK_EQ(42, value->Int32Value());
+}
+
+
+THREADED_TEST(HiddenPrototype) {
+  v8::HandleScope handle_scope;
+  LocalContext context;
+
+  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
+  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
+  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
+  t1->SetHiddenPrototype(true);
+  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
+  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
+  t2->SetHiddenPrototype(true);
+  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
+  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
+  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
+
+  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
+  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
+  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
+  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
+
+  // Setting the prototype on an object skips hidden prototypes.
+  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
+  o0->Set(v8_str("__proto__"), o1);
+  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
+  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
+  o0->Set(v8_str("__proto__"), o2);
+  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
+  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
+  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
+  o0->Set(v8_str("__proto__"), o3);
+  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
+  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
+  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
+  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
+
+  // Getting the prototype of o0 should get the first visible one
+  // which is o3.  Therefore, z should not be defined on the prototype
+  // object.
+  Local<Value> proto = o0->Get(v8_str("__proto__"));
+  CHECK(proto->IsObject());
+  CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
+}
+
+
+THREADED_TEST(GetterSetterExceptions) {
+  v8::HandleScope handle_scope;
+  LocalContext context;
+  CompileRun(
+    "function Foo() { };"
+    "function Throw() { throw 5; };"
+    "var x = { };"
+    "x.__defineSetter__('set', Throw);"
+    "x.__defineGetter__('get', Throw);");
+  Local<v8::Object> x =
+      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
+  v8::TryCatch try_catch;
+  x->Set(v8_str("set"), v8::Integer::New(8));
+  x->Get(v8_str("get"));
+  x->Set(v8_str("set"), v8::Integer::New(8));
+  x->Get(v8_str("get"));
+  x->Set(v8_str("set"), v8::Integer::New(8));
+  x->Get(v8_str("get"));
+  x->Set(v8_str("set"), v8::Integer::New(8));
+  x->Get(v8_str("get"));
+}
+
+
+THREADED_TEST(Constructor) {
+  v8::HandleScope handle_scope;
+  LocalContext context;
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->SetClassName(v8_str("Fun"));
+  Local<Function> cons = templ->GetFunction();
+  context->Global()->Set(v8_str("Fun"), cons);
+  Local<v8::Object> inst = cons->NewInstance();
+  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
+  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
+  CHECK(value->BooleanValue());
+}
+
+THREADED_TEST(FunctionDescriptorException) {
+  v8::HandleScope handle_scope;
+  LocalContext context;
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->SetClassName(v8_str("Fun"));
+  Local<Function> cons = templ->GetFunction();
+  context->Global()->Set(v8_str("Fun"), cons);
+  Local<Value> value = CompileRun(
+    "function test() {"
+    "  try {"
+    "    (new Fun()).blah()"
+    "  } catch (e) {"
+    "    var str = String(e);"
+    "    if (str.indexOf('TypeError') == -1) return 1;"
+    "    if (str.indexOf('[object Fun]') != -1) return 2;"
+    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
+    "    return 0;"
+    "  }"
+    "  return 4;"
+    "}"
+    "test();");
+  CHECK_EQ(0, value->Int32Value());
+}
+
+
+THREADED_TEST(CrossEval) {
+  v8::HandleScope scope;
+  LocalContext other;
+  LocalContext current;
+
+  Local<String> token = v8_str("<security token>");
+  other->SetSecurityToken(token);
+  current->SetSecurityToken(token);
+
+  // Setup reference from current to other.
+  current->Global()->Set(v8_str("other"), other->Global());
+
+  // Check that new variables are introduced in other context.
+  Local<Script> script =
+      Script::Compile(v8_str("other.eval('var foo = 1234')"));
+  script->Run();
+  Local<Value> foo = other->Global()->Get(v8_str("foo"));
+  CHECK_EQ(1234, foo->Int32Value());
+  CHECK(!current->Global()->Has(v8_str("foo")));
+
+  // Check that writing to non-existing properties introduces them in
+  // the current context.
+  script =
+      Script::Compile(v8_str("other.eval('na = 1234')"));
+  script->Run();
+  CHECK_EQ(1234, current->Global()->Get(v8_str("na"))->Int32Value());
+  CHECK(!other->Global()->Has(v8_str("na")));
+
+  // Check that variables in current context are visible in other
+  // context. This must include local variables.
+  script =
+      Script::Compile(v8_str("var bar = 42;"
+                                      "(function() { "
+                                      "  var baz = 87;"
+                                      "  return other.eval('bar + baz');"
+                                      "})();"));
+  Local<Value> result = script->Run();
+  CHECK_EQ(42 + 87, result->Int32Value());
+
+  // Check that global variables in the other environment are visible
+  // when evaluting code.
+  other->Global()->Set(v8_str("bis"), v8_num(1234));
+  script = Script::Compile(v8_str("other.eval('bis')"));
+  CHECK_EQ(1234, script->Run()->Int32Value());
+
+  // Check that the 'this' pointer isn't touched as a result of
+  // calling eval across environments.
+  script =
+      Script::Compile(v8_str("var t = this; other.eval('this == t')"));
+  result = script->Run();
+  CHECK(result->IsBoolean());
+  CHECK(result->BooleanValue());
+
+  // Check that doing a cross eval works from within a global
+  // with-statement.
+  script =
+      Script::Compile(v8_str("other.y = 1;"
+                                      "with({x:2}){other.eval('x+y')}"));
+  result = script->Run();
+  CHECK_EQ(3, result->Int32Value());
+}
+
+
+THREADED_TEST(CrossLazyLoad) {
+  v8::HandleScope scope;
+  LocalContext other;
+  LocalContext current;
+
+  Local<String> token = v8_str("<security token>");
+  other->SetSecurityToken(token);
+  current->SetSecurityToken(token);
+
+  // Setup reference from current to other.
+  current->Global()->Set(v8_str("other"), other->Global());
+
+  // Trigger lazy loading in other context.
+  Local<Script> script =
+      Script::Compile(v8_str("other.eval('new Date(42)')"));
+  Local<Value> value = script->Run();
+  CHECK_EQ(42.0, value->NumberValue());
+}
+
+
+static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return args[0];
+}
+
+
+// Test that a call handler can be set for objects which will allow
+// non-function objects created through the API to be called as
+// functions.
+THREADED_TEST(CallAsFunction) {
+  v8::HandleScope scope;
+  LocalContext context;
+
+  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+  instance_template->SetCallAsFunctionHandler(call_as_function);
+  Local<v8::Object> instance = t->GetFunction()->NewInstance();
+  context->Global()->Set(v8_str("obj"), instance);
+  v8::TryCatch try_catch;
+  Local<Value> value;
+  CHECK(!try_catch.HasCaught());
+
+  value = Script::Compile(v8_str("obj(42)"))->Run();
+  CHECK(!try_catch.HasCaught());
+  CHECK_EQ(42, value->Int32Value());
+
+  value = Script::Compile(v8_str("(function(o){return o(49)})(obj)"))->Run();
+  CHECK(!try_catch.HasCaught());
+  CHECK_EQ(49, value->Int32Value());
+
+  // test special case of call as function
+  value = Script::Compile(v8_str("[obj]['0'](45)"))->Run();
+  CHECK(!try_catch.HasCaught());
+  CHECK_EQ(45, value->Int32Value());
+
+  value = Script::Compile(v8_str("obj.call = Function.prototype.call;"
+                                 "obj.call(null, 87)"))->Run();
+  CHECK(!try_catch.HasCaught());
+  CHECK_EQ(87, value->Int32Value());
+
+  // Regression tests for bug #1116356: Calling call through call/apply
+  // must work for non-function receivers.
+  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
+  value = Script::Compile(v8_str(apply_99))->Run();
+  CHECK(!try_catch.HasCaught());
+  CHECK_EQ(99, value->Int32Value());
+
+  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
+  value = Script::Compile(v8_str(call_17))->Run();
+  CHECK(!try_catch.HasCaught());
+  CHECK_EQ(17, value->Int32Value());
+
+  // Try something that will cause an exception: Call the object as a
+  // constructor. This should be the last test.
+  value = Script::Compile(v8_str("new obj(42)"))->Run();
+  CHECK(try_catch.HasCaught());
+}
+
+
+static int CountHandles() {
+  return v8::HandleScope::NumberOfHandles();
+}
+
+
+static int Recurse(int depth, int iterations) {
+  v8::HandleScope scope;
+  if (depth == 0) return CountHandles();
+  for (int i = 0; i < iterations; i++) {
+    Local<v8::Number> n = v8::Integer::New(42);
+  }
+  return Recurse(depth - 1, iterations);
+}
+
+
+THREADED_TEST(HandleIteration) {
+  static const int kIterations = 500;
+  static const int kNesting = 200;
+  CHECK_EQ(0, CountHandles());
+  {
+    v8::HandleScope scope1;
+    CHECK_EQ(0, CountHandles());
+    for (int i = 0; i < kIterations; i++) {
+      Local<v8::Number> n = v8::Integer::New(42);
+      CHECK_EQ(i + 1, CountHandles());
+    }
+
+    CHECK_EQ(kIterations, CountHandles());
+    {
+      v8::HandleScope scope2;
+      for (int j = 0; j < kIterations; j++) {
+        Local<v8::Number> n = v8::Integer::New(42);
+        CHECK_EQ(j + 1 + kIterations, CountHandles());
+      }
+    }
+    CHECK_EQ(kIterations, CountHandles());
+  }
+  CHECK_EQ(0, CountHandles());
+  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
+}
+
+
+static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
+    Local<String> name,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  return v8::Handle<Value>();
+}
+
+
+THREADED_TEST(InterceptorHasOwnProperty) {
+  v8::HandleScope scope;
+  LocalContext context;
+  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
+  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
+  Local<Function> function = fun_templ->GetFunction();
+  context->Global()->Set(v8_str("constructor"), function);
+  v8::Handle<Value> value = CompileRun(
+      "var o = new constructor();"
+      "o.hasOwnProperty('ostehaps');");
+  CHECK_EQ(false, value->BooleanValue());
+  value = CompileRun(
+      "o.ostehaps = 42;"
+      "o.hasOwnProperty('ostehaps');");
+  CHECK_EQ(true, value->BooleanValue());
+  value = CompileRun(
+      "var p = new constructor();"
+      "p.hasOwnProperty('ostehaps');");
+  CHECK_EQ(false, value->BooleanValue());
+}
+
+
+static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
+                                                 const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(v8_str("x")->Equals(name));
+  return v8::Integer::New(42);
+}
+
+
+// This test should hit the load IC for the interceptor case.
+THREADED_TEST(InterceptorLoadIC) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorLoadICGetter);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result = o.x;"
+    "}");
+  CHECK_EQ(42, value->Int32Value());
+}
+
+
+static v8::Handle<Value> InterceptorStoreICSetter(
+    Local<String> key, Local<Value> value, const AccessorInfo&) {
+  CHECK(v8_str("x")->Equals(key));
+  CHECK_EQ(42, value->Int32Value());
+  return value;
+}
+
+
+// This test should hit the store IC for the interceptor case.
+THREADED_TEST(InterceptorStoreIC) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
+                                 InterceptorStoreICSetter);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  v8::Handle<Value> value = CompileRun(
+    "for (var i = 0; i < 1000; i++) {"
+    "  o.x = 42;"
+    "}");
+}
+
+
+
+v8::Handle<Value> call_ic_function;
+v8::Handle<Value> call_ic_function2;
+v8::Handle<Value> call_ic_function3;
+
+static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
+                                                 const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(v8_str("x")->Equals(name));
+  return call_ic_function;
+}
+
+
+// This test should hit the call IC for the interceptor case.
+THREADED_TEST(InterceptorCallIC) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
+  LocalContext context;
+  context->Global()->Set(v8_str("o"), templ->NewInstance());
+  call_ic_function =
+      v8_compile("function f(x) { return x + 1; }; f")->Run();
+  v8::Handle<Value> value = CompileRun(
+    "var result = 0;"
+    "for (var i = 0; i < 1000; i++) {"
+    "  result = o.x(41);"
+    "}");
+  CHECK_EQ(42, value->Int32Value());
+}
+
+static int interceptor_call_count = 0;
+
+static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
+                                                     const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
+    return call_ic_function2;
+  }
+  return v8::Handle<Value>();
+}
+
+
+// This test should hit load and call ICs for the interceptor case.
+// Once in a while, the interceptor will reply that a property was not
+// found in which case we should get a reference error.
+THREADED_TEST(InterceptorICReferenceErrors) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
+  LocalContext context(0, templ, v8::Handle<Value>());
+  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
+  v8::Handle<Value> value = CompileRun(
+    "function f() {"
+    "  for (var i = 0; i < 1000; i++) {"
+    "    try { x; } catch(e) { return true; }"
+    "  }"
+    "  return false;"
+    "};"
+    "f();");
+  CHECK_EQ(true, value->BooleanValue());
+  interceptor_call_count = 0;
+  value = CompileRun(
+    "function g() {"
+    "  for (var i = 0; i < 1000; i++) {"
+    "    try { x(42); } catch(e) { return true; }"
+    "  }"
+    "  return false;"
+    "};"
+    "g();");
+  CHECK_EQ(true, value->BooleanValue());
+}
+
+
+static int interceptor_ic_exception_get_count = 0;
+
+static v8::Handle<Value> InterceptorICExceptionGetter(
+    Local<String> name,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
+    return call_ic_function3;
+  }
+  if (interceptor_ic_exception_get_count == 20) {
+    return v8::ThrowException(v8_num(42));
+  }
+  // Do not handle get for properties other than x.
+  return v8::Handle<Value>();
+}
+
+// Test interceptor load/call IC where the interceptor throws an
+// exception once in a while.
+THREADED_TEST(InterceptorICGetterExceptions) {
+  interceptor_ic_exception_get_count = 0;
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
+  LocalContext context(0, templ, v8::Handle<Value>());
+  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
+  v8::Handle<Value> value = CompileRun(
+    "function f() {"
+    "  for (var i = 0; i < 100; i++) {"
+    "    try { x; } catch(e) { return true; }"
+    "  }"
+    "  return false;"
+    "};"
+    "f();");
+  CHECK_EQ(true, value->BooleanValue());
+  interceptor_ic_exception_get_count = 0;
+  value = CompileRun(
+    "function f() {"
+    "  for (var i = 0; i < 100; i++) {"
+    "    try { x(42); } catch(e) { return true; }"
+    "  }"
+    "  return false;"
+    "};"
+    "f();");
+  CHECK_EQ(true, value->BooleanValue());
+}
+
+
+static int interceptor_ic_exception_set_count = 0;
+
+static v8::Handle<Value> InterceptorICExceptionSetter(
+      Local<String> key, Local<Value> value, const AccessorInfo&) {
+  ApiTestFuzzer::Fuzz();
+  if (++interceptor_ic_exception_set_count > 20) {
+    return v8::ThrowException(v8_num(42));
+  }
+  // Do not actually handle setting.
+  return v8::Handle<Value>();
+}
+
+// Test interceptor store IC where the interceptor throws an exception
+// once in a while.
+THREADED_TEST(InterceptorICSetterExceptions) {
+  interceptor_ic_exception_set_count = 0;
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
+  LocalContext context(0, templ, v8::Handle<Value>());
+  v8::Handle<Value> value = CompileRun(
+    "function f() {"
+    "  for (var i = 0; i < 100; i++) {"
+    "    try { x = 42; } catch(e) { return true; }"
+    "  }"
+    "  return false;"
+    "};"
+    "f();");
+  CHECK_EQ(true, value->BooleanValue());
+}
+
+
+// Test that we ignore null interceptors.
+THREADED_TEST(NullNamedInterceptor) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetNamedPropertyHandler(0);
+  LocalContext context;
+  templ->Set("x", v8_num(42));
+  v8::Handle<v8::Object> obj = templ->NewInstance();
+  context->Global()->Set(v8_str("obj"), obj);
+  v8::Handle<Value> value = CompileRun("obj.x");
+  CHECK(value->IsInt32());
+  CHECK_EQ(42, value->Int32Value());
+}
+
+
+// Test that we ignore null interceptors.
+THREADED_TEST(NullIndexedInterceptor) {
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetIndexedPropertyHandler(0);
+  LocalContext context;
+  templ->Set("42", v8_num(42));
+  v8::Handle<v8::Object> obj = templ->NewInstance();
+  context->Global()->Set(v8_str("obj"), obj);
+  v8::Handle<Value> value = CompileRun("obj[42]");
+  CHECK(value->IsInt32());
+  CHECK_EQ(42, value->Int32Value());
+}
+
+
+static v8::Handle<Value> ParentGetter(Local<String> name,
+                                      const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(1);
+}
+
+
+static v8::Handle<Value> ChildGetter(Local<String> name,
+                                     const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(42);
+}
+
+
+THREADED_TEST(Overriding) {
+  v8::HandleScope scope;
+  LocalContext context;
+
+  // Parent template.
+  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
+  Local<ObjectTemplate> parent_instance_templ =
+      parent_templ->InstanceTemplate();
+  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
+
+  // Template that inherits from the parent template.
+  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
+  Local<ObjectTemplate> child_instance_templ =
+      child_templ->InstanceTemplate();
+  child_templ->Inherit(parent_templ);
+  // Override 'f'.  The child version of 'f' should get called for child
+  // instances.
+  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
+  // Add 'g' twice.  The 'g' added last should get called for instances.
+  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
+  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
+
+  // Add 'h' as an accessor to the proto template with ReadOnly attributes
+  // so 'h' can be shadowed on the instance object.
+  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
+  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
+      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
+
+  // Add 'i' as an accessor to the instance template with ReadOnly attributes
+  // but the attribute does not have effect because it is duplicated with
+  // NULL setter.
+  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
+      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
+
+
+
+  // Instantiate the child template.
+  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
+
+  // Check that the child function overrides the parent one.
+  context->Global()->Set(v8_str("o"), instance);
+  Local<Value> value = v8_compile("o.f")->Run();
+  // Check that the 'g' that was added last is hit.
+  CHECK_EQ(42, value->Int32Value());
+  value = v8_compile("o.g")->Run();
+  CHECK_EQ(42, value->Int32Value());
+
+  // Check 'h' can be shadowed.
+  value = v8_compile("o.h = 3; o.h")->Run();
+  CHECK_EQ(3, value->Int32Value());
+
+  // Check 'i' is cannot be shadowed or changed.
+  value = v8_compile("o.i = 3; o.i")->Run();
+  CHECK_EQ(42, value->Int32Value());
+}
+
+
+static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  if (args.IsConstructCall()) {
+    return v8::Boolean::New(true);
+  }
+  return v8::Boolean::New(false);
+}
+
+
+THREADED_TEST(IsConstructCall) {
+  v8::HandleScope scope;
+
+  // Function template with call handler.
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->SetCallHandler(IsConstructHandler);
+
+  LocalContext context;
+
+  context->Global()->Set(v8_str("f"), templ->GetFunction());
+  Local<Value> value = v8_compile("f()")->Run();
+  CHECK(!value->BooleanValue());
+  value = v8_compile("new f()")->Run();
+  CHECK(value->BooleanValue());
+}
+
+
+THREADED_TEST(ObjectProtoToString) {
+  v8::HandleScope scope;
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+  templ->SetClassName(v8_str("MyClass"));
+
+  LocalContext context;
+
+  Local<String> customized_tostring = v8_str("customized toString");
+
+  // Replace Object.prototype.toString
+  v8_compile("Object.prototype.toString = function() {"
+                  "  return 'customized toString';"
+                  "}")->Run();
+
+  // Normal ToString call should call replaced Object.prototype.toString
+  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
+  Local<String> value = instance->ToString();
+  CHECK(value->IsString() && value->Equals(customized_tostring));
+
+  // ObjectProtoToString should not call replace toString function.
+  value = instance->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
+
+  // Check global
+  value = context->Global()->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
+
+  // Check ordinary object
+  Local<Value> object = v8_compile("new Object()")->Run();
+  value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
+}
+
+
+bool ApiTestFuzzer::fuzzing_ = false;
+v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
+  v8::internal::OS::CreateSemaphore(0);
+int ApiTestFuzzer::active_tests_;
+int ApiTestFuzzer::tests_being_run_;
+int ApiTestFuzzer::current_;
+
+
+// We are in a callback and want to switch to another thread (if we
+// are currently running the thread fuzzing test).
+void ApiTestFuzzer::Fuzz() {
+  if (!fuzzing_) return;
+  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
+  test->ContextSwitch();
+}
+
+
+// Let the next thread go.  Since it is also waiting on the V8 lock it may
+// not start immediately.
+bool ApiTestFuzzer::NextThread() {
+  int test_position = GetNextTestNumber();
+  int test_number = RegisterThreadedTest::nth(current_)->fuzzer_->test_number_;
+  if (test_position == current_) {
+    printf("Stay with %d\n", test_number);
+    return false;
+  }
+  printf("Switch from %d to %d\n",
+         current_ < 0 ? 0 : test_number, test_position < 0 ? 0 : test_number);
+  current_ = test_position;
+  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
+  return true;
+}
+
+
+void ApiTestFuzzer::Run() {
+  // When it is our turn...
+  gate_->Wait();
+  {
+    // ... get the V8 lock and start running the test.
+    v8::Locker locker;
+    CallTest();
+  }
+  // This test finished.
+  active_ = false;
+  active_tests_--;
+  // If it was the last then signal that fact.
+  if (active_tests_ == 0) {
+    all_tests_done_->Signal();
+  } else {
+    // Otherwise select a new test and start that.
+    NextThread();
+  }
+}
+
+
+static unsigned linear_congruential_generator;
+
+
+void ApiTestFuzzer::Setup(PartOfTest part) {
+  linear_congruential_generator = i::FLAG_testing_prng_seed;
+  fuzzing_ = true;
+  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
+  int end = (part == FIRST_PART)
+      ? (RegisterThreadedTest::count() >> 1)
+      : RegisterThreadedTest::count();
+  active_tests_ = tests_being_run_ = end - start;
+  for (int i = 0; i < tests_being_run_; i++) {
+    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
+  }
+  for (int i = 0; i < active_tests_; i++) {
+    RegisterThreadedTest::nth(i)->fuzzer_->Start();
+  }
+}
+
+
+static void CallTestNumber(int test_number) {
+  (RegisterThreadedTest::nth(test_number)->callback())();
+}
+
+
+void ApiTestFuzzer::RunAllTests() {
+  // Set off the first test.
+  current_ = -1;
+  NextThread();
+  // Wait till they are all done.
+  all_tests_done_->Wait();
+}
+
+
+int ApiTestFuzzer::GetNextTestNumber() {
+  int next_test;
+  do {
+    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
+    linear_congruential_generator *= 1664525u;
+    linear_congruential_generator += 1013904223u;
+  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
+  return next_test;
+}
+
+
+void ApiTestFuzzer::ContextSwitch() {
+  // If the new thread is the same as the current thread there is nothing to do.
+  if (NextThread()) {
+    // Now it can start.
+    v8::Unlocker unlocker;
+    // Wait till someone starts us again.
+    gate_->Wait();
+    // And we're off.
+  }
+}
+
+
+void ApiTestFuzzer::TearDown() {
+  fuzzing_ = false;
+}
+
+
+// Lets not be needlessly self-referential.
+TEST(Threading) {
+  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
+  ApiTestFuzzer::RunAllTests();
+  ApiTestFuzzer::TearDown();
+}
+
+TEST(Threading2) {
+  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
+  ApiTestFuzzer::RunAllTests();
+  ApiTestFuzzer::TearDown();
+}
+
+
+void ApiTestFuzzer::CallTest() {
+  printf("Start test %d\n", test_number_);
+  CallTestNumber(test_number_);
+  printf("End test %d\n", test_number_);
+}
+
+
+static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
+  CHECK(v8::Locker::IsLocked());
+  ApiTestFuzzer::Fuzz();
+  v8::Unlocker unlocker;
+  const char* code = "throw 7;";
+  {
+    v8::Locker nested_locker;
+    v8::HandleScope scope;
+    v8::Handle<Value> exception;
+    { v8::TryCatch try_catch;
+      v8::Handle<Value> value = CompileRun(code);
+      CHECK(value.IsEmpty());
+      CHECK(try_catch.HasCaught());
+      // Make sure to wrap the exception in a new handle because
+      // the handle returned from the TryCatch is destroyed
+      // when the TryCatch is destroyed.
+      exception = Local<Value>::New(try_catch.Exception());
+    }
+    return v8::ThrowException(exception);
+  }
+}
+
+
+static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
+  CHECK(v8::Locker::IsLocked());
+  ApiTestFuzzer::Fuzz();
+  v8::Unlocker unlocker;
+  const char* code = "throw 7;";
+  {
+    v8::Locker nested_locker;
+    v8::HandleScope scope;
+    v8::Handle<Value> value = CompileRun(code);
+    CHECK(value.IsEmpty());
+    return v8_str("foo");
+  }
+}
+
+
+// These are locking tests that don't need to be run again
+// as part of the locking aggregation tests.
+TEST(NestedLockers) {
+  v8::Locker locker;
+  CHECK(v8::Locker::IsLocked());
+  v8::HandleScope scope;
+  LocalContext env;
+  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
+  Local<Function> fun = fun_templ->GetFunction();
+  env->Global()->Set(v8_str("throw_in_js"), fun);
+  Local<Script> script = v8_compile("(function () {"
+                                    "  try {"
+                                    "    throw_in_js();"
+                                    "    return 42;"
+                                    "  } catch (e) {"
+                                    "    return e * 13;"
+                                    "  }"
+                                    "})();");
+  CHECK_EQ(91, script->Run()->Int32Value());
+}
+
+
+// These are locking tests that don't need to be run again
+// as part of the locking aggregation tests.
+TEST(NestedLockersNoTryCatch) {
+  v8::Locker locker;
+  v8::HandleScope scope;
+  LocalContext env;
+  Local<v8::FunctionTemplate> fun_templ =
+      v8::FunctionTemplate::New(ThrowInJSNoCatch);
+  Local<Function> fun = fun_templ->GetFunction();
+  env->Global()->Set(v8_str("throw_in_js"), fun);
+  Local<Script> script = v8_compile("(function () {"
+                                    "  try {"
+                                    "    throw_in_js();"
+                                    "    return 42;"
+                                    "  } catch (e) {"
+                                    "    return e * 13;"
+                                    "  }"
+                                    "})();");
+  CHECK_EQ(91, script->Run()->Int32Value());
+}
+
+
+THREADED_TEST(RecursiveLocking) {
+  v8::Locker locker;
+  {
+    v8::Locker locker2;
+    CHECK(v8::Locker::IsLocked());
+  }
+}
+
+
+static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  v8::Unlocker unlocker;
+  return v8::Undefined();
+}
+
+
+THREADED_TEST(LockUnlockLock) {
+  {
+    v8::Locker locker;
+    v8::HandleScope scope;
+    LocalContext env;
+    Local<v8::FunctionTemplate> fun_templ =
+        v8::FunctionTemplate::New(UnlockForAMoment);
+    Local<Function> fun = fun_templ->GetFunction();
+    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
+    Local<Script> script = v8_compile("(function () {"
+                                      "  unlock_for_a_moment();"
+                                      "  return 42;"
+                                      "})();");
+    CHECK_EQ(42, script->Run()->Int32Value());
+  }
+  {
+    v8::Locker locker;
+    v8::HandleScope scope;
+    LocalContext env;
+    Local<v8::FunctionTemplate> fun_templ =
+        v8::FunctionTemplate::New(UnlockForAMoment);
+    Local<Function> fun = fun_templ->GetFunction();
+    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
+    Local<Script> script = v8_compile("(function () {"
+                                      "  unlock_for_a_moment();"
+                                      "  return 42;"
+                                      "})();");
+    CHECK_EQ(42, script->Run()->Int32Value());
+  }
+}
+
+
+static int GetSurvivingGlobalObjectsCount() {
+  int count = 0;
+  v8::internal::Heap::CollectAllGarbage();
+  v8::internal::HeapIterator it;
+  while (it.has_next()) {
+    v8::internal::HeapObject* object = it.next();
+    if (object->IsJSGlobalObject()) {
+      count++;
+    }
+  }
+#ifdef DEBUG
+  if (count > 0) v8::internal::Heap::TracePathToGlobal();
+#endif
+  return count;
+}
+
+
+TEST(DontLeakGlobalObjects) {
+  // Regression test for issues 1139850 and 1174891.
+
+  v8::V8::Initialize();
+
+  // TODO(121): when running "cctest test-api", the initial count is 2,
+  // after second GC, the counter drops to 1. Needs to figure out why
+  // one GC is not enough to collect all garbage.
+  GetSurvivingGlobalObjectsCount();
+  int count = GetSurvivingGlobalObjectsCount();
+
+  for (int i = 0; i < 5; i++) {
+    { v8::HandleScope scope;
+      LocalContext context;
+    }
+    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
+
+    { v8::HandleScope scope;
+      LocalContext context;
+      v8_compile("Date")->Run();
+    }
+    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
+
+    { v8::HandleScope scope;
+      LocalContext context;
+      v8_compile("/aaa/")->Run();
+    }
+    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
+
+    { v8::HandleScope scope;
+      const char* extension_list[] = { "v8/gc" };
+      v8::ExtensionConfiguration extensions(1, extension_list);
+      LocalContext context(&extensions);
+      v8_compile("gc();")->Run();
+    }
+    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
+  }
+}
+
+
+THREADED_TEST(CheckForCrossContextObjectLiterals) {
+  v8::V8::Initialize();
+
+  const int nof = 2;
+  const char* sources[nof] = {
+    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
+    "Object()"
+  };
+
+  for (int i = 0; i < nof; i++) {
+    const char* source = sources[i];
+    { v8::HandleScope scope;
+      LocalContext context;
+      CompileRun(source);
+    }
+    { v8::HandleScope scope;
+      LocalContext context;
+      CompileRun(source);
+    }
+  }
+}
+
+
+static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
+  v8::HandleScope inner;
+  env->Enter();
+  v8::Handle<Value> three = v8_num(3);
+  v8::Handle<Value> value = inner.Close(three);
+  env->Exit();
+  return value;
+}
+
+
+THREADED_TEST(NestedHandleScopeAndContexts) {
+  v8::HandleScope outer;
+  v8::Persistent<Context> env = Context::New();
+  env->Enter();
+  v8::Handle<Value> value = NestedScope(env);
+  v8::Handle<String> str = value->ToString();
+  env->Exit();
+  env.Dispose();
+}
+
+
+THREADED_TEST(ExternalAllocatedMemory) {
+  v8::HandleScope outer;
+  const int kSize = 1024*1024;
+  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
+  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
+}
+
+
+THREADED_TEST(DisposeEnteredContext) {
+  v8::HandleScope scope;
+  LocalContext outer;
+  { v8::Persistent<v8::Context> inner = v8::Context::New();
+    inner->Enter();
+    inner.Dispose();
+    inner.Clear();
+    inner->Exit();
+  }
+}
+
+
+// Regression test for issue 54, object templates with internal fields
+// but no accessors or interceptors did not get their internal field
+// count set on instances.
+THREADED_TEST(Regress54) {
+  v8::HandleScope outer;
+  LocalContext context;
+  static v8::Persistent<v8::ObjectTemplate> templ;
+  if (templ.IsEmpty()) {
+    v8::HandleScope inner;
+    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
+    local->SetInternalFieldCount(1);
+    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
+  }
+  v8::Handle<v8::Object> result = templ->NewInstance();
+  CHECK_EQ(1, result->InternalFieldCount());
+}
+
+
+// If part of the threaded tests, this test makes ThreadingTest fail
+// on mac.
+TEST(CatchStackOverflow) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::TryCatch try_catch;
+  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
+    "function f() {"
+    "  return f();"
+    "}"
+    ""
+    "f();"));
+  v8::Handle<v8::Value> result = script->Run();
+  CHECK(result.IsEmpty());
+}
+
+
+THREADED_TEST(TryCatchSourceInfo) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::Handle<v8::String> source = v8::String::New(
+      "function Foo() {\n"
+      "  return Bar();\n"
+      "}\n"
+      "\n"
+      "function Bar() {\n"
+      "  return Baz();\n"
+      "}\n"
+      "\n"
+      "function Baz() {\n"
+      "  throw 'nirk';\n"
+      "}\n"
+      "\n"
+      "Foo();\n");
+  v8::Handle<v8::Script> script =
+      v8::Script::Compile(source, v8::String::New("test.js"));
+  v8::TryCatch try_catch;
+  v8::Handle<v8::Value> result = script->Run();
+  CHECK(result.IsEmpty());
+  CHECK(try_catch.HasCaught());
+  v8::Handle<v8::Message> message = try_catch.Message();
+  CHECK(!message.IsEmpty());
+  CHECK_EQ(10, message->GetLineNumber());
+  CHECK_EQ(91, message->GetStartPosition());
+  CHECK_EQ(92, message->GetEndPosition());
+  CHECK_EQ(2, message->GetStartColumn());
+  CHECK_EQ(3, message->GetEndColumn());
+  v8::String::AsciiValue line(message->GetSourceLine());
+  CHECK_EQ("  throw 'nirk';", *line);
+  v8::String::AsciiValue name(message->GetScriptResourceName());
+  CHECK_EQ("test.js", *name);
+}
+
+
+THREADED_TEST(CompilationCache) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::Handle<v8::String> source0 = v8::String::New("1234");
+  v8::Handle<v8::String> source1 = v8::String::New("1234");
+  v8::Handle<v8::Script> script0 =
+      v8::Script::Compile(source0, v8::String::New("test.js"));
+  v8::Handle<v8::Script> script1 =
+      v8::Script::Compile(source1, v8::String::New("test.js"));
+  v8::Handle<v8::Script> script2 =
+      v8::Script::Compile(source0);  // different origin
+  CHECK_EQ(1234, script0->Run()->Int32Value());
+  CHECK_EQ(1234, script1->Run()->Int32Value());
+  CHECK_EQ(1234, script2->Run()->Int32Value());
+}
+
+
+static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  return v8_num(42);
+}
+
+
+THREADED_TEST(CallbackFunctionName) {
+  v8::HandleScope scope;
+  LocalContext context;
+  Local<ObjectTemplate> t = ObjectTemplate::New();
+  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
+  context->Global()->Set(v8_str("obj"), t->NewInstance());
+  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
+  CHECK(value->IsString());
+  v8::String::AsciiValue name(value);
+  CHECK_EQ("asdf", *name);
+}
+
+
+THREADED_TEST(DateAccess) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
+  CHECK(date->IsDate());
+  CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
+}
+
+
+void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
+  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
+  v8::Handle<v8::Array> props = obj->GetPropertyNames();
+  CHECK_EQ(elmc, props->Length());
+  for (int i = 0; i < elmc; i++) {
+    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
+    CHECK_EQ(elmv[i], *elm);
+  }
+}
+
+
+THREADED_TEST(PropertyEnumeration) {
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
+      "var result = [];"
+      "result[0] = {};"
+      "result[1] = {a: 1, b: 2};"
+      "result[2] = [1, 2, 3];"
+      "var proto = {x: 1, y: 2, z: 3};"
+      "var x = { __proto__: proto, w: 0, z: 1 };"
+      "result[3] = x;"
+      "result;"))->Run();
+  v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
+  CHECK_EQ(4, elms->Length());
+  int elmc0 = 0;
+  const char** elmv0 = NULL;
+  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
+  int elmc1 = 2;
+  const char* elmv1[] = {"a", "b"};
+  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
+  int elmc2 = 3;
+  const char* elmv2[] = {"0", "1", "2"};
+  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
+  int elmc3 = 4;
+  const char* elmv3[] = {"w", "z", "x", "y"};
+  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
+}
diff --git a/regexp2000/test/cctest/test-assembler-arm.cc b/regexp2000/test/cctest/test-assembler-arm.cc
new file mode 100644 (file)
index 0000000..f8a952c
--- /dev/null
@@ -0,0 +1,215 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "disassembler.h"
+#include "factory.h"
+#include "simulator-arm.h"
+#include "assembler-arm-inl.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+
+// Define these function prototypes to match JSEntryFunction in execution.cc.
+typedef int (*F1)(int x, int p1, int p2, int p3, int p4);
+typedef int (*F2)(int x, int y, int p2, int p3, int p4);
+typedef int (*F3)(void* p, int p1, int p2, int p3, int p4);
+
+
+static v8::Persistent<v8::Context> env;
+
+
+// The test framework does not accept flags on the command line, so we set them
+static void InitializeVM() {
+  // disable compilation of natives by specifying an empty natives file
+  FLAG_natives_file = "";
+
+  // enable generation of comments
+  FLAG_debug_code = true;
+
+  if (env.IsEmpty()) {
+    env = v8::Context::New();
+  }
+}
+
+
+#define __ assm.
+
+TEST(0) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  Assembler assm(NULL, 0);
+
+  __ add(r0, r0, Operand(r1));
+  __ mov(pc, Operand(lr));
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
+  int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 3, 4, 0, 0, 0));
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(7, res);
+}
+
+
+TEST(1) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  Assembler assm(NULL, 0);
+  Label L, C;
+
+  __ mov(r1, Operand(r0));
+  __ mov(r0, Operand(0));
+  __ b(&C);
+
+  __ bind(&L);
+  __ add(r0, r0, Operand(r1));
+  __ sub(r1, r1, Operand(1));
+
+  __ bind(&C);
+  __ teq(r1, Operand(0));
+  __ b(ne, &L);
+  __ mov(pc, Operand(lr));
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+  int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 100, 0, 0, 0, 0));
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(5050, res);
+}
+
+
+TEST(2) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  Assembler assm(NULL, 0);
+  Label L, C;
+
+  __ mov(r1, Operand(r0));
+  __ mov(r0, Operand(1));
+  __ b(&C);
+
+  __ bind(&L);
+  __ mul(r0, r1, r0);
+  __ sub(r1, r1, Operand(1));
+
+  __ bind(&C);
+  __ teq(r1, Operand(0));
+  __ b(ne, &L);
+  __ mov(pc, Operand(lr));
+
+  // some relocated stuff here, not executed
+  __ RecordComment("dead code, just testing relocations");
+  __ mov(r0, Operand(Factory::true_value()));
+  __ RecordComment("dead code, just testing immediate operands");
+  __ mov(r0, Operand(-1));
+  __ mov(r0, Operand(0xFF000000));
+  __ mov(r0, Operand(0xF0F0F0F0));
+  __ mov(r0, Operand(0xFFF0FFFF));
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+  int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 10, 0, 0, 0, 0));
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(3628800, res);
+}
+
+
+TEST(3) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  typedef struct {
+    int i;
+    char c;
+    int16_t s;
+  } T;
+  T t;
+
+  Assembler assm(NULL, 0);
+  Label L, C;
+
+  __ mov(ip, Operand(sp));
+  __ stm(db_w, sp, r4.bit() | fp.bit() | sp.bit() | lr.bit());
+  __ sub(fp, ip, Operand(4));
+  __ mov(r4, Operand(r0));
+  __ ldr(r0, MemOperand(r4, OFFSET_OF(T, i)));
+  __ mov(r2, Operand(r0, ASR, 1));
+  __ str(r2, MemOperand(r4, OFFSET_OF(T, i)));
+  __ ldrsb(r2, MemOperand(r4, OFFSET_OF(T, c)));
+  __ add(r0, r2, Operand(r0));
+  __ mov(r2, Operand(r2, LSL, 2));
+  __ strb(r2, MemOperand(r4, OFFSET_OF(T, c)));
+  __ ldrsh(r2, MemOperand(r4, OFFSET_OF(T, s)));
+  __ add(r0, r2, Operand(r0));
+  __ mov(r2, Operand(r2, ASR, 3));
+  __ strh(r2, MemOperand(r4, OFFSET_OF(T, s)));
+  __ ldm(ia, sp, r4.bit() | fp.bit() | sp.bit() | pc.bit());
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  t.i = 100000;
+  t.c = 10;
+  t.s = 1000;
+  int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0));
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(101010, res);
+  CHECK_EQ(100000/2, t.i);
+  CHECK_EQ(10*4, t.c);
+  CHECK_EQ(1000/8, t.s);
+}
+
+
+#undef __
diff --git a/regexp2000/test/cctest/test-assembler-ia32.cc b/regexp2000/test/cctest/test-assembler-ia32.cc
new file mode 100644 (file)
index 0000000..2b68300
--- /dev/null
@@ -0,0 +1,376 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "disassembler.h"
+#include "factory.h"
+#include "macro-assembler.h"
+#include "platform.h"
+#include "serialize.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+
+typedef int (*F0)();
+typedef int (*F1)(int x);
+typedef int (*F2)(int x, int y);
+
+
+static v8::Persistent<v8::Context> env;
+
+
+static void InitializeVM() {
+  if (env.IsEmpty()) {
+    env = v8::Context::New();
+  }
+}
+
+
+#define __ assm.
+
+TEST(AssemblerIa320) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+
+  __ mov(eax, Operand(esp, 4));
+  __ add(eax, Operand(esp, 8));
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
+  int res = f(3, 4);
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(7, res);
+}
+
+
+TEST(AssemblerIa321) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+  Label L, C;
+
+  __ mov(edx, Operand(esp, 4));
+  __ xor_(eax, Operand(eax));  // clear eax
+  __ jmp(&C);
+
+  __ bind(&L);
+  __ add(eax, Operand(edx));
+  __ sub(Operand(edx), Immediate(1));
+
+  __ bind(&C);
+  __ test(edx, Operand(edx));
+  __ j(not_zero, &L, taken);
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+  int res = f(100);
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(5050, res);
+}
+
+
+TEST(AssemblerIa322) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+  Label L, C;
+
+  __ mov(edx, Operand(esp, 4));
+  __ mov(eax, 1);
+  __ jmp(&C);
+
+  __ bind(&L);
+  __ imul(eax, Operand(edx));
+  __ sub(Operand(edx), Immediate(1));
+
+  __ bind(&C);
+  __ test(edx, Operand(edx));
+  __ j(not_zero, &L, taken);
+  __ ret(0);
+
+  // some relocated stuff here, not executed
+  __ mov(eax, Factory::true_value());
+  __ jmp(NULL, RelocInfo::RUNTIME_ENTRY);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+  int res = f(10);
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(3628800, res);
+}
+
+
+typedef int (*F3)(float x);
+
+TEST(AssemblerIa323) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+
+  Serializer::disable();  // Needed for Probe when running without snapshot.
+  CpuFeatures::Probe();
+  CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
+  { CpuFeatures::Scope fscope(CpuFeatures::SSE2);
+    __ cvttss2si(eax, Operand(esp, 4));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Code* code =
+      Code::cast(Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB)));
+  // don't print the code - our disassembler can't handle cvttss2si
+  // instead print bytes
+  Disassembler::Dump(stdout,
+                     code->instruction_start(),
+                     code->instruction_start() + code->instruction_size());
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  int res = f(static_cast<float>(-3.1415));
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(-3, res);
+}
+
+
+typedef int (*F4)(double x);
+
+TEST(AssemblerIa324) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+
+  Serializer::disable();  // Needed for Probe when running without snapshot.
+  CpuFeatures::Probe();
+  CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
+  CpuFeatures::Scope fscope(CpuFeatures::SSE2);
+  __ cvttsd2si(eax, Operand(esp, 4));
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Code* code =
+      Code::cast(Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB)));
+  // don't print the code - our disassembler can't handle cvttsd2si
+  // instead print bytes
+  Disassembler::Dump(stdout,
+                     code->instruction_start(),
+                     code->instruction_start() + code->instruction_size());
+  F4 f = FUNCTION_CAST<F4>(code->entry());
+  int res = f(2.718281828);
+  ::printf("f() = %d\n", res);
+  CHECK_EQ(2, res);
+}
+
+
+static int baz = 42;
+TEST(AssemblerIa325) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+
+  __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE));
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Code* code =
+      Code::cast(Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB)));
+  F0 f = FUNCTION_CAST<F0>(code->entry());
+  int res = f();
+  CHECK_EQ(42, res);
+}
+
+
+typedef double (*F5)(double x, double y);
+
+TEST(AssemblerIa326) {
+  InitializeVM();
+  v8::HandleScope scope;
+  Serializer::disable();  // Needed for Probe when running without snapshot.
+  CpuFeatures::Probe();
+  CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
+  CpuFeatures::Scope fscope(CpuFeatures::SSE2);
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+
+  __ movdbl(xmm0, Operand(esp, 1 * kPointerSize));
+  __ movdbl(xmm1, Operand(esp, 3 * kPointerSize));
+  __ addsd(xmm0, xmm1);
+  __ mulsd(xmm0, xmm1);
+  __ subsd(xmm0, xmm1);
+  __ divsd(xmm0, xmm1);
+  // Copy xmm0 to st(0) using eight bytes of stack.
+  __ sub(Operand(esp), Immediate(8));
+  __ movdbl(Operand(esp, 0), xmm0);
+  __ fld_d(Operand(esp, 0));
+  __ add(Operand(esp), Immediate(8));
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Code* code =
+      Code::cast(Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB)));
+#ifdef DEBUG
+  ::printf("\n---\n");
+  // don't print the code - our disassembler can't handle SSE instructions
+  // instead print bytes
+  Disassembler::Dump(stdout,
+                     code->instruction_start(),
+                     code->instruction_start() + code->instruction_size());
+#endif
+  F5 f = FUNCTION_CAST<F5>(code->entry());
+  double res = f(2.2, 1.1);
+  ::printf("f() = %f\n", res);
+  CHECK(2.29 < res && res < 2.31);
+}
+
+
+typedef double (*F6)(int x);
+
+TEST(AssemblerIa328) {
+  InitializeVM();
+  v8::HandleScope scope;
+  Serializer::disable();  // Needed for Probe when running without snapshot.
+  CpuFeatures::Probe();
+  CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
+  CpuFeatures::Scope fscope(CpuFeatures::SSE2);
+  v8::internal::byte buffer[256];
+  Assembler assm(buffer, sizeof buffer);
+  __ mov(eax, Operand(esp, 4));
+  __ cvtsi2sd(xmm0, Operand(eax));
+  // Copy xmm0 to st(0) using eight bytes of stack.
+  __ sub(Operand(esp), Immediate(8));
+  __ movdbl(Operand(esp, 0), xmm0);
+  __ fld_d(Operand(esp, 0));
+  __ add(Operand(esp), Immediate(8));
+  __ ret(0);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Code* code =
+      Code::cast(Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB)));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry());
+  double res = f(12);
+
+  ::printf("f() = %f\n", res);
+  CHECK(11.99 < res && res < 12.001);
+}
+
+
+typedef int (*F7)(double x, double y);
+
+TEST(AssemblerIa329) {
+  InitializeVM();
+  v8::HandleScope scope;
+  v8::internal::byte buffer[256];
+  MacroAssembler assm(buffer, sizeof buffer);
+  enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 };
+  Label equal_l, less_l, greater_l, nan_l;
+  __ fld_d(Operand(esp, 3 * kPointerSize));
+  __ fld_d(Operand(esp, 1 * kPointerSize));
+  __ FCmp();
+  __ j(parity_even, &nan_l, taken);
+  __ j(equal, &equal_l, taken);
+  __ j(below, &less_l, taken);
+  __ j(above, &greater_l, taken);
+
+  __ mov(eax, kUndefined);
+  __ ret(0);
+
+  __ bind(&equal_l);
+  __ mov(eax, kEqual);
+  __ ret(0);
+
+  __ bind(&greater_l);
+  __ mov(eax, kGreater);
+  __ ret(0);
+
+  __ bind(&less_l);
+  __ mov(eax, kLess);
+  __ ret(0);
+
+  __ bind(&nan_l);
+  __ mov(eax, kNaN);
+  __ ret(0);
+
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Code* code =
+      Code::cast(Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB)));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+
+  F7 f = FUNCTION_CAST<F7>(Code::cast(code)->entry());
+  CHECK_EQ(kLess, f(1.1, 2.2));
+  CHECK_EQ(kEqual, f(2.2, 2.2));
+  CHECK_EQ(kGreater, f(3.3, 2.2));
+  CHECK_EQ(kNaN, f(OS::nan_value(), 1.1));
+}
+
+#undef __
diff --git a/regexp2000/test/cctest/test-ast.cc b/regexp2000/test/cctest/test-ast.cc
new file mode 100644 (file)
index 0000000..7d10c82
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "ast.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+TEST(List) {
+  List<Node*>* list = new List<Node*>(0);
+  CHECK_EQ(0, list->length());
+
+  Node* node = new EmptyStatement();
+  list->Add(node);
+  CHECK_EQ(1, list->length());
+  CHECK_EQ(node, list->at(0));
+  CHECK_EQ(node, list->last());
+
+  const int kElements = 100;
+  for (int i = 0; i < kElements; i++) {
+    list->Add(node);
+  }
+  CHECK_EQ(1 + kElements, list->length());
+
+  list->Clear();
+  CHECK_EQ(0, list->length());
+}
+
+
+TEST(RemoveLast) {
+  List<int> list(4);
+  CHECK_EQ(0, list.length());
+  list.Add(1);
+  CHECK_EQ(1, list.length());
+  CHECK_EQ(1, list.last());
+  list.RemoveLast();
+  CHECK_EQ(0, list.length());
+  list.Add(2);
+  list.Add(3);
+  CHECK_EQ(2, list.length());
+  CHECK_EQ(3, list.last());
+  list.RemoveLast();
+  CHECK_EQ(1, list.length());
+  CHECK_EQ(2, list.last());
+  list.RemoveLast();
+  CHECK_EQ(0, list.length());
+
+  const int kElements = 100;
+  for (int i = 0; i < kElements; i++) list.Add(i);
+  for (int j = kElements - 1; j >= 0; j--) {
+    CHECK_EQ(j + 1, list.length());
+    CHECK_EQ(j, list.last());
+    list.RemoveLast();
+    CHECK_EQ(j, list.length());
+  }
+}
+
+
+TEST(DeleteEmpty) {
+  {
+    List<int>* list = new List<int>(0);
+    delete list;
+  }
+  {
+    List<int> list(0);
+  }
+}
diff --git a/regexp2000/test/cctest/test-compiler.cc b/regexp2000/test/cctest/test-compiler.cc
new file mode 100644 (file)
index 0000000..6bfd53b
--- /dev/null
@@ -0,0 +1,304 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "compiler.h"
+#include "execution.h"
+#include "factory.h"
+#include "platform.h"
+#include "top.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static v8::Persistent<v8::Context> env;
+
+// --- P r i n t   E x t e n s i o n ---
+
+class PrintExtension : public v8::Extension {
+ public:
+  PrintExtension() : v8::Extension("v8/print", kSource) { }
+  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
+      v8::Handle<v8::String> name);
+  static v8::Handle<v8::Value> Print(const v8::Arguments& args);
+ private:
+  static const char* kSource;
+};
+
+
+const char* PrintExtension::kSource = "native function print();";
+
+
+v8::Handle<v8::FunctionTemplate> PrintExtension::GetNativeFunction(
+    v8::Handle<v8::String> str) {
+  return v8::FunctionTemplate::New(PrintExtension::Print);
+}
+
+
+v8::Handle<v8::Value> PrintExtension::Print(const v8::Arguments& args) {
+  for (int i = 0; i < args.Length(); i++) {
+    if (i != 0) printf(" ");
+    v8::HandleScope scope;
+    v8::Handle<v8::Value> arg = args[i];
+    v8::Handle<v8::String> string_obj = arg->ToString();
+    if (string_obj.IsEmpty()) return string_obj;
+    int length = string_obj->Length();
+    uint16_t* string = NewArray<uint16_t>(length + 1);
+    string_obj->Write(string);
+    for (int j = 0; j < length; j++)
+      printf("%lc", string[j]);
+    DeleteArray(string);
+  }
+  printf("\n");
+  return v8::Undefined();
+}
+
+
+static PrintExtension kPrintExtension;
+v8::DeclareExtension kPrintExtensionDeclaration(&kPrintExtension);
+
+
+static void InitializeVM() {
+  if (env.IsEmpty()) {
+    v8::HandleScope scope;
+    const char* extensions[] = { "v8/print", "v8/gc" };
+    v8::ExtensionConfiguration config(2, extensions);
+    env = v8::Context::New(&config);
+  }
+  v8::HandleScope scope;
+  env->Enter();
+}
+
+
+static Object* GetGlobalProperty(const char* name) {
+  Handle<String> symbol = Factory::LookupAsciiSymbol(name);
+  return Top::context()->global()->GetProperty(*symbol);
+}
+
+
+static void SetGlobalProperty(const char* name, Object* value) {
+  Handle<Object> object(value);
+  Handle<String> symbol = Factory::LookupAsciiSymbol(name);
+  Handle<JSObject> global(Top::context()->global());
+  SetProperty(global, symbol, object, NONE);
+}
+
+
+static Handle<JSFunction> Compile(const char* source) {
+  Handle<String> source_code(Factory::NewStringFromUtf8(CStrVector(source)));
+  Handle<JSFunction> boilerplate =
+      Compiler::Compile(source_code, Handle<String>(), 0, 0, NULL, NULL);
+  return Factory::NewFunctionFromBoilerplate(boilerplate,
+                                             Top::global_context());
+}
+
+
+static double Inc(int x) {
+  const char* source = "result = %d + 1;";
+  EmbeddedVector<char, 512> buffer;
+  OS::SNPrintF(buffer, source, x);
+
+  Handle<JSFunction> fun = Compile(buffer.start());
+  if (fun.is_null()) return -1;
+
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
+  CHECK(!has_pending_exception);
+  return GetGlobalProperty("result")->Number();
+}
+
+
+TEST(Inc) {
+  InitializeVM();
+  v8::HandleScope scope;
+  CHECK_EQ(4.0, Inc(3));
+}
+
+
+static double Add(int x, int y) {
+  Handle<JSFunction> fun = Compile("result = x + y;");
+  if (fun.is_null()) return -1;
+
+  SetGlobalProperty("x", Smi::FromInt(x));
+  SetGlobalProperty("y", Smi::FromInt(y));
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
+  CHECK(!has_pending_exception);
+  return GetGlobalProperty("result")->Number();
+}
+
+
+TEST(Add) {
+  InitializeVM();
+  v8::HandleScope scope;
+  CHECK_EQ(5.0, Add(2, 3));
+}
+
+
+static double Abs(int x) {
+  Handle<JSFunction> fun = Compile("if (x < 0) result = -x; else result = x;");
+  if (fun.is_null()) return -1;
+
+  SetGlobalProperty("x", Smi::FromInt(x));
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
+  CHECK(!has_pending_exception);
+  return GetGlobalProperty("result")->Number();
+}
+
+
+TEST(Abs) {
+  InitializeVM();
+  v8::HandleScope scope;
+  CHECK_EQ(3.0, Abs(-3));
+}
+
+
+static double Sum(int n) {
+  Handle<JSFunction> fun =
+      Compile("s = 0; while (n > 0) { s += n; n -= 1; }; result = s;");
+  if (fun.is_null()) return -1;
+
+  SetGlobalProperty("n", Smi::FromInt(n));
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
+  CHECK(!has_pending_exception);
+  return GetGlobalProperty("result")->Number();
+}
+
+
+TEST(Sum) {
+  InitializeVM();
+  v8::HandleScope scope;
+  CHECK_EQ(5050.0, Sum(100));
+}
+
+
+TEST(Print) {
+  InitializeVM();
+  v8::HandleScope scope;
+  const char* source = "for (n = 0; n < 100; ++n) print(n, 1, 2);";
+  Handle<JSFunction> fun = Compile(source);
+  if (fun.is_null()) return;
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
+  CHECK(!has_pending_exception);
+}
+
+
+// The following test method stems from my coding efforts today. It
+// tests all the functionality I have added to the compiler today
+TEST(Stuff) {
+  InitializeVM();
+  v8::HandleScope scope;
+  const char* source =
+    "r = 0;\n"
+    "a = new Object;\n"
+    "if (a == a) r+=1;\n"  // 1
+    "if (a != new Object()) r+=2;\n"  // 2
+    "a.x = 42;\n"
+    "if (a.x == 42) r+=4;\n"  // 4
+    "function foo() { var x = 87; return x; }\n"
+    "if (foo() == 87) r+=8;\n"  // 8
+    "function bar() { var x; x = 99; return x; }\n"
+    "if (bar() == 99) r+=16;\n"  // 16
+    "function baz() { var x = 1, y, z = 2; y = 3; return x + y + z; }\n"
+    "if (baz() == 6) r+=32;\n"  // 32
+    "function Cons0() { this.x = 42; this.y = 87; }\n"
+    "if (new Cons0().x == 42) r+=64;\n"  // 64
+    "if (new Cons0().y == 87) r+=128;\n"  // 128
+    "function Cons2(x, y) { this.sum = x + y; }\n"
+    "if (new Cons2(3,4).sum == 7) r+=256;";  // 256
+
+  Handle<JSFunction> fun = Compile(source);
+  CHECK(!fun.is_null());
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
+  CHECK(!has_pending_exception);
+  CHECK_EQ(511.0, GetGlobalProperty("r")->Number());
+}
+
+
+TEST(UncaughtThrow) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  const char* source = "throw 42;";
+  Handle<JSFunction> fun = Compile(source);
+  CHECK(!fun.is_null());
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Handle<Object> result =
+      Execution::Call(fun, global, 0, NULL, &has_pending_exception);
+  CHECK(has_pending_exception);
+  CHECK_EQ(42.0, Top::pending_exception()->Number());
+}
+
+
+// Tests calling a builtin function from C/C++ code, and the builtin function
+// performs GC. It creates a stack frame looks like following:
+//   | C (PerformGC) |
+//   |   JS-to-C     |
+//   |      JS       |
+//   |   C-to-JS     |
+TEST(C2JSFrames) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  const char* source = "function foo(a) { gc(), print(a); }";
+
+  Handle<JSFunction> fun0 = Compile(source);
+  CHECK(!fun0.is_null());
+
+  // Run the generated code to populate the global object with 'foo'.
+  bool has_pending_exception;
+  Handle<JSObject> global(Top::context()->global());
+  Execution::Call(fun0, global, 0, NULL, &has_pending_exception);
+  CHECK(!has_pending_exception);
+
+  Handle<Object> fun1 =
+      Handle<Object>(
+          Top::context()->global()->GetProperty(
+              *Factory::LookupAsciiSymbol("foo")));
+  CHECK(fun1->IsJSFunction());
+
+  Object** argv[1] = {
+    Handle<Object>::cast(Factory::LookupAsciiSymbol("hello")).location()
+  };
+  Execution::Call(Handle<JSFunction>::cast(fun1), global, 1, argv,
+                  &has_pending_exception);
+  CHECK(!has_pending_exception);
+}
diff --git a/regexp2000/test/cctest/test-conversions.cc b/regexp2000/test/cctest/test-conversions.cc
new file mode 100644 (file)
index 0000000..6c0b9a6
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+
+TEST(Hex) {
+  CHECK_EQ(0.0, StringToDouble("0x0", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.0, StringToDouble("0X0", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(1.0, StringToDouble("0x1", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(16.0, StringToDouble("0x10", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(255.0, StringToDouble("0xff", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(175.0, StringToDouble("0xAF", ALLOW_HEX | ALLOW_OCTALS));
+
+  CHECK_EQ(0.0, StringToDouble("0x0", ALLOW_HEX));
+  CHECK_EQ(0.0, StringToDouble("0X0", ALLOW_HEX));
+  CHECK_EQ(1.0, StringToDouble("0x1", ALLOW_HEX));
+  CHECK_EQ(16.0, StringToDouble("0x10", ALLOW_HEX));
+  CHECK_EQ(255.0, StringToDouble("0xff", ALLOW_HEX));
+  CHECK_EQ(175.0, StringToDouble("0xAF", ALLOW_HEX));
+}
+
+
+TEST(Octal) {
+  CHECK_EQ(0.0, StringToDouble("0", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.0, StringToDouble("00", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(1.0, StringToDouble("01", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(7.0, StringToDouble("07", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(8.0, StringToDouble("010", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(63.0, StringToDouble("077", ALLOW_HEX | ALLOW_OCTALS));
+
+  CHECK_EQ(0.0, StringToDouble("0", ALLOW_HEX));
+  CHECK_EQ(0.0, StringToDouble("00", ALLOW_HEX));
+  CHECK_EQ(1.0, StringToDouble("01", ALLOW_HEX));
+  CHECK_EQ(7.0, StringToDouble("07", ALLOW_HEX));
+  CHECK_EQ(10.0, StringToDouble("010", ALLOW_HEX));
+  CHECK_EQ(77.0, StringToDouble("077", ALLOW_HEX));
+}
+
+
+TEST(MalformedOctal) {
+  CHECK_EQ(8.0, StringToDouble("08", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(81.0, StringToDouble("081", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(78.0, StringToDouble("078", ALLOW_HEX | ALLOW_OCTALS));
+
+  CHECK(isnan(StringToDouble("07.7", ALLOW_HEX | ALLOW_OCTALS)));
+  CHECK(isnan(StringToDouble("07.8", ALLOW_HEX | ALLOW_OCTALS)));
+  CHECK(isnan(StringToDouble("07e8", ALLOW_HEX | ALLOW_OCTALS)));
+  CHECK(isnan(StringToDouble("07e7", ALLOW_HEX | ALLOW_OCTALS)));
+
+  CHECK_EQ(8.7, StringToDouble("08.7", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(8e7, StringToDouble("08e7", ALLOW_HEX | ALLOW_OCTALS));
+
+  CHECK_EQ(0.001, StringToDouble("0.001", ALLOW_HEX | ALLOW_OCTALS));
+  CHECK_EQ(0.713, StringToDouble("0.713", ALLOW_HEX | ALLOW_OCTALS));
+
+  CHECK_EQ(8.0, StringToDouble("08", ALLOW_HEX));
+  CHECK_EQ(81.0, StringToDouble("081", ALLOW_HEX));
+  CHECK_EQ(78.0, StringToDouble("078", ALLOW_HEX));
+
+  CHECK_EQ(7.7, StringToDouble("07.7", ALLOW_HEX));
+  CHECK_EQ(7.8, StringToDouble("07.8", ALLOW_HEX));
+  CHECK_EQ(7e8, StringToDouble("07e8", ALLOW_HEX));
+  CHECK_EQ(7e7, StringToDouble("07e7", ALLOW_HEX));
+
+  CHECK_EQ(8.7, StringToDouble("08.7", ALLOW_HEX));
+  CHECK_EQ(8e7, StringToDouble("08e7", ALLOW_HEX));
+
+  CHECK_EQ(0.001, StringToDouble("0.001", ALLOW_HEX));
+  CHECK_EQ(0.713, StringToDouble("0.713", ALLOW_HEX));
+}
+
+
+TEST(TrailingJunk) {
+  CHECK_EQ(8.0, StringToDouble("8q", ALLOW_TRAILING_JUNK));
+  CHECK_EQ(63.0, StringToDouble("077qqq", ALLOW_OCTALS | ALLOW_TRAILING_JUNK));
+}
+
+
+TEST(NonStrDecimalLiteral) {
+  CHECK(isnan(StringToDouble(" ", NO_FLAGS, OS::nan_value())));
+  CHECK(isnan(StringToDouble("", NO_FLAGS, OS::nan_value())));
+  CHECK(isnan(StringToDouble(" ", NO_FLAGS, OS::nan_value())));
+  CHECK_EQ(0.0, StringToDouble("", NO_FLAGS));
+  CHECK_EQ(0.0, StringToDouble(" ", NO_FLAGS));
+}
+
+
+TEST(BitField) {
+  uint32_t x;
+
+  // One bit bit field can hold values 0 and 1.
+  class OneBit1: public BitField<uint32_t, 0, 1> {};
+  class OneBit2: public BitField<uint32_t, 7, 1> {};
+  CHECK(!OneBit1::is_valid(static_cast<uint32_t>(-1)));
+  CHECK(!OneBit2::is_valid(static_cast<uint32_t>(-1)));
+  for (int i = 0; i < 2; i++) {
+    CHECK(OneBit1::is_valid(i));
+    x = OneBit1::encode(i);
+    CHECK_EQ(i, OneBit1::decode(x));
+
+    CHECK(OneBit2::is_valid(i));
+    x = OneBit2::encode(i);
+    CHECK_EQ(i, OneBit2::decode(x));
+  }
+  CHECK(!OneBit1::is_valid(2));
+  CHECK(!OneBit2::is_valid(2));
+
+  // Eight bit bit field can hold values from 0 tp 255.
+  class EightBit1: public BitField<uint32_t, 0, 8> {};
+  class EightBit2: public BitField<uint32_t, 13, 8> {};
+  CHECK(!EightBit1::is_valid(static_cast<uint32_t>(-1)));
+  CHECK(!EightBit2::is_valid(static_cast<uint32_t>(-1)));
+  for (int i = 0; i < 256; i++) {
+    CHECK(EightBit1::is_valid(i));
+    x = EightBit1::encode(i);
+    CHECK_EQ(i, EightBit1::decode(x));
+    CHECK(EightBit2::is_valid(i));
+    x = EightBit2::encode(i);
+    CHECK_EQ(i, EightBit2::decode(x));
+  }
+  CHECK(!EightBit1::is_valid(256));
+  CHECK(!EightBit2::is_valid(256));
+}
diff --git a/regexp2000/test/cctest/test-debug.cc b/regexp2000/test/cctest/test-debug.cc
new file mode 100644 (file)
index 0000000..2ad3347
--- /dev/null
@@ -0,0 +1,3133 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "api.h"
+#include "debug.h"
+#include "platform.h"
+#include "stub-cache.h"
+#include "cctest.h"
+
+
+using ::v8::internal::EmbeddedVector;
+using ::v8::internal::Object;
+using ::v8::internal::OS;
+using ::v8::internal::Handle;
+using ::v8::internal::Heap;
+using ::v8::internal::JSGlobalProxy;
+using ::v8::internal::Code;
+using ::v8::internal::Debug;
+using ::v8::internal::Debugger;
+using ::v8::internal::StepAction;
+using ::v8::internal::StepIn;  // From StepAction enum
+using ::v8::internal::StepNext;  // From StepAction enum
+using ::v8::internal::StepOut;  // From StepAction enum
+
+
+// Size of temp buffer for formatting small strings.
+#define SMALL_STRING_BUFFER_SIZE 80
+
+// --- A d d i t i o n a l   C h e c k   H e l p e r s
+
+
+// Helper function used by the CHECK_EQ function when given Address
+// arguments.  Should not be called directly.
+static inline void CheckEqualsHelper(const char* file, int line,
+                                     const char* expected_source,
+                                     ::v8::internal::Address expected,
+                                     const char* value_source,
+                                     ::v8::internal::Address value) {
+  if (expected != value) {
+    V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n#   "
+                         "Expected: %i\n#   Found: %i",
+             expected_source, value_source, expected, value);
+  }
+}
+
+
+// Helper function used by the CHECK_NE function when given Address
+// arguments.  Should not be called directly.
+static inline void CheckNonEqualsHelper(const char* file, int line,
+                                        const char* unexpected_source,
+                                        ::v8::internal::Address unexpected,
+                                        const char* value_source,
+                                        ::v8::internal::Address value) {
+  if (unexpected == value) {
+    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %i",
+             unexpected_source, value_source, value);
+  }
+}
+
+
+// Helper function used by the CHECK function when given code
+// arguments.  Should not be called directly.
+static inline void CheckEqualsHelper(const char* file, int line,
+                                     const char* expected_source,
+                                     const Code* expected,
+                                     const char* value_source,
+                                     const Code* value) {
+  if (expected != value) {
+    V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n#   "
+                         "Expected: %p\n#   Found: %p",
+             expected_source, value_source, expected, value);
+  }
+}
+
+
+static inline void CheckNonEqualsHelper(const char* file, int line,
+                                        const char* expected_source,
+                                        const Code* expected,
+                                        const char* value_source,
+                                        const Code* value) {
+  if (expected == value) {
+    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %p",
+             expected_source, value_source, value);
+  }
+}
+
+
+// --- H e l p e r   C l a s s e s
+
+
+// Helper class for creating a V8 enviromnent for running tests
+class DebugLocalContext {
+ public:
+  inline DebugLocalContext(
+      v8::ExtensionConfiguration* extensions = 0,
+      v8::Handle<v8::ObjectTemplate> global_template =
+          v8::Handle<v8::ObjectTemplate>(),
+      v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
+      : context_(v8::Context::New(extensions, global_template, global_object)) {
+    context_->Enter();
+  }
+  inline ~DebugLocalContext() {
+    context_->Exit();
+    context_.Dispose();
+  }
+  inline v8::Context* operator->() { return *context_; }
+  inline v8::Context* operator*() { return *context_; }
+  inline bool IsReady() { return !context_.IsEmpty(); }
+  void ExposeDebug() {
+    // Expose the debug context global object in the global object for testing.
+    Debug::Load();
+    Debug::debug_context()->set_security_token(
+        v8::Utils::OpenHandle(*context_)->security_token());
+
+    Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
+        v8::Utils::OpenHandle(*context_->Global())));
+    Handle<v8::internal::String> debug_string =
+        v8::internal::Factory::LookupAsciiSymbol("debug");
+    SetProperty(global, debug_string,
+        Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM);
+  }
+ private:
+  v8::Persistent<v8::Context> context_;
+};
+
+
+// --- H e l p e r   F u n c t i o n s
+
+
+// Compile and run the supplied source and return the fequested function.
+static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
+                                               const char* source,
+                                               const char* function_name) {
+  v8::Script::Compile(v8::String::New(source))->Run();
+  return v8::Local<v8::Function>::Cast(
+      (*env)->Global()->Get(v8::String::New(function_name)));
+}
+
+// Helper function that compiles and runs the source.
+static v8::Local<v8::Value> CompileRun(const char* source) {
+  return v8::Script::Compile(v8::String::New(source))->Run();
+}
+
+// Is there any debug info for the function?
+static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
+  Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
+  Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
+  return Debug::HasDebugInfo(shared);
+}
+
+
+// Set a break point in a function and return the associated break point
+// number.
+static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
+  static int break_point = 0;
+  Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
+  Debug::SetBreakPoint(
+      shared, position,
+      Handle<Object>(v8::internal::Smi::FromInt(++break_point)));
+  return break_point;
+}
+
+
+// Set a break point in a function and return the associated break point
+// number.
+static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
+  return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
+}
+
+
+// Set a break point in a function using the Debug object and return the
+// associated break point number.
+static int SetBreakPointFromJS(const char* function_name,
+                               int line, int position) {
+  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
+  OS::SNPrintF(buffer,
+               "debug.Debug.setBreakPoint(%s,%d,%d)",
+               function_name, line, position);
+  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
+  v8::Handle<v8::String> str = v8::String::New(buffer.start());
+  return v8::Script::Compile(str)->Run()->Int32Value();
+}
+
+
+// Set a break point in a script using the global Debug object.
+static int SetScriptBreakPointFromJS(const char* script_data,
+                                     int line, int column) {
+  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
+  if (column >= 0) {
+    // Column specified set script break point on precise location.
+    OS::SNPrintF(buffer,
+                 "debug.Debug.setScriptBreakPoint(\"%s\",%d,%d)",
+                 script_data, line, column);
+  } else {
+    // Column not specified set script break point on line.
+    OS::SNPrintF(buffer,
+                 "debug.Debug.setScriptBreakPoint(\"%s\",%d)",
+                 script_data, line);
+  }
+  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
+  {
+    v8::TryCatch try_catch;
+    v8::Handle<v8::String> str = v8::String::New(buffer.start());
+    v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
+    ASSERT(!try_catch.HasCaught());
+    return value->Int32Value();
+  }
+}
+
+
+// Clear a break point.
+static void ClearBreakPoint(int break_point) {
+  Debug::ClearBreakPoint(
+      Handle<Object>(v8::internal::Smi::FromInt(break_point)));
+}
+
+
+// Clear a break point using the global Debug object.
+static void ClearBreakPointFromJS(int break_point_number) {
+  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
+  OS::SNPrintF(buffer,
+               "debug.Debug.clearBreakPoint(%d)",
+               break_point_number);
+  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
+  v8::Script::Compile(v8::String::New(buffer.start()))->Run();
+}
+
+
+static void EnableScriptBreakPointFromJS(int break_point_number) {
+  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
+  OS::SNPrintF(buffer,
+               "debug.Debug.enableScriptBreakPoint(%d)",
+               break_point_number);
+  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
+  v8::Script::Compile(v8::String::New(buffer.start()))->Run();
+}
+
+
+static void DisableScriptBreakPointFromJS(int break_point_number) {
+  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
+  OS::SNPrintF(buffer,
+               "debug.Debug.disableScriptBreakPoint(%d)",
+               break_point_number);
+  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
+  v8::Script::Compile(v8::String::New(buffer.start()))->Run();
+}
+
+
+static void ChangeScriptBreakPointConditionFromJS(int break_point_number,
+                                                  const char* condition) {
+  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
+  OS::SNPrintF(buffer,
+               "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
+               break_point_number, condition);
+  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
+  v8::Script::Compile(v8::String::New(buffer.start()))->Run();
+}
+
+
+static void ChangeScriptBreakPointIgnoreCountFromJS(int break_point_number,
+                                                    int ignoreCount) {
+  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
+  OS::SNPrintF(buffer,
+               "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
+               break_point_number, ignoreCount);
+  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
+  v8::Script::Compile(v8::String::New(buffer.start()))->Run();
+}
+
+
+// Change break on exception.
+static void ChangeBreakOnException(bool caught, bool uncaught) {
+  Debug::ChangeBreakOnException(v8::internal::BreakException, caught);
+  Debug::ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
+}
+
+
+// Change break on exception using the global Debug object.
+static void ChangeBreakOnExceptionFromJS(bool caught, bool uncaught) {
+  if (caught) {
+    v8::Script::Compile(
+        v8::String::New("debug.Debug.setBreakOnException()"))->Run();
+  } else {
+    v8::Script::Compile(
+        v8::String::New("debug.Debug.clearBreakOnException()"))->Run();
+  }
+  if (uncaught) {
+    v8::Script::Compile(
+        v8::String::New("debug.Debug.setBreakOnUncaughtException()"))->Run();
+  } else {
+    v8::Script::Compile(
+        v8::String::New("debug.Debug.clearBreakOnUncaughtException()"))->Run();
+  }
+}
+
+
+// Prepare to step to next break location.
+static void PrepareStep(StepAction step_action) {
+  Debug::PrepareStep(step_action, 1);
+}
+
+
+// This function is in namespace v8::internal to be friend with class
+// v8::internal::Debug.
+namespace v8 { namespace internal {  // NOLINT
+
+// Collect the currently debugged functions.
+Handle<FixedArray> GetDebuggedFunctions() {
+  v8::internal::DebugInfoListNode* node = Debug::debug_info_list_;
+
+  // Find the number of debugged functions.
+  int count = 0;
+  while (node) {
+    count++;
+    node = node->next();
+  }
+
+  // Allocate array for the debugged functions
+  Handle<FixedArray> debugged_functions =
+      v8::internal::Factory::NewFixedArray(count);
+
+  // Run through the debug info objects and collect all functions.
+  count = 0;
+  while (node) {
+    debugged_functions->set(count++, *node->debug_info());
+    node = node->next();
+  }
+
+  return debugged_functions;
+}
+
+
+static Handle<Code> ComputeCallDebugBreak(int argc) {
+  CALL_HEAP_FUNCTION(v8::internal::StubCache::ComputeCallDebugBreak(argc),
+                     Code);
+}
+
+} }  // namespace v8::internal
+
+// Inherit from BreakLocationIterator to get access to protected parts for
+// testing.
+class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
+ public:
+  explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
+    : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
+  v8::internal::RelocIterator* it() { return reloc_iterator_; }
+  v8::internal::RelocIterator* it_original() {
+    return reloc_iterator_original_;
+  }
+};
+
+
+// Compile a function, set a break point and check that the call at the break
+// location in the code is the expected debug_break function.
+void CheckDebugBreakFunction(DebugLocalContext* env,
+                             const char* source, const char* name,
+                             int position, v8::internal::RelocInfo::Mode mode,
+                             Code* debug_break) {
+  // Create function and set the break point.
+  Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
+      *CompileFunction(env, source, name));
+  int bp = SetBreakPoint(fun, position);
+
+  // Check that the debug break function is as expected.
+  Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
+  CHECK(Debug::HasDebugInfo(shared));
+  TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
+  it1.FindBreakLocationFromPosition(position);
+  CHECK_EQ(mode, it1.it()->rinfo()->rmode());
+  if (mode != v8::internal::RelocInfo::JS_RETURN) {
+    CHECK_EQ(debug_break,
+             Debug::GetCodeTarget(it1.it()->rinfo()->target_address()));
+  } else {
+    // TODO(1240753): Make the test architecture independent or split
+    // parts of the debugger into architecture dependent files.
+    CHECK_EQ(0xE8, *(it1.rinfo()->pc()));
+  }
+
+  // Clear the break point and check that the debug break function is no longer
+  // there
+  ClearBreakPoint(bp);
+  CHECK(!Debug::HasDebugInfo(shared));
+  CHECK(Debug::EnsureDebugInfo(shared));
+  TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
+  it2.FindBreakLocationFromPosition(position);
+  CHECK_EQ(mode, it2.it()->rinfo()->rmode());
+  if (mode == v8::internal::RelocInfo::JS_RETURN) {
+    // TODO(1240753): Make the test architecture independent or split
+    // parts of the debugger into architecture dependent files.
+    CHECK_NE(0xE8, *(it2.rinfo()->pc()));
+  }
+}
+
+
+// --- D e b u g   E v e n t   H a n d l e r s
+// ---
+// --- The different tests uses a number of debug event handlers.
+// ---
+
+
+// Source for The JavaScript function which picks out the function name on the
+// top frame.
+const char* frame_function_name_source =
+    "function frame_function_name(exec_state) {"
+    "  return exec_state.frame(0).func().name();"
+    "}";
+v8::Local<v8::Function> frame_function_name;
+
+// Global variable to store the last function hit - used by some tests.
+char last_function_hit[80];
+
+// Debug event handler which counts the break points which have been hit.
+int break_point_hit_count = 0;
+static void DebugEventBreakPointHitCount(v8::DebugEvent event,
+                                         v8::Handle<v8::Object> exec_state,
+                                         v8::Handle<v8::Object> event_data,
+                                         v8::Handle<v8::Value> data) {
+  // Count the number of breaks.
+  if (event == v8::Break) {
+    break_point_hit_count++;
+    if (!frame_function_name.IsEmpty()) {
+      // Get the name of the function.
+      const int argc = 1;
+      v8::Handle<v8::Value> argv[argc] = { exec_state };
+      v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
+                                                               argc, argv);
+      if (result->IsUndefined()) {
+        last_function_hit[0] = '\0';
+      } else {
+        CHECK(result->IsString());
+        v8::Handle<v8::String> function_name(result->ToString());
+        function_name->WriteAscii(last_function_hit);
+      }
+    }
+  }
+}
+
+
+// Debug event handler which counts a number of events.
+int exception_hit_count = 0;
+int uncaught_exception_hit_count = 0;
+
+static void DebugEventCounterClear() {
+  break_point_hit_count = 0;
+  exception_hit_count = 0;
+  uncaught_exception_hit_count = 0;
+}
+
+static void DebugEventCounter(v8::DebugEvent event,
+                              v8::Handle<v8::Object> exec_state,
+                              v8::Handle<v8::Object> event_data,
+                              v8::Handle<v8::Value> data) {
+  // Count the number of breaks.
+  if (event == v8::Break) {
+    break_point_hit_count++;
+  } else if (event == v8::Exception) {
+    exception_hit_count++;
+
+    // Check whether the exception was uncaught.
+    v8::Local<v8::String> fun_name = v8::String::New("uncaught");
+    v8::Local<v8::Function> fun =
+        v8::Function::Cast(*event_data->Get(fun_name));
+    v8::Local<v8::Value> result = *fun->Call(event_data, 0, NULL);
+    if (result->IsTrue()) {
+      uncaught_exception_hit_count++;
+    }
+  }
+}
+
+
+// Debug event handler which evaluates a number of expressions when a break
+// point is hit. Each evaluated expression is compared with an expected value.
+// For this debug event handler to work the following two global varaibles
+// must be initialized.
+//   checks: An array of expressions and expected results
+//   evaluate_check_function: A JavaScript function (see below)
+
+// Structure for holding checks to do.
+struct EvaluateCheck {
+  const char* expr;  // An expression to evaluate when a break point is hit.
+  v8::Handle<v8::Value> expected;  // The expected result.
+};
+// Array of checks to do.
+struct EvaluateCheck* checks = NULL;
+// Source for The JavaScript function which can do the evaluation when a break
+// point is hit.
+const char* evaluate_check_source =
+    "function evaluate_check(exec_state, expr, expected) {"
+    "  return exec_state.frame(0).evaluate(expr).value() === expected;"
+    "}";
+v8::Local<v8::Function> evaluate_check_function;
+
+// The actual debug event described by the longer comment above.
+static void DebugEventEvaluate(v8::DebugEvent event,
+                               v8::Handle<v8::Object> exec_state,
+                               v8::Handle<v8::Object> event_data,
+                               v8::Handle<v8::Value> data) {
+  if (event == v8::Break) {
+    for (int i = 0; checks[i].expr != NULL; i++) {
+      const int argc = 3;
+      v8::Handle<v8::Value> argv[argc] = { exec_state,
+                                           v8::String::New(checks[i].expr),
+                                           checks[i].expected };
+      v8::Handle<v8::Value> result =
+          evaluate_check_function->Call(exec_state, argc, argv);
+      if (!result->IsTrue()) {
+        v8::String::AsciiValue ascii(checks[i].expected->ToString());
+        V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *ascii);
+      }
+    }
+  }
+}
+
+
+// This debug event listener removes a breakpoint in a function
+int debug_event_remove_break_point = 0;
+static void DebugEventRemoveBreakPoint(v8::DebugEvent event,
+                                       v8::Handle<v8::Object> exec_state,
+                                       v8::Handle<v8::Object> event_data,
+                                       v8::Handle<v8::Value> data) {
+  if (event == v8::Break) {
+    break_point_hit_count++;
+    v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(data);
+    ClearBreakPoint(debug_event_remove_break_point);
+  }
+}
+
+
+// Debug event handler which counts break points hit and performs a step
+// afterwards.
+StepAction step_action = StepIn;  // Step action to perform when stepping.
+static void DebugEventStep(v8::DebugEvent event,
+                           v8::Handle<v8::Object> exec_state,
+                           v8::Handle<v8::Object> event_data,
+                           v8::Handle<v8::Value> data) {
+  if (event == v8::Break) {
+    break_point_hit_count++;
+    PrepareStep(step_action);
+  }
+}
+
+
+// Debug event handler which counts break points hit and performs a step
+// afterwards. For each call the expected function is checked.
+// For this debug event handler to work the following two global varaibles
+// must be initialized.
+//   expected_step_sequence: An array of the expected function call sequence.
+//   frame_function_name: A JavaScript function (see below).
+
+// String containing the expected function call sequence. Note: this only works
+// if functions have name length of one.
+const char* expected_step_sequence = NULL;
+
+// The actual debug event described by the longer comment above.
+static void DebugEventStepSequence(v8::DebugEvent event,
+                                   v8::Handle<v8::Object> exec_state,
+                                   v8::Handle<v8::Object> event_data,
+                                   v8::Handle<v8::Value> data) {
+  if (event == v8::Break || event == v8::Exception) {
+    // Check that the current function is the expected.
+    CHECK(break_point_hit_count <
+          static_cast<int>(strlen(expected_step_sequence)));
+    const int argc = 1;
+    v8::Handle<v8::Value> argv[argc] = { exec_state };
+    v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
+                                                             argc, argv);
+    CHECK(result->IsString());
+    v8::String::AsciiValue function_name(result->ToString());
+    CHECK_EQ(1, strlen(*function_name));
+    CHECK_EQ((*function_name)[0],
+              expected_step_sequence[break_point_hit_count]);
+
+    // Perform step.
+    break_point_hit_count++;
+    PrepareStep(step_action);
+  }
+}
+
+
+// Debug event handler which performs a garbage collection.
+static void DebugEventBreakPointCollectGarbage(
+    v8::DebugEvent event,
+    v8::Handle<v8::Object> exec_state,
+    v8::Handle<v8::Object> event_data,
+    v8::Handle<v8::Value> data) {
+  // Perform a garbage collection when break point is hit and continue. Based
+  // on the number of break points hit either scavenge or mark compact
+  // collector is used.
+  if (event == v8::Break) {
+    break_point_hit_count++;
+    if (break_point_hit_count % 2 == 0) {
+      // Scavenge.
+      Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
+    } else {
+      // Mark sweep (and perhaps compact).
+      Heap::CollectAllGarbage();
+    }
+  }
+}
+
+
+// Debug event handler which re-issues a debug break and calls the garbage
+// collector to have the heap verified.
+static void DebugEventBreak(v8::DebugEvent event,
+                            v8::Handle<v8::Object> exec_state,
+                            v8::Handle<v8::Object> event_data,
+                            v8::Handle<v8::Value> data) {
+  if (event == v8::Break) {
+    // Count the number of breaks.
+    break_point_hit_count++;
+
+    // Run the garbage collector to enforce heap verification if option
+    // --verify-heap is set.
+    Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
+
+    // Set the break flag again to come back here as soon as possible.
+    v8::Debug::DebugBreak();
+  }
+}
+
+
+// --- M e s s a g e   C a l l b a c k
+
+
+// Message callback which counts the number of messages.
+int message_callback_count = 0;
+
+static void MessageCallbackCountClear() {
+  message_callback_count = 0;
+}
+
+static void MessageCallbackCount(v8::Handle<v8::Message> message,
+                                 v8::Handle<v8::Value> data) {
+  message_callback_count++;
+}
+
+
+// --- T h e   A c t u a l   T e s t s
+
+
+// Test that the debug break function is the expected one for different kinds
+// of break locations.
+TEST(DebugStub) {
+  using ::v8::internal::Builtins;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  CheckDebugBreakFunction(&env,
+                          "function f1(){}", "f1",
+                          0,
+                          v8::internal::RelocInfo::JS_RETURN,
+                          NULL);
+  CheckDebugBreakFunction(&env,
+                          "function f2(){x=1;}", "f2",
+                          0,
+                          v8::internal::RelocInfo::CODE_TARGET,
+                          Builtins::builtin(Builtins::StoreIC_DebugBreak));
+  CheckDebugBreakFunction(&env,
+                          "function f3(){var a=x;}", "f3",
+                          0,
+                          v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
+                          Builtins::builtin(Builtins::LoadIC_DebugBreak));
+
+// TODO(1240753): Make the test architecture independent or split
+// parts of the debugger into architecture dependent files. This
+// part currently disabled as it is not portable between IA32/ARM.
+// Currently on ICs for keyed store/load on ARM.
+#if !defined (__arm__) && !defined(__thumb__)
+  CheckDebugBreakFunction(
+      &env,
+      "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}",
+      "f4",
+      0,
+      v8::internal::RelocInfo::CODE_TARGET,
+      Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
+  CheckDebugBreakFunction(
+      &env,
+      "function f5(){var index='propertyName'; var a={}; return a[index];}",
+      "f5",
+      0,
+      v8::internal::RelocInfo::CODE_TARGET,
+      Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
+#endif
+
+  // Check the debug break code stubs for call ICs with different number of
+  // parameters.
+  Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0);
+  Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1);
+  Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4);
+
+  CheckDebugBreakFunction(&env,
+                          "function f4_0(){x();}", "f4_0",
+                          0,
+                          v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
+                          *debug_break_0);
+
+  CheckDebugBreakFunction(&env,
+                          "function f4_1(){x(1);}", "f4_1",
+                          0,
+                          v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
+                          *debug_break_1);
+
+  CheckDebugBreakFunction(&env,
+                          "function f4_4(){x(1,2,3,4);}", "f4_4",
+                          0,
+                          v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
+                          *debug_break_4);
+}
+
+
+// Test that the debug info in the VM is in sync with the functions being
+// debugged.
+TEST(DebugInfo) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  // Create a couple of functions for the test.
+  v8::Local<v8::Function> foo =
+      CompileFunction(&env, "function foo(){}", "foo");
+  v8::Local<v8::Function> bar =
+      CompileFunction(&env, "function bar(){}", "bar");
+  // Initially no functions are debugged.
+  CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
+  CHECK(!HasDebugInfo(foo));
+  CHECK(!HasDebugInfo(bar));
+  // One function (foo) is debugged.
+  int bp1 = SetBreakPoint(foo, 0);
+  CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
+  CHECK(HasDebugInfo(foo));
+  CHECK(!HasDebugInfo(bar));
+  // Two functions are debugged.
+  int bp2 = SetBreakPoint(bar, 0);
+  CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
+  CHECK(HasDebugInfo(foo));
+  CHECK(HasDebugInfo(bar));
+  // One function (bar) is debugged.
+  ClearBreakPoint(bp1);
+  CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
+  CHECK(!HasDebugInfo(foo));
+  CHECK(HasDebugInfo(bar));
+  // No functions are debugged.
+  ClearBreakPoint(bp2);
+  CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
+  CHECK(!HasDebugInfo(foo));
+  CHECK(!HasDebugInfo(bar));
+}
+
+
+// Test that a break point can be set at an IC store location.
+TEST(BreakPointICStore) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run();
+  v8::Local<v8::Function> foo =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
+
+  // Run without breakpoints.
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Run with breakpoint
+  int bp = SetBreakPoint(foo, 0);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Run without breakpoints.
+  ClearBreakPoint(bp);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test that a break point can be set at an IC load location.
+TEST(BreakPointICLoad) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("bar=1"))->Run();
+  v8::Script::Compile(v8::String::New("function foo(){var x=bar;}"))->Run();
+  v8::Local<v8::Function> foo =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
+
+  // Run without breakpoints.
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Run with breakpoint
+  int bp = SetBreakPoint(foo, 0);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Run without breakpoints.
+  ClearBreakPoint(bp);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test that a break point can be set at an IC call location.
+TEST(BreakPointICCall) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
+  v8::Script::Compile(v8::String::New("function foo(){bar();}"))->Run();
+  v8::Local<v8::Function> foo =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
+
+  // Run without breakpoints.
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Run with breakpoint
+  int bp = SetBreakPoint(foo, 0);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Run without breakpoints.
+  ClearBreakPoint(bp);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test that a break point can be set at a return store location.
+TEST(BreakPointReturn) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
+  v8::Local<v8::Function> foo =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
+
+  // Run without breakpoints.
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Run with breakpoint
+  int bp = SetBreakPoint(foo, 0);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Run without breakpoints.
+  ClearBreakPoint(bp);
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+static void CallWithBreakPoints(v8::Local<v8::Object> recv,
+                                v8::Local<v8::Function> f,
+                                int break_point_count,
+                                int call_count) {
+  break_point_hit_count = 0;
+  for (int i = 0; i < call_count; i++) {
+    f->Call(recv, 0, NULL);
+    CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
+  }
+}
+
+// Test GC during break point processing.
+TEST(GCDuringBreakPointProcessing) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointCollectGarbage,
+                                   v8::Undefined());
+  v8::Local<v8::Function> foo;
+
+  // Test IC store break point with garbage collection.
+  foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
+  SetBreakPoint(foo, 0);
+  CallWithBreakPoints(env->Global(), foo, 1, 10);
+
+  // Test IC load break point with garbage collection.
+  foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
+  SetBreakPoint(foo, 0);
+  CallWithBreakPoints(env->Global(), foo, 1, 10);
+
+  // Test IC call break point with garbage collection.
+  foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
+  SetBreakPoint(foo, 0);
+  CallWithBreakPoints(env->Global(), foo, 1, 10);
+
+  // Test return break point with garbage collection.
+  foo = CompileFunction(&env, "function foo(){}", "foo");
+  SetBreakPoint(foo, 0);
+  CallWithBreakPoints(env->Global(), foo, 1, 25);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointCollectGarbage);
+}
+
+
+// Call the function three times with different garbage collections in between
+// and make sure that the break point survives.
+static void CallAndGC(v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
+  break_point_hit_count = 0;
+
+  for (int i = 0; i < 3; i++) {
+    // Call function.
+    f->Call(recv, 0, NULL);
+    CHECK_EQ(1 + i * 3, break_point_hit_count);
+
+    // Scavenge and call function.
+    Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
+    f->Call(recv, 0, NULL);
+    CHECK_EQ(2 + i * 3, break_point_hit_count);
+
+    // Mark sweep (and perhaps compact) and call function.
+    Heap::CollectAllGarbage();
+    f->Call(recv, 0, NULL);
+    CHECK_EQ(3 + i * 3, break_point_hit_count);
+  }
+}
+
+
+// Test that a break point can be set at a return store location.
+TEST(BreakPointSurviveGC) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Local<v8::Function> foo;
+
+  // Test IC store break point with garbage collection.
+  foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
+  SetBreakPoint(foo, 0);
+  CallAndGC(env->Global(), foo);
+
+  // Test IC load break point with garbage collection.
+  foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
+  SetBreakPoint(foo, 0);
+  CallAndGC(env->Global(), foo);
+
+  // Test IC call break point with garbage collection.
+  foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
+  SetBreakPoint(foo, 0);
+  CallAndGC(env->Global(), foo);
+
+  // Test return break point with garbage collection.
+  foo = CompileFunction(&env, "function foo(){}", "foo");
+  SetBreakPoint(foo, 0);
+  CallAndGC(env->Global(), foo);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test that break points can be set using the global Debug object.
+TEST(BreakPointThroughJavaScript) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
+  v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
+  //                                               012345678901234567890
+  //                                                         1         2
+  // Break points are set at position 3 and 9
+  v8::Local<v8::Script> foo = v8::Script::Compile(v8::String::New("foo()"));
+
+  // Run without breakpoints.
+  foo->Run();
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Run with one breakpoint
+  int bp1 = SetBreakPointFromJS("foo", 0, 3);
+  foo->Run();
+  CHECK_EQ(1, break_point_hit_count);
+  foo->Run();
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Run with two breakpoints
+  int bp2 = SetBreakPointFromJS("foo", 0, 9);
+  foo->Run();
+  CHECK_EQ(4, break_point_hit_count);
+  foo->Run();
+  CHECK_EQ(6, break_point_hit_count);
+
+  // Run with one breakpoint
+  ClearBreakPointFromJS(bp2);
+  foo->Run();
+  CHECK_EQ(7, break_point_hit_count);
+  foo->Run();
+  CHECK_EQ(8, break_point_hit_count);
+
+  // Run without breakpoints.
+  ClearBreakPointFromJS(bp1);
+  foo->Run();
+  CHECK_EQ(8, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+
+  // Make sure that the break point numbers are consecutive.
+  CHECK_EQ(1, bp1);
+  CHECK_EQ(2, bp2);
+}
+
+
+// Test that break points can be set using the global Debug object.
+TEST(ScriptBreakPointThroughJavaScript) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
+
+  v8::Local<v8::String> script = v8::String::New(
+    "function f() {\n"
+    "  function h() {\n"
+    "    a = 0;  // line 2\n"
+    "  }\n"
+    "  b = 1;  // line 4\n"
+    "  return h();\n"
+    "}\n"
+    "\n"
+    "function g() {\n"
+    "  function h() {\n"
+    "    a = 0;\n"
+    "  }\n"
+    "  b = 2;  // line 12\n"
+    "  h();\n"
+    "  b = 3;  // line 14\n"
+    "  f();    // line 15\n"
+    "}");
+
+  // Compile the script and get the two functions.
+  v8::ScriptOrigin origin =
+      v8::ScriptOrigin(v8::String::New("test"));
+  v8::Script::Compile(script, &origin)->Run();
+  v8::Local<v8::Function> f =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+  v8::Local<v8::Function> g =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
+
+  // Call f and g without break points.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Call f and g with break point on line 12.
+  int sbp1 = SetScriptBreakPointFromJS("test", 12, 0);
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  // Remove the break point again.
+  break_point_hit_count = 0;
+  ClearBreakPointFromJS(sbp1);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Call f and g with break point on line 2.
+  int sbp2 = SetScriptBreakPointFromJS("test", 2, 0);
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Call f and g with break point on line 2, 4, 12, 14 and 15.
+  int sbp3 = SetScriptBreakPointFromJS("test", 4, 0);
+  int sbp4 = SetScriptBreakPointFromJS("test", 12, 0);
+  int sbp5 = SetScriptBreakPointFromJS("test", 14, 0);
+  int sbp6 = SetScriptBreakPointFromJS("test", 15, 0);
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(7, break_point_hit_count);
+
+  // Remove the all the break points again.
+  break_point_hit_count = 0;
+  ClearBreakPointFromJS(sbp2);
+  ClearBreakPointFromJS(sbp3);
+  ClearBreakPointFromJS(sbp4);
+  ClearBreakPointFromJS(sbp5);
+  ClearBreakPointFromJS(sbp6);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Now set a function break point
+  int bp7 = SetBreakPointFromJS("g", 0, 0);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  // Reload the script and get g again checking that the break point survives.
+  // This tests that the function break point was converted to a script break
+  // point.
+  v8::Script::Compile(script, &origin)->Run();
+  g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+
+  // Make sure that the break point numbers are consecutive.
+  CHECK_EQ(1, sbp1);
+  CHECK_EQ(2, sbp2);
+  CHECK_EQ(3, sbp3);
+  CHECK_EQ(4, sbp4);
+  CHECK_EQ(5, sbp5);
+  CHECK_EQ(6, sbp6);
+  CHECK_EQ(7, bp7);
+}
+
+
+// Test conditional script break points.
+TEST(EnableDisableScriptBreakPoint) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+
+  v8::Local<v8::String> script = v8::String::New(
+    "function f() {\n"
+    "  a = 0;  // line 1\n"
+    "};");
+
+  // Compile the script and get function f.
+  v8::ScriptOrigin origin =
+      v8::ScriptOrigin(v8::String::New("test"));
+  v8::Script::Compile(script, &origin)->Run();
+  v8::Local<v8::Function> f =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  // Set script break point on line 1 (in function f).
+  int sbp = SetScriptBreakPointFromJS("test", 1, 0);
+
+  // Call f while enabeling and disabling the script break point.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  DisableScriptBreakPointFromJS(sbp);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  EnableScriptBreakPointFromJS(sbp);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  DisableScriptBreakPointFromJS(sbp);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Reload the script and get f again checking that the disabeling survives.
+  v8::Script::Compile(script, &origin)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  EnableScriptBreakPointFromJS(sbp);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(3, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test conditional script break points.
+TEST(ConditionalScriptBreakPoint) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+
+  v8::Local<v8::String> script = v8::String::New(
+    "count = 0;\n"
+    "function f() {\n"
+    "  g(count++);  // line 2\n"
+    "};\n"
+    "function g(x) {\n"
+    "  var a=x;  // line 5\n"
+    "};");
+
+  // Compile the script and get function f.
+  v8::ScriptOrigin origin =
+      v8::ScriptOrigin(v8::String::New("test"));
+  v8::Script::Compile(script, &origin)->Run();
+  v8::Local<v8::Function> f =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  // Set script break point on line 5 (in function g).
+  int sbp1 = SetScriptBreakPointFromJS("test", 5, 0);
+
+  // Call f with different conditions on the script break point.
+  break_point_hit_count = 0;
+  ChangeScriptBreakPointConditionFromJS(sbp1, "false");
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  ChangeScriptBreakPointConditionFromJS(sbp1, "true");
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  ChangeScriptBreakPointConditionFromJS(sbp1, "a % 2 == 0");
+  break_point_hit_count = 0;
+  for (int i = 0; i < 10; i++) {
+    f->Call(env->Global(), 0, NULL);
+  }
+  CHECK_EQ(5, break_point_hit_count);
+
+  // Reload the script and get f again checking that the condition survives.
+  v8::Script::Compile(script, &origin)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  break_point_hit_count = 0;
+  for (int i = 0; i < 10; i++) {
+    f->Call(env->Global(), 0, NULL);
+  }
+  CHECK_EQ(5, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test ignore count on script break points.
+TEST(ScriptBreakPointIgnoreCount) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+
+  v8::Local<v8::String> script = v8::String::New(
+    "function f() {\n"
+    "  a = 0;  // line 1\n"
+    "};");
+
+  // Compile the script and get function f.
+  v8::ScriptOrigin origin =
+      v8::ScriptOrigin(v8::String::New("test"));
+  v8::Script::Compile(script, &origin)->Run();
+  v8::Local<v8::Function> f =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  // Set script break point on line 1 (in function f).
+  int sbp = SetScriptBreakPointFromJS("test", 1, 0);
+
+  // Call f with different ignores on the script break point.
+  break_point_hit_count = 0;
+  ChangeScriptBreakPointIgnoreCountFromJS(sbp, 1);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  ChangeScriptBreakPointIgnoreCountFromJS(sbp, 5);
+  break_point_hit_count = 0;
+  for (int i = 0; i < 10; i++) {
+    f->Call(env->Global(), 0, NULL);
+  }
+  CHECK_EQ(5, break_point_hit_count);
+
+  // Reload the script and get f again checking that the ignore survives.
+  v8::Script::Compile(script, &origin)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  break_point_hit_count = 0;
+  for (int i = 0; i < 10; i++) {
+    f->Call(env->Global(), 0, NULL);
+  }
+  CHECK_EQ(5, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test that script break points survive when a script is reloaded.
+TEST(ScriptBreakPointReload) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+
+  v8::Local<v8::Function> f;
+  v8::Local<v8::String> script = v8::String::New(
+    "function f() {\n"
+    "  function h() {\n"
+    "    a = 0;  // line 2\n"
+    "  }\n"
+    "  b = 1;  // line 4\n"
+    "  return h();\n"
+    "}");
+
+  v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8::String::New("1"));
+  v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8::String::New("2"));
+
+  // Set a script break point before the script is loaded.
+  SetScriptBreakPointFromJS("1", 2, 0);
+
+  // Compile the script and get the function.
+  v8::Script::Compile(script, &origin_1)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  // Call f and check that the script break point is active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  // Compile the script again with a different script data and get the
+  // function.
+  v8::Script::Compile(script, &origin_2)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  // Call f and check that no break points are set.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Compile the script again and get the function.
+  v8::Script::Compile(script, &origin_1)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  // Call f and check that the script break point is active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test when several scripts has the same script data
+TEST(ScriptBreakPointMultiple) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+
+  v8::Local<v8::Function> f;
+  v8::Local<v8::String> script_f = v8::String::New(
+    "function f() {\n"
+    "  a = 0;  // line 1\n"
+    "}");
+
+  v8::Local<v8::Function> g;
+  v8::Local<v8::String> script_g = v8::String::New(
+    "function g() {\n"
+    "  b = 0;  // line 1\n"
+    "}");
+
+  v8::ScriptOrigin origin =
+      v8::ScriptOrigin(v8::String::New("test"));
+
+  // Set a script break point before the scripts are loaded.
+  int sbp = SetScriptBreakPointFromJS("test", 1, 0);
+
+  // Compile the scripts with same script data and get the functions.
+  v8::Script::Compile(script_f, &origin)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+  v8::Script::Compile(script_g, &origin)->Run();
+  g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
+
+  // Call f and g and check that the script break point is active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Clear the script break point.
+  ClearBreakPointFromJS(sbp);
+
+  // Call f and g and check that the script break point is no longer active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Set script break point with the scripts loaded.
+  sbp = SetScriptBreakPointFromJS("test", 1, 0);
+
+  // Call f and g and check that the script break point is active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test the script origin which has both name and line offset.
+TEST(ScriptBreakPointLineOffset) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+
+  v8::Local<v8::Function> f;
+  v8::Local<v8::String> script = v8::String::New(
+    "function f() {\n"
+    "  a = 0;  // line 8 as this script has line offset 7\n"
+    "  b = 0;  // line 9 as this script has line offset 7\n"
+    "}");
+
+  // Create script origin both name and line offset.
+  v8::ScriptOrigin origin(v8::String::New("test.html"),
+                          v8::Integer::New(7));
+
+  // Set two script break points before the script is loaded.
+  int sbp1 = SetScriptBreakPointFromJS("test.html", 8, 0);
+  int sbp2 = SetScriptBreakPointFromJS("test.html", 9, 0);
+
+  // Compile the script and get the function.
+  v8::Script::Compile(script, &origin)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+
+  // Call f and check that the script break point is active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Clear the script break points.
+  ClearBreakPointFromJS(sbp1);
+  ClearBreakPointFromJS(sbp2);
+
+  // Call f and check that no script break points are active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Set a script break point with the script loaded.
+  sbp1 = SetScriptBreakPointFromJS("test.html", 9, 0);
+
+  // Call f and check that the script break point is active.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test script break points set on lines.
+TEST(ScriptBreakPointLine) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  // Create a function for checking the function when hitting a break point.
+  frame_function_name = CompileFunction(&env,
+                                        frame_function_name_source,
+                                        "frame_function_name");
+
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+
+  v8::Local<v8::Function> f;
+  v8::Local<v8::Function> g;
+  v8::Local<v8::String> script = v8::String::New(
+    "a = 0                      // line 0\n"
+    "function f() {\n"
+    "  a = 1;                   // line 2\n"
+    "}\n"
+    " a = 2;                    // line 4\n"
+    "  /* xx */ function g() {  // line 5\n"
+    "    function h() {         // line 6\n"
+    "      a = 3;               // line 7\n"
+    "    }\n"
+    "    h();                   // line 9\n"
+    "    a = 4;                 // line 10\n"
+    "  }\n"
+    " a=5;                      // line 12");
+
+  // Set a couple script break point before the script is loaded.
+  int sbp1 = SetScriptBreakPointFromJS("test.html", 0, -1);
+  int sbp2 = SetScriptBreakPointFromJS("test.html", 1, -1);
+  int sbp3 = SetScriptBreakPointFromJS("test.html", 5, -1);
+
+  // Compile the script and get the function.
+  break_point_hit_count = 0;
+  v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
+  v8::Script::Compile(script, &origin)->Run();
+  f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+  g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
+
+  // Chesk that a break point was hit when the script was run.
+  CHECK_EQ(1, break_point_hit_count);
+  CHECK_EQ(0, strlen(last_function_hit));
+
+  // Call f and check that the script break point.
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+  CHECK_EQ("f", last_function_hit);
+
+  // Call g and check that the script break point.
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(3, break_point_hit_count);
+  CHECK_EQ("g", last_function_hit);
+
+  // Clear the script break point on g and set one on h.
+  ClearBreakPointFromJS(sbp3);
+  int sbp4 = SetScriptBreakPointFromJS("test.html", 6, -1);
+
+  // Call g and check that the script break point in h is hit.
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(4, break_point_hit_count);
+  CHECK_EQ("h", last_function_hit);
+
+  // Clear break points in f and h. Set a new one in the script between
+  // functions f and g and test that there is no break points in f and g any
+  // more.
+  ClearBreakPointFromJS(sbp2);
+  ClearBreakPointFromJS(sbp4);
+  int sbp5 = SetScriptBreakPointFromJS("test.html", 4, -1);
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  g->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  // Reload the script which should hit two break points.
+  break_point_hit_count = 0;
+  v8::Script::Compile(script, &origin)->Run();
+  CHECK_EQ(2, break_point_hit_count);
+  CHECK_EQ(0, strlen(last_function_hit));
+
+  // Set a break point in the code after the last function decleration.
+  int sbp6 = SetScriptBreakPointFromJS("test.html", 12, -1);
+
+  // Reload the script which should hit three break points.
+  break_point_hit_count = 0;
+  v8::Script::Compile(script, &origin)->Run();
+  CHECK_EQ(3, break_point_hit_count);
+  CHECK_EQ(0, strlen(last_function_hit));
+
+  // Clear the last break points, and reload the script which should not hit any
+  // break points.
+  ClearBreakPointFromJS(sbp1);
+  ClearBreakPointFromJS(sbp5);
+  ClearBreakPointFromJS(sbp6);
+  break_point_hit_count = 0;
+  v8::Script::Compile(script, &origin)->Run();
+  CHECK_EQ(0, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test that it is possible to remove the last break point for a function
+// inside the break handling of that break point.
+TEST(RemoveBreakPointInBreak) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  v8::Local<v8::Function> foo =
+      CompileFunction(&env, "function foo(){a=1;}", "foo");
+  debug_event_remove_break_point = SetBreakPoint(foo, 0);
+
+  // Register the debug event listener pasing the function
+  v8::Debug::AddDebugEventListener(DebugEventRemoveBreakPoint, foo);
+
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventRemoveBreakPoint);
+}
+
+
+// Test that the debugger statement causes a break.
+TEST(DebuggerStatement) {
+  break_point_hit_count = 0;
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
+                                   v8::Undefined());
+  v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
+  v8::Script::Compile(v8::String::New(
+      "function foo(){debugger;debugger;}"))->Run();
+  v8::Local<v8::Function> foo =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
+  v8::Local<v8::Function> bar =
+      v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("bar")));
+
+  // Run function with debugger statement
+  bar->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  // Run function with two debugger statement
+  foo->Call(env->Global(), 0, NULL);
+  CHECK_EQ(3, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Thest that the evaluation of expressions when a break point is hit generates
+// the correct results.
+TEST(DebugEvaluate) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  // Create a function for checking the evaluation when hitting a break point.
+  evaluate_check_function = CompileFunction(&env,
+                                            evaluate_check_source,
+                                            "evaluate_check");
+  // Register the debug event listener
+  v8::Debug::AddDebugEventListener(DebugEventEvaluate);
+
+  // Different expected vaules of x and a when in a break point (u = undefined,
+  // d = Hello, world!).
+  struct EvaluateCheck checks_uu[] = {
+    {"x", v8::Undefined()},
+    {"a", v8::Undefined()},
+    {NULL, v8::Handle<v8::Value>()}
+  };
+  struct EvaluateCheck checks_hu[] = {
+    {"x", v8::String::New("Hello, world!")},
+    {"a", v8::Undefined()},
+    {NULL, v8::Handle<v8::Value>()}
+  };
+  struct EvaluateCheck checks_hh[] = {
+    {"x", v8::String::New("Hello, world!")},
+    {"a", v8::String::New("Hello, world!")},
+    {NULL, v8::Handle<v8::Value>()}
+  };
+
+  // Simple test function. The "y=0" is in the function foo to provide a break
+  // location. For "y=0" the "y" is at position 15 in the barbar function
+  // therefore setting breakpoint at position 15 will break at "y=0" and
+  // setting it higher will break after.
+  v8::Local<v8::Function> foo = CompileFunction(&env,
+    "function foo(x) {"
+    "  var a;"
+    "  y=0; /* To ensure break location.*/"
+    "  a=x;"
+    "}",
+    "foo");
+  const int foo_break_position = 15;
+
+  // Arguments with one parameter "Hello, world!"
+  v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
+
+  // Call foo with breakpoint set before a=x and undefined as parameter.
+  int bp = SetBreakPoint(foo, foo_break_position);
+  checks = checks_uu;
+  foo->Call(env->Global(), 0, NULL);
+
+  // Call foo with breakpoint set before a=x and parameter "Hello, world!".
+  checks = checks_hu;
+  foo->Call(env->Global(), 1, argv_foo);
+
+  // Call foo with breakpoint set after a=x and parameter "Hello, world!".
+  ClearBreakPoint(bp);
+  SetBreakPoint(foo, foo_break_position + 1);
+  checks = checks_hh;
+  foo->Call(env->Global(), 1, argv_foo);
+
+  // Test function with an inner function. The "y=0" is in function barbar
+  // to provide a break location. For "y=0" the "y" is at position 8 in the
+  // barbar function therefore setting breakpoint at position 8 will break at
+  // "y=0" and setting it higher will break after.
+  v8::Local<v8::Function> bar = CompileFunction(&env,
+    "y = 0;"
+    "x = 'Goodbye, world!';"
+    "function bar(x, b) {"
+    "  var a;"
+    "  function barbar() {"
+    "    y=0; /* To ensure break location.*/"
+    "    a=x;"
+    "  };"
+    "  debug.Debug.clearAllBreakPoints();"
+    "  barbar();"
+    "  y=0;a=x;"
+    "}",
+    "bar");
+  const int barbar_break_position = 8;
+
+  // Call bar setting breakpoint before a=x in barbar and undefined as
+  // parameter.
+  checks = checks_uu;
+  v8::Handle<v8::Value> argv_bar_1[2] = {
+    v8::Undefined(),
+    v8::Number::New(barbar_break_position)
+  };
+  bar->Call(env->Global(), 2, argv_bar_1);
+
+  // Call bar setting breakpoint before a=x in barbar and parameter
+  // "Hello, world!".
+  checks = checks_hu;
+  v8::Handle<v8::Value> argv_bar_2[2] = {
+    v8::String::New("Hello, world!"),
+    v8::Number::New(barbar_break_position)
+  };
+  bar->Call(env->Global(), 2, argv_bar_2);
+
+  // Call bar setting breakpoint after a=x in barbar and parameter
+  // "Hello, world!".
+  checks = checks_hh;
+  v8::Handle<v8::Value> argv_bar_3[2] = {
+    v8::String::New("Hello, world!"),
+    v8::Number::New(barbar_break_position + 1)
+  };
+  bar->Call(env->Global(), 2, argv_bar_3);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventEvaluate);
+}
+
+
+// Simple test of the stepping mechanism using only store ICs.
+TEST(DebugStepLinear) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Create a function for testing stepping.
+  v8::Local<v8::Function> foo = CompileFunction(&env,
+                                                "function foo(){a=1;b=1;c=1;}",
+                                                "foo");
+  SetBreakPoint(foo, 3);
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStep);
+
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+
+  // With stepping all break locations are hit.
+  CHECK_EQ(4, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventStep);
+
+  // Register a debug event listener which just counts.
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount);
+
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+
+  // Without stepping only active break points are hit.
+  CHECK_EQ(1, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test the stepping mechanism with different ICs.
+TEST(DebugStepLinearMixedICs) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Create a function for testing stepping.
+  v8::Local<v8::Function> foo = CompileFunction(&env,
+      "function bar() {};"
+      "function foo() {"
+      "  var x;"
+      "  var index='name';"
+      "  var y = {};"
+      "  a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
+  SetBreakPoint(foo, 0);
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStep);
+
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+
+  // With stepping all break locations are hit. For ARM the keyed load/store
+  // is not hit as they are not implemented as ICs.
+#if defined (__arm__) || defined(__thumb__)
+  CHECK_EQ(6, break_point_hit_count);
+#else
+  CHECK_EQ(8, break_point_hit_count);
+#endif
+
+  v8::Debug::RemoveDebugEventListener(DebugEventStep);
+
+  // Register a debug event listener which just counts.
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount);
+
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+
+  // Without stepping only active break points are hit.
+  CHECK_EQ(1, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+TEST(DebugStepIf) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStep);
+
+  // Create a function for testing stepping.
+  const int argc = 1;
+  const char* src = "function foo(x) { "
+                    "  a = 1;"
+                    "  if (x) {"
+                    "    b = 1;"
+                    "  } else {"
+                    "    c = 1;"
+                    "    d = 1;"
+                    "  }"
+                    "}";
+  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+  SetBreakPoint(foo, 0);
+
+  // Stepping through the true part.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
+  foo->Call(env->Global(), argc, argv_true);
+  CHECK_EQ(3, break_point_hit_count);
+
+  // Stepping through the false part.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
+  foo->Call(env->Global(), argc, argv_false);
+  CHECK_EQ(4, break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventStep);
+}
+
+
+TEST(DebugStepSwitch) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStep);
+
+  // Create a function for testing stepping.
+  const int argc = 1;
+  const char* src = "function foo(x) { "
+                    "  a = 1;"
+                    "  switch (x) {"
+                    "    case 1:"
+                    "      b = 1;"
+                    "    case 2:"
+                    "      c = 1;"
+                    "      break;"
+                    "    case 3:"
+                    "      d = 1;"
+                    "      e = 1;"
+                    "      break;"
+                    "  }"
+                    "}";
+  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+  SetBreakPoint(foo, 0);
+
+  // One case with fall-through.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
+  foo->Call(env->Global(), argc, argv_1);
+  CHECK_EQ(4, break_point_hit_count);
+
+  // Another case.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
+  foo->Call(env->Global(), argc, argv_2);
+  CHECK_EQ(3, break_point_hit_count);
+
+  // Last case.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
+  foo->Call(env->Global(), argc, argv_3);
+  CHECK_EQ(4, break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventStep);
+}
+
+
+TEST(DebugStepFor) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStep);
+
+  // Create a function for testing stepping.
+  const int argc = 1;
+  const char* src = "function foo(x) { "
+                    "  a = 1;"
+                    "  for (i = 0; i < x; i++) {"
+                    "    b = 1;"
+                    "  }"
+                    "}";
+  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+  SetBreakPoint(foo, 8);  // "a = 1;"
+
+  // Looping 10 times.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
+  foo->Call(env->Global(), argc, argv_10);
+  CHECK_EQ(23, break_point_hit_count);
+
+  // Looping 100 times.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
+  foo->Call(env->Global(), argc, argv_100);
+  CHECK_EQ(203, break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventStep);
+}
+
+
+TEST(StepInOutSimple) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Create a function for checking the function when hitting a break point.
+  frame_function_name = CompileFunction(&env,
+                                        frame_function_name_source,
+                                        "frame_function_name");
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStepSequence);
+
+  // Create functions for testing stepping.
+  const char* src = "function a() {b();c();}; "
+                    "function b() {c();}; "
+                    "function c() {}; ";
+  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
+  SetBreakPoint(a, 0);
+
+  // Step through invocation of a with step in.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "abcbaca";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of a with step next.
+  step_action = StepNext;
+  break_point_hit_count = 0;
+  expected_step_sequence = "aaa";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of a with step out.
+  step_action = StepOut;
+  break_point_hit_count = 0;
+  expected_step_sequence = "a";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventStepSequence);
+}
+
+
+TEST(StepInOutTree) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Create a function for checking the function when hitting a break point.
+  frame_function_name = CompileFunction(&env,
+                                        frame_function_name_source,
+                                        "frame_function_name");
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStepSequence);
+
+  // Create functions for testing stepping.
+  const char* src = "function a() {b(c(d()),d());c(d());d()}; "
+                    "function b(x,y) {c();}; "
+                    "function c(x) {}; "
+                    "function d() {}; ";
+  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
+  SetBreakPoint(a, 0);
+
+  // Step through invocation of a with step in.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "adacadabcbadacada";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of a with step next.
+  step_action = StepNext;
+  break_point_hit_count = 0;
+  expected_step_sequence = "aaaa";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of a with step out.
+  step_action = StepOut;
+  break_point_hit_count = 0;
+  expected_step_sequence = "a";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventStepSequence);
+}
+
+
+TEST(StepInOutBranch) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Create a function for checking the function when hitting a break point.
+  frame_function_name = CompileFunction(&env,
+                                        frame_function_name_source,
+                                        "frame_function_name");
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStepSequence);
+
+  // Create functions for testing stepping.
+  const char* src = "function a() {b(false);c();}; "
+                    "function b(x) {if(x){c();};}; "
+                    "function c() {}; ";
+  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
+  SetBreakPoint(a, 0);
+
+  // Step through invocation of a.
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "abaca";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventStepSequence);
+}
+
+
+// Test that step in does not step into native functions.
+TEST(DebugStepNatives) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Create a function for testing stepping.
+  v8::Local<v8::Function> foo = CompileFunction(
+      &env,
+      "function foo(){debugger;Math.sin(1);}",
+      "foo");
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStep);
+
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+
+  // With stepping all break locations are hit.
+  CHECK_EQ(3, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventStep);
+
+  // Register a debug event listener which just counts.
+  v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount);
+
+  break_point_hit_count = 0;
+  foo->Call(env->Global(), 0, NULL);
+
+  // Without stepping only active break points are hit.
+  CHECK_EQ(1, break_point_hit_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventBreakPointHitCount);
+}
+
+
+// Test break on exceptions. For each exception break combination the number
+// of debug event exception callbacks and message callbacks are collected. The
+// number of debug event exception callbacks are cused to check that the
+// debugger is called correctly and the number of message callbacks is used to
+// check that uncaught exceptions are still returned even if there is a break
+// for them.
+TEST(BreakOnException) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  v8::internal::Top::TraceException(false);
+
+  // Create functions for testing break on exception.
+  v8::Local<v8::Function> throws =
+      CompileFunction(&env, "function throws(){throw 1;}", "throws");
+  v8::Local<v8::Function> caught =
+      CompileFunction(&env,
+                      "function caught(){try {throws();} catch(e) {};}",
+                      "caught");
+  v8::Local<v8::Function> notCaught =
+      CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
+
+  v8::V8::AddMessageListener(MessageCallbackCount);
+  v8::Debug::AddDebugEventListener(DebugEventCounter);
+
+  // Initial state should be break on uncaught exception.
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, exception_hit_count);
+  CHECK_EQ(1, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // No break on exception
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnException(false, false);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // Break on uncaught exception
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnException(false, true);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, exception_hit_count);
+  CHECK_EQ(1, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // Break on exception and uncaught exception
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnException(true, true);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, exception_hit_count);
+  CHECK_EQ(1, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // Break on exception
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnException(true, false);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, exception_hit_count);
+  CHECK_EQ(1, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // No break on exception using JavaScript
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnExceptionFromJS(false, false);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // Break on uncaught exception using JavaScript
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnExceptionFromJS(false, true);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(0, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, exception_hit_count);
+  CHECK_EQ(1, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // Break on exception and uncaught exception using JavaScript
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnExceptionFromJS(true, true);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, exception_hit_count);
+  CHECK_EQ(1, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  // Break on exception using JavaScript
+  DebugEventCounterClear();
+  MessageCallbackCountClear();
+  ChangeBreakOnExceptionFromJS(true, false);
+  caught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, exception_hit_count);
+  CHECK_EQ(0, uncaught_exception_hit_count);
+  CHECK_EQ(0, message_callback_count);
+  notCaught->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, exception_hit_count);
+  CHECK_EQ(1, uncaught_exception_hit_count);
+  CHECK_EQ(1, message_callback_count);
+
+  v8::Debug::RemoveDebugEventListener(DebugEventCounter);
+  v8::V8::RemoveMessageListeners(MessageCallbackCount);
+}
+
+
+TEST(StepWithException) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Create a function for checking the function when hitting a break point.
+  frame_function_name = CompileFunction(&env,
+                                        frame_function_name_source,
+                                        "frame_function_name");
+
+  // Register a debug event listener which steps and counts.
+  v8::Debug::AddDebugEventListener(DebugEventStepSequence);
+
+  // Create functions for testing stepping.
+  const char* src = "function a() { n(); }; "
+                    "function b() { c(); }; "
+                    "function c() { n(); }; "
+                    "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
+                    "function e() { n(); }; "
+                    "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
+                    "function g() { h(); }; "
+                    "function h() { x = 1; throw 1; }; ";
+
+  // Step through invocation of a.
+  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
+  SetBreakPoint(a, 0);
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "aa";
+  a->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of b + c.
+  v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
+  SetBreakPoint(b, 0);
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "bcc";
+  b->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of d + e.
+  v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
+  SetBreakPoint(d, 0);
+  ChangeBreakOnException(false, true);
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "ddedd";
+  d->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of d + e now with break on caught exceptions.
+  ChangeBreakOnException(true, true);
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "ddeedd";
+  d->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of f + g + h.
+  v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
+  SetBreakPoint(f, 0);
+  ChangeBreakOnException(false, true);
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "ffghff";
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Step through invocation of f + g + h now with break on caught exceptions.
+  ChangeBreakOnException(true, true);
+  step_action = StepIn;
+  break_point_hit_count = 0;
+  expected_step_sequence = "ffghhff";
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(strlen(expected_step_sequence), break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventStepSequence);
+}
+
+
+TEST(DebugBreak) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // This test should be run with option --verify-heap. This is an ASSERT and
+  // not a CHECK as --verify-heap is only available in debug mode.
+  ASSERT(v8::internal::FLAG_verify_heap);
+
+  // Register a debug event listener which sets the break flag and counts.
+  v8::Debug::AddDebugEventListener(DebugEventBreak);
+
+  // Create a function for testing stepping.
+  const char* src = "function f0() {}"
+                    "function f1(x1) {}"
+                    "function f2(x1,x2) {}"
+                    "function f3(x1,x2,x3) {}";
+  v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
+  v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
+  v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
+  v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
+
+  // Call the function to make sure it is compiled.
+  v8::Handle<v8::Value> argv[] = { v8::Number::New(1),
+                                   v8::Number::New(1),
+                                   v8::Number::New(1),
+                                   v8::Number::New(1) };
+
+  // Call all functions to make sure that they are compiled.
+  f0->Call(env->Global(), 0, NULL);
+  f1->Call(env->Global(), 0, NULL);
+  f2->Call(env->Global(), 0, NULL);
+  f3->Call(env->Global(), 0, NULL);
+
+  // Set the debug break flag.
+  v8::Debug::DebugBreak();
+
+  // Call all functions with different argument count.
+  break_point_hit_count = 0;
+  for (unsigned int i = 0; i < ARRAY_SIZE(argv); i++) {
+    f0->Call(env->Global(), i, argv);
+    f1->Call(env->Global(), i, argv);
+    f2->Call(env->Global(), i, argv);
+    f3->Call(env->Global(), i, argv);
+  }
+
+  // One break for each function called.
+  CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventBreak);
+}
+
+
+// Test to ensure that JavaScript code keeps running while the debug break
+// through the stack limit flag is set but breaks are disabled.
+TEST(DisableBreak) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Register a debug event listener which sets the break flag and counts.
+  v8::Debug::AddDebugEventListener(DebugEventCounter);
+
+  // Create a function for testing stepping.
+  const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
+  v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
+
+  // Set the debug break flag.
+  v8::Debug::DebugBreak();
+
+  // Call all functions with different argument count.
+  break_point_hit_count = 0;
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(1, break_point_hit_count);
+
+  {
+    v8::Debug::DebugBreak();
+    v8::internal::DisableBreak disable_break(true);
+    f->Call(env->Global(), 0, NULL);
+    CHECK_EQ(1, break_point_hit_count);
+  }
+
+  f->Call(env->Global(), 0, NULL);
+  CHECK_EQ(2, break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::RemoveDebugEventListener(DebugEventBreak);
+}
+
+
+static v8::Handle<v8::Array> NamedEnum(const v8::AccessorInfo&) {
+  v8::Handle<v8::Array> result = v8::Array::New(3);
+  result->Set(v8::Integer::New(0), v8::String::New("a"));
+  result->Set(v8::Integer::New(1), v8::String::New("b"));
+  result->Set(v8::Integer::New(2), v8::String::New("c"));
+  return result;
+}
+
+
+static v8::Handle<v8::Array> IndexedEnum(const v8::AccessorInfo&) {
+  v8::Handle<v8::Array> result = v8::Array::New(2);
+  result->Set(v8::Integer::New(0), v8::Number::New(1));
+  result->Set(v8::Integer::New(1), v8::Number::New(10));
+  return result;
+}
+
+
+static v8::Handle<v8::Value> NamedGetter(v8::Local<v8::String> name,
+                                         const v8::AccessorInfo& info) {
+  v8::String::AsciiValue n(name);
+  if (strcmp(*n, "a") == 0) {
+    return v8::String::New("AA");
+  } else if (strcmp(*n, "b") == 0) {
+    return v8::String::New("BB");
+  } else if (strcmp(*n, "c") == 0) {
+    return v8::String::New("CC");
+  } else {
+    return v8::Undefined();
+  }
+
+  return name;
+}
+
+
+static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
+                                           const v8::AccessorInfo& info) {
+  return v8::Number::New(index + 1);
+}
+
+
+TEST(InterceptorPropertyMirror) {
+  // Create a V8 environment with debug access.
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  env.ExposeDebug();
+
+  // Create object with named interceptor.
+  v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
+  named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
+  env->Global()->Set(v8::String::New("intercepted_named"),
+                     named->NewInstance());
+
+  // Create object with indexed interceptor.
+  v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New();
+  indexed->SetIndexedPropertyHandler(IndexedGetter,
+                                     NULL,
+                                     NULL,
+                                     NULL,
+                                     IndexedEnum);
+  env->Global()->Set(v8::String::New("intercepted_indexed"),
+                     indexed->NewInstance());
+
+  // Create object with both named and indexed interceptor.
+  v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New();
+  both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
+  both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
+  env->Global()->Set(v8::String::New("intercepted_both"), both->NewInstance());
+
+  // Get mirrors for the three objects with interceptor.
+  CompileRun(
+      "named_mirror = debug.MakeMirror(intercepted_named);"
+      "indexed_mirror = debug.MakeMirror(intercepted_indexed);"
+      "both_mirror = debug.MakeMirror(intercepted_both)");
+  CHECK(CompileRun(
+       "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
+  CHECK(CompileRun(
+        "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
+  CHECK(CompileRun(
+        "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
+
+  // Get the property names from the interceptors
+  CompileRun(
+      "named_names = named_mirror.interceptorPropertyNames();"
+      "indexed_names = indexed_mirror.interceptorPropertyNames();"
+      "both_names = both_mirror.interceptorPropertyNames()");
+  CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
+  CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
+  CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
+
+  // Check the expected number of properties.
+  const char* source;
+  source = "named_mirror.interceptorProperties().length";
+  CHECK_EQ(3, CompileRun(source)->Int32Value());
+
+  source = "indexed_mirror.interceptorProperties().length";
+  CHECK_EQ(2, CompileRun(source)->Int32Value());
+
+  source = "both_mirror.interceptorProperties().length";
+  CHECK_EQ(5, CompileRun(source)->Int32Value());
+
+  source = "both_mirror.interceptorProperties(1).length";
+  CHECK_EQ(3, CompileRun(source)->Int32Value());
+
+  source = "both_mirror.interceptorProperties(2).length";
+  CHECK_EQ(2, CompileRun(source)->Int32Value());
+
+  source = "both_mirror.interceptorProperties(3).length";
+  CHECK_EQ(5, CompileRun(source)->Int32Value());
+
+  // Get the interceptor properties for the object with both types of
+  // interceptors.
+  CompileRun("both_values = both_mirror.interceptorProperties()");
+
+  // Check the mirror hierachy
+  source = "both_values[0] instanceof debug.PropertyMirror";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[0] instanceof debug.InterceptorPropertyMirror";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[1] instanceof debug.InterceptorPropertyMirror";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[2] instanceof debug.InterceptorPropertyMirror";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[3] instanceof debug.PropertyMirror";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[3] instanceof debug.InterceptorPropertyMirror";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[4] instanceof debug.InterceptorPropertyMirror";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  // Check the property names.
+  source = "both_values[0].name() == 'a'";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[1].name() == 'b'";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[2].name() == 'c'";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[3].name() == 1";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[4].name() == 10";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  // Check the property values.
+  source = "both_values[0].value().value() == 'AA'";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[1].value().value() == 'BB'";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[2].value().value() == 'CC'";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[3].value().value() == 2";
+  CHECK(CompileRun(source)->BooleanValue());
+
+  source = "both_values[4].value().value() == 11";
+  CHECK(CompileRun(source)->BooleanValue());
+}
+
+
+// Multithreaded tests of JSON debugger protocol
+
+// Support classes
+
+// Copies a C string to a 16-bit string.  Does not check for buffer overflow.
+// Does not use the V8 engine to convert strings, so it can be used
+// in any thread.  Returns the length of the string.
+int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
+  int i;
+  for (i = 0; input_buffer[i] != '\0'; ++i) {
+    // ASCII does not use chars > 127, but be careful anyway.
+    output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
+  }
+  output_buffer[i] = 0;
+  return i;
+}
+
+// Copies a 16-bit string to a C string by dropping the high byte of
+// each character.  Does not check for buffer overflow.
+// Can be used in any thread.  Requires string length as an input.
+int Utf16ToAscii(const uint16_t* input_buffer, int length,
+                 char* output_buffer) {
+  for (int i = 0; i < length; ++i) {
+    output_buffer[i] = static_cast<char>(input_buffer[i]);
+  }
+  output_buffer[length] = '\0';
+  return length;
+}
+
+// Provides synchronization between k threads, where k is an input to the
+// constructor.  The Wait() call blocks a thread until it is called for the
+// k'th time, then all calls return.  Each ThreadBarrier object can only
+// be used once.
+class ThreadBarrier {
+ public:
+  explicit ThreadBarrier(int num_threads);
+  ~ThreadBarrier();
+  void Wait();
+ private:
+  int num_threads_;
+  int num_blocked_;
+  v8::internal::Mutex* lock_;
+  v8::internal::Semaphore* sem_;
+  bool invalid_;
+};
+
+ThreadBarrier::ThreadBarrier(int num_threads)
+    : num_threads_(num_threads), num_blocked_(0) {
+  lock_ = OS::CreateMutex();
+  sem_ = OS::CreateSemaphore(0);
+  invalid_ = false;  // A barrier may only be used once.  Then it is invalid.
+}
+
+// Do not call, due to race condition with Wait().
+// Could be resolved with Pthread condition variables.
+ThreadBarrier::~ThreadBarrier() {
+  lock_->Lock();
+  delete lock_;
+  delete sem_;
+}
+
+void ThreadBarrier::Wait() {
+  lock_->Lock();
+  ASSERT(!invalid_);
+  if (num_blocked_ == num_threads_ - 1) {
+    // Signal and unblock all waiting threads.
+    for (int i = 0; i < num_threads_ - 1; ++i) {
+      sem_->Signal();
+    }
+    invalid_ = true;
+    printf("BARRIER\n\n");
+    fflush(stdout);
+    lock_->Unlock();
+  } else {  // Wait for the semaphore.
+    ++num_blocked_;
+    lock_->Unlock();  // Potential race condition with destructor because
+    sem_->Wait();  // these two lines are not atomic.
+  }
+}
+
+// A set containing enough barriers and semaphores for any of the tests.
+class Barriers {
+ public:
+  Barriers();
+  void Initialize();
+  ThreadBarrier barrier_1;
+  ThreadBarrier barrier_2;
+  ThreadBarrier barrier_3;
+  ThreadBarrier barrier_4;
+  ThreadBarrier barrier_5;
+  v8::internal::Semaphore* semaphore_1;
+  v8::internal::Semaphore* semaphore_2;
+};
+
+Barriers::Barriers() : barrier_1(2), barrier_2(2),
+    barrier_3(2), barrier_4(2), barrier_5(2) {}
+
+void Barriers::Initialize() {
+  semaphore_1 = OS::CreateSemaphore(0);
+  semaphore_2 = OS::CreateSemaphore(0);
+}
+
+
+// We match parts of the message to decide if it is a break message.
+bool IsBreakEventMessage(char *message) {
+  const char* type_event = "\"type\":\"event\"";
+  const char* event_break = "\"event\":\"break\"";
+  // Does the message contain both type:event and event:break?
+  return strstr(message, type_event) != NULL &&
+         strstr(message, event_break) != NULL;
+}
+
+
+/* Test MessageQueues */
+/* Tests the message queues that hold debugger commands and
+ * response messages to the debugger.  Fills queues and makes
+ * them grow.
+ */
+Barriers message_queue_barriers;
+
+// This is the debugger thread, that executes no v8 calls except
+// placing JSON debugger commands in the queue.
+class MessageQueueDebuggerThread : public v8::internal::Thread {
+ public:
+  void Run();
+};
+
+static void MessageHandler(const uint16_t* message, int length, void *data) {
+  static char print_buffer[1000];
+  Utf16ToAscii(message, length, print_buffer);
+  if (IsBreakEventMessage(print_buffer)) {
+    // Lets test script wait until break occurs to send commands.
+    // Signals when a break is reported.
+    message_queue_barriers.semaphore_2->Signal();
+  }
+  // Allow message handler to block on a semaphore, to test queueing of
+  // messages while blocked.
+  message_queue_barriers.semaphore_1->Wait();
+  printf("%s\n", print_buffer);
+  fflush(stdout);
+}
+
+
+void MessageQueueDebuggerThread::Run() {
+  const int kBufferSize = 1000;
+  uint16_t buffer_1[kBufferSize];
+  uint16_t buffer_2[kBufferSize];
+  const char* command_1 =
+      "{\"seq\":117,"
+       "\"type\":\"request\","
+       "\"command\":\"evaluate\","
+       "\"arguments\":{\"expression\":\"1+2\"}}";
+  const char* command_2 =
+    "{\"seq\":118,"
+     "\"type\":\"request\","
+     "\"command\":\"evaluate\","
+     "\"arguments\":{\"expression\":\"1+a\"}}";
+  const char* command_3 =
+    "{\"seq\":119,"
+     "\"type\":\"request\","
+     "\"command\":\"evaluate\","
+     "\"arguments\":{\"expression\":\"c.d * b\"}}";
+  const char* command_continue =
+    "{\"seq\":106,"
+     "\"type\":\"request\","
+     "\"command\":\"continue\"}";
+  const char* command_single_step =
+    "{\"seq\":107,"
+     "\"type\":\"request\","
+     "\"command\":\"continue\","
+     "\"arguments\":{\"stepaction\":\"next\"}}";
+
+  /* Interleaved sequence of actions by the two threads:*/
+  // Main thread compiles and runs source_1
+  message_queue_barriers.barrier_1.Wait();
+  // Post 6 commands, filling the command queue and making it expand.
+  // These calls return immediately, but the commands stay on the queue
+  // until the execution of source_2.
+  // Note: AsciiToUtf16 executes before SendCommand, so command is copied
+  // to buffer before buffer is sent to SendCommand.
+  v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
+  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
+  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
+  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
+  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
+  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
+  message_queue_barriers.barrier_2.Wait();
+  // Main thread compiles and runs source_2.
+  // Queued commands are executed at the start of compilation of source_2.
+  message_queue_barriers.barrier_3.Wait();
+  // Free the message handler to process all the messages from the queue.
+  for (int i = 0; i < 20 ; ++i) {
+    message_queue_barriers.semaphore_1->Signal();
+  }
+  // Main thread compiles and runs source_3.
+  // source_3 includes a debugger statement, which causes a break event.
+  // Wait on break event from hitting "debugger" statement
+  message_queue_barriers.semaphore_2->Wait();
+  // These should execute after the "debugger" statement in source_2
+  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2));
+  // Wait on break event after a single step executes.
+  message_queue_barriers.semaphore_2->Wait();
+  v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1));
+  v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
+  // Main thread continues running source_3 to end, waits for this thread.
+}
+
+MessageQueueDebuggerThread message_queue_debugger_thread;
+
+// This thread runs the v8 engine.
+TEST(MessageQueues) {
+  // Create a V8 environment
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  message_queue_barriers.Initialize();
+  v8::Debug::SetMessageHandler(MessageHandler);
+  message_queue_debugger_thread.Start();
+
+  const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
+  const char* source_2 = "e = 17;";
+  const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
+
+  // See MessageQueueDebuggerThread::Run for interleaved sequence of
+  // API calls and events in the two threads.
+  CompileRun(source_1);
+  message_queue_barriers.barrier_1.Wait();
+  message_queue_barriers.barrier_2.Wait();
+  v8::Debug::DebugBreak();
+  CompileRun(source_2);
+  message_queue_barriers.barrier_3.Wait();
+  CompileRun(source_3);
+  message_queue_debugger_thread.Join();
+  fflush(stdout);
+}
+
+/* Test ThreadedDebugging */
+/* This test interrupts a running infinite loop that is
+ * occupying the v8 thread by a break command from the
+ * debugger thread.  It then changes the value of a
+ * global object, to make the loop terminate.
+ */
+
+Barriers threaded_debugging_barriers;
+
+class V8Thread : public v8::internal::Thread {
+ public:
+  void Run();
+};
+
+class DebuggerThread : public v8::internal::Thread {
+ public:
+  void Run();
+};
+
+
+static void ThreadedMessageHandler(const uint16_t* message, int length,
+                                   void *data) {
+  static char print_buffer[1000];
+  Utf16ToAscii(message, length, print_buffer);
+  if (IsBreakEventMessage(print_buffer)) {
+    threaded_debugging_barriers.barrier_2.Wait();
+  }
+  printf("%s\n", print_buffer);
+  fflush(stdout);
+}
+
+
+void V8Thread::Run() {
+  const char* source_1 =
+      "flag = true;\n"
+      "function bar( new_value ) {\n"
+      "  flag = new_value;\n"
+      "  return \"Return from bar(\" + new_value + \")\";\n"
+      "}\n"
+      "\n"
+      "function foo() {\n"
+      "  var x = 1;\n"
+      "  while ( flag == true ) {\n"
+      "    x = x + 1;\n"
+      "  }\n"
+      "}\n"
+      "\n";
+  const char* source_2 = "foo();\n";
+
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::SetMessageHandler(&ThreadedMessageHandler);
+
+  CompileRun(source_1);
+  threaded_debugging_barriers.barrier_1.Wait();
+  CompileRun(source_2);
+}
+
+void DebuggerThread::Run() {
+  const int kBufSize = 1000;
+  uint16_t buffer[kBufSize];
+
+  const char* command_1 = "{\"seq\":102,"
+      "\"type\":\"request\","
+      "\"command\":\"evaluate\","
+      "\"arguments\":{\"expression\":\"bar(false)\"}}";
+  const char* command_2 = "{\"seq\":103,"
+      "\"type\":\"request\","
+      "\"command\":\"continue\"}";
+
+  threaded_debugging_barriers.barrier_1.Wait();
+  v8::Debug::DebugBreak();
+  threaded_debugging_barriers.barrier_2.Wait();
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
+}
+
+DebuggerThread debugger_thread;
+V8Thread v8_thread;
+
+TEST(ThreadedDebugging) {
+  // Create a V8 environment
+  threaded_debugging_barriers.Initialize();
+
+  v8_thread.Start();
+  debugger_thread.Start();
+
+  v8_thread.Join();
+  debugger_thread.Join();
+}
+
+/* Test RecursiveBreakpoints */
+/* In this test, the debugger evaluates a function with a breakpoint, after
+ * hitting a breakpoint in another function.  We do this with both values
+ * of the flag enabling recursive breakpoints, and verify that the second
+ * breakpoint is hit when enabled, and missed when disabled.
+ */
+
+class BreakpointsV8Thread : public v8::internal::Thread {
+ public:
+  void Run();
+};
+
+class BreakpointsDebuggerThread : public v8::internal::Thread {
+ public:
+  void Run();
+};
+
+
+Barriers* breakpoints_barriers;
+
+static void BreakpointsMessageHandler(const uint16_t* message,
+                                      int length,
+                                      void *data) {
+  static char print_buffer[1000];
+  Utf16ToAscii(message, length, print_buffer);
+  printf("%s\n", print_buffer);
+  fflush(stdout);
+
+  // Is break_template a prefix of the message?
+  if (IsBreakEventMessage(print_buffer)) {
+    breakpoints_barriers->semaphore_1->Signal();
+  }
+}
+
+
+void BreakpointsV8Thread::Run() {
+  const char* source_1 = "var y_global = 3;\n"
+    "function cat( new_value ) {\n"
+    "  var x = new_value;\n"
+    "  y_global = 4;\n"
+    "  x = 3 * x + 1;\n"
+    "  y_global = 5;\n"
+    "  return x;\n"
+    "}\n"
+    "\n"
+    "function dog() {\n"
+    "  var x = 1;\n"
+    "  x = y_global;"
+    "  var z = 3;"
+    "  x += 100;\n"
+    "  return x;\n"
+    "}\n"
+    "\n";
+  const char* source_2 = "cat(17);\n"
+    "cat(19);\n";
+
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::SetMessageHandler(&BreakpointsMessageHandler);
+
+  CompileRun(source_1);
+  breakpoints_barriers->barrier_1.Wait();
+  breakpoints_barriers->barrier_2.Wait();
+  CompileRun(source_2);
+}
+
+
+void BreakpointsDebuggerThread::Run() {
+  const int kBufSize = 1000;
+  uint16_t buffer[kBufSize];
+
+  const char* command_1 = "{\"seq\":101,"
+      "\"type\":\"request\","
+      "\"command\":\"setbreakpoint\","
+      "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
+  const char* command_2 = "{\"seq\":102,"
+      "\"type\":\"request\","
+      "\"command\":\"setbreakpoint\","
+      "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
+  const char* command_3 = "{\"seq\":103,"
+      "\"type\":\"request\","
+      "\"command\":\"continue\"}";
+  const char* command_4 = "{\"seq\":104,"
+      "\"type\":\"request\","
+      "\"command\":\"evaluate\","
+      "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
+  const char* command_5 = "{\"seq\":105,"
+      "\"type\":\"request\","
+      "\"command\":\"evaluate\","
+      "\"arguments\":{\"expression\":\"x\",\"disable_break\":true}}";
+  const char* command_6 = "{\"seq\":106,"
+      "\"type\":\"request\","
+      "\"command\":\"continue\"}";
+  const char* command_7 = "{\"seq\":107,"
+      "\"type\":\"request\","
+      "\"command\":\"continue\"}";
+  const char* command_8 = "{\"seq\":108,"
+     "\"type\":\"request\","
+     "\"command\":\"evaluate\","
+     "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
+  const char* command_9 = "{\"seq\":109,"
+      "\"type\":\"request\","
+      "\"command\":\"continue\"}";
+
+
+  // v8 thread initializes, runs source_1
+  breakpoints_barriers->barrier_1.Wait();
+  // 1:Set breakpoint in cat().
+  v8::Debug::DebugBreak();
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
+  // 2:Set breakpoint in dog()
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
+  // 3:Continue
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
+  breakpoints_barriers->barrier_2.Wait();
+  // v8 thread starts compiling source_2.
+  // Automatic break happens, to run queued commands
+  // breakpoints_barriers->semaphore_1->Wait();
+  // Commands 1 through 3 run, thread continues.
+  // v8 thread runs source_2 to breakpoint in cat().
+  // message callback receives break event.
+  breakpoints_barriers->semaphore_1->Wait();
+  // 4:Evaluate dog() (which has a breakpoint).
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
+  // v8 thread hits breakpoint in dog()
+  breakpoints_barriers->semaphore_1->Wait();  // wait for break event
+  // 5:Evaluate x
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
+  // 6:Continue evaluation of dog()
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
+  // dog() finishes.
+  // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
+  // in cat(19).
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
+  // message callback gets break event
+  breakpoints_barriers->semaphore_1->Wait();  // wait for break event
+  // 8: Evaluate dog() with breaks disabled
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
+  // 9: Continue evaluation of source2, reach end.
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_9, buffer));
+}
+
+BreakpointsDebuggerThread breakpoints_debugger_thread;
+BreakpointsV8Thread breakpoints_v8_thread;
+
+TEST(RecursiveBreakpoints) {
+  // Create a V8 environment
+  Barriers stack_allocated_breakpoints_barriers;
+  stack_allocated_breakpoints_barriers.Initialize();
+  breakpoints_barriers = &stack_allocated_breakpoints_barriers;
+
+  breakpoints_v8_thread.Start();
+  breakpoints_debugger_thread.Start();
+
+  breakpoints_v8_thread.Join();
+  breakpoints_debugger_thread.Join();
+}
diff --git a/regexp2000/test/cctest/test-decls.cc b/regexp2000/test/cctest/test-decls.cc
new file mode 100644 (file)
index 0000000..e798fee
--- /dev/null
@@ -0,0 +1,594 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "heap.h"
+#include "cctest.h"
+
+using namespace v8;
+
+
+enum Expectations {
+  EXPECT_RESULT,
+  EXPECT_EXCEPTION
+};
+
+
+// A DeclarationContext holds a reference to a v8::Context and keeps
+// track of various declaration related counters to make it easier to
+// track if global declarations in the presence of interceptors behave
+// the right way.
+class DeclarationContext {
+ public:
+  DeclarationContext();
+
+  virtual ~DeclarationContext() {
+    if (is_initialized_) {
+      context_->Exit();
+      context_.Dispose();
+    }
+  }
+
+  void Check(const char* source,
+             int get, int set, int has,
+             Expectations expectations,
+             v8::Handle<Value> value = Local<Value>());
+
+  int get_count() const { return get_count_; }
+  int set_count() const { return set_count_; }
+  int has_count() const { return has_count_; }
+
+ protected:
+  virtual v8::Handle<Value> Get(Local<String> key);
+  virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
+  virtual v8::Handle<Boolean> Has(Local<String> key);
+
+  void InitializeIfNeeded();
+
+  // Get the holder for the interceptor. Default to the instance template
+  // but may be overwritten.
+  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
+    return function->InstanceTemplate();
+  }
+
+  // The handlers are called as static functions that forward
+  // to the instance specific virtual methods.
+  static v8::Handle<Value> HandleGet(Local<String> key,
+                                     const AccessorInfo& info);
+  static v8::Handle<Value> HandleSet(Local<String> key,
+                                     Local<Value> value,
+                                     const AccessorInfo& info);
+  static v8::Handle<Boolean> HandleHas(Local<String> key,
+                                       const AccessorInfo& info);
+
+ private:
+  bool is_initialized_;
+  Persistent<Context> context_;
+  Local<String> property_;
+
+  int get_count_;
+  int set_count_;
+  int has_count_;
+
+  static DeclarationContext* GetInstance(const AccessorInfo& info);
+};
+
+
+DeclarationContext::DeclarationContext()
+    : is_initialized_(false), get_count_(0), set_count_(0), has_count_(0) {
+  // Do nothing.
+}
+
+
+void DeclarationContext::InitializeIfNeeded() {
+  if (is_initialized_) return;
+  HandleScope scope;
+  Local<FunctionTemplate> function = FunctionTemplate::New();
+  Local<Value> data = Integer::New(reinterpret_cast<intptr_t>(this));
+  GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
+                                               &HandleSet,
+                                               &HandleHas,
+                                               0, 0,
+                                               data);
+  context_ = Context::New(0, function->InstanceTemplate(), Local<Value>());
+  context_->Enter();
+  is_initialized_ = true;
+}
+
+
+void DeclarationContext::Check(const char* source,
+                               int get, int set, int has,
+                               Expectations expectations,
+                               v8::Handle<Value> value) {
+  InitializeIfNeeded();
+  // A retry after a GC may pollute the counts, so perform gc now
+  // to avoid that.
+  v8::internal::Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
+  HandleScope scope;
+  TryCatch catcher;
+  catcher.SetVerbose(true);
+  Local<Value> result = Script::Compile(String::New(source))->Run();
+  CHECK_EQ(get, get_count());
+  CHECK_EQ(set, set_count());
+  CHECK_EQ(has, has_count());
+  if (expectations == EXPECT_RESULT) {
+    CHECK(!catcher.HasCaught());
+    if (!value.IsEmpty()) {
+      CHECK_EQ(value, result);
+    }
+  } else {
+    CHECK(expectations == EXPECT_EXCEPTION);
+    CHECK(catcher.HasCaught());
+    if (!value.IsEmpty()) {
+      CHECK_EQ(value, catcher.Exception());
+    }
+  }
+}
+
+
+v8::Handle<Value> DeclarationContext::HandleGet(Local<String> key,
+                                                const AccessorInfo& info) {
+  DeclarationContext* context = GetInstance(info);
+  context->get_count_++;
+  return context->Get(key);
+}
+
+
+v8::Handle<Value> DeclarationContext::HandleSet(Local<String> key,
+                                                Local<Value> value,
+                                                const AccessorInfo& info) {
+  DeclarationContext* context = GetInstance(info);
+  context->set_count_++;
+  return context->Set(key, value);
+}
+
+
+v8::Handle<Boolean> DeclarationContext::HandleHas(Local<String> key,
+                                                  const AccessorInfo& info) {
+  DeclarationContext* context = GetInstance(info);
+  context->has_count_++;
+  return context->Has(key);
+}
+
+
+DeclarationContext* DeclarationContext::GetInstance(const AccessorInfo& info) {
+  Local<Value> data = info.Data();
+  return reinterpret_cast<DeclarationContext*>(Int32::Cast(*data)->Value());
+}
+
+
+v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
+  return v8::Handle<Value>();
+}
+
+
+v8::Handle<Value> DeclarationContext::Set(Local<String> key,
+                                          Local<Value> value) {
+  return v8::Handle<Value>();
+}
+
+
+v8::Handle<Boolean> DeclarationContext::Has(Local<String> key) {
+  return v8::Handle<Boolean>();
+}
+
+
+// Test global declaration of a property the interceptor doesn't know
+// about and doesn't handle.
+TEST(Unknown) {
+  HandleScope scope;
+
+  { DeclarationContext context;
+    context.Check("var x; x",
+                  1,  // access
+                  1,  // declaration
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Undefined());
+  }
+
+  { DeclarationContext context;
+    context.Check("var x = 0; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Number::New(0));
+  }
+
+  { DeclarationContext context;
+    context.Check("function x() { }; x",
+                  1,  // access
+                  1,  // declaration
+                  0,
+                  EXPECT_RESULT);
+  }
+
+  { DeclarationContext context;
+    context.Check("const x; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Undefined());
+  }
+
+  { DeclarationContext context;
+    context.Check("const x = 0; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Undefined());  // SB 0 - BUG 1213579
+  }
+}
+
+
+
+class PresentPropertyContext: public DeclarationContext {
+ protected:
+  virtual v8::Handle<Boolean> Has(Local<String> key) {
+    return True();
+  }
+};
+
+
+
+TEST(Present) {
+  HandleScope scope;
+
+  { PresentPropertyContext context;
+    context.Check("var x; x",
+                  1,  // access
+                  0,
+                  2,  // declaration + initialization
+                  EXPECT_EXCEPTION);  // x is not defined!
+  }
+
+  { PresentPropertyContext context;
+    context.Check("var x = 0; x",
+                  1,  // access
+                  1,  // initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Number::New(0));
+  }
+
+  { PresentPropertyContext context;
+    context.Check("function x() { }; x",
+                  1,  // access
+                  1,  // declaration
+                  0,
+                  EXPECT_RESULT);
+  }
+
+  { PresentPropertyContext context;
+    context.Check("const x; x",
+                  0,
+                  0,
+                  1,  // (re-)declaration
+                  EXPECT_EXCEPTION);  // x has already been declared!
+  }
+
+  { PresentPropertyContext context;
+    context.Check("const x = 0; x",
+                  0,
+                  0,
+                  1,  // (re-)declaration
+                  EXPECT_EXCEPTION);  // x has already been declared!
+  }
+}
+
+
+
+class AbsentPropertyContext: public DeclarationContext {
+ protected:
+  virtual v8::Handle<Boolean> Has(Local<String> key) {
+    return False();
+  }
+};
+
+
+TEST(Absent) {
+  HandleScope scope;
+
+  { AbsentPropertyContext context;
+    context.Check("var x; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Undefined());
+  }
+
+  { AbsentPropertyContext context;
+    context.Check("var x = 0; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Number::New(0));
+  }
+
+  { AbsentPropertyContext context;
+    context.Check("function x() { }; x",
+                  1,  // access
+                  1,  // declaration
+                  0,
+                  EXPECT_RESULT);
+  }
+
+  { AbsentPropertyContext context;
+    context.Check("const x; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initializetion
+                  EXPECT_RESULT, Undefined());
+  }
+
+  { AbsentPropertyContext context;
+    context.Check("const x = 0; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Undefined());  // SB 0 - BUG 1213579
+  }
+
+  { AbsentPropertyContext context;
+    context.Check("if (false) { var x = 0 }; x",
+                  1,  // access
+                  1,  // declaration
+                  1,  // declaration + initialization
+                  EXPECT_RESULT, Undefined());
+  }
+}
+
+
+
+class AppearingPropertyContext: public DeclarationContext {
+ public:
+  enum State {
+    DECLARE,
+    INITIALIZE_IF_ASSIGN,
+    UNKNOWN
+  };
+
+  AppearingPropertyContext() : state_(DECLARE) { }
+
+ protected:
+  virtual v8::Handle<Boolean> Has(Local<String> key) {
+    switch (state_) {
+      case DECLARE:
+        // Force declaration by returning that the
+        // property is absent.
+        state_ = INITIALIZE_IF_ASSIGN;
+        return False();
+      case INITIALIZE_IF_ASSIGN:
+        // Return that the property is present so we only get the
+        // setter called when initializing with a value.
+        state_ = UNKNOWN;
+        return True();
+      default:
+        ASSERT(state_ == UNKNOWN);
+        break;
+    }
+    // Do the lookup in the object.
+    return v8::Local<Boolean>();
+  }
+
+ private:
+  State state_;
+};
+
+
+TEST(Appearing) {
+  HandleScope scope;
+
+  { AppearingPropertyContext context;
+    context.Check("var x; x",
+                  1,  // access
+                  1,  // declaration
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Undefined());
+  }
+
+  { AppearingPropertyContext context;
+    context.Check("var x = 0; x",
+                  1,  // access
+                  2,  // declaration + initialization
+                  2,  // declaration + initialization
+                  EXPECT_RESULT, Number::New(0));
+  }
+
+  { AppearingPropertyContext context;
+    context.Check("function x() { }; x",
+                  1,  // access
+                  1,  // declaration
+                  0,
+                  EXPECT_RESULT);
+  }
+
+  { AppearingPropertyContext context;
+    context.Check("const x; x",
+                  0,
+                  1,  // declaration
+                  2,  // declaration + initialization
+                  EXPECT_EXCEPTION);  // x has already been declared!
+  }
+
+  { AppearingPropertyContext context;
+    context.Check("const x = 0; x",
+                  0,
+                  1,  // declaration
+                  2,  // declaration + initialization
+                  EXPECT_EXCEPTION);  //  x has already been declared!
+  }
+}
+
+
+
+class ReappearingPropertyContext: public DeclarationContext {
+ public:
+  enum State {
+    DECLARE,
+    DONT_DECLARE,
+    INITIALIZE,
+    UNKNOWN
+  };
+
+  ReappearingPropertyContext() : state_(DECLARE) { }
+
+ protected:
+  virtual v8::Handle<Boolean> Has(Local<String> key) {
+    switch (state_) {
+      case DECLARE:
+        // Force the first declaration by returning that
+        // the property is absent.
+        state_ = DONT_DECLARE;
+        return False();
+      case DONT_DECLARE:
+        // Ignore the second declaration by returning
+        // that the property is already there.
+        state_ = INITIALIZE;
+        return True();
+      case INITIALIZE:
+        // Force an initialization by returning that
+        // the property is absent. This will make sure
+        // that the setter is called and it will not
+        // lead to redeclaration conflicts (yet).
+        state_ = UNKNOWN;
+        return False();
+      default:
+        ASSERT(state_ == UNKNOWN);
+        break;
+    }
+    // Do the lookup in the object.
+    return v8::Local<Boolean>();
+  }
+
+ private:
+  State state_;
+};
+
+
+TEST(Reappearing) {
+  HandleScope scope;
+
+  { ReappearingPropertyContext context;
+    context.Check("const x; var x = 0",
+                  0,
+                  2,  // var declaration + const initialization
+                  4,  // 2 x declaration + 2 x initialization
+                  EXPECT_EXCEPTION);  // x has already been declared!
+  }
+}
+
+
+
+class ExistsInPrototypeContext: public DeclarationContext {
+ protected:
+  virtual v8::Handle<Boolean> Has(Local<String> key) {
+    // Let it seem that the property exists in the prototype object.
+    return True();
+  }
+
+  // Use the prototype as the holder for the interceptors.
+  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
+    return function->PrototypeTemplate();
+  }
+};
+
+
+TEST(ExistsInPrototype) {
+  HandleScope scope;
+
+  // Sanity check to make sure that the holder of the interceptor
+  // really is the prototype object.
+  { ExistsInPrototypeContext context;
+    context.Check("this.x = 87; this.x",
+                  0,
+                  0,
+                  0,
+                  EXPECT_RESULT, Number::New(87));
+  }
+
+  { ExistsInPrototypeContext context;
+    context.Check("var x; x",
+                  0,
+                  0,
+                  1,  // declaration
+                  EXPECT_RESULT, Undefined());
+  }
+
+  { ExistsInPrototypeContext context;
+    context.Check("var x = 0; x",
+                  0,
+                  0,
+                  1,  // declaration
+                  EXPECT_RESULT, Number::New(0));
+  }
+
+  { ExistsInPrototypeContext context;
+    context.Check("const x; x",
+                  0,
+                  0,
+                  1,  // declaration
+                  EXPECT_RESULT, Undefined());
+  }
+
+  { ExistsInPrototypeContext context;
+    context.Check("const x = 0; x",
+                  0,
+                  0,
+                  1,  // declaration
+                  EXPECT_RESULT, Number::New(0));
+  }
+}
+
+
+
+class AbsentInPrototypeContext: public DeclarationContext {
+ protected:
+  virtual v8::Handle<Boolean> Has(Local<String> key) {
+    // Let it seem that the property is absent in the prototype object.
+    return False();
+  }
+
+  // Use the prototype as the holder for the interceptors.
+  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
+    return function->PrototypeTemplate();
+  }
+};
+
+
+TEST(AbsentInPrototype) {
+  HandleScope scope;
+
+  { AbsentInPrototypeContext context;
+    context.Check("if (false) { var x = 0; }; x",
+                  0,
+                  0,
+                  1,  // declaration
+                  EXPECT_RESULT, Undefined());
+  }
+}
diff --git a/regexp2000/test/cctest/test-disasm-arm.cc b/regexp2000/test/cctest/test-disasm-arm.cc
new file mode 100644 (file)
index 0000000..7df292a
--- /dev/null
@@ -0,0 +1,272 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "debug.h"
+#include "disasm.h"
+#include "disassembler.h"
+#include "macro-assembler.h"
+#include "serialize.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+
+static v8::Persistent<v8::Context> env;
+
+static void InitializeVM() {
+  if (env.IsEmpty()) {
+    env = v8::Context::New();
+  }
+}
+
+
+bool DisassembleAndCompare(byte* pc, const char* compare_string) {
+  disasm::Disassembler disasm;
+  EmbeddedVector<char, 128> disasm_buffer;
+
+  disasm.InstructionDecode(disasm_buffer, pc);
+
+  if (strcmp(compare_string, disasm_buffer.start()) != 0) {
+    fprintf(stderr,
+            "expected: \n"
+            "%s\n"
+            "disassembled: \n"
+            "%s\n\n",
+            compare_string, disasm_buffer.start());
+    return false;
+  }
+  return true;
+}
+
+
+#define SETUP() \
+  InitializeVM(); \
+  Serializer::disable(); \
+  v8::HandleScope scope; \
+  byte *buffer = reinterpret_cast<byte*>(malloc(4*1024)); \
+  Assembler assm(buffer, 4*1024); \
+  bool failure = false;
+
+
+#define COMPARE(asm_, compare_string) \
+  { \
+    int pc_offset = assm.pc_offset(); \
+    byte *pc = &buffer[pc_offset]; \
+    assm.asm_; \
+    if (!DisassembleAndCompare(pc, compare_string)) failure = true; \
+  }
+
+
+#define OUTPUT() \
+  if (failure) { \
+    V8_Fatal(__FILE__, __LINE__, "ARM Disassembler tests failed.\n"); \
+  }
+
+
+TEST(Type0) {
+  SETUP();
+
+  COMPARE(and_(r0, r1, Operand(r2)),
+          "e0010002       and r0, r1, r2");
+  COMPARE(and_(r1, r2, Operand(r3), LeaveCC),
+          "e0021003       and r1, r2, r3");
+  COMPARE(and_(r2, r3, Operand(r4), SetCC),
+          "e0132004       ands r2, r3, r4");
+  COMPARE(and_(r3, r4, Operand(r5), LeaveCC, eq),
+          "00043005       andeq r3, r4, r5");
+
+  COMPARE(eor(r4, r5, Operand(r6, LSL, 0)),
+          "e0254006       eor r4, r5, r6");
+  COMPARE(eor(r4, r5, Operand(r7, LSL, 1), SetCC),
+          "e0354087       eors r4, r5, r7, lsl #1");
+  COMPARE(eor(r4, r5, Operand(r8, LSL, 2), LeaveCC, ne),
+          "10254108       eorne r4, r5, r8, lsl #2");
+  COMPARE(eor(r4, r5, Operand(r9, LSL, 3), SetCC, cs),
+          "20354189       eorcss r4, r5, r9, lsl #3");
+
+  COMPARE(sub(r5, r6, Operand(r10, LSL, 31), LeaveCC, hs),
+          "20465f8a       subcs r5, r6, sl, lsl #31");
+  COMPARE(sub(r5, r6, Operand(r10, LSL, 30), SetCC, cc),
+          "30565f0a       subccs r5, r6, sl, lsl #30");
+  COMPARE(sub(r5, r6, Operand(r10, LSL, 24), LeaveCC, lo),
+          "30465c0a       subcc r5, r6, sl, lsl #24");
+  COMPARE(sub(r5, r6, Operand(r10, LSL, 16), SetCC, mi),
+          "4056580a       submis r5, r6, sl, lsl #16");
+
+  COMPARE(rsb(r6, r7, Operand(fp)),
+          "e067600b       rsb r6, r7, fp");
+  COMPARE(rsb(r6, r7, Operand(fp, LSR, 1)),
+          "e06760ab       rsb r6, r7, fp, lsr #1");
+  COMPARE(rsb(r6, r7, Operand(fp, LSR, 0), SetCC),
+          "e077602b       rsbs r6, r7, fp, lsr #32");
+  COMPARE(rsb(r6, r7, Operand(fp, LSR, 31), LeaveCC, pl),
+          "50676fab       rsbpl r6, r7, fp, lsr #31");
+
+  COMPARE(add(r7, r8, Operand(ip, ASR, 1)),
+          "e08870cc       add r7, r8, ip, asr #1");
+  COMPARE(add(r7, r8, Operand(ip, ASR, 0)),
+          "e088704c       add r7, r8, ip, asr #32");
+  COMPARE(add(r7, r8, Operand(ip), SetCC),
+          "e098700c       adds r7, r8, ip");
+  COMPARE(add(r7, r8, Operand(ip, ASR, 31), SetCC, vs),
+          "60987fcc       addvss r7, r8, ip, asr #31");
+
+  COMPARE(adc(r7, fp, Operand(ip, ASR, 5)),
+          "e0ab72cc       adc r7, fp, ip, asr #5");
+  COMPARE(adc(r4, ip, Operand(ip, ASR, 1), LeaveCC, vc),
+          "70ac40cc       adcvc r4, ip, ip, asr #1");
+  COMPARE(adc(r5, sp, Operand(ip), SetCC),
+          "e0bd500c       adcs r5, sp, ip");
+  COMPARE(adc(r8, lr, Operand(ip, ASR, 31), SetCC, vc),
+          "70be8fcc       adcvcs r8, lr, ip, asr #31");
+
+  COMPARE(sbc(r7, r1, Operand(ip, ROR, 1), LeaveCC, hi),
+          "80c170ec       sbchi r7, r1, ip, ror #1");
+  COMPARE(sbc(r7, r9, Operand(ip, ROR, 4)),
+          "e0c9726c       sbc r7, r9, ip, ror #4");
+  COMPARE(sbc(r7, r10, Operand(ip), SetCC),
+          "e0da700c       sbcs r7, sl, ip");
+  COMPARE(sbc(r7, ip, Operand(ip, ROR, 31), SetCC, hi),
+          "80dc7fec       sbchis r7, ip, ip, ror #31");
+
+  COMPARE(rsc(r7, r8, Operand(ip, LSL, r0)),
+          "e0e8701c       rsc r7, r8, ip, lsl r0");
+  COMPARE(rsc(r7, r8, Operand(ip, LSL, r1)),
+          "e0e8711c       rsc r7, r8, ip, lsl r1");
+  COMPARE(rsc(r7, r8, Operand(ip), SetCC),
+          "e0f8700c       rscs r7, r8, ip");
+  COMPARE(rsc(r7, r8, Operand(ip, LSL, r3), SetCC, ls),
+          "90f8731c       rsclss r7, r8, ip, lsl r3");
+
+  COMPARE(tst(r7, Operand(r5, ASR, ip), ge),
+          "a1170c55       tstge r7, r5, asr ip");
+  COMPARE(tst(r7, Operand(r6, ASR, sp)),
+          "e1170d56       tst r7, r6, asr sp");
+  COMPARE(tst(r7, Operand(r7), ge),
+          "a1170007       tstge r7, r7");
+  COMPARE(tst(r7, Operand(r8, ASR, fp), ge),
+          "a1170b58       tstge r7, r8, asr fp");
+
+  COMPARE(teq(r7, Operand(r5, ROR, r0), lt),
+          "b1370075       teqlt r7, r5, ror r0");
+  COMPARE(teq(r7, Operand(r6, ROR, lr)),
+          "e1370e76       teq r7, r6, ror lr");
+  COMPARE(teq(r7, Operand(r7), lt),
+          "b1370007       teqlt r7, r7");
+  COMPARE(teq(r7, Operand(r8, ROR, r1)),
+          "e1370178       teq r7, r8, ror r1");
+
+  COMPARE(cmp(r7, Operand(r4)),
+          "e1570004       cmp r7, r4");
+  COMPARE(cmp(r7, Operand(r6, LSL, 1), gt),
+          "c1570086       cmpgt r7, r6, lsl #1");
+  COMPARE(cmp(r7, Operand(r8, LSR, 3), gt),
+          "c15701a8       cmpgt r7, r8, lsr #3");
+  COMPARE(cmp(r7, Operand(r8, ASR, 19)),
+          "e15709c8       cmp r7, r8, asr #19");
+
+  COMPARE(cmn(r0, Operand(r4)),
+          "e1700004       cmn r0, r4");
+  COMPARE(cmn(r1, Operand(r6, ROR, 1)),
+          "e17100e6       cmn r1, r6, ror #1");
+  COMPARE(cmn(r2, Operand(r8)),
+          "e1720008       cmn r2, r8");
+  COMPARE(cmn(r3, Operand(fp), le),
+          "d173000b       cmnle r3, fp");
+
+  COMPARE(orr(r7, r8, Operand(lr), LeaveCC, al),
+          "e188700e       orr r7, r8, lr");
+  COMPARE(orr(r7, r8, Operand(fp)),
+          "e188700b       orr r7, r8, fp");
+  COMPARE(orr(r7, r8, Operand(sp), SetCC),
+          "e198700d       orrs r7, r8, sp");
+  COMPARE(orr(r7, r8, Operand(ip), SetCC, al),
+          "e198700c       orrs r7, r8, ip");
+
+  COMPARE(mov(r0, Operand(r1), LeaveCC, eq),
+          "01a00001       moveq r0, r1");
+  COMPARE(mov(r0, Operand(r2)),
+          "e1a00002       mov r0, r2");
+  COMPARE(mov(r0, Operand(r3), SetCC),
+          "e1b00003       movs r0, r3");
+  COMPARE(mov(r0, Operand(r4), SetCC, pl),
+          "51b00004       movpls r0, r4");
+
+  COMPARE(bic(r0, lr, Operand(r1), LeaveCC, vs),
+          "61ce0001       bicvs r0, lr, r1");
+  COMPARE(bic(r0, r9, Operand(r2), LeaveCC, vc),
+          "71c90002       bicvc r0, r9, r2");
+  COMPARE(bic(r0, r5, Operand(r3), SetCC),
+          "e1d50003       bics r0, r5, r3");
+  COMPARE(bic(r0, r1, Operand(r4), SetCC, pl),
+          "51d10004       bicpls r0, r1, r4");
+
+  COMPARE(mvn(r10, Operand(r1)),
+          "e1e0a001       mvn sl, r1");
+  COMPARE(mvn(r9, Operand(r2)),
+          "e1e09002       mvn r9, r2");
+  COMPARE(mvn(r0, Operand(r3), SetCC),
+          "e1f00003       mvns r0, r3");
+  COMPARE(mvn(r5, Operand(r4), SetCC, cc),
+          "31f05004       mvnccs r5, r4");
+
+  OUTPUT();
+}
+
+
+TEST(Type1) {
+  SETUP();
+
+  COMPARE(and_(r0, r1, Operand(0x00000000)),
+          "e2010000       and r0, r1, #0");
+  COMPARE(and_(r1, r2, Operand(0x00000001), LeaveCC),
+          "e2021001       and r1, r2, #1");
+  COMPARE(and_(r2, r3, Operand(0x00000010), SetCC),
+          "e2132010       ands r2, r3, #16");
+  COMPARE(and_(r3, r4, Operand(0x00000100), LeaveCC, eq),
+          "02043c01       andeq r3, r4, #256");
+  COMPARE(and_(r4, r5, Operand(0x00001000), SetCC, ne),
+          "12154a01       andnes r4, r5, #4096");
+
+  COMPARE(eor(r4, r5, Operand(0x00001000)),
+          "e2254a01       eor r4, r5, #4096");
+  COMPARE(eor(r4, r4, Operand(0x00010000), LeaveCC),
+          "e2244801       eor r4, r4, #65536");
+  COMPARE(eor(r4, r3, Operand(0x00100000), SetCC),
+          "e2334601       eors r4, r3, #1048576");
+  COMPARE(eor(r4, r2, Operand(0x01000000), LeaveCC, cs),
+          "22224401       eorcs r4, r2, #16777216");
+  COMPARE(eor(r4, r1, Operand(0x10000000), SetCC, cc),
+          "32314201       eorccs r4, r1, #268435456");
+
+  OUTPUT();
+}
diff --git a/regexp2000/test/cctest/test-disasm-ia32.cc b/regexp2000/test/cctest/test-disasm-ia32.cc
new file mode 100644 (file)
index 0000000..35a39b3
--- /dev/null
@@ -0,0 +1,383 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "debug.h"
+#include "disasm.h"
+#include "disassembler.h"
+#include "macro-assembler.h"
+#include "serialize.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static v8::Persistent<v8::Context> env;
+
+static void InitializeVM() {
+  if (env.IsEmpty()) {
+    env = v8::Context::New();
+  }
+}
+
+
+#define __ assm.
+
+
+static void DummyStaticFunction(Object* result) {
+}
+
+
+TEST(DisasmIa320) {
+  InitializeVM();
+  Serializer::disable();  // Needed for Probe when running without snapshot.
+  CpuFeatures::Probe();
+  v8::HandleScope scope;
+  v8::internal::byte buffer[1024];
+  Assembler assm(buffer, sizeof buffer);
+  DummyStaticFunction(NULL);  // just bloody use it (DELETE; debugging)
+
+  // Short immediate instructions
+  __ adc(eax, 12345678);
+  __ add(Operand(eax), Immediate(12345678));
+  __ or_(eax, 12345678);
+  __ sub(Operand(eax), Immediate(12345678));
+  __ xor_(eax, 12345678);
+  __ and_(eax, 12345678);
+  Handle<FixedArray> foo = Factory::NewFixedArray(10, TENURED);
+  __ cmp(eax, foo);
+
+  // ---- This one caused crash
+  __ mov(ebx,  Operand(esp, ecx, times_2, 0));  // [esp+ecx*4]
+
+  // ---- All instructions that I can think of
+  __ add(edx, Operand(ebx));
+  __ add(edx, Operand(12, RelocInfo::NONE));
+  __ add(edx, Operand(ebx, 0));
+  __ add(edx, Operand(ebx, 16));
+  __ add(edx, Operand(ebx, 1999));
+  __ add(edx, Operand(esp, 0));
+  __ add(edx, Operand(esp, 16));
+  __ add(edx, Operand(esp, 1999));
+  __ nop();
+  __ add(edi, Operand(ebp, ecx, times_4, 0));
+  __ add(edi, Operand(ebp, ecx, times_4, 12));
+  __ add(Operand(ebp, ecx, times_4, 12), Immediate(12));
+
+  __ nop();
+  __ add(Operand(ebx), Immediate(12));
+  __ nop();
+  __ adc(ecx, 12);
+  __ adc(ecx, 1000);
+  __ nop();
+  __ and_(edx, 3);
+  __ and_(edx, Operand(esp, 4));
+  __ cmp(edx, 3);
+  __ cmp(edx, Operand(esp, 4));
+  __ cmp(Operand(ebp, ecx, times_4, 0), Immediate(1000));
+  Handle<FixedArray> foo2 = Factory::NewFixedArray(10, TENURED);
+  __ cmp(ebx, foo2);
+  __ or_(edx, 3);
+  __ xor_(edx, 3);
+  __ nop();
+  {
+    CHECK(CpuFeatures::IsSupported(CpuFeatures::CPUID));
+    CpuFeatures::Scope fscope(CpuFeatures::CPUID);
+    __ cpuid();
+  }
+  {
+    CHECK(CpuFeatures::IsSupported(CpuFeatures::RDTSC));
+    CpuFeatures::Scope fscope(CpuFeatures::RDTSC);
+    __ rdtsc();
+  }
+  __ movsx_b(edx, Operand(ecx));
+  __ movsx_w(edx, Operand(ecx));
+  __ movzx_b(edx, Operand(ecx));
+  __ movzx_w(edx, Operand(ecx));
+
+  __ nop();
+  __ imul(edx, Operand(ecx));
+  __ shld(edx, Operand(ecx));
+  __ shrd(edx, Operand(ecx));
+  __ bts(Operand(edx), ecx);
+  __ bts(Operand(ebx, ecx, times_4, 0), ecx);
+  __ nop();
+  __ pushad();
+  __ popad();
+  __ pushfd();
+  __ popfd();
+  __ push(Immediate(12));
+  __ push(Immediate(23456));
+  __ push(ecx);
+  __ push(esi);
+  __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+  __ push(Operand(ebx, ecx, times_4, 0));
+  __ push(Operand(ebx, ecx, times_4, 0));
+  __ push(Operand(ebx, ecx, times_4, 10000));
+  __ pop(edx);
+  __ pop(eax);
+  __ pop(Operand(ebx, ecx, times_4, 0));
+  __ nop();
+
+  __ add(edx, Operand(esp, 16));
+  __ add(edx, Operand(ecx));
+  __ mov_b(edx, Operand(ecx));
+  __ mov_b(Operand(ecx), 6);
+  __ mov_b(Operand(ebx, ecx, times_4, 10000), 6);
+  __ mov_b(Operand(esp, 16), edx);
+  __ mov_w(edx, Operand(esp, 16));
+  __ mov_w(Operand(esp, 16), edx);
+  __ nop();
+  __ movsx_w(edx, Operand(esp, 12));
+  __ movsx_b(edx, Operand(esp, 12));
+  __ movzx_w(edx, Operand(esp, 12));
+  __ movzx_b(edx, Operand(esp, 12));
+  __ nop();
+  __ mov(edx, 1234567);
+  __ mov(edx, Operand(esp, 12));
+  __ mov(Operand(ebx, ecx, times_4, 10000), Immediate(12345));
+  __ mov(Operand(ebx, ecx, times_4, 10000), edx);
+  __ nop();
+  __ dec_b(edx);
+  __ dec(edx);
+  __ cdq();
+
+  __ nop();
+  __ idiv(edx);
+  __ mul(edx);
+  __ neg(edx);
+  __ not_(edx);
+  __ test(Operand(ebx, ecx, times_4, 10000), Immediate(123456));
+
+  __ imul(edx, Operand(ebx, ecx, times_4, 10000));
+  __ imul(edx, ecx, 12);
+  __ imul(edx, ecx, 1000);
+
+  __ inc(edx);
+  __ inc(Operand(ebx, ecx, times_4, 10000));
+  __ push(Operand(ebx, ecx, times_4, 10000));
+  __ pop(Operand(ebx, ecx, times_4, 10000));
+  __ call(Operand(ebx, ecx, times_4, 10000));
+  __ jmp(Operand(ebx, ecx, times_4, 10000));
+
+  __ lea(edx, Operand(ebx, ecx, times_4, 10000));
+  __ or_(edx, 12345);
+  __ or_(edx, Operand(ebx, ecx, times_4, 10000));
+
+  __ nop();
+
+  __ rcl(edx, 1);
+  __ rcl(edx, 7);
+  __ sar(edx, 1);
+  __ sar(edx, 6);
+  __ sar(edx);
+  __ sbb(edx, Operand(ebx, ecx, times_4, 10000));
+  __ shld(edx, Operand(ebx, ecx, times_4, 10000));
+  __ shl(edx, 1);
+  __ shl(edx, 6);
+  __ shl(edx);
+  __ shrd(edx, Operand(ebx, ecx, times_4, 10000));
+  __ shr(edx, 7);
+  __ shr(edx);
+
+
+  // Immediates
+
+  __ adc(edx, 12345);
+
+  __ add(Operand(ebx), Immediate(12));
+  __ add(Operand(edx, ecx, times_4, 10000), Immediate(12));
+
+  __ and_(ebx, 12345);
+
+  __ cmp(ebx, 12345);
+  __ cmp(Operand(ebx), Immediate(12));
+  __ cmp(Operand(edx, ecx, times_4, 10000), Immediate(12));
+
+  __ or_(ebx, 12345);
+
+  __ sub(Operand(ebx), Immediate(12));
+  __ sub(Operand(edx, ecx, times_4, 10000), Immediate(12));
+
+  __ xor_(ebx, 12345);
+
+  __ imul(edx, ecx, 12);
+  __ imul(edx, ecx, 1000);
+
+
+
+  __ sub(edx, Operand(ebx, ecx, times_4, 10000));
+  __ sub(edx, Operand(ebx));
+
+  __ test(edx, Immediate(12345));
+  __ test(edx, Operand(ebx, ecx, times_8, 10000));
+  __ nop();
+
+  __ xor_(edx, 12345);
+  __ xor_(edx, Operand(ebx, ecx, times_8, 10000));
+  __ bts(Operand(ebx, ecx, times_8, 10000), edx);
+  __ hlt();
+  __ int3();
+  __ ret(0);
+  __ ret(8);
+
+  // Calls
+
+  Label L1, L2;
+  __ bind(&L1);
+  __ nop();
+  __ call(&L1);
+  __ call(&L2);
+  __ nop();
+  __ bind(&L2);
+  __ call(Operand(ebx, ecx, times_4, 10000));
+  __ nop();
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+  __ call(ic, RelocInfo::CODE_TARGET);
+  __ nop();
+  __ call(FUNCTION_ADDR(DummyStaticFunction), RelocInfo::RUNTIME_ENTRY);
+  __ nop();
+
+  __ jmp(&L1);
+  __ jmp(Operand(ebx, ecx, times_4, 10000));
+  ExternalReference after_break_target =
+      ExternalReference(Debug_Address::AfterBreakTarget());
+  __ jmp(Operand::StaticVariable(after_break_target));
+  __ jmp(ic, RelocInfo::CODE_TARGET);
+  __ nop();
+
+
+  Label Ljcc;
+  __ nop();
+  // long jumps
+  __ j(overflow, &Ljcc);
+  __ j(no_overflow, &Ljcc);
+  __ j(below, &Ljcc);
+  __ j(above_equal, &Ljcc);
+  __ j(equal, &Ljcc);
+  __ j(not_equal, &Ljcc);
+  __ j(below_equal, &Ljcc);
+  __ j(above, &Ljcc);
+  __ j(sign, &Ljcc);
+  __ j(not_sign, &Ljcc);
+  __ j(parity_even, &Ljcc);
+  __ j(parity_odd, &Ljcc);
+  __ j(less, &Ljcc);
+  __ j(greater_equal, &Ljcc);
+  __ j(less_equal, &Ljcc);
+  __ j(greater, &Ljcc);
+  __ nop();
+  __ bind(&Ljcc);
+  // short jumps
+  __ j(overflow, &Ljcc);
+  __ j(no_overflow, &Ljcc);
+  __ j(below, &Ljcc);
+  __ j(above_equal, &Ljcc);
+  __ j(equal, &Ljcc);
+  __ j(not_equal, &Ljcc);
+  __ j(below_equal, &Ljcc);
+  __ j(above, &Ljcc);
+  __ j(sign, &Ljcc);
+  __ j(not_sign, &Ljcc);
+  __ j(parity_even, &Ljcc);
+  __ j(parity_odd, &Ljcc);
+  __ j(less, &Ljcc);
+  __ j(greater_equal, &Ljcc);
+  __ j(less_equal, &Ljcc);
+  __ j(greater, &Ljcc);
+
+  // checking hints
+  __ j(zero, &Ljcc, taken);
+  __ j(zero, &Ljcc, not_taken);
+
+  // __ mov(Operand::StaticVariable(Top::handler_address()), eax);
+  // 0xD9 instructions
+  __ nop();
+
+  __ fld1();
+  __ fldz();
+  __ fabs();
+  __ fchs();
+  __ fprem();
+  __ fprem1();
+  __ fincstp();
+  __ ftst();
+  __ fxch(3);
+  __ fld_s(Operand(ebx, ecx, times_4, 10000));
+  __ fstp_s(Operand(ebx, ecx, times_4, 10000));
+  __ ffree(3);
+  __ fld_d(Operand(ebx, ecx, times_4, 10000));
+  __ fstp_d(Operand(ebx, ecx, times_4, 10000));
+  __ nop();
+
+  __ fild_s(Operand(ebx, ecx, times_4, 10000));
+  __ fistp_s(Operand(ebx, ecx, times_4, 10000));
+  __ fild_d(Operand(ebx, ecx, times_4, 10000));
+  __ fistp_d(Operand(ebx, ecx, times_4, 10000));
+  __ fnstsw_ax();
+  __ nop();
+  __ fadd(3);
+  __ fsub(3);
+  __ fmul(3);
+  __ fdiv(3);
+
+  __ faddp(3);
+  __ fsubp(3);
+  __ fmulp(3);
+  __ fdivp(3);
+  __ fcompp();
+  __ fwait();
+  __ nop();
+  {
+    CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
+    CpuFeatures::Scope fscope(CpuFeatures::SSE2);
+    __ cvttss2si(edx, Operand(ebx, ecx, times_4, 10000));
+    __ cvtsi2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ addsd(xmm1, xmm0);
+    __ mulsd(xmm1, xmm0);
+    __ subsd(xmm1, xmm0);
+    __ divsd(xmm1, xmm0);
+    __ movdbl(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ movdbl(Operand(ebx, ecx, times_4, 10000), xmm1);
+  }
+  __ ret(0);
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+  byte* begin = Code::cast(code)->instruction_start();
+  byte* end = begin + Code::cast(code)->instruction_size();
+  disasm::Disassembler::Disassemble(stdout, begin, end);
+#endif
+}
+
+#undef __
diff --git a/regexp2000/test/cctest/test-flags.cc b/regexp2000/test/cctest/test-flags.cc
new file mode 100644 (file)
index 0000000..a3aa4b2
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+// This test must be executed first!
+TEST(Default) {
+  CHECK(FLAG_testing_bool_flag);
+  CHECK_EQ(13, FLAG_testing_int_flag);
+  CHECK_EQ(2.5, FLAG_testing_float_flag);
+  CHECK_EQ(0, strcmp(FLAG_testing_string_flag, "Hello, world!"));
+}
+
+
+static void SetFlagsToDefault() {
+  FlagList::ResetAllFlags();
+  TestDefault();
+}
+
+
+TEST(Flags1) {
+  FlagList::PrintHelp();
+}
+
+
+TEST(Flags2) {
+  SetFlagsToDefault();
+  int argc = 7;
+  const char* argv[] = { "Test2", "-notesting-bool-flag", "notaflag",
+                         "--testing_int_flag=77", "-testing_float_flag=.25",
+                         "--testing_string_flag", "no way!" };
+  CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc,
+                                                const_cast<char **>(argv),
+                                                false));
+  CHECK_EQ(7, argc);
+  CHECK(!FLAG_testing_bool_flag);
+  CHECK_EQ(77, FLAG_testing_int_flag);
+  CHECK_EQ(.25, FLAG_testing_float_flag);
+  CHECK_EQ(0, strcmp(FLAG_testing_string_flag, "no way!"));
+}
+
+
+TEST(Flags2b) {
+  SetFlagsToDefault();
+  const char* str =
+      " -notesting-bool-flag notaflag   --testing_int_flag=77 "
+      "-testing_float_flag=.25  "
+      "--testing_string_flag   no_way!  ";
+  CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+  CHECK(!FLAG_testing_bool_flag);
+  CHECK_EQ(77, FLAG_testing_int_flag);
+  CHECK_EQ(.25, FLAG_testing_float_flag);
+  CHECK_EQ(0, strcmp(FLAG_testing_string_flag, "no_way!"));
+}
+
+
+TEST(Flags3) {
+  SetFlagsToDefault();
+  int argc = 8;
+  const char* argv[] =
+      { "Test3", "--testing_bool_flag", "notaflag",
+        "--testing_int_flag", "-666",
+        "--testing_float_flag", "-12E10", "-testing-string-flag=foo-bar" };
+  CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc,
+                                                const_cast<char **>(argv),
+                                                true));
+  CHECK_EQ(2, argc);
+  CHECK(FLAG_testing_bool_flag);
+  CHECK_EQ(-666, FLAG_testing_int_flag);
+  CHECK_EQ(-12E10, FLAG_testing_float_flag);
+  CHECK_EQ(0, strcmp(FLAG_testing_string_flag, "foo-bar"));
+}
+
+
+TEST(Flags3b) {
+  SetFlagsToDefault();
+  const char* str =
+      "--testing_bool_flag notaflag --testing_int_flag -666 "
+      "--testing_float_flag -12E10 "
+      "-testing-string-flag=foo-bar";
+  CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+  CHECK(FLAG_testing_bool_flag);
+  CHECK_EQ(-666, FLAG_testing_int_flag);
+  CHECK_EQ(-12E10, FLAG_testing_float_flag);
+  CHECK_EQ(0, strcmp(FLAG_testing_string_flag, "foo-bar"));
+}
+
+
+TEST(Flags4) {
+  SetFlagsToDefault();
+  int argc = 3;
+  const char* argv[] = { "Test4", "--testing_bool_flag", "--foo" };
+  CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc,
+                                                const_cast<char **>(argv),
+                                                true));
+  CHECK_EQ(2, argc);
+}
+
+
+TEST(Flags4b) {
+  SetFlagsToDefault();
+  const char* str = "--testing_bool_flag --foo";
+  CHECK_EQ(2, FlagList::SetFlagsFromString(str, strlen(str)));
+}
+
+
+TEST(Flags5) {
+  SetFlagsToDefault();
+  int argc = 2;
+  const char* argv[] = { "Test5", "--testing_int_flag=\"foobar\"" };
+  CHECK_EQ(1, FlagList::SetFlagsFromCommandLine(&argc,
+                                                const_cast<char **>(argv),
+                                                true));
+  CHECK_EQ(2, argc);
+}
+
+
+TEST(Flags5b) {
+  SetFlagsToDefault();
+  const char* str = "                     --testing_int_flag=\"foobar\"";
+  CHECK_EQ(1, FlagList::SetFlagsFromString(str, strlen(str)));
+}
+
+
+TEST(Flags6) {
+  SetFlagsToDefault();
+  int argc = 4;
+  const char* argv[] = { "Test5", "--testing-int-flag", "0",
+                         "--testing_float_flag" };
+  CHECK_EQ(3, FlagList::SetFlagsFromCommandLine(&argc,
+                                                const_cast<char **>(argv),
+                                                true));
+  CHECK_EQ(4, argc);
+}
+
+
+TEST(Flags6b) {
+  SetFlagsToDefault();
+  const char* str = "       --testing-int-flag 0      --testing_float_flag    ";
+  CHECK_EQ(3, FlagList::SetFlagsFromString(str, strlen(str)));
+}
diff --git a/regexp2000/test/cctest/test-hashmap.cc b/regexp2000/test/cctest/test-hashmap.cc
new file mode 100644 (file)
index 0000000..4918d5d
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+#include "hashmap.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static bool DefaultMatchFun(void* a, void* b) {
+  return a == b;
+}
+
+
+class IntSet {
+ public:
+  IntSet() : map_(DefaultMatchFun)  {}
+
+  void Insert(int x) {
+    ASSERT(x != 0);  // 0 corresponds to (void*)NULL - illegal key value
+    HashMap::Entry* p = map_.Lookup(reinterpret_cast<void*>(x), Hash(x), true);
+    CHECK(p != NULL);  // insert is set!
+    CHECK_EQ(reinterpret_cast<void*>(x), p->key);
+    // we don't care about p->value
+  }
+
+  bool Present(int x) {
+    HashMap::Entry* p = map_.Lookup(reinterpret_cast<void*>(x), Hash(x), false);
+    if (p != NULL) {
+      CHECK_EQ(reinterpret_cast<void*>(x), p->key);
+    }
+    return p != NULL;
+  }
+
+  void Clear() {
+    map_.Clear();
+  }
+
+  uint32_t occupancy() const {
+    uint32_t count = 0;
+    for (HashMap::Entry* p = map_.Start(); p != NULL; p = map_.Next(p)) {
+      count++;
+    }
+    CHECK_EQ(map_.occupancy(), static_cast<double>(count));
+    return count;
+  }
+
+ private:
+  HashMap map_;
+  static uint32_t Hash(uint32_t key)  { return key * 23; }
+};
+
+
+TEST(Set) {
+  IntSet set;
+  CHECK_EQ(0, set.occupancy());
+
+  set.Insert(1);
+  set.Insert(2);
+  set.Insert(3);
+  CHECK_EQ(3, set.occupancy());
+
+  set.Insert(2);
+  set.Insert(3);
+  CHECK_EQ(3, set.occupancy());
+
+  CHECK(set.Present(1));
+  CHECK(set.Present(2));
+  CHECK(set.Present(3));
+  CHECK(!set.Present(4));
+  CHECK_EQ(3, set.occupancy());
+
+  set.Clear();
+  CHECK_EQ(0, set.occupancy());
+
+  // Insert a long series of values.
+  const int start = 453;
+  const int factor = 13;
+  const int offset = 7;
+  const uint32_t n = 1000;
+
+  int x = start;
+  for (uint32_t i = 0; i < n; i++) {
+    CHECK_EQ(i, static_cast<double>(set.occupancy()));
+    set.Insert(x);
+    x = x*factor + offset;
+  }
+
+  // Verify the same sequence of values.
+  x = start;
+  for (uint32_t i = 0; i < n; i++) {
+    CHECK(set.Present(x));
+    x = x*factor + offset;
+  }
+
+  CHECK_EQ(n, static_cast<double>(set.occupancy()));
+}
diff --git a/regexp2000/test/cctest/test-heap.cc b/regexp2000/test/cctest/test-heap.cc
new file mode 100644 (file)
index 0000000..0a4f90f
--- /dev/null
@@ -0,0 +1,779 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "execution.h"
+#include "factory.h"
+#include "macro-assembler.h"
+#include "global-handles.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static v8::Persistent<v8::Context> env;
+
+static void InitializeVM() {
+  if (env.IsEmpty()) env = v8::Context::New();
+  v8::HandleScope scope;
+  env->Enter();
+}
+
+
+static void CheckMap(Map* map, int type, int instance_size) {
+  CHECK(map->IsHeapObject());
+#ifdef DEBUG
+  CHECK(Heap::Contains(map));
+#endif
+  CHECK_EQ(Heap::meta_map(), map->map());
+  CHECK_EQ(type, map->instance_type());
+  CHECK_EQ(instance_size, map->instance_size());
+}
+
+
+TEST(HeapMaps) {
+  InitializeVM();
+  CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
+  CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
+  CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, Array::kHeaderSize);
+  CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
+           SeqTwoByteString::kHeaderSize);
+}
+
+
+static void CheckOddball(Object* obj, const char* string) {
+  CHECK(obj->IsOddball());
+  bool exc;
+  Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
+  CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
+}
+
+
+static void CheckSmi(int value, const char* string) {
+  bool exc;
+  Object* print_string =
+      *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
+  CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
+}
+
+
+static void CheckNumber(double value, const char* string) {
+  Object* obj = Heap::NumberFromDouble(value);
+  CHECK(obj->IsNumber());
+  bool exc;
+  Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
+  CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
+}
+
+
+static void CheckFindCodeObject() {
+  // Test FindCodeObject
+#define __ assm.
+
+  Assembler assm(NULL, 0);
+
+  __ nop();  // supported on all architectures
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(code->IsCode());
+
+  HeapObject* obj = HeapObject::cast(code);
+  Address obj_addr = obj->address();
+
+  for (int i = 0; i < obj->Size(); i += kPointerSize) {
+    Object* found = Heap::FindCodeObject(obj_addr + i);
+    CHECK_EQ(code, found);
+  }
+
+  Object* copy = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
+  CHECK(copy->IsCode());
+  HeapObject* obj_copy = HeapObject::cast(copy);
+  Object* not_right = Heap::FindCodeObject(obj_copy->address() +
+                                           obj_copy->Size() / 2);
+  CHECK(not_right != code);
+}
+
+
+TEST(HeapObjects) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  Object* value = Heap::NumberFromDouble(1.000123);
+  CHECK(value->IsHeapNumber());
+  CHECK(value->IsNumber());
+  CHECK_EQ(1.000123, value->Number());
+
+  value = Heap::NumberFromDouble(1.0);
+  CHECK(value->IsSmi());
+  CHECK(value->IsNumber());
+  CHECK_EQ(1.0, value->Number());
+
+  value = Heap::NumberFromInt32(1024);
+  CHECK(value->IsSmi());
+  CHECK(value->IsNumber());
+  CHECK_EQ(1024.0, value->Number());
+
+  value = Heap::NumberFromInt32(Smi::kMinValue);
+  CHECK(value->IsSmi());
+  CHECK(value->IsNumber());
+  CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
+
+  value = Heap::NumberFromInt32(Smi::kMaxValue);
+  CHECK(value->IsSmi());
+  CHECK(value->IsNumber());
+  CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
+
+  value = Heap::NumberFromInt32(Smi::kMinValue - 1);
+  CHECK(value->IsHeapNumber());
+  CHECK(value->IsNumber());
+  CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
+
+  value = Heap::NumberFromInt32(Smi::kMaxValue + 1);
+  CHECK(value->IsHeapNumber());
+  CHECK(value->IsNumber());
+  CHECK_EQ(static_cast<double>(Smi::kMaxValue + 1), value->Number());
+
+  // nan oddball checks
+  CHECK(Heap::nan_value()->IsNumber());
+  CHECK(isnan(Heap::nan_value()->Number()));
+
+  Object* str = Heap::AllocateStringFromAscii(CStrVector("fisk hest "));
+  if (!str->IsFailure()) {
+    String* s =  String::cast(str);
+    CHECK(s->IsString());
+    CHECK_EQ(10, s->length());
+  } else {
+    CHECK(false);
+  }
+
+  String* object_symbol = String::cast(Heap::Object_symbol());
+  CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
+
+  // Check ToString for oddballs
+  CheckOddball(Heap::true_value(), "true");
+  CheckOddball(Heap::false_value(), "false");
+  CheckOddball(Heap::null_value(), "null");
+  CheckOddball(Heap::undefined_value(), "undefined");
+
+  // Check ToString for Smis
+  CheckSmi(0, "0");
+  CheckSmi(42, "42");
+  CheckSmi(-42, "-42");
+
+  // Check ToString for Numbers
+  CheckNumber(1.1, "1.1");
+
+  CheckFindCodeObject();
+}
+
+
+TEST(Tagging) {
+  InitializeVM();
+  CHECK(Smi::FromInt(42)->IsSmi());
+  CHECK(Failure::RetryAfterGC(12, NEW_SPACE)->IsFailure());
+  CHECK_EQ(12, Failure::RetryAfterGC(12, NEW_SPACE)->requested());
+  CHECK_EQ(NEW_SPACE, Failure::RetryAfterGC(12, NEW_SPACE)->allocation_space());
+  CHECK_EQ(OLD_POINTER_SPACE,
+           Failure::RetryAfterGC(12, OLD_POINTER_SPACE)->allocation_space());
+  CHECK(Failure::Exception()->IsFailure());
+  CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
+  CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
+}
+
+
+TEST(GarbageCollection) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  // check GC when heap is empty
+  int free_bytes = Heap::MaxHeapObjectSize();
+  CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
+
+  // allocate a function and keep it in global object's property
+  String* func_name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
+  SharedFunctionInfo* function_share =
+    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name));
+  JSFunction* function =
+      JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
+                                              function_share,
+                                              Heap::undefined_value()));
+  Map* initial_map =
+      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
+  function->set_initial_map(initial_map);
+  Top::context()->global()->SetProperty(func_name, function, NONE);
+
+  // allocate an object, but it is unrooted
+  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
+  String* prop_namex = String::cast(Heap::LookupAsciiSymbol("theSlotx"));
+  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
+  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
+  obj->SetProperty(prop_namex, Smi::FromInt(24), NONE);
+
+  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
+  CHECK_EQ(Smi::FromInt(24), obj->GetProperty(prop_namex));
+
+  CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
+
+  // function should be alive, func_name might be invalid after GC
+  func_name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
+  CHECK(Top::context()->global()->HasLocalProperty(func_name));
+  // check function is retained
+  Object* func_value = Top::context()->global()->GetProperty(func_name);
+  CHECK(func_value->IsJSFunction());
+  // old function pointer may not be valid
+  function = JSFunction::cast(func_value);
+
+  // allocate another object, make it reachable from global
+  obj = JSObject::cast(Heap::AllocateJSObject(function));
+  String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
+  Top::context()->global()->SetProperty(obj_name, obj, NONE);
+  // set property
+  prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
+  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
+
+  // after gc, it should survive
+  CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
+
+  obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
+  CHECK(Top::context()->global()->HasLocalProperty(obj_name));
+  CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject());
+  obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name));
+  prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
+  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
+}
+
+
+static void VerifyStringAllocation(const char* string) {
+  String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
+  CHECK_EQ(static_cast<int>(strlen(string)), s->length());
+  for (int index = 0; index < s->length(); index++) {
+    CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));  }
+}
+
+
+TEST(String) {
+  InitializeVM();
+
+  VerifyStringAllocation("a");
+  VerifyStringAllocation("ab");
+  VerifyStringAllocation("abc");
+  VerifyStringAllocation("abcd");
+  VerifyStringAllocation("fiskerdrengen er paa havet");
+}
+
+
+TEST(LocalHandles) {
+  InitializeVM();
+
+  v8::HandleScope scope;
+  const char* name = "Kasper the spunky";
+  Handle<String> string = Factory::NewStringFromAscii(CStrVector(name));
+  CHECK_EQ(static_cast<int>(strlen(name)), string->length());
+}
+
+
+TEST(GlobalHandles) {
+  InitializeVM();
+
+  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
+  Object* u = Heap::AllocateHeapNumber(1.12344);
+
+  Handle<Object> h1 = GlobalHandles::Create(i);
+  Handle<Object> h2 = GlobalHandles::Create(u);
+  Handle<Object> h3 = GlobalHandles::Create(i);
+  Handle<Object> h4 = GlobalHandles::Create(u);
+
+  // after gc, it should survive
+  CHECK(Heap::CollectGarbage(0, NEW_SPACE));
+
+  CHECK((*h1)->IsString());
+  CHECK((*h2)->IsHeapNumber());
+  CHECK((*h3)->IsString());
+  CHECK((*h4)->IsHeapNumber());
+
+  CHECK_EQ(*h3, *h1);
+  GlobalHandles::Destroy(h1.location());
+  GlobalHandles::Destroy(h3.location());
+
+  CHECK_EQ(*h4, *h2);
+  GlobalHandles::Destroy(h2.location());
+  GlobalHandles::Destroy(h4.location());
+}
+
+
+static bool WeakPointerCleared = false;
+
+static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
+                                         void* id) {
+  USE(handle);
+  if (1234 == reinterpret_cast<int>(id)) WeakPointerCleared = true;
+}
+
+
+TEST(WeakGlobalHandlesScavenge) {
+  InitializeVM();
+
+  WeakPointerCleared = false;
+
+  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
+  Object* u = Heap::AllocateHeapNumber(1.12344);
+
+  Handle<Object> h1 = GlobalHandles::Create(i);
+  Handle<Object> h2 = GlobalHandles::Create(u);
+
+  GlobalHandles::MakeWeak(h2.location(),
+                          reinterpret_cast<void*>(1234),
+                          &TestWeakGlobalHandleCallback);
+
+  // Scavenge treats weak pointers as normal roots.
+  Heap::PerformScavenge();
+
+  CHECK((*h1)->IsString());
+  CHECK((*h2)->IsHeapNumber());
+
+  CHECK(!WeakPointerCleared);
+  CHECK(!GlobalHandles::IsNearDeath(h2.location()));
+  CHECK(!GlobalHandles::IsNearDeath(h1.location()));
+
+  GlobalHandles::Destroy(h1.location());
+  GlobalHandles::Destroy(h2.location());
+}
+
+
+TEST(WeakGlobalHandlesMark) {
+  InitializeVM();
+
+  WeakPointerCleared = false;
+
+  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
+  Object* u = Heap::AllocateHeapNumber(1.12344);
+
+  Handle<Object> h1 = GlobalHandles::Create(i);
+  Handle<Object> h2 = GlobalHandles::Create(u);
+
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+  CHECK(Heap::CollectGarbage(0, NEW_SPACE));
+  // Make sure the object is promoted.
+
+  GlobalHandles::MakeWeak(h2.location(),
+                          reinterpret_cast<void*>(1234),
+                          &TestWeakGlobalHandleCallback);
+  CHECK(!GlobalHandles::IsNearDeath(h1.location()));
+  CHECK(!GlobalHandles::IsNearDeath(h2.location()));
+
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  CHECK((*h1)->IsString());
+
+  CHECK(WeakPointerCleared);
+  CHECK(!GlobalHandles::IsNearDeath(h1.location()));
+  CHECK(GlobalHandles::IsNearDeath(h2.location()));
+
+  GlobalHandles::Destroy(h1.location());
+  GlobalHandles::Destroy(h2.location());
+}
+
+static void TestDeleteWeakGlobalHandleCallback(
+    v8::Persistent<v8::Value> handle,
+    void* id) {
+  if (1234 == reinterpret_cast<int>(id)) WeakPointerCleared = true;
+  handle.Dispose();
+}
+
+TEST(DeleteWeakGlobalHandle) {
+  InitializeVM();
+
+  WeakPointerCleared = false;
+
+  Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
+  Handle<Object> h = GlobalHandles::Create(i);
+
+  GlobalHandles::MakeWeak(h.location(),
+                          reinterpret_cast<void*>(1234),
+                          &TestDeleteWeakGlobalHandleCallback);
+
+  // Scanvenge does not recognize weak reference.
+  Heap::PerformScavenge();
+
+  CHECK(!WeakPointerCleared);
+
+  // Mark-compact treats weak reference properly.
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  CHECK(WeakPointerCleared);
+}
+
+static const char* not_so_random_string_table[] = {
+  "abstract",
+  "boolean",
+  "break",
+  "byte",
+  "case",
+  "catch",
+  "char",
+  "class",
+  "const",
+  "continue",
+  "debugger",
+  "default",
+  "delete",
+  "do",
+  "double",
+  "else",
+  "enum",
+  "export",
+  "extends",
+  "false",
+  "final",
+  "finally",
+  "float",
+  "for",
+  "function",
+  "goto",
+  "if",
+  "implements",
+  "import",
+  "in",
+  "instanceof",
+  "int",
+  "interface",
+  "long",
+  "native",
+  "new",
+  "null",
+  "package",
+  "private",
+  "protected",
+  "public",
+  "return",
+  "short",
+  "static",
+  "super",
+  "switch",
+  "synchronized",
+  "this",
+  "throw",
+  "throws",
+  "transient",
+  "true",
+  "try",
+  "typeof",
+  "var",
+  "void",
+  "volatile",
+  "while",
+  "with",
+  0
+};
+
+
+static void CheckSymbols(const char** strings) {
+  for (const char* string = *strings; *strings != 0; string = *strings++) {
+    Object* a = Heap::LookupAsciiSymbol(string);
+    CHECK(a->IsSymbol());
+    Object* b = Heap::LookupAsciiSymbol(string);
+    CHECK_EQ(b, a);
+    CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
+  }
+}
+
+
+TEST(SymbolTable) {
+  InitializeVM();
+
+  CheckSymbols(not_so_random_string_table);
+  CheckSymbols(not_so_random_string_table);
+}
+
+
+TEST(FunctionAllocation) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  String* name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
+  SharedFunctionInfo* function_share =
+    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
+  JSFunction* function =
+    JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
+                                            function_share,
+                                            Heap::undefined_value()));
+  Map* initial_map =
+      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
+  function->set_initial_map(initial_map);
+
+  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
+  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
+  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
+  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
+  // Check that we can add properties to function objects.
+  function->SetProperty(prop_name, Smi::FromInt(24), NONE);
+  CHECK_EQ(Smi::FromInt(24), function->GetProperty(prop_name));
+}
+
+
+TEST(ObjectProperties) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  JSFunction* constructor =
+      JSFunction::cast(
+          Top::context()->global()->GetProperty(String::cast(
+                                                    Heap::Object_symbol())));
+  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
+  String* first = String::cast(Heap::LookupAsciiSymbol("first"));
+  String* second = String::cast(Heap::LookupAsciiSymbol("second"));
+
+  // check for empty
+  CHECK(!obj->HasLocalProperty(first));
+
+  // add first
+  obj->SetProperty(first, Smi::FromInt(1), NONE);
+  CHECK(obj->HasLocalProperty(first));
+
+  // delete first
+  CHECK(obj->DeleteProperty(first));
+  CHECK(!obj->HasLocalProperty(first));
+
+  // add first and then second
+  obj->SetProperty(first, Smi::FromInt(1), NONE);
+  obj->SetProperty(second, Smi::FromInt(2), NONE);
+  CHECK(obj->HasLocalProperty(first));
+  CHECK(obj->HasLocalProperty(second));
+
+  // delete first and then second
+  CHECK(obj->DeleteProperty(first));
+  CHECK(obj->HasLocalProperty(second));
+  CHECK(obj->DeleteProperty(second));
+  CHECK(!obj->HasLocalProperty(first));
+  CHECK(!obj->HasLocalProperty(second));
+
+  // add first and then second
+  obj->SetProperty(first, Smi::FromInt(1), NONE);
+  obj->SetProperty(second, Smi::FromInt(2), NONE);
+  CHECK(obj->HasLocalProperty(first));
+  CHECK(obj->HasLocalProperty(second));
+
+  // delete second and then first
+  CHECK(obj->DeleteProperty(second));
+  CHECK(obj->HasLocalProperty(first));
+  CHECK(obj->DeleteProperty(first));
+  CHECK(!obj->HasLocalProperty(first));
+  CHECK(!obj->HasLocalProperty(second));
+
+  // check string and symbol match
+  static const char* string1 = "fisk";
+  String* s1 =
+      String::cast(Heap::AllocateStringFromAscii(CStrVector(string1)));
+  obj->SetProperty(s1, Smi::FromInt(1), NONE);
+  CHECK(obj->HasLocalProperty(String::cast(Heap::LookupAsciiSymbol(string1))));
+
+  // check symbol and string match
+  static const char* string2 = "fugl";
+  String* s2 = String::cast(Heap::LookupAsciiSymbol(string2));
+  obj->SetProperty(s2, Smi::FromInt(1), NONE);
+  CHECK(obj->HasLocalProperty(
+            String::cast(Heap::AllocateStringFromAscii(CStrVector(string2)))));
+}
+
+
+TEST(JSObjectMaps) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  String* name  = String::cast(Heap::LookupAsciiSymbol("theFunction"));
+  SharedFunctionInfo* function_share =
+    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
+  JSFunction* function =
+    JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
+                                            function_share,
+                                            Heap::undefined_value()));
+  Map* initial_map =
+      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
+  function->set_initial_map(initial_map);
+  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
+  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
+
+  // Set a propery
+  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
+  CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
+
+  // Check the map has changed
+  CHECK(initial_map != obj->map());
+}
+
+
+TEST(JSArray) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  String* name = String::cast(Heap::LookupAsciiSymbol("Array"));
+  JSFunction* function =
+      JSFunction::cast(Top::context()->global()->GetProperty(name));
+
+  // Allocate the object.
+  JSArray* array = JSArray::cast(Heap::AllocateJSObject(function));
+  array->Initialize(0);
+
+  // Set array length to 0.
+  array->SetElementsLength(Smi::FromInt(0));
+  CHECK_EQ(Smi::FromInt(0), array->length());
+  CHECK(array->HasFastElements());  // Must be in fast mode.
+
+  // array[length] = name.
+  array->SetElement(0, name);
+  CHECK_EQ(Smi::FromInt(1), array->length());
+  CHECK_EQ(array->GetElement(0), name);
+
+  // Set array length with larger than smi value.
+  Object* length = Heap::NumberFromInt32(Smi::kMaxValue + 1);
+  array->SetElementsLength(length);
+
+  uint32_t int_length = 0;
+  CHECK(Array::IndexFromObject(length, &int_length));
+  CHECK_EQ(length, array->length());
+  CHECK(!array->HasFastElements());  // Must be in slow mode.
+
+  // array[length] = name.
+  array->SetElement(int_length, name);
+  uint32_t new_int_length = 0;
+  CHECK(Array::IndexFromObject(array->length(), &new_int_length));
+  CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
+  CHECK_EQ(array->GetElement(int_length), name);
+  CHECK_EQ(array->GetElement(0), name);
+}
+
+
+TEST(JSObjectCopy) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  String* name = String::cast(Heap::Object_symbol());
+  JSFunction* constructor =
+      JSFunction::cast(Top::context()->global()->GetProperty(name));
+  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
+  String* first = String::cast(Heap::LookupAsciiSymbol("first"));
+  String* second = String::cast(Heap::LookupAsciiSymbol("second"));
+
+  obj->SetProperty(first, Smi::FromInt(1), NONE);
+  obj->SetProperty(second, Smi::FromInt(2), NONE);
+
+  obj->SetElement(0, first);
+  obj->SetElement(1, second);
+
+  // Make the clone.
+  JSObject* clone = JSObject::cast(Heap::CopyJSObject(obj));
+  CHECK(clone != obj);
+
+  CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
+  CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
+
+  CHECK_EQ(obj->GetProperty(first), clone->GetProperty(first));
+  CHECK_EQ(obj->GetProperty(second), clone->GetProperty(second));
+
+  // Flip the values.
+  clone->SetProperty(first, Smi::FromInt(2), NONE);
+  clone->SetProperty(second, Smi::FromInt(1), NONE);
+
+  clone->SetElement(0, second);
+  clone->SetElement(1, first);
+
+  CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
+  CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
+
+  CHECK_EQ(obj->GetProperty(second), clone->GetProperty(first));
+  CHECK_EQ(obj->GetProperty(first), clone->GetProperty(second));
+}
+
+
+TEST(StringAllocation) {
+  InitializeVM();
+
+
+  const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
+  for (int length = 0; length < 100; length++) {
+    v8::HandleScope scope;
+    char* non_ascii = NewArray<char>(3 * length + 1);
+    char* ascii = NewArray<char>(length + 1);
+    non_ascii[3 * length] = 0;
+    ascii[length] = 0;
+    for (int i = 0; i < length; i++) {
+      ascii[i] = 'a';
+      non_ascii[3 * i] = chars[0];
+      non_ascii[3 * i + 1] = chars[1];
+      non_ascii[3 * i + 2] = chars[2];
+    }
+    Handle<String> non_ascii_sym =
+        Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length));
+    CHECK_EQ(length, non_ascii_sym->length());
+    Handle<String> ascii_sym =
+        Factory::LookupSymbol(Vector<const char>(ascii, length));
+    CHECK_EQ(length, ascii_sym->length());
+    Handle<String> non_ascii_str =
+        Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
+    non_ascii_str->Hash();
+    CHECK_EQ(length, non_ascii_str->length());
+    Handle<String> ascii_str =
+        Factory::NewStringFromUtf8(Vector<const char>(ascii, length));
+    ascii_str->Hash();
+    CHECK_EQ(length, ascii_str->length());
+    DeleteArray(non_ascii);
+    DeleteArray(ascii);
+  }
+}
+
+
+static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
+  // Count the number of objects found in the heap.
+  int found_count = 0;
+  HeapIterator iterator;
+  while (iterator.has_next()) {
+    HeapObject* obj = iterator.next();
+    CHECK(obj != NULL);
+    for (int i = 0; i < size; i++) {
+      if (*objs[i] == obj) {
+        found_count++;
+      }
+    }
+  }
+  CHECK(!iterator.has_next());
+  return found_count;
+}
+
+
+TEST(Iteration) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  // Array of objects to scan haep for.
+  const int objs_count = 6;
+  Handle<Object> objs[objs_count];
+  int next_objs_index = 0;
+
+  // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
+  objs[next_objs_index++] = Factory::NewJSArray(10);
+  objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
+
+  // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
+  objs[next_objs_index++] =
+      Factory::NewStringFromAscii(CStrVector("abcdefghij"));
+  objs[next_objs_index++] =
+      Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
+
+  // Allocate a large string (for large object space).
+  int large_size = Heap::MaxHeapObjectSize() + 1;
+  char* str = new char[large_size];
+  for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
+  str[large_size - 1] = '\0';
+  objs[next_objs_index++] =
+      Factory::NewStringFromAscii(CStrVector(str), TENURED);
+  delete[] str;
+
+  // Add a Map object to look for.
+  objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
+
+  CHECK_EQ(objs_count, next_objs_index);
+  CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
+}
diff --git a/regexp2000/test/cctest/test-lock.cc b/regexp2000/test/cctest/test-lock.cc
new file mode 100644 (file)
index 0000000..37e3853
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+//
+// Tests of the TokenLock class from lock.h
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+
+
+using namespace ::v8::internal;
+
+
+// Simple test of locking logic
+TEST(Simple) {
+  Mutex* mutex = OS::CreateMutex();
+  CHECK_EQ(0, mutex->Lock());  // acquire the lock with the right token
+  CHECK_EQ(0, mutex->Unlock());  // can unlock with the right token
+  delete mutex;
+}
+
+
+TEST(MultiLock) {
+  Mutex* mutex = OS::CreateMutex();
+  CHECK_EQ(0, mutex->Lock());
+  CHECK_EQ(0, mutex->Unlock());
+  delete mutex;
+}
+
+
+TEST(ShallowLock) {
+  Mutex* mutex = OS::CreateMutex();
+  CHECK_EQ(0, mutex->Lock());
+  CHECK_EQ(0, mutex->Unlock());
+  CHECK_EQ(0, mutex->Lock());
+  CHECK_EQ(0, mutex->Unlock());
+  delete mutex;
+}
diff --git a/regexp2000/test/cctest/test-mark-compact.cc b/regexp2000/test/cctest/test-mark-compact.cc
new file mode 100644 (file)
index 0000000..d468c24
--- /dev/null
@@ -0,0 +1,310 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "global-handles.h"
+#include "snapshot.h"
+#include "top.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static v8::Persistent<v8::Context> env;
+
+static void InitializeVM() {
+  if (env.IsEmpty()) env = v8::Context::New();
+  v8::HandleScope scope;
+  env->Enter();
+}
+
+
+TEST(MarkingStack) {
+  int mem_size = 20 * kPointerSize;
+  byte* mem = NewArray<byte>(20*kPointerSize);
+  Address low = reinterpret_cast<Address>(mem);
+  Address high = low + mem_size;
+  MarkingStack s;
+  s.Initialize(low, high);
+
+  Address address = NULL;
+  while (!s.is_full()) {
+    s.Push(HeapObject::FromAddress(address));
+    address += kPointerSize;
+  }
+
+  while (!s.is_empty()) {
+    Address value = s.Pop()->address();
+    address -= kPointerSize;
+    CHECK_EQ(address, value);
+  }
+
+  CHECK_EQ(NULL, address);
+  DeleteArray(mem);
+}
+
+
+TEST(Promotion) {
+  // Test the situation that some objects in new space are promoted to the
+  // old space
+  if (Snapshot::IsEnabled()) return;
+
+  // Ensure that we get a compacting collection so that objects are promoted
+  // from new space.
+  FLAG_gc_global = true;
+  FLAG_always_compact = true;
+  Heap::ConfigureHeap(2*256*KB, 4*MB);
+
+  InitializeVM();
+
+  v8::HandleScope sc;
+
+  // Allocate a fixed array in the new space.
+  int array_size =
+      (Heap::MaxHeapObjectSize() - Array::kHeaderSize) / (kPointerSize * 4);
+  Object* obj = Heap::AllocateFixedArray(array_size);
+  CHECK(!obj->IsFailure());
+
+  Handle<FixedArray> array(FixedArray::cast(obj));
+
+  // Array should be in the new space.
+  CHECK(Heap::InSpace(*array, NEW_SPACE));
+
+  // Call the m-c collector, so array becomes an old object.
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  // Array now sits in the old space
+  CHECK(Heap::InSpace(*array, OLD_POINTER_SPACE));
+}
+
+
+TEST(NoPromotion) {
+  if (Snapshot::IsEnabled()) return;
+  Heap::ConfigureHeap(2*256*KB, 4*MB);
+
+  // Test the situation that some objects in new space are promoted to
+  // the old space
+  InitializeVM();
+
+  v8::HandleScope sc;
+
+  // Do a mark compact GC to shrink the heap.
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  // Allocate a big Fixed array in the new space.
+  int size = (Heap::MaxHeapObjectSize() - Array::kHeaderSize) / kPointerSize;
+  Object* obj = Heap::AllocateFixedArray(size);
+
+  Handle<FixedArray> array(FixedArray::cast(obj));
+
+  // Array still stays in the new space.
+  CHECK(Heap::InSpace(*array, NEW_SPACE));
+
+  // Allocate objects in the old space until out of memory.
+  FixedArray* host = *array;
+  while (true) {
+    Object* obj = Heap::AllocateFixedArray(100, TENURED);
+    if (obj->IsFailure()) break;
+
+    host->set(0, obj);
+    host = FixedArray::cast(obj);
+  }
+
+  // Call mark compact GC, and it should pass.
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  // array should not be promoted because the old space is full.
+  CHECK(Heap::InSpace(*array, NEW_SPACE));
+}
+
+
+TEST(MarkCompactCollector) {
+  InitializeVM();
+
+  v8::HandleScope sc;
+  // call mark-compact when heap is empty
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  // keep allocating garbage in new space until it fails
+  const int ARRAY_SIZE = 100;
+  Object* array;
+  do {
+    array = Heap::AllocateFixedArray(ARRAY_SIZE);
+  } while (!array->IsFailure());
+  CHECK(Heap::CollectGarbage(0, NEW_SPACE));
+
+  array = Heap::AllocateFixedArray(ARRAY_SIZE);
+  CHECK(!array->IsFailure());
+
+  // keep allocating maps until it fails
+  Object* mapp;
+  do {
+    mapp = Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+  } while (!mapp->IsFailure());
+  CHECK(Heap::CollectGarbage(0, MAP_SPACE));
+  mapp = Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+  CHECK(!mapp->IsFailure());
+
+  // allocate a garbage
+  String* func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
+  SharedFunctionInfo* function_share =
+    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name));
+  JSFunction* function =
+    JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
+                                            function_share,
+                                            Heap::undefined_value()));
+  Map* initial_map =
+      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
+  function->set_initial_map(initial_map);
+  Top::context()->global()->SetProperty(func_name, function, NONE);
+
+  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
+  CHECK(Top::context()->global()->HasLocalProperty(func_name));
+  Object* func_value = Top::context()->global()->GetProperty(func_name);
+  CHECK(func_value->IsJSFunction());
+  function = JSFunction::cast(func_value);
+
+  obj = JSObject::cast(Heap::AllocateJSObject(function));
+  String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
+  Top::context()->global()->SetProperty(obj_name, obj, NONE);
+  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
+  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
+
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
+  CHECK(Top::context()->global()->HasLocalProperty(obj_name));
+  CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject());
+  obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name));
+  prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
+  CHECK(obj->GetProperty(prop_name) == Smi::FromInt(23));
+}
+
+
+static int gc_starts = 0;
+static int gc_ends = 0;
+
+static void GCPrologueCallbackFunc() {
+  CHECK(gc_starts == gc_ends);
+  gc_starts++;
+}
+
+
+static void GCEpilogueCallbackFunc() {
+  CHECK(gc_starts == gc_ends + 1);
+  gc_ends++;
+}
+
+
+TEST(GCCallback) {
+  InitializeVM();
+
+  Heap::SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
+  Heap::SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
+
+  // Scavenge does not call GC callback functions.
+  Heap::PerformScavenge();
+
+  CHECK_EQ(0, gc_starts);
+  CHECK_EQ(gc_ends, gc_starts);
+
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+  CHECK_EQ(1, gc_starts);
+  CHECK_EQ(gc_ends, gc_starts);
+}
+
+
+static int NumberOfWeakCalls = 0;
+static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) {
+  NumberOfWeakCalls++;
+}
+
+TEST(ObjectGroups) {
+  InitializeVM();
+
+  NumberOfWeakCalls = 0;
+  v8::HandleScope handle_scope;
+
+  Handle<Object> g1s1 =
+    GlobalHandles::Create(Heap::AllocateFixedArray(1));
+  Handle<Object> g1s2 =
+    GlobalHandles::Create(Heap::AllocateFixedArray(1));
+  GlobalHandles::MakeWeak(g1s1.location(),
+                          reinterpret_cast<void*>(1234),
+                          &WeakPointerCallback);
+  GlobalHandles::MakeWeak(g1s2.location(),
+                          reinterpret_cast<void*>(1234),
+                          &WeakPointerCallback);
+
+  Handle<Object> g2s1 =
+    GlobalHandles::Create(Heap::AllocateFixedArray(1));
+  Handle<Object> g2s2 =
+    GlobalHandles::Create(Heap::AllocateFixedArray(1));
+  GlobalHandles::MakeWeak(g2s1.location(),
+                          reinterpret_cast<void*>(1234),
+                          &WeakPointerCallback);
+  GlobalHandles::MakeWeak(g2s2.location(),
+                          reinterpret_cast<void*>(1234),
+                          &WeakPointerCallback);
+
+  Handle<Object> root = GlobalHandles::Create(*g1s1);  // make a root.
+
+  // Connect group 1 and 2, make a cycle.
+  Handle<FixedArray>::cast(g1s2)->set(0, *g2s2);
+  Handle<FixedArray>::cast(g2s1)->set(0, *g1s1);
+
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(1), g1s1.location());
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(1), g1s2.location());
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(2), g2s1.location());
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(2), g2s2.location());
+  // Do a full GC
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  // All object should be alive.
+  CHECK_EQ(0, NumberOfWeakCalls);
+
+  // Weaken the root.
+  GlobalHandles::MakeWeak(root.location(),
+                          reinterpret_cast<void*>(1234),
+                          &WeakPointerCallback);
+
+  // Groups are deleted, rebuild groups.
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(1), g1s1.location());
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(1), g1s2.location());
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(2), g2s1.location());
+  GlobalHandles::AddToGroup(reinterpret_cast<void*>(2), g2s2.location());
+
+  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
+
+  // All objects should be gone. 5 global handles in total.
+  CHECK_EQ(5, NumberOfWeakCalls);
+}
diff --git a/regexp2000/test/cctest/test-platform-linux.cc b/regexp2000/test/cctest/test-platform-linux.cc
new file mode 100644 (file)
index 0000000..e1a00e1
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+//
+// Tests of the TokenLock class from lock.h
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>  // for usleep()
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+
+using namespace ::v8::internal;
+
+
+static void yield() {
+  usleep(1);
+}
+
+static const int kLockCounterLimit = 50;
+static int busy_lock_counter = 0;
+
+
+static void LoopIncrement(Mutex* mutex, int rem) {
+  while (true) {
+    int count = 0;
+    int last_count = -1;
+    do {
+      CHECK_EQ(0, mutex->Lock());
+      count = busy_lock_counter;
+      CHECK_EQ(0, mutex->Unlock());
+      yield();
+    } while (count % 2 == rem && count < kLockCounterLimit);
+    if (count >= kLockCounterLimit) break;
+    CHECK_EQ(0, mutex->Lock());
+    CHECK_EQ(count, busy_lock_counter);
+    CHECK(last_count == -1 || count == last_count + 1);
+    busy_lock_counter++;
+    last_count = count;
+    CHECK_EQ(0, mutex->Unlock());
+    yield();
+  }
+}
+
+
+static void* RunTestBusyLock(void* arg) {
+  LoopIncrement(static_cast<Mutex*>(arg), 0);
+  return 0;
+}
+
+
+// Runs two threads that repeatedly acquire the lock and conditionally
+// increment a variable.
+TEST(BusyLock) {
+  pthread_t other;
+  Mutex* mutex = OS::CreateMutex();
+  int thread_created = pthread_create(&other,
+                                      NULL,
+                                      &RunTestBusyLock,
+                                      mutex);
+  CHECK_EQ(0, thread_created);
+  LoopIncrement(mutex, 1);
+  pthread_join(other, NULL);
+  delete mutex;
+}
+
+
+TEST(VirtualMemory) {
+  VirtualMemory* vm = new VirtualMemory(1 * MB);
+  CHECK(vm->IsReserved());
+  void* block_addr = vm->address();
+  size_t block_size = 4 * KB;
+  CHECK(vm->Commit(block_addr, block_size, false));
+  // Check whether we can write to memory.
+  int* addr = static_cast<int*>(block_addr);
+  addr[KB-1] = 2;
+  CHECK(vm->Uncommit(block_addr, block_size));
+  delete vm;
+}
diff --git a/regexp2000/test/cctest/test-platform-macos.cc b/regexp2000/test/cctest/test-platform-macos.cc
new file mode 100644 (file)
index 0000000..d80fa54
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+//
+// Tests of the TokenLock class from lock.h
+
+#include <stdlib.h>
+
+#include "v8.h"
+#include "cctest.h"
+
+using namespace ::v8::internal;
diff --git a/regexp2000/test/cctest/test-platform-nullos.cc b/regexp2000/test/cctest/test-platform-nullos.cc
new file mode 100644 (file)
index 0000000..c0d6ae5
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+//
+// Tests of the TokenLock class from lock.h
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>  // for usleep()
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+
+using namespace ::v8::internal;
+
+
+static void yield() {
+  UNIMPLEMENTED();
+}
+
+static const int kLockCounterLimit = 50;
+static int busy_lock_counter = 0;
+
+
+static void LoopIncrement(Mutex* mutex, int rem) {
+  while (true) {
+    int count = 0;
+    int last_count = -1;
+    do {
+      CHECK_EQ(0, mutex->Lock());
+      count = busy_lock_counter;
+      CHECK_EQ(0, mutex->Unlock());
+      yield();
+    } while (count % 2 == rem && count < kLockCounterLimit);
+    if (count >= kLockCounterLimit) break;
+    CHECK_EQ(0, mutex->Lock());
+    CHECK_EQ(count, busy_lock_counter);
+    CHECK(last_count == -1 || count == last_count + 1);
+    busy_lock_counter++;
+    last_count = count;
+    CHECK_EQ(0, mutex->Unlock());
+    yield();
+  }
+}
+
+
+static void* RunTestBusyLock(void* arg) {
+  LoopIncrement(static_cast<Mutex*>(arg), 0);
+  return 0;
+}
+
+
+// Runs two threads that repeatedly acquire the lock and conditionally
+// increment a variable.
+TEST(BusyLock) {
+  pthread_t other;
+  Mutex* mutex = OS::CreateMutex();
+  int thread_created = pthread_create(&other,
+                                      NULL,
+                                      &RunTestBusyLock,
+                                      mutex);
+  CHECK_EQ(0, thread_created);
+  LoopIncrement(mutex, 1);
+  pthread_join(other, NULL);
+  delete mutex;
+}
+
+
+TEST(VirtualMemory) {
+  VirtualMemory* vm = new VirtualMemory(1 * MB);
+  CHECK(vm->IsReserved());
+  void* block_addr = vm->address();
+  size_t block_size = 4 * KB;
+  CHECK(vm->Commit(block_addr, block_size, false));
+  // Check whether we can write to memory.
+  int* addr = static_cast<int*>(block_addr);
+  addr[KB-1] = 2;
+  CHECK(vm->Uncommit(block_addr, block_size));
+  delete vm;
+}
diff --git a/regexp2000/test/cctest/test-platform-win32.cc b/regexp2000/test/cctest/test-platform-win32.cc
new file mode 100644 (file)
index 0000000..a5a6dd5
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+//
+// Tests of the TokenLock class from lock.h
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+
+using namespace ::v8::internal;
+
+
+TEST(VirtualMemory) {
+  VirtualMemory* vm = new VirtualMemory(1 * MB);
+  CHECK(vm->IsReserved());
+  void* block_addr = vm->address();
+  size_t block_size = 4 * KB;
+  CHECK(vm->Commit(block_addr, block_size, false));
+  // Check whether we can write to memory.
+  int* addr = static_cast<int*>(block_addr);
+  addr[KB-1] = 2;
+  CHECK(vm->Uncommit(block_addr, block_size));
+  delete vm;
+}
diff --git a/regexp2000/test/cctest/test-regexp.cc b/regexp2000/test/cctest/test-regexp.cc
new file mode 100644 (file)
index 0000000..0630510
--- /dev/null
@@ -0,0 +1,272 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "zone-inl.h"
+#include "parser.h"
+#include "ast.h"
+#include "jsregexp.h"
+
+
+using namespace v8::internal;
+
+
+class RegExpTestCase {
+ public:
+  RegExpTestCase()
+    : pattern_(NULL),
+      flags_(NULL),
+      input_(NULL),
+      compile_error_(NULL) { }
+  RegExpTestCase(const char* pattern,
+                 const char* flags,
+                 const char* input,
+                 const char* compile_error)
+    : pattern_(pattern),
+      flags_(flags),
+      input_(input),
+      compile_error_(compile_error) { }
+  const char* pattern() const { return pattern_; }
+  bool expect_error() const { return compile_error_ != NULL; }
+ private:
+  const char* pattern_;
+  const char* flags_;
+  const char* input_;
+  const char* compile_error_;
+};
+
+
+#ifdef USE_FUZZ_TEST_DATA
+#include "regexp-test-data.cc"
+#else
+static const int kCaseCount = 0;
+static const RegExpTestCase kCases[1] = { RegExpTestCase() };
+#endif
+
+
+static SmartPointer<char> Parse(const char* input) {
+  v8::HandleScope scope;
+  unibrow::Utf8InputBuffer<> buffer(input, strlen(input));
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  Handle<String> error;
+  RegExpTree* node = v8::internal::ParseRegExp(&buffer, &error);
+  CHECK(node != NULL);
+  CHECK(error.is_null());
+  SmartPointer<char> output = node->ToString();
+  return output;
+}
+
+
+#define CHECK_PARSE_EQ(input, expected) CHECK_EQ(expected, *Parse(input))
+
+
+TEST(Parser) {
+  V8::Initialize(NULL);
+  CHECK_PARSE_EQ("abc", "'abc'");
+  CHECK_PARSE_EQ("", "%");
+  CHECK_PARSE_EQ("abc|def", "(| 'abc' 'def')");
+  CHECK_PARSE_EQ("abc|def|ghi", "(| 'abc' 'def' 'ghi')");
+  CHECK_PARSE_EQ("\\w\\W\\s\\S\\d\\D", "(: [&w] [&W] [&s] [&S] [&d] [&D])");
+  CHECK_PARSE_EQ("^xxx$", "(: @^i 'xxx' @$i)");
+  CHECK_PARSE_EQ("ab\\b\\w\\bcd", "(: 'ab' @b [&w] @b 'cd')");
+  CHECK_PARSE_EQ("\\w|\\s|.", "(| [&w] [&s] [&.])");
+  CHECK_PARSE_EQ("a*", "(# 0 - g 'a')");
+  CHECK_PARSE_EQ("a*?", "(# 0 - n 'a')");
+  CHECK_PARSE_EQ("abc+", "(# 1 - g 'abc')");
+  CHECK_PARSE_EQ("abc+?", "(# 1 - n 'abc')");
+  CHECK_PARSE_EQ("xyz?", "(# 0 1 g 'xyz')");
+  CHECK_PARSE_EQ("xyz??", "(# 0 1 n 'xyz')");
+  CHECK_PARSE_EQ("xyz{0,1}", "(# 0 1 g 'xyz')");
+  CHECK_PARSE_EQ("xyz{0,1}?", "(# 0 1 n 'xyz')");
+  CHECK_PARSE_EQ("xyz{93}", "(# 93 93 g 'xyz')");
+  CHECK_PARSE_EQ("xyz{93}?", "(# 93 93 n 'xyz')");
+  CHECK_PARSE_EQ("xyz{1,32}", "(# 1 32 g 'xyz')");
+  CHECK_PARSE_EQ("xyz{1,32}?", "(# 1 32 n 'xyz')");
+  CHECK_PARSE_EQ("xyz{1,}", "(# 1 - g 'xyz')");
+  CHECK_PARSE_EQ("xyz{1,}?", "(# 1 - n 'xyz')");
+  CHECK_PARSE_EQ("a\\fb\\nc\\rd\\te\\vf", "'a\fb\nc\rd\te\vf'");
+  CHECK_PARSE_EQ("a\\nb\\bc", "(: 'a\nb' @b 'c')");
+  CHECK_PARSE_EQ("(?:foo)", "'foo'");
+  CHECK_PARSE_EQ("(?: foo )", "' foo '");
+  CHECK_PARSE_EQ("(foo|bar|baz)", "(^ (| 'foo' 'bar' 'baz'))");
+  CHECK_PARSE_EQ("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')");
+  CHECK_PARSE_EQ("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')");
+  CHECK_PARSE_EQ("foo(?!bar)baz", "(: 'foo' (-> - 'bar') 'baz')");
+  CHECK_PARSE_EQ("()", "(^ %)");
+  CHECK_PARSE_EQ("(?=)", "(-> + %)");
+  CHECK_PARSE_EQ("[]", "%");
+  CHECK_PARSE_EQ("[x]", "[x]");
+  CHECK_PARSE_EQ("[xyz]", "[x y z]");
+  CHECK_PARSE_EQ("[a-zA-Z0-9]", "[a-z A-Z 0-9]");
+  CHECK_PARSE_EQ("[-123]", "[- 1 2 3]");
+  CHECK_PARSE_EQ("[^123]", "^[1 2 3]");
+  CHECK_PARSE_EQ("]", "']'");
+  CHECK_PARSE_EQ("}", "'}'");
+  CHECK_PARSE_EQ("[a-b-c]", "[a-b - c]");
+  CHECK_PARSE_EQ("[\\w]", "[&w]");
+  CHECK_PARSE_EQ("[x\\wz]", "[x &w z]");
+  CHECK_PARSE_EQ("[\\w-z]", "[&w - z]");
+  CHECK_PARSE_EQ("[\\w-\\d]", "[&w - &d]");
+  CHECK_PARSE_EQ("\\cj\\cJ\\ci\\cI\\ck\\cK", "'\n\n\t\t\v\v'");
+  CHECK_PARSE_EQ("\\c!", "'c!'");
+  CHECK_PARSE_EQ("\\c_", "'c_'");
+  CHECK_PARSE_EQ("\\c~", "'c~'");
+  CHECK_PARSE_EQ("[a\\]c]", "[a ] c]");
+  CHECK_PARSE_EQ("\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ", "'[]{}()%^# '");
+  CHECK_PARSE_EQ("[\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ]", "[[ ] { } ( ) % ^ #  ]");
+  CHECK_PARSE_EQ("\\0", "'\0'");
+  CHECK_PARSE_EQ("\\8", "'8'");
+  CHECK_PARSE_EQ("\\9", "'9'");
+  CHECK_PARSE_EQ("\\11", "'\t'");
+  CHECK_PARSE_EQ("\\11a", "'\ta'");
+  CHECK_PARSE_EQ("\\011", "'\t'");
+  CHECK_PARSE_EQ("\\00011", "'\00011'");
+  CHECK_PARSE_EQ("\\118", "'\t8'");
+  CHECK_PARSE_EQ("\\111", "'I'");
+  CHECK_PARSE_EQ("\\1111", "'I1'");
+  CHECK_PARSE_EQ("(.)(.)(.)\\1", "(: (^ [&.]) (^ [&.]) (^ [&.]) (<- 1))");
+  CHECK_PARSE_EQ("(.)(.)(.)\\2", "(: (^ [&.]) (^ [&.]) (^ [&.]) (<- 2))");
+  CHECK_PARSE_EQ("(.)(.)(.)\\3", "(: (^ [&.]) (^ [&.]) (^ [&.]) (<- 3))");
+  CHECK_PARSE_EQ("(.)(.)(.)\\4", "(: (^ [&.]) (^ [&.]) (^ [&.]) '\x04')");
+  CHECK_PARSE_EQ("(.)(.)(.)\\1*", "(: (^ [&.]) (^ [&.]) (^ [&.])"
+                               " (# 0 - g (<- 1)))");
+  CHECK_PARSE_EQ("(.)(.)(.)\\2*", "(: (^ [&.]) (^ [&.]) (^ [&.])"
+                               " (# 0 - g (<- 2)))");
+  CHECK_PARSE_EQ("(.)(.)(.)\\3*", "(: (^ [&.]) (^ [&.]) (^ [&.])"
+                               " (# 0 - g (<- 3)))");
+  CHECK_PARSE_EQ("(.)(.)(.)\\4*", "(: (^ [&.]) (^ [&.]) (^ [&.])"
+                               " (# 0 - g '\x04'))");
+  CHECK_PARSE_EQ("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\\10",
+              "(: (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.])"
+              " (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.]) (<- 10))");
+  CHECK_PARSE_EQ("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\\11",
+              "(: (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.])"
+              " (^ [&.]) (^ [&.]) (^ [&.]) (^ [&.]) '\x09')");
+  CHECK_PARSE_EQ("[\\0]", "[\0]");
+  CHECK_PARSE_EQ("[\\11]", "[\t]");
+  CHECK_PARSE_EQ("[\\11a]", "[\t a]");
+  CHECK_PARSE_EQ("[\\011]", "[\t]");
+  CHECK_PARSE_EQ("[\\00011]", "[\000 1 1]");
+  CHECK_PARSE_EQ("[\\118]", "[\t 8]");
+  CHECK_PARSE_EQ("[\\111]", "[I]");
+  CHECK_PARSE_EQ("[\\1111]", "[I 1]");
+  CHECK_PARSE_EQ("\\x34", "'\x34'");
+  CHECK_PARSE_EQ("\\x3z", "'x3z'");
+  CHECK_PARSE_EQ("\\u0034", "'\x34'");
+  CHECK_PARSE_EQ("\\u003z", "'u003z'");
+}
+
+
+static void ExpectError(const char* input,
+                        const char* expected) {
+  v8::HandleScope scope;
+  unibrow::Utf8InputBuffer<> buffer(input, strlen(input));
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  Handle<String> error;
+  RegExpTree* node = v8::internal::ParseRegExp(&buffer, &error);
+  CHECK(node == NULL);
+  CHECK(!error.is_null());
+  SmartPointer<char> str = error->ToCString(ALLOW_NULLS);
+  CHECK_EQ(expected, *str);
+}
+
+
+TEST(Errors) {
+  V8::Initialize(NULL);
+  const char* kEndBackslash = "\\ at end of pattern";
+  ExpectError("\\", kEndBackslash);
+  const char* kInvalidQuantifier = "Invalid quantifier";
+  ExpectError("a{}", kInvalidQuantifier);
+  ExpectError("a{,}", kInvalidQuantifier);
+  ExpectError("a{", kInvalidQuantifier);
+  ExpectError("a{z}", kInvalidQuantifier);
+  ExpectError("a{1z}", kInvalidQuantifier);
+  ExpectError("a{12z}", kInvalidQuantifier);
+  ExpectError("a{12,", kInvalidQuantifier);
+  ExpectError("a{12,3b", kInvalidQuantifier);
+  const char* kUnterminatedGroup = "Unterminated group";
+  ExpectError("(foo", kUnterminatedGroup);
+  const char* kInvalidGroup = "Invalid group";
+  ExpectError("(?", kInvalidGroup);
+  const char* kUnterminatedCharacterClass = "Unterminated character class";
+  ExpectError("[", kUnterminatedCharacterClass);
+  ExpectError("[a-", kUnterminatedCharacterClass);
+  const char* kIllegalCharacterClass = "Illegal character class";
+  ExpectError("[a-\\w]", kIllegalCharacterClass);
+  const char* kEndControl = "\\c at end of pattern";
+  ExpectError("\\c", kEndControl);
+}
+
+
+static void Execute(bool expected, const char* input, const char* str) {
+  v8::HandleScope scops;
+  unibrow::Utf8InputBuffer<> buffer(input, strlen(input));
+  ZoneScope zone_scope(DELETE_ON_EXIT);
+  Handle<String> error;
+  RegExpTree* tree = v8::internal::ParseRegExp(&buffer, &error);
+  CHECK(tree != NULL);
+  CHECK(error.is_null());
+  RegExpNode<const char>* node = RegExpEngine::Compile<const char>(tree);
+  bool outcome = RegExpEngine::Execute(node, CStrVector(str));
+  CHECK_EQ(outcome, expected);
+}
+
+
+TEST(Execution) {
+  V8::Initialize(NULL);
+  Execute(true, ".*?(?:a[bc]d|e[fg]h)", "xxxabbegh");
+  Execute(true, ".*?(?:a[bc]d|e[fg]h)", "xxxabbefh");
+  Execute(false, ".*?(?:a[bc]d|e[fg]h)", "xxxabbefd");
+}
+
+
+TEST(Fuzz) {
+  V8::Initialize(NULL);
+  for (int i = 0; i < kCaseCount; i++) {
+    const RegExpTestCase* c = &kCases[i];
+    v8::HandleScope scope;
+    printf("%s\n", c->pattern());
+    unibrow::Utf8InputBuffer<> buffer(c->pattern(), strlen(c->pattern()));
+    ZoneScope zone_scope(DELETE_ON_EXIT);
+    Handle<String> error;
+    RegExpTree* node = v8::internal::ParseRegExp(&buffer, &error);
+    if (c->expect_error()) {
+      CHECK(node == NULL);
+      CHECK(!error.is_null());
+    } else {
+      CHECK(node != NULL);
+      CHECK(error.is_null());
+    }
+  }
+}
+
+
+// "123456789abcdb".match(/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(\11)/)
+// 123456789abcdb,1,2,3,4,5,6,7,8,9,a,b,c,d,b
diff --git a/regexp2000/test/cctest/test-serialize.cc b/regexp2000/test/cctest/test-serialize.cc
new file mode 100644 (file)
index 0000000..f351bf0
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <signal.h>
+#include <map>
+#include <string>
+
+#include "sys/stat.h"
+#include "v8.h"
+
+#include "debug.h"
+#include "ic-inl.h"
+#include "runtime.h"
+#include "serialize.h"
+#include "scopeinfo.h"
+#include "snapshot.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static int local_counters[256];
+static int counter_count = 0;
+static std::map<std::wstring, int> counter_table;
+
+
+// Callback receiver to track counters in test.
+static int* counter_function(const wchar_t* name) {
+  std::wstring counter(name);
+  if (counter_table.find(counter) == counter_table.end()) {
+    local_counters[counter_count] = 0;
+    counter_table[counter] = counter_count++;
+  }
+
+  return &local_counters[counter_table[counter]];
+}
+
+
+template <class T>
+static Address AddressOf(T id) {
+  return ExternalReference(id).address();
+}
+
+
+template <class T>
+static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
+  return encoder.Encode(AddressOf(id));
+}
+
+
+static int make_code(TypeCode type, int id) {
+  return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
+}
+
+
+static int register_code(int reg) {
+  return Debug::k_register_address << kDebugIdShift | reg;
+}
+
+
+TEST(ExternalReferenceEncoder) {
+  StatsTable::SetCounterFunction(counter_function);
+  Heap::Setup(false);
+  ExternalReferenceEncoder encoder;
+  CHECK_EQ(make_code(BUILTIN, Builtins::ArrayCode),
+           Encode(encoder, Builtins::ArrayCode));
+  CHECK_EQ(make_code(RUNTIME_FUNCTION, Runtime::kAbort),
+           Encode(encoder, Runtime::kAbort));
+  CHECK_EQ(make_code(IC_UTILITY, IC::kLoadCallbackProperty),
+           Encode(encoder, IC_Utility(IC::kLoadCallbackProperty)));
+  CHECK_EQ(make_code(DEBUG_ADDRESS, register_code(3)),
+           Encode(encoder, Debug_Address(Debug::k_register_address, 3)));
+  ExternalReference keyed_load_function_prototype =
+      ExternalReference(&Counters::keyed_load_function_prototype);
+  CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype),
+           encoder.Encode(keyed_load_function_prototype.address()));
+  ExternalReference passed_function =
+      ExternalReference::builtin_passed_function();
+  CHECK_EQ(make_code(UNCLASSIFIED, 1),
+           encoder.Encode(passed_function.address()));
+  ExternalReference the_hole_value_location =
+      ExternalReference::the_hole_value_location();
+  CHECK_EQ(make_code(UNCLASSIFIED, 2),
+           encoder.Encode(the_hole_value_location.address()));
+  ExternalReference stack_guard_limit_address =
+      ExternalReference::address_of_stack_guard_limit();
+  CHECK_EQ(make_code(UNCLASSIFIED, 3),
+           encoder.Encode(stack_guard_limit_address.address()));
+  CHECK_EQ(make_code(UNCLASSIFIED, 4),
+           encoder.Encode(ExternalReference::debug_break().address()));
+  CHECK_EQ(make_code(UNCLASSIFIED, 5),
+           encoder.Encode(ExternalReference::new_space_start().address()));
+}
+
+
+TEST(ExternalReferenceDecoder) {
+  StatsTable::SetCounterFunction(counter_function);
+  Heap::Setup(false);
+  ExternalReferenceDecoder decoder;
+  CHECK_EQ(AddressOf(Builtins::ArrayCode),
+           decoder.Decode(make_code(BUILTIN, Builtins::ArrayCode)));
+  CHECK_EQ(AddressOf(Runtime::kAbort),
+           decoder.Decode(make_code(RUNTIME_FUNCTION, Runtime::kAbort)));
+  CHECK_EQ(AddressOf(IC_Utility(IC::kLoadCallbackProperty)),
+           decoder.Decode(make_code(IC_UTILITY, IC::kLoadCallbackProperty)));
+  CHECK_EQ(AddressOf(Debug_Address(Debug::k_register_address, 3)),
+           decoder.Decode(make_code(DEBUG_ADDRESS, register_code(3))));
+  ExternalReference keyed_load_function =
+      ExternalReference(&Counters::keyed_load_function_prototype);
+  CHECK_EQ(keyed_load_function.address(),
+           decoder.Decode(
+               make_code(STATS_COUNTER,
+                         Counters::k_keyed_load_function_prototype)));
+  CHECK_EQ(ExternalReference::builtin_passed_function().address(),
+           decoder.Decode(make_code(UNCLASSIFIED, 1)));
+  CHECK_EQ(ExternalReference::the_hole_value_location().address(),
+           decoder.Decode(make_code(UNCLASSIFIED, 2)));
+  CHECK_EQ(ExternalReference::address_of_stack_guard_limit().address(),
+           decoder.Decode(make_code(UNCLASSIFIED, 3)));
+  CHECK_EQ(ExternalReference::debug_break().address(),
+           decoder.Decode(make_code(UNCLASSIFIED, 4)));
+  CHECK_EQ(ExternalReference::new_space_start().address(),
+           decoder.Decode(make_code(UNCLASSIFIED, 5)));
+}
+
+
+static void Serialize() {
+#ifdef DEBUG
+  FLAG_debug_serialization = true;
+#endif
+  StatsTable::SetCounterFunction(counter_function);
+
+  v8::HandleScope scope;
+  const int kExtensionCount = 1;
+  const char* extension_list[kExtensionCount] = { "v8/gc" };
+  v8::ExtensionConfiguration extensions(kExtensionCount, extension_list);
+  v8::Persistent<v8::Context> env = v8::Context::New(&extensions);
+  env->Enter();
+
+  Snapshot::WriteToFile(FLAG_testing_serialization_file);
+}
+
+
+// Test that the whole heap can be serialized when running from the
+// internal snapshot.
+// (Smoke test.)
+TEST(SerializeInternal) {
+  Snapshot::Initialize(NULL);
+  Serialize();
+}
+
+
+// Test that the whole heap can be serialized when running from a
+// bootstrapped heap.
+// (Smoke test.)
+TEST(Serialize) {
+  if (Snapshot::IsEnabled()) return;
+  Serialize();
+}
+
+
+// Test that the heap isn't destroyed after a serialization.
+TEST(SerializeNondestructive) {
+  if (Snapshot::IsEnabled()) return;
+  StatsTable::SetCounterFunction(counter_function);
+  v8::HandleScope scope;
+  v8::Persistent<v8::Context> env = v8::Context::New();
+  v8::Context::Scope context_scope(env);
+  Serializer().Serialize();
+  const char* c_source = "\"abcd\".charAt(2) == 'c'";
+  v8::Local<v8::String> source = v8::String::New(c_source);
+  v8::Local<v8::Script> script = v8::Script::Compile(source);
+  v8::Local<v8::Value> value = script->Run();
+  CHECK(value->BooleanValue());
+}
+
+//----------------------------------------------------------------------------
+// Tests that the heap can be deserialized.
+
+static void Deserialize() {
+#ifdef DEBUG
+  FLAG_debug_serialization = true;
+#endif
+  CHECK(Snapshot::Initialize(FLAG_testing_serialization_file));
+}
+
+
+static void SanityCheck() {
+  v8::HandleScope scope;
+#ifdef DEBUG
+  Heap::Verify();
+#endif
+  CHECK(Top::global()->IsJSObject());
+  CHECK(Top::global_context()->IsContext());
+  CHECK(Top::special_function_table()->IsFixedArray());
+  CHECK(Heap::symbol_table()->IsSymbolTable());
+  CHECK(!Factory::LookupAsciiSymbol("Empty")->IsFailure());
+}
+
+
+TEST(Deserialize) {
+  v8::HandleScope scope;
+
+  Deserialize();
+
+  SanityCheck();
+}
+
+TEST(DeserializeAndRunScript) {
+  v8::HandleScope scope;
+
+  Deserialize();
+
+  const char* c_source = "\"1234\".length";
+  v8::Local<v8::String> source = v8::String::New(c_source);
+  v8::Local<v8::Script> script = v8::Script::Compile(source);
+  CHECK_EQ(4, script->Run()->Int32Value());
+}
+
+
+TEST(DeserializeNatives) {
+  v8::HandleScope scope;
+
+  Deserialize();
+
+  const char* c_source = "\"abcd\".charAt(2) == 'c'";
+  v8::Local<v8::String> source = v8::String::New(c_source);
+  v8::Local<v8::Script> script = v8::Script::Compile(source);
+  v8::Local<v8::Value> value = script->Run();
+  CHECK(value->BooleanValue());
+}
+
+
+TEST(DeserializeExtensions) {
+  v8::HandleScope scope;
+
+  Deserialize();
+  const char* c_source = "gc();";
+  v8::Local<v8::String> source = v8::String::New(c_source);
+  v8::Local<v8::Script> script = v8::Script::Compile(source);
+  v8::Local<v8::Value> value = script->Run();
+  CHECK(value->IsUndefined());
+}
diff --git a/regexp2000/test/cctest/test-spaces.cc b/regexp2000/test/cctest/test-spaces.cc
new file mode 100644 (file)
index 0000000..86aa5f8
--- /dev/null
@@ -0,0 +1,251 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static void VerifyRSet(Address page_start) {
+#ifdef DEBUG
+  Page::set_rset_state(Page::IN_USE);
+#endif
+
+  Page* p = Page::FromAddress(page_start);
+
+  p->ClearRSet();
+
+  for (Address addr = p->ObjectAreaStart();
+       addr < p->ObjectAreaEnd();
+       addr += kPointerSize) {
+    CHECK(!Page::IsRSetSet(addr, 0));
+  }
+
+  for (Address addr = p->ObjectAreaStart();
+       addr < p->ObjectAreaEnd();
+       addr += kPointerSize) {
+    Page::SetRSet(addr, 0);
+  }
+
+  for (Address addr = p->ObjectAreaStart();
+       addr < p->ObjectAreaEnd();
+       addr += kPointerSize) {
+    CHECK(Page::IsRSetSet(addr, 0));
+  }
+}
+
+
+TEST(Page) {
+#ifdef DEBUG
+  Page::set_rset_state(Page::NOT_IN_USE);
+#endif
+
+  byte* mem = NewArray<byte>(2*Page::kPageSize);
+  CHECK(mem != NULL);
+
+  Address start = reinterpret_cast<Address>(mem);
+  Address page_start = RoundUp(start, Page::kPageSize);
+
+  Page* p = Page::FromAddress(page_start);
+  CHECK(p->address() == page_start);
+  CHECK(p->is_valid());
+
+  p->opaque_header = 0;
+  p->is_normal_page = 0x1;
+  CHECK(!p->next_page()->is_valid());
+
+  CHECK(p->ObjectAreaStart() == page_start + Page::kObjectStartOffset);
+  CHECK(p->ObjectAreaEnd() == page_start + Page::kPageSize);
+
+  CHECK(p->Offset(page_start + Page::kObjectStartOffset) ==
+        Page::kObjectStartOffset);
+  CHECK(p->Offset(page_start + Page::kPageSize) == Page::kPageSize);
+
+  CHECK(p->OffsetToAddress(Page::kObjectStartOffset) == p->ObjectAreaStart());
+  CHECK(p->OffsetToAddress(Page::kPageSize) == p->ObjectAreaEnd());
+
+  // test remember set
+  VerifyRSet(page_start);
+
+  DeleteArray(mem);
+}
+
+
+TEST(MemoryAllocator) {
+  CHECK(Heap::ConfigureHeapDefault());
+  CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
+
+  OldSpace faked_space(Heap::MaxCapacity(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
+  int total_pages = 0;
+  int requested = 2;
+  int allocated;
+  // If we request two pages, we should get one or two.
+  Page* first_page =
+      MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
+  CHECK(first_page->is_valid());
+  CHECK(allocated > 0 && allocated <= 2);
+  total_pages += allocated;
+
+  Page* last_page = first_page;
+  for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
+    CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
+    last_page = p;
+  }
+
+  // Again, we should get one or two pages.
+  Page* others =
+      MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
+  CHECK(others->is_valid());
+  CHECK(allocated > 0 && allocated <= 2);
+  total_pages += allocated;
+
+  MemoryAllocator::SetNextPage(last_page, others);
+  int page_count = 0;
+  for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
+    CHECK(MemoryAllocator::IsPageInSpace(p, &faked_space));
+    page_count++;
+  }
+  CHECK(total_pages == page_count);
+
+  Page* second_page = first_page->next_page();
+  CHECK(second_page->is_valid());
+
+  // Freeing pages at the first chunk starting at or after the second page
+  // should free the entire second chunk.  It will return the last page in the
+  // first chunk (if the second page was in the first chunk) or else an
+  // invalid page (if the second page was the start of the second chunk).
+  Page* free_return = MemoryAllocator::FreePages(second_page);
+  CHECK(free_return == last_page || !free_return->is_valid());
+  MemoryAllocator::SetNextPage(first_page, free_return);
+
+  // Freeing pages in the first chunk starting at the first page should free
+  // the first chunk and return an invalid page.
+  Page* invalid_page = MemoryAllocator::FreePages(first_page);
+  CHECK(!invalid_page->is_valid());
+
+  MemoryAllocator::TearDown();
+}
+
+
+TEST(NewSpace) {
+  CHECK(Heap::ConfigureHeapDefault());
+  CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
+
+  NewSpace new_space;
+
+  void* chunk =
+      MemoryAllocator::ReserveInitialChunk(2 * Heap::YoungGenerationSize());
+  CHECK(chunk != NULL);
+  Address start = RoundUp(static_cast<Address>(chunk),
+                          Heap::YoungGenerationSize());
+  CHECK(new_space.Setup(start, Heap::YoungGenerationSize()));
+  CHECK(new_space.HasBeenSetup());
+
+  while (new_space.Available() >= Page::kMaxHeapObjectSize) {
+    Object* obj = new_space.AllocateRaw(Page::kMaxHeapObjectSize);
+    CHECK(!obj->IsFailure());
+    CHECK(new_space.Contains(HeapObject::cast(obj)));
+  }
+
+  new_space.TearDown();
+  MemoryAllocator::TearDown();
+}
+
+
+TEST(OldSpace) {
+  CHECK(Heap::ConfigureHeapDefault());
+  CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
+
+  OldSpace* s = new OldSpace(Heap::OldGenerationSize(),
+                             OLD_POINTER_SPACE,
+                             NOT_EXECUTABLE);
+  CHECK(s != NULL);
+
+  void* chunk =
+      MemoryAllocator::ReserveInitialChunk(2 * Heap::YoungGenerationSize());
+  CHECK(chunk != NULL);
+  Address start = static_cast<Address>(chunk);
+  size_t size = RoundUp(start, Heap::YoungGenerationSize()) - start;
+
+  CHECK(s->Setup(start, size));
+
+  while (s->Available() > 0) {
+    Object* obj = s->AllocateRaw(Page::kMaxHeapObjectSize);
+    CHECK(!obj->IsFailure());
+  }
+
+  s->TearDown();
+  delete s;
+  MemoryAllocator::TearDown();
+}
+
+
+TEST(LargeObjectSpace) {
+  CHECK(Heap::ConfigureHeapDefault());
+  MemoryAllocator::Setup(Heap::MaxCapacity());
+
+  LargeObjectSpace* lo = new LargeObjectSpace(LO_SPACE);
+  CHECK(lo != NULL);
+
+  CHECK(lo->Setup());
+
+  Map* faked_map = reinterpret_cast<Map*>(HeapObject::FromAddress(0));
+  int lo_size = Page::kPageSize;
+
+  Object* obj = lo->AllocateRaw(lo_size);
+  CHECK(!obj->IsFailure());
+  CHECK(obj->IsHeapObject());
+
+  HeapObject* ho = HeapObject::cast(obj);
+  ho->set_map(faked_map);
+
+  CHECK(lo->Contains(HeapObject::cast(obj)));
+
+  CHECK(lo->FindObject(ho->address()) == obj);
+
+  CHECK(lo->Contains(ho));
+
+  while (true) {
+    int available = lo->Available();
+    obj = lo->AllocateRaw(lo_size);
+    if (obj->IsFailure()) break;
+    HeapObject::cast(obj)->set_map(faked_map);
+    CHECK(lo->Available() < available);
+  };
+
+  CHECK(!lo->IsEmpty());
+
+  obj = lo->AllocateRaw(lo_size);
+  CHECK(obj->IsFailure());
+
+  lo->TearDown();
+  delete lo;
+
+  MemoryAllocator::TearDown();
+}
diff --git a/regexp2000/test/cctest/test-strings.cc b/regexp2000/test/cctest/test-strings.cc
new file mode 100644 (file)
index 0000000..4484dd5
--- /dev/null
@@ -0,0 +1,376 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+// Check that we can traverse very deep stacks of ConsStrings using
+// StringInputBuffer.  Check that Get(int) works on very deep stacks
+// of ConsStrings.  These operations may not be very fast, but they
+// should be possible without getting errors due to too deep recursion.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "factory.h"
+#include "cctest.h"
+
+unsigned int seed = 123;
+
+static uint32_t gen() {
+        uint64_t z;
+        z = seed;
+        z *= 279470273;
+        z %= 4294967291U;
+        seed = static_cast<unsigned int>(z);
+        return static_cast<uint32_t>(seed >> 16);
+}
+
+
+using namespace v8::internal;
+
+static v8::Persistent<v8::Context> env;
+
+
+static void InitializeVM() {
+  if (env.IsEmpty()) {
+    v8::HandleScope scope;
+    const char* extensions[] = { "v8/print" };
+    v8::ExtensionConfiguration config(1, extensions);
+    env = v8::Context::New(&config);
+  }
+  v8::HandleScope scope;
+  env->Enter();
+}
+
+
+static const int NUMBER_OF_BUILDING_BLOCKS = 128;
+static const int DEEP_DEPTH = 8 * 1024;
+static const int SUPER_DEEP_DEPTH = 80 * 1024;
+
+
+static void InitializeBuildingBlocks(
+    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
+  for (int i = 0; i < NUMBER_OF_BUILDING_BLOCKS; i++) {
+    int len = gen() % 16;
+    if (len > 14) {
+      len += 1234;
+    }
+    switch (gen() % 4) {
+      case 0: {
+        uc16 buf[2000];
+        for (int j = 0; j < len; j++) {
+          buf[j] = gen() % 65536;
+        }
+        building_blocks[i] =
+            Factory::NewStringFromTwoByte(Vector<const uc16>(buf, len));
+        for (int j = 0; j < len; j++) {
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+        }
+        break;
+      }
+      case 1: {
+        char buf[2000];
+        for (int j = 0; j < len; j++) {
+          buf[j] = gen() % 128;
+        }
+        building_blocks[i] =
+            Factory::NewStringFromAscii(Vector<const char>(buf, len));
+        for (int j = 0; j < len; j++) {
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+        }
+        break;
+      }
+      case 2: {
+        class Resource: public v8::String::ExternalStringResource,
+                        public Malloced {
+         public:
+          explicit Resource(Vector<const uc16> string): data_(string.start()) {
+            length_ = string.length();
+          }
+          virtual const uint16_t* data() const { return data_; }
+          virtual size_t length() const { return length_; }
+
+         private:
+          const uc16* data_;
+          size_t length_;
+        };
+        uc16* buf = NewArray<uc16>(len);
+        for (int j = 0; j < len; j++) {
+          buf[j] = gen() % 65536;
+        }
+        Resource* resource = new Resource(Vector<const uc16>(buf, len));
+        building_blocks[i] = Factory::NewExternalStringFromTwoByte(resource);
+        for (int j = 0; j < len; j++) {
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+        }
+        break;
+      }
+      case 3: {
+        char* buf = NewArray<char>(len);
+        for (int j = 0; j < len; j++) {
+          buf[j] = gen() % 128;
+        }
+        building_blocks[i] =
+            Factory::NewStringFromAscii(Vector<const char>(buf, len));
+        for (int j = 0; j < len; j++) {
+          CHECK_EQ(buf[j], building_blocks[i]->Get(j));
+        }
+        break;
+      }
+    }
+  }
+}
+
+
+static Handle<String> ConstructLeft(
+    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
+    int depth) {
+  Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
+  for (int i = 0; i < depth; i++) {
+    answer =
+        Factory::NewConsString(answer,
+                               building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
+  }
+  return answer;
+}
+
+
+static Handle<String> ConstructRight(
+    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
+    int depth) {
+  Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
+  for (int i = depth - 1; i >= 0; i--) {
+    answer =
+        Factory::NewConsString(building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
+                               answer);
+  }
+  return answer;
+}
+
+
+static Handle<String> ConstructBalancedHelper(
+    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
+    int from,
+    int to) {
+  ASSERT(to > from);
+  if (to - from == 1) {
+    return building_blocks[from % NUMBER_OF_BUILDING_BLOCKS];
+  }
+  if (to - from == 2) {
+    return Factory::NewConsString(
+        building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
+        building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
+  }
+  return Factory::NewConsString(
+    ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2)),
+    ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to));
+}
+
+
+static Handle<String> ConstructBalanced(
+    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
+  return ConstructBalancedHelper(building_blocks, 0, DEEP_DEPTH);
+}
+
+
+static StringInputBuffer buffer;
+
+
+static void Traverse(Handle<String> s1, Handle<String> s2) {
+  int i = 0;
+  buffer.Reset(*s1);
+  StringInputBuffer buffer2(*s2);
+  while (buffer.has_more()) {
+    CHECK(buffer2.has_more());
+    uint16_t c = buffer.GetNext();
+    CHECK_EQ(c, buffer2.GetNext());
+    i++;
+  }
+  CHECK_EQ(s1->length(), i);
+  CHECK_EQ(s2->length(), i);
+}
+
+
+static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
+  int i = 0;
+  buffer.Reset(*s1);
+  StringInputBuffer buffer2(*s2);
+  while (buffer.has_more() && i < chars) {
+    CHECK(buffer2.has_more());
+    uint16_t c = buffer.GetNext();
+    CHECK_EQ(c, buffer2.GetNext());
+    i++;
+  }
+  s1->Get(s1->length() - 1);
+  s2->Get(s2->length() - 1);
+}
+
+
+TEST(Traverse) {
+  printf("TestTraverse\n");
+  InitializeVM();
+  v8::HandleScope scope;
+  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
+  InitializeBuildingBlocks(building_blocks);
+  Handle<String> flat = ConstructBalanced(building_blocks);
+  FlattenString(flat);
+  Handle<String> left_asymmetric = ConstructLeft(building_blocks, DEEP_DEPTH);
+  Handle<String> right_asymmetric = ConstructRight(building_blocks, DEEP_DEPTH);
+  Handle<String> symmetric = ConstructBalanced(building_blocks);
+  printf("1\n");
+  Traverse(flat, symmetric);
+  printf("2\n");
+  Traverse(flat, left_asymmetric);
+  printf("3\n");
+  Traverse(flat, right_asymmetric);
+  printf("4\n");
+  Handle<String> left_deep_asymmetric =
+      ConstructLeft(building_blocks, SUPER_DEEP_DEPTH);
+  Handle<String> right_deep_asymmetric =
+      ConstructRight(building_blocks, SUPER_DEEP_DEPTH);
+  printf("5\n");
+  TraverseFirst(left_asymmetric, left_deep_asymmetric, 1050);
+  printf("6\n");
+  TraverseFirst(left_asymmetric, right_deep_asymmetric, 65536);
+  printf("7\n");
+  Handle<String> right_deep_slice =
+      Factory::NewStringSlice(left_deep_asymmetric,
+                              left_deep_asymmetric->length() - 1050,
+                              left_deep_asymmetric->length() - 50);
+  Handle<String> left_deep_slice =
+      Factory::NewStringSlice(right_deep_asymmetric,
+                              right_deep_asymmetric->length() - 1050,
+                              right_deep_asymmetric->length() - 50);
+  printf("8\n");
+  Traverse(right_deep_slice, left_deep_slice);
+  printf("9\n");
+  FlattenString(left_asymmetric);
+  printf("10\n");
+  Traverse(flat, left_asymmetric);
+  printf("11\n");
+  FlattenString(right_asymmetric);
+  printf("12\n");
+  Traverse(flat, right_asymmetric);
+  printf("14\n");
+  FlattenString(symmetric);
+  printf("15\n");
+  Traverse(flat, symmetric);
+  printf("16\n");
+  FlattenString(left_deep_asymmetric);
+  printf("18\n");
+}
+
+
+static Handle<String> SliceOf(Handle<String> underlying) {
+  int start = gen() % underlying->length();
+  int end = start + gen() % (underlying->length() - start);
+  return Factory::NewStringSlice(underlying, start, end);
+}
+
+
+static Handle<String> ConstructSliceTree(
+    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
+    int from,
+    int to) {
+  ASSERT(to > from);
+  if (to - from <= 1)
+    return SliceOf(building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]);
+  if (to - from == 2) {
+    Handle<String> lhs = building_blocks[from % NUMBER_OF_BUILDING_BLOCKS];
+    if (gen() % 2 == 0)
+      lhs = SliceOf(lhs);
+    Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS];
+    if (gen() % 2 == 0)
+      rhs = SliceOf(rhs);
+    return Factory::NewConsString(lhs, rhs);
+  }
+  Handle<String> branch = Factory::NewConsString(
+    ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2)),
+    ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to));
+  if (gen() % 2 == 0)
+    return branch;
+  return(SliceOf(branch));
+}
+
+
+TEST(Slice) {
+  printf("TestSlice\n");
+  InitializeVM();
+  v8::HandleScope scope;
+  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
+  InitializeBuildingBlocks(building_blocks);
+
+  seed = 42;
+  Handle<String> slice_tree =
+      ConstructSliceTree(building_blocks, 0, DEEP_DEPTH);
+  seed = 42;
+  Handle<String> flat_slice_tree =
+      ConstructSliceTree(building_blocks, 0, DEEP_DEPTH);
+  FlattenString(flat_slice_tree);
+  Traverse(flat_slice_tree, slice_tree);
+}
+
+static const int DEEP_ASCII_DEPTH = 100000;
+
+
+TEST(DeepAscii) {
+  printf("TestDeepAscii\n");
+  InitializeVM();
+  v8::HandleScope scope;
+
+  char* foo = NewArray<char>(DEEP_ASCII_DEPTH);
+  for (int i = 0; i < DEEP_ASCII_DEPTH; i++) {
+    foo[i] = "foo "[i % 4];
+  }
+  Handle<String> string =
+      Factory::NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
+  Handle<String> foo_string = Factory::NewStringFromAscii(CStrVector("foo"));
+  for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
+    string = Factory::NewConsString(string, foo_string);
+  }
+  Handle<String> flat_string = Factory::NewConsString(string, foo_string);
+  FlattenString(flat_string);
+
+  for (int i = 0; i < 500; i++) {
+    TraverseFirst(flat_string, string, DEEP_ASCII_DEPTH);
+  }
+}
+
+
+TEST(Utf8Conversion) {
+  // Smoke test for converting strings to utf-8.
+  InitializeVM();
+  v8::HandleScope handle_scope;
+  // A simple ascii string
+  const char* ascii_string = "abcdef12345";
+  int len = v8::String::New(ascii_string, strlen(ascii_string))->Utf8Length();
+  CHECK_EQ(strlen(ascii_string), len);
+  // A mixed ascii and non-ascii string
+  // U+02E4 -> CB A4
+  // U+0064 -> 64
+  // U+12E4 -> E1 8B A4
+  // U+0030 -> 30
+  // U+3045 -> E3 81 85
+  const uint16_t mixed_string[] = {0x02E4, 0x0064, 0x12E4, 0x0030, 0x3045};
+  // The characters we expect to be output
+  const unsigned char as_utf8[11] = {0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4, 0x30,
+      0xE3, 0x81, 0x85, 0x00};
+  // The number of bytes expected to be written for each length
+  const int lengths[12] = {0, 0, 2, 3, 3, 3, 6, 7, 7, 7, 10, 11};
+  v8::Handle<v8::String> mixed = v8::String::New(mixed_string, 5);
+  CHECK_EQ(10, mixed->Utf8Length());
+  // Try encoding the string with all capacities
+  char buffer[11];
+  const char kNoChar = static_cast<char>(-1);
+  for (int i = 0; i <= 11; i++) {
+    // Clear the buffer before reusing it
+    for (int j = 0; j < 11; j++)
+      buffer[j] = kNoChar;
+    int written = mixed->WriteUtf8(buffer, i);
+    CHECK_EQ(lengths[i], written);
+    // Check that the contents are correct
+    for (int j = 0; j < lengths[i]; j++)
+      CHECK_EQ(as_utf8[j], static_cast<unsigned char>(buffer[j]));
+    // Check that the rest of the buffer hasn't been touched
+    for (int j = lengths[i]; j < 11; j++)
+      CHECK_EQ(kNoChar, buffer[j]);
+  }
+}
diff --git a/regexp2000/test/cctest/test-utils.cc b/regexp2000/test/cctest/test-utils.cc
new file mode 100644 (file)
index 0000000..187cba9
--- /dev/null
@@ -0,0 +1,178 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+
+enum Mode {
+  forward,
+  backward_unsigned
+};
+
+
+static v8::internal::byte* Write(v8::internal::byte* p, Mode m, int x) {
+  v8::internal::byte* q = NULL;
+  switch (m) {
+    case forward:
+      q = EncodeInt(p, x);
+      CHECK(q <= p + sizeof(x) + 1);
+      break;
+    case backward_unsigned:
+      q = EncodeUnsignedIntBackward(p, x);
+      CHECK(q >= p - sizeof(x) - 1);
+      break;
+  }
+  return q;
+}
+
+
+static v8::internal::byte* Read(v8::internal::byte* p, Mode m, int x) {
+  v8::internal::byte* q = NULL;
+  int y;
+  switch (m) {
+    case forward:
+      q = DecodeInt(p, &y);
+      CHECK(q <= p + sizeof(y) + 1);
+      break;
+    case backward_unsigned: {
+      unsigned int uy;
+      q = DecodeUnsignedIntBackward(p, &uy);
+      y = uy;
+      CHECK(q >= p - sizeof(uy) - 1);
+      break;
+    }
+  }
+  CHECK(y == x);
+  return q;
+}
+
+
+static v8::internal::byte* WriteMany(v8::internal::byte* p, Mode m, int x) {
+  p = Write(p, m, x - 7);
+  p = Write(p, m, x - 1);
+  p = Write(p, m, x);
+  p = Write(p, m, x + 1);
+  p = Write(p, m, x + 2);
+  p = Write(p, m, -x - 5);
+  p = Write(p, m, -x - 1);
+  p = Write(p, m, -x);
+  p = Write(p, m, -x + 1);
+  p = Write(p, m, -x + 3);
+
+  return p;
+}
+
+
+static v8::internal::byte* ReadMany(v8::internal::byte* p, Mode m, int x) {
+  p = Read(p, m, x - 7);
+  p = Read(p, m, x - 1);
+  p = Read(p, m, x);
+  p = Read(p, m, x + 1);
+  p = Read(p, m, x + 2);
+  p = Read(p, m, -x - 5);
+  p = Read(p, m, -x - 1);
+  p = Read(p, m, -x);
+  p = Read(p, m, -x + 1);
+  p = Read(p, m, -x + 3);
+
+  return p;
+}
+
+
+void ProcessValues(int* values, int n, Mode m) {
+  v8::internal::byte buf[4 * KB];  // make this big enough
+  v8::internal::byte* p0 = (m == forward ? buf : buf + ARRAY_SIZE(buf));
+
+  v8::internal::byte* p = p0;
+  for (int i = 0; i < n; i++) {
+    p = WriteMany(p, m, values[i]);
+  }
+
+  v8::internal::byte* q = p0;
+  for (int i = 0; i < n; i++) {
+    q = ReadMany(q, m, values[i]);
+  }
+
+  CHECK(p == q);
+}
+
+
+TEST(Utils0) {
+  int values[] = {
+    0, 1, 10, 16, 32, 64, 128, 256, 512, 1024, 1234, 5731,
+    10000, 100000, 1000000, 10000000, 100000000, 1000000000
+  };
+  const int n = ARRAY_SIZE(values);
+
+  ProcessValues(values, n, forward);
+  ProcessValues(values, n, backward_unsigned);
+}
+
+
+TEST(Utils1) {
+  CHECK_EQ(-1000000, FastD2I(-1000000.0));
+  CHECK_EQ(-1, FastD2I(-1.0));
+  CHECK_EQ(0, FastD2I(0.0));
+  CHECK_EQ(1, FastD2I(1.0));
+  CHECK_EQ(1000000, FastD2I(1000000.0));
+
+  CHECK_EQ(-1000000, FastD2I(-1000000.123));
+  CHECK_EQ(-1, FastD2I(-1.234));
+  CHECK_EQ(0, FastD2I(0.345));
+  CHECK_EQ(1, FastD2I(1.234));
+  CHECK_EQ(1000000, FastD2I(1000000.123));
+}
+
+
+TEST(SNPrintF) {
+  // Make sure that strings that are truncated because of too small
+  // buffers are zero-terminated anyway.
+  const char* s = "the quick lazy .... oh forget it!";
+  int length = strlen(s);
+  for (int i = 1; i < length * 2; i++) {
+    static const char kMarker = static_cast<char>(42);
+    Vector<char> buffer = Vector<char>::New(i + 1);
+    buffer[i] = kMarker;
+    int n = OS::SNPrintF(Vector<char>(buffer.start(), i), "%s", s);
+    CHECK(n <= i);
+    CHECK(n == length || n == -1);
+    CHECK_EQ(0, strncmp(buffer.start(), s, i - 1));
+    CHECK_EQ(kMarker, buffer[i]);
+    if (i <= length) {
+      CHECK_EQ(i - 1, strlen(buffer.start()));
+    } else {
+      CHECK_EQ(length, strlen(buffer.start()));
+    }
+  }
+}
diff --git a/regexp2000/test/cctest/testcfg.py b/regexp2000/test/cctest/testcfg.py
new file mode 100644 (file)
index 0000000..08226aa
--- /dev/null
@@ -0,0 +1,89 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import test
+import os
+from os.path import join, dirname, exists
+import platform
+
+
+DEBUG_FLAGS = ['--enable-slow-asserts', '--debug-code', '--verify-heap']
+
+
+class CcTestCase(test.TestCase):
+
+  def __init__(self, path, executable, mode, raw_name, context):
+    super(CcTestCase, self).__init__(context, path)
+    self.executable = executable
+    self.mode = mode
+    self.raw_name = raw_name
+
+  def GetLabel(self):
+    return "%s %s %s" % (self.mode, self.path[-2], self.path[-1])
+
+  def GetName(self):
+    return self.path[-1]
+
+  def GetCommand(self):
+    result = [ self.executable, self.raw_name ]
+    if self.mode == 'debug':
+      result += DEBUG_FLAGS
+    return result
+
+
+class CcTestConfiguration(test.TestConfiguration):
+
+  def __init__(self, context, root):
+    super(CcTestConfiguration, self).__init__(context, root)
+
+  def GetBuildRequirements(self):
+    return ['cctests']
+
+  def ListTests(self, current_path, path, mode):
+    executable = join('obj', 'test', mode, 'cctest')
+    if (platform.system() == 'Windows'):
+      executable += '.exe'
+    output = test.Execute([executable, '--list'], self.context)
+    if output.exit_code != 0:
+      print output.stdout
+      print output.stderr
+      return []
+    result = []
+    for raw_test in output.stdout.strip().split():
+      full_path = current_path + raw_test.split('/')
+      if self.Contains(path, full_path):
+        result.append(CcTestCase(full_path, executable, mode, raw_test, self.context))
+    return result
+  
+  def GetTestStatus(self, sections, defs):
+    status_file = join(self.root, 'cctest.status')
+    if exists(status_file):
+      test.ReadConfigurationInto(status_file, sections, defs)
+
+
+def GetConfiguration(context, root):
+  return CcTestConfiguration(context, root)
diff --git a/regexp2000/test/message/message.status b/regexp2000/test/message/message.status
new file mode 100644 (file)
index 0000000..fc2896b
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+prefix message
+
+# All tests in the bug directory are expected to fail.
+bugs: FAIL
diff --git a/regexp2000/test/message/regress/regress-73.js b/regexp2000/test/message/regress/regress-73.js
new file mode 100644 (file)
index 0000000..72652d7
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {\r
+  throw 'a';\r
+} catch (e) {\r
+  throw 'b';\r
+  print('c');\r
+}\r
diff --git a/regexp2000/test/message/regress/regress-73.out b/regexp2000/test/message/regress/regress-73.out
new file mode 100644 (file)
index 0000000..28606dd
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:31: b
+  throw 'b';
+  ^
diff --git a/regexp2000/test/message/regress/regress-75.js b/regexp2000/test/message/regress/regress-75.js
new file mode 100644 (file)
index 0000000..428fac9
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  throw "foo";
+} finally {
+  "bar";
+}
diff --git a/regexp2000/test/message/regress/regress-75.out b/regexp2000/test/message/regress/regress-75.out
new file mode 100644 (file)
index 0000000..336d4ce
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:29: foo
+  throw "foo";
+  ^
diff --git a/regexp2000/test/message/simple-throw.js b/regexp2000/test/message/simple-throw.js
new file mode 100644 (file)
index 0000000..7b3b4ca
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+throw "wow";
diff --git a/regexp2000/test/message/simple-throw.out b/regexp2000/test/message/simple-throw.out
new file mode 100644 (file)
index 0000000..0f359cf
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:28: wow
+throw "wow";
+^
diff --git a/regexp2000/test/message/testcfg.py b/regexp2000/test/message/testcfg.py
new file mode 100644 (file)
index 0000000..381ad5c
--- /dev/null
@@ -0,0 +1,126 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import test
+import os
+from os.path import join, dirname, exists, basename
+import re
+
+FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
+
+class MessageTestCase(test.TestCase):
+
+  def __init__(self, path, file, expected, mode, context, config):
+    super(MessageTestCase, self).__init__(context, path)
+    self.file = file
+    self.expected = expected
+    self.config = config
+    self.mode = mode
+
+  def IsFailureOutput(self, output):
+    f = file(self.expected)
+    # Skip initial '#' comment and spaces
+    for line in f:
+      if (not line.startswith('#')) and (not line.strip()):
+        break
+    # Convert output lines to regexps that we can match
+    env = { 'basename': basename(self.file) }
+    patterns = [ ]
+    for line in f:
+      if not line.strip():
+        continue
+      pattern = re.escape(line.rstrip() % env)
+      pattern = pattern.replace('\\*', '.*')
+      pattern = '^%s$' % pattern
+      patterns.append(pattern)
+    # Compare actual output with the expected
+    outlines = [ s for s in output.stdout.split('\n') if s ]
+    if len(outlines) != len(patterns):
+      return True
+    for i in xrange(len(patterns)):
+      if not re.match(patterns[i], outlines[i]):
+        return True
+    return False
+
+  def GetLabel(self):
+    return "%s %s" % (self.mode, self.GetName())
+
+  def GetName(self):
+    return self.path[-1]
+
+  def GetCommand(self):
+    result = [self.config.context.GetVm(self.mode)]
+    source = open(self.file).read()
+    flags_match = FLAGS_PATTERN.search(source)
+    if flags_match:
+      result += flags_match.group(1).strip().split()
+    result.append(self.file)
+    return result
+
+  def GetSource(self):
+    return (open(self.file).read()
+          + "\n--- expected output ---\n"
+          + open(self.expected).read())
+
+
+class MessageTestConfiguration(test.TestConfiguration):
+
+  def __init__(self, context, root):
+    super(MessageTestConfiguration, self).__init__(context, root)
+
+  def Ls(self, path):
+    return [f[:-3] for f in os.listdir(path) if f.endswith('.js')]
+
+  def ListTests(self, current_path, path, mode):
+    mjsunit = [current_path + [t] for t in self.Ls(self.root)]
+    regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
+    bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
+    all_tests = mjsunit + regress + bugs
+    result = []
+    for test in all_tests:
+      if self.Contains(path, test):
+        file_prefix = join(self.root, reduce(join, test[1:], ""))
+        file_path = file_prefix + ".js"
+        output_path = file_prefix + ".out"
+        if not exists(output_path):
+          print "Could not find %s" % output_path
+          continue
+        result.append(MessageTestCase(test, file_path, output_path, mode,
+                                      self.context, self))
+    return result
+
+  def GetBuildRequirements(self):
+    return ['sample', 'sample=shell']
+
+  def GetTestStatus(self, sections, defs):
+    status_file = join(self.root, 'message.status')
+    if exists(status_file):
+      test.ReadConfigurationInto(status_file, sections, defs)
+
+
+def GetConfiguration(context, root):
+  return MessageTestConfiguration(context, root)
diff --git a/regexp2000/test/message/try-catch-finally-no-message.js b/regexp2000/test/message/try-catch-finally-no-message.js
new file mode 100644 (file)
index 0000000..6459ed8
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() {
+  try {
+    throw "foo";
+  } catch (e) {
+    throw "bar";
+  } finally {
+    return 4;
+  }
+}
+
+function g() {
+  while (true) {
+    try {
+      throw "foo";
+    } catch (e) {
+      throw "bar";
+    } finally {
+      break;
+    }
+  }
+}
+
+f();
+g();
diff --git a/regexp2000/test/message/try-catch-finally-no-message.out b/regexp2000/test/message/try-catch-finally-no-message.out
new file mode 100644 (file)
index 0000000..d85fc7d
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/regexp2000/test/message/try-catch-finally-throw-in-catch-and-finally.js b/regexp2000/test/message/try-catch-finally-throw-in-catch-and-finally.js
new file mode 100644 (file)
index 0000000..164ab69
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  throw "foo";
+} catch (e) {
+  throw "bar";
+} finally {
+  throw "baz";
+}
diff --git a/regexp2000/test/message/try-catch-finally-throw-in-catch-and-finally.out b/regexp2000/test/message/try-catch-finally-throw-in-catch-and-finally.out
new file mode 100644 (file)
index 0000000..e3e2348
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:33: baz
+  throw "baz";
+  ^
diff --git a/regexp2000/test/message/try-catch-finally-throw-in-catch.js b/regexp2000/test/message/try-catch-finally-throw-in-catch.js
new file mode 100644 (file)
index 0000000..afba12c
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  throw "foo";
+} catch (e) {
+  throw "bar";
+} finally {
+  "baz";
+}
diff --git a/regexp2000/test/message/try-catch-finally-throw-in-catch.out b/regexp2000/test/message/try-catch-finally-throw-in-catch.out
new file mode 100644 (file)
index 0000000..618c13c
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:31: bar
+  throw "bar";
+  ^
diff --git a/regexp2000/test/message/try-catch-finally-throw-in-finally.js b/regexp2000/test/message/try-catch-finally-throw-in-finally.js
new file mode 100644 (file)
index 0000000..387df7a
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  throw "foo";
+} catch (e) {
+  "bar"
+} finally {
+  throw "baz";
+}
diff --git a/regexp2000/test/message/try-catch-finally-throw-in-finally.out b/regexp2000/test/message/try-catch-finally-throw-in-finally.out
new file mode 100644 (file)
index 0000000..e3e2348
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:33: baz
+  throw "baz";
+  ^
diff --git a/regexp2000/test/message/try-finally-throw-in-finally.js b/regexp2000/test/message/try-finally-throw-in-finally.js
new file mode 100644 (file)
index 0000000..fbd5764
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  "foo";
+} finally {
+  throw "bar";
+}
diff --git a/regexp2000/test/message/try-finally-throw-in-finally.out b/regexp2000/test/message/try-finally-throw-in-finally.out
new file mode 100644 (file)
index 0000000..618c13c
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:31: bar
+  throw "bar";
+  ^
diff --git a/regexp2000/test/message/try-finally-throw-in-try-and-finally.js b/regexp2000/test/message/try-finally-throw-in-try-and-finally.js
new file mode 100644 (file)
index 0000000..1a9660c
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  throw "foo";
+} finally {
+  throw "bar";
+}
diff --git a/regexp2000/test/message/try-finally-throw-in-try-and-finally.out b/regexp2000/test/message/try-finally-throw-in-try-and-finally.out
new file mode 100644 (file)
index 0000000..618c13c
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:31: bar
+  throw "bar";
+  ^
diff --git a/regexp2000/test/message/try-finally-throw-in-try.js b/regexp2000/test/message/try-finally-throw-in-try.js
new file mode 100644 (file)
index 0000000..428fac9
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  throw "foo";
+} finally {
+  "bar";
+}
diff --git a/regexp2000/test/message/try-finally-throw-in-try.out b/regexp2000/test/message/try-finally-throw-in-try.out
new file mode 100644 (file)
index 0000000..336d4ce
--- /dev/null
@@ -0,0 +1,30 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*%(basename)s:29: foo
+  throw "foo";
+  ^
diff --git a/regexp2000/test/mjsunit/api-call-after-bypassed-exception.js b/regexp2000/test/mjsunit/api-call-after-bypassed-exception.js
new file mode 100644 (file)
index 0000000..f77b514
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2008 the V8 project authors. All rights reserved.\r
+// Redistribution and use in source and binary forms, with or without\r
+// modification, are permitted provided that the following conditions are\r
+// met:\r
+//\r
+//     * Redistributions of source code must retain the above copyright\r
+//       notice, this list of conditions and the following disclaimer.\r
+//     * Redistributions in binary form must reproduce the above\r
+//       copyright notice, this list of conditions and the following\r
+//       disclaimer in the documentation and/or other materials provided\r
+//       with the distribution.\r
+//     * Neither the name of Google Inc. nor the names of its\r
+//       contributors may be used to endorse or promote products derived\r
+//       from this software without specific prior written permission.\r
+//\r
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+
+// This is a test of making an API call after an exception thrown in JavaScript
+// has been bypassed by a return in the finally block.
+function foo() {
+  try {
+    throw "bar";
+  } finally {
+    return "baz";
+  }
+}
+
+foo();
+print({});
diff --git a/regexp2000/test/mjsunit/apply.js b/regexp2000/test/mjsunit/apply.js
new file mode 100644 (file)
index 0000000..1d9dde9
--- /dev/null
@@ -0,0 +1,184 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f0() {
+  return this;
+}
+
+function f1(a) {
+  return a;
+}
+
+assertTrue(this === f0.apply(), "1-0");
+
+assertTrue(this === f0.apply(this), "2a");
+assertTrue(this === f0.apply(this, new Array(1)), "2b");
+assertTrue(this === f0.apply(this, new Array(2)), "2c");
+assertTrue(this === f0.apply(this, new Array(4242)), "2c");
+
+assertTrue(this === f0.apply(null), "3a");
+assertTrue(this === f0.apply(null, new Array(1)), "3b");
+assertTrue(this === f0.apply(null, new Array(2)), "3c");
+assertTrue(this === f0.apply(this, new Array(4242)), "2c");
+
+assertTrue(this === f0.apply(void 0), "4a");
+assertTrue(this === f0.apply(void 0, new Array(1)), "4b");
+assertTrue(this === f0.apply(void 0, new Array(2)), "4c");
+
+assertTrue(void 0 === f1.apply(), "1-1");
+
+assertTrue(void 0 === f1.apply(this), "2a");
+assertTrue(void 0 === f1.apply(this, new Array(1)), "2b");
+assertTrue(void 0 === f1.apply(this, new Array(2)), "2c");
+assertTrue(void 0 === f1.apply(this, new Array(4242)), "2c");
+assertTrue(42 === f1.apply(this, new Array(42, 43)), "2c");
+assertEquals("foo", f1.apply(this, new Array("foo", "bar", "baz", "boo")), "2c");
+
+assertTrue(void 0 === f1.apply(null), "3a");
+assertTrue(void 0 === f1.apply(null, new Array(1)), "3b");
+assertTrue(void 0 === f1.apply(null, new Array(2)), "3c");
+assertTrue(void 0 === f1.apply(null, new Array(4242)), "2c");
+assertTrue(42 === f1.apply(null, new Array(42, 43)), "2c");
+assertEquals("foo", f1.apply(null, new Array("foo", "bar", "baz", "boo")), "2c");
+
+assertTrue(void 0 === f1.apply(void 0), "4a");
+assertTrue(void 0 === f1.apply(void 0, new Array(1)), "4b");
+assertTrue(void 0 === f1.apply(void 0, new Array(2)), "4c");
+assertTrue(void 0 === f1.apply(void 0, new Array(4242)), "4c");
+assertTrue(42 === f1.apply(void 0, new Array(42, 43)), "2c");
+assertEquals("foo", f1.apply(void 0, new Array("foo", "bar", "baz", "boo")), "2c");
+
+var arr = new Array(42, "foo", "fish", "horse");
+function j(a, b, c, d, e, f, g, h, i, j, k, l) {
+  return "" + a + b + c + d + e + f + g + h + i + j + k + l;
+}
+
+
+var expect = "42foofishhorse";
+for (var i = 0; i < 8; i++)
+  expect += "undefined";
+assertEquals(expect, j.apply(undefined, arr));
+
+assertThrows("f0.apply(this, 1);");
+assertThrows("f0.apply(this, 1, 2);");
+assertThrows("f0.apply(this, 1, new Array(2));");
+
+function f() {
+  var doo = "";
+  for (var i = 0; i < arguments.length; i++) {
+    doo += arguments[i];
+  }
+  return doo;
+}
+  
+assertEquals("42foofishhorse", f.apply(this, arr));
+
+function s() {
+  var doo = this;
+  for (var i = 0; i < arguments.length; i++) {
+    doo += arguments[i];
+  }
+  return doo;
+}
+
+assertEquals("bar42foofishhorse", s.apply("bar", arr));
+
+function al() {
+  assertEquals(345, this);
+  return arguments.length + arguments[arguments.length - 1];
+}
+
+for (var j = 1; j < 0x40000000; j <<= 1) {
+  try {
+    var a = new Array(j);
+    a[j - 1] = 42;
+    assertEquals(42 + j, al.apply(345, a));
+  } catch (e) {
+    assertTrue(e.toString().indexOf("Function.prototype.apply") != -1);
+    for (; j < 0x40000000; j <<= 1) {
+      var caught = false;
+      try {
+        a = new Array(j);
+        a[j - 1] = 42;
+        al.apply(345, a);
+        assertEquals("Shouldn't get", "here");
+      } catch (e) {
+        assertTrue(e.toString().indexOf("Function.prototype.apply") != -1);
+        caught = true;
+      }
+      assertTrue(caught);
+    }
+    break;
+  }
+}
+
+var primes = new Array(0);
+
+function isPrime(possible_prime) {
+  for (var d = 0; d < primes.length; d++) {
+    var p = primes[d];
+    if (possible_prime % p == 0)
+      return false;
+    if (p * p > possible_prime)
+      return true;
+  }
+  return true;
+}
+
+for (var i = 2; i < 10000; i++) {
+  if (isPrime(i)) {
+    primes.push(i);
+  }
+}
+
+assertEquals(1229, primes.length);
+
+var same_primes = Array.prototype.constructor.apply(Array, primes);
+
+for (var i = 0; i < primes.length; i++)
+  assertEquals(primes[i], same_primes[i]);
+assertEquals(primes.length, same_primes.length);
+
+
+Array.prototype["1"] = "sep";
+
+var holey = new Array(3);
+holey[0] = "mor";
+holey[2] = "er";
+
+assertEquals("morseper", String.prototype.concat.apply("", holey));
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1));
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2));
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2, 3));
+assertEquals("morseper", String.prototype.concat.apply("", holey, 1, 2, 3, 4));
+
+primes[0] = "";
+primes[1] = holey;
+assertThrows("String.prototype.concat.apply.apply('foo', primes)");
+assertEquals("morseper", String.prototype.concat.apply.apply(String.prototype.concat, primes));
+
+delete(Array.prototype["1"]);
diff --git a/regexp2000/test/mjsunit/arguments-call-apply.js b/regexp2000/test/mjsunit/arguments-call-apply.js
new file mode 100644 (file)
index 0000000..a5cadf5
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function sum(a, b, c) {
+  var result = 0;
+  for (var i = 0; i < arguments.length; i++) {
+    result += arguments[i];
+  }
+  return result;
+}
+
+// Try invoking call before sum has been compiled lazily.
+assertEquals(6, sum.call(this, 1, 2, 3), "lazy call");
+
+assertEquals(6, sum(1, 2, 3), "normal");
+assertEquals(6, sum.call(this, 1, 2, 3), "call");
+assertEquals(6, sum.apply(this, [1, 2, 3]), "apply");
diff --git a/regexp2000/test/mjsunit/arguments-enum.js b/regexp2000/test/mjsunit/arguments-enum.js
new file mode 100644 (file)
index 0000000..f76240f
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function countArguments() {
+  var count = 0;
+  for (var prop in arguments)
+    count++;
+  return count;
+}
+
+function setArgumentCount() {
+  arguments[10] = 5;
+  arguments.x = 4;
+  var count = 0;
+  for (var prop in arguments)
+    count++;
+  return count;
+}
+
+assertEquals(0, countArguments());
+assertEquals(0, countArguments(1));
+assertEquals(0, countArguments(1, 2));
+assertEquals(0, countArguments(1, 2, 3, 4, 5));
+
+assertEquals(0, setArgumentCount());
+assertEquals(0, setArgumentCount(1));
+assertEquals(0, setArgumentCount(1, 2));
+assertEquals(0, setArgumentCount(1, 2, 3, 4, 5));
diff --git a/regexp2000/test/mjsunit/arguments-indirect.js b/regexp2000/test/mjsunit/arguments-indirect.js
new file mode 100644 (file)
index 0000000..2d37027
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f1() {
+  g(f1);
+}
+
+function f2(x) {
+  var a = arguments;
+  x++;
+  g(f2);
+}
+
+
+function g(f) {
+  assertEquals(3, f.arguments.length);
+  assertEquals(1, f.arguments[0]);
+  assertEquals(2, f.arguments[1]);
+  assertEquals(3, f.arguments[2]);
+}
+
+f1(1,2,3);
+f2(0,2,3);
diff --git a/regexp2000/test/mjsunit/arguments-opt.js b/regexp2000/test/mjsunit/arguments-opt.js
new file mode 100644 (file)
index 0000000..c74fc75
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+function L0() {
+  return %_ArgumentsLength();
+}
+
+function L1(a) {
+  return %_ArgumentsLength();
+}
+
+function L5(a,b,c,d,e) {
+  return %_ArgumentsLength();
+}
+
+
+assertEquals(0, L0());
+assertEquals(1, L0(1));
+assertEquals(2, L0(1,2));
+assertEquals(5, L0(1,2,3,4,5));
+
+assertEquals(0, L1());
+assertEquals(1, L1(1));
+assertEquals(2, L1(1,2));
+assertEquals(5, L1(1,2,3,4,5));
+
+assertEquals(0, L5());
+assertEquals(1, L5(1));
+assertEquals(2, L5(1,2));
+assertEquals(5, L5(1,2,3,4,5));
+
+
+function A(key) {
+  return %_Arguments(key);
+}
+
+// Integer access.
+assertEquals(0, A(0));
+assertEquals(0, A(0,1));
+assertEquals(2, A(1,2));
+assertEquals(2, A(1,2,3,4,5));
+assertEquals(5, A(4,2,3,4,5));
+assertTrue(typeof A(1) == 'undefined');
+assertTrue(typeof A(3,2,1) == 'undefined');
+
+// Out-of-bounds integer access with and without argument
+// adaptor frames.
+assertTrue(typeof(A(-10000)) == 'undefined');
+assertTrue(typeof(A(-10000, 0)) == 'undefined');
+assertTrue(typeof(A(-1)) == 'undefined');
+assertTrue(typeof(A(-1, 0)) == 'undefined');
+assertTrue(typeof(A(10000)) == 'undefined');
+assertTrue(typeof(A(10000, 0)) == 'undefined');
+
+// String access.
+assertEquals(0, A('0'));
+assertEquals(0, A('0',1));
+assertEquals(2, A('1',2));
+assertEquals(2, A('1',2,3,4,5));
+assertEquals(5, A('4',2,3,4,5));
+assertTrue(typeof A('1') == 'undefined');
+assertTrue(typeof A('3',2,1) == 'undefined');
+assertEquals(A, A('callee'));
+assertEquals(1, A('length'));
+assertEquals(2, A('length',2));
+assertEquals(5, A('length',2,3,4,5));
+assertEquals({}.toString, A('toString'));
+assertEquals({}.isPrototypeOf, A('isPrototypeOf'));
+assertTrue(typeof A('xxx') == 'undefined');
+
+// Object access.
+function O(key) {
+  return { toString: function() { return key; } };
+}
+
+assertEquals(0, A(O(0)));
+assertEquals(0, A(O(0),1));
+assertEquals(2, A(O(1),2));
+assertEquals(2, A(O(1),2,3,4,5));
+assertEquals(5, A(O(4),2,3,4,5));
+assertTrue(typeof A(O(1)) == 'undefined');
+assertTrue(typeof A(O(3),2,1) == 'undefined');
+
+assertEquals(0, A(O('0')));
+assertEquals(0, A(O('0'),1));
+assertEquals(2, A(O('1'),2));
+assertEquals(2, A(O('1'),2,3,4,5));
+assertEquals(5, A(O('4'),2,3,4,5));
+assertTrue(typeof A(O('1')) == 'undefined');
+assertTrue(typeof A(O('3'),2,1) == 'undefined');
+assertEquals(A, A(O('callee')));
+assertEquals(1, A(O('length')));
+assertEquals(2, A(O('length'),2));
+assertEquals(5, A(O('length'),2,3,4,5));
+assertEquals({}.toString, A(O('toString')));
+assertEquals({}.isPrototypeOf, A(O('isPrototypeOf')));
+assertTrue(typeof A(O('xxx')) == 'undefined');
+
+// Make sure that out-of-bounds access do lookups in the
+// prototype chain.
+Object.prototype[5] = 42;
+assertEquals(42, A(5));
+Object.prototype[-5] = 87;
+assertEquals(87, A(-5));
diff --git a/regexp2000/test/mjsunit/arguments.js b/regexp2000/test/mjsunit/arguments.js
new file mode 100644 (file)
index 0000000..0302739
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function argc0() {
+  return arguments.length;
+}
+
+function argc1(i) {
+  return arguments.length;
+}
+
+function argc2(i, j) {
+  return arguments.length;
+}
+
+assertEquals(0, argc0());
+assertEquals(1, argc0(1));
+assertEquals(2, argc0(1, 2));
+assertEquals(3, argc0(1, 2, 3));
+assertEquals(0, argc1());
+assertEquals(1, argc1(1));
+assertEquals(2, argc1(1, 2));
+assertEquals(3, argc1(1, 2, 3));
+assertEquals(0, argc2());
+assertEquals(1, argc2(1));
+assertEquals(2, argc2(1, 2));
+assertEquals(3, argc2(1, 2, 3));
+
+
+
+var index;
+
+function argv0() {
+  return arguments[index];
+}
+
+function argv1(i) {
+  return arguments[index];
+}
+
+function argv2(i, j) {
+  return arguments[index];
+}
+
+index = 0;
+assertEquals(7, argv0(7));
+assertEquals(7, argv0(7, 8));
+assertEquals(7, argv0(7, 8, 9));
+assertEquals(7, argv1(7));
+assertEquals(7, argv1(7, 8));
+assertEquals(7, argv1(7, 8, 9));
+assertEquals(7, argv2(7));
+assertEquals(7, argv2(7, 8));
+assertEquals(7, argv2(7, 8, 9));
+
+index = 1;
+assertEquals(8, argv0(7, 8));
+assertEquals(8, argv0(7, 8));
+assertEquals(8, argv1(7, 8, 9));
+assertEquals(8, argv1(7, 8, 9));
+assertEquals(8, argv2(7, 8, 9));
+assertEquals(8, argv2(7, 8, 9));
+
+index = 2;
+assertEquals(9, argv0(7, 8, 9));
+assertEquals(9, argv1(7, 8, 9));
+assertEquals(9, argv2(7, 8, 9));
+
+
+// Test that calling a lazily compiled function with
+// an unexpected number of arguments works.
+function f(a) { return arguments.length; };
+assertEquals(3, f(1, 2, 3));
diff --git a/regexp2000/test/mjsunit/array-concat.js b/regexp2000/test/mjsunit/array-concat.js
new file mode 100644 (file)
index 0000000..bb8c570
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Test concat on small and large arrays
+ */
+
+var poses = [140, 4000000000];
+while (pos = poses.shift()) {
+  var a = new Array(pos);
+  assertEquals(pos, a.length);
+  a.push('foo');
+  assertEquals(pos + 1, a.length);
+  var b = ['bar'];
+  var c = a.concat(b);
+  assertEquals(pos + 2, c.length);
+  assertEquals("undefined", typeof(c[pos - 1]));
+  assertEquals("foo", c[pos]);
+  assertEquals("bar", c[pos + 1]);
+
+  // Can we fool the system by putting a number in a string?
+  var onetwofour = "124";
+  a[onetwofour] = 'doo';
+  assertEquals(a[124], 'doo');
+  c = a.concat(b);
+  assertEquals(c[124], 'doo');
+
+  // If we put a number in the prototype, then the spec says it should be
+  // copied on concat.
+  Array.prototype["123"] = 'baz';
+  assertEquals(a[123], 'baz');
+
+  c = a.concat(b);
+  assertEquals(pos + 2, c.length);
+  assertEquals("baz", c[123]);
+  assertEquals("undefined", typeof(c[pos - 1]));
+  assertEquals("foo", c[pos]);
+  assertEquals("bar", c[pos + 1]);
+
+  // When we take the number off the prototype it disappears from a, but
+  // the concat put it in c itself.
+  Array.prototype["123"] = undefined;
+  assertEquals("undefined", typeof(a[123]));
+  assertEquals("baz", c[123]);
+
+  // Non-numeric properties on the prototype or the array shouldn't get
+  // copied.
+  Array.prototype.moe = 'joe';
+  a.ben = 'jerry';
+  assertEquals(a["moe"], 'joe');
+  assertEquals(a["ben"], 'jerry');
+  c = a.concat(b);
+  // ben was not copied
+  assertEquals("undefined", typeof(c.ben));
+  // moe was not copied, but we can see it through the prototype
+  assertEquals("joe", c.moe);
+
+  // When we take moe off the prototype it disappears from all arrays.
+  Array.prototype.moe = undefined;
+  assertEquals("undefined", typeof(c.moe));
+
+  // Negative indeces don't get concated.
+  a[-1] = 'minus1';
+  assertEquals("minus1", a[-1]);
+  assertEquals("undefined", typeof(a[0xffffffff]));
+  c = a.concat(b);
+  assertEquals("undefined", typeof(c[-1]));
+  assertEquals("undefined", typeof(c[0xffffffff]));
+  assertEquals(c.length, a.length + 1);
+
+}
+
+a = [];
+c = a.concat('Hello');
+assertEquals(1, c.length);
+assertEquals("Hello", c[0]);
+assertEquals("Hello", c.toString());
diff --git a/regexp2000/test/mjsunit/array-functions-prototype.js b/regexp2000/test/mjsunit/array-functions-prototype.js
new file mode 100644 (file)
index 0000000..ea0dc61
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file contains a number of tests of array functions and their
+// interaction with properties in the prototype chain.
+//
+// The behavior of SpiderMonkey is slightly different for arrays (see
+// below).  Our behavior is consistent and matches the bahavior of
+// KJS.
+
+var proto = { length:3, 0:'zero', 1:'one', 2:'two' }
+function constructor() {};
+constructor.prototype = proto;
+
+// Set elements on the array prototype.
+Array.prototype[0] = 'zero';
+Array.prototype[1] = 'one';
+Array.prototype[2] = 'two';
+
+// ----------------------------------------------------------------------
+// Helper functions.
+// ----------------------------------------------------------------------
+function assertHasOwnProperties(object, limit) {
+  for (var i = 0; i < limit; i++) {
+    assertTrue(object.hasOwnProperty(i));
+  }
+}
+
+
+// ----------------------------------------------------------------------
+// shift.
+// ----------------------------------------------------------------------
+
+function runTest() {
+  var nonArray = new constructor();
+  var array = ['zero', , 'two'];
+  // Shift away the zero.
+  assertEquals('zero', array.shift());
+  assertEquals('zero', Array.prototype.shift.call(nonArray));
+  // Check that the local object has properties 0 and 1 with the right
+  // values.
+  assertEquals(2, array.length);
+  assertEquals(2, nonArray.length);
+  assertHasOwnProperties(array, 2);
+  assertHasOwnProperties(nonArray, 2);
+  // Note: Spidermonkey is inconsistent here.  It treats arrays
+  // differently from non-arrays.  It only consults the prototype for
+  // non-arrays.  Therefore, array[0] is undefined in Spidermonkey and
+  // 'one' in V8 and KJS.
+  assertEquals('one', array[0]);
+  assertEquals('one', nonArray[0]);
+  assertEquals('two', array[1]);
+  assertEquals('two', nonArray[1]);
+  // Get index 2 from the prototype.
+  assertEquals('two', array[2]);
+  assertEquals('two', nonArray[2]);
+}
+
+runTest();
+
+// ----------------------------------------------------------------------
+// unshift.
+// ----------------------------------------------------------------------
+
+runTest = function() {
+  var nonArray = new constructor();
+  var array = ['zero', , 'two'];
+  // Unshift a new 'zero'.
+  assertEquals(4, array.unshift('zero'));
+  assertEquals(4, Array.prototype.unshift.call(nonArray, 'zero'));
+  // Check that the local object has properties 0 through 3 with the
+  // right values.
+  assertEquals(4, array.length);
+  assertEquals(4, nonArray.length);
+  assertHasOwnProperties(array, 4);
+  assertHasOwnProperties(nonArray, 4);
+  assertEquals('zero', array[0]);
+  assertEquals('zero', nonArray[0]);
+  assertEquals('zero', array[1]);
+  assertEquals('zero', nonArray[1]);
+  // Again Spidermonkey is inconsistent.  array[2] is undefined
+  // instead of 'one'.
+  assertEquals('one', array[2]);
+  assertEquals('one', nonArray[2]);
+  assertEquals('two', array[3]);
+  assertEquals('two', nonArray[3]);
+}
+
+runTest();
+
+
+// ----------------------------------------------------------------------
+// splice
+// ----------------------------------------------------------------------
+
+runTest = function() {
+  var nonArray = new constructor();
+  var array = ['zero', , 'two'];
+  // Delete the first element by splicing in nothing.
+  assertArrayEquals(['zero'], array.splice(0, 1));
+  assertArrayEquals(['zero'], Array.prototype.splice.call(nonArray, 0, 1));
+  // Check that the local object has properties 0 and 1 with the right
+  // values.
+  assertEquals(2, array.length);
+  assertEquals(2, nonArray.length);
+  assertHasOwnProperties(array, 2);
+  assertHasOwnProperties(nonArray, 2);
+  // Again Spidermonkey is inconsistent.  array[0] is undefined
+  // instead of 'one'.
+  assertEquals('one', array[0]);
+  assertEquals('one', nonArray[0]);
+  assertEquals('two', array[1]);
+  assertEquals('two', nonArray[1]);
+  // Get index 2 from the prototype.
+  assertEquals('two', array[2]);
+  assertEquals('two', nonArray[2]);
+};
+
+runTest();
+
+
+// ----------------------------------------------------------------------
+// slice
+// ----------------------------------------------------------------------
+
+runTest = function() {
+  var nonArray = new constructor();
+  var array = ['zero', , 'two'];
+  // Again Spidermonkey is inconsistent.  (array.slice(0, 3))[1] is
+  // undefined instead of 'one'.
+  assertArrayEquals(['zero', 'one', 'two'], array.slice(0, 3));
+  assertArrayEquals(['zero', 'one', 'two'], Array.prototype.slice.call(nonArray, 0, 3));
+};
+
+runTest();
diff --git a/regexp2000/test/mjsunit/array-indexing.js b/regexp2000/test/mjsunit/array-indexing.js
new file mode 100644 (file)
index 0000000..2322c54
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var array = [1,2,3,1,2,3,1,2,3,1,2,3];
+
+// ----------------------------------------------------------------------
+// Array.prototype.indexOf.
+// ----------------------------------------------------------------------
+
+// Negative cases.
+assertEquals([].indexOf(1), -1);
+assertEquals(array.indexOf(4), -1);
+assertEquals(array.indexOf(3, array.length), -1);
+
+assertEquals(array.indexOf(3), 2);
+// Negative index out of range.
+assertEquals(array.indexOf(1, -17), 0);
+// Negative index in rage.
+assertEquals(array.indexOf(1, -11), 3);
+// Index in range.
+assertEquals(array.indexOf(1, 1), 3);
+assertEquals(array.indexOf(1, 3), 3);
+assertEquals(array.indexOf(1, 4), 6);
+
+// ----------------------------------------------------------------------
+// Array.prototype.lastIndexOf.
+// ----------------------------------------------------------------------
+
+// Negative cases.
+assertEquals([].lastIndexOf(1), -1);
+assertEquals(array.lastIndexOf(1, -17), -1);
+
+assertEquals(array.lastIndexOf(1), 9);
+// Index out of range.
+assertEquals(array.lastIndexOf(1, array.length), 9);
+// Index in range.
+assertEquals(array.lastIndexOf(1, 2), 0);
+assertEquals(array.lastIndexOf(1, 4), 3);
+assertEquals(array.lastIndexOf(1, 3), 3);
+// Negative index in range.
+assertEquals(array.lastIndexOf(1, -11), 0);
+
diff --git a/regexp2000/test/mjsunit/array-iteration.js b/regexp2000/test/mjsunit/array-iteration.js
new file mode 100644 (file)
index 0000000..f11b51c
--- /dev/null
@@ -0,0 +1,228 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests for non-standard array iteration functions.
+//
+// See
+//
+// <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array>
+//
+// for an explanation of each of the functions.
+
+//
+// Array.prototype.filter
+//
+(function() {
+  // Simple use.
+  var a = [0,1];
+  assertArrayEquals([0], a.filter(function(n) { return n == 0; }));
+  assertArrayEquals(a, a);
+
+  // Use specified object as this object when calling the function.
+  var o = { value: 42 }
+  a = [1,42,3,42,4];
+  assertArrayEquals([42,42], a.filter(function(n) { return this.value == n }, o))
+
+  // Modify original array.
+  a = [1,42,3,42,4];
+  assertArrayEquals([42,42], a.filter(function(n, index, array) { array[index] = 43; return 42 == n; }));
+  assertArrayEquals([43,43,43,43,43], a);
+
+  // Only loop through initial part of array eventhough elements are
+  // added.
+  a = [1,1];
+  assertArrayEquals([], a.filter(function(n, index, array) { array.push(n+1); return n == 2; }));
+  assertArrayEquals([1,1,2,2], a);
+
+  // Respect holes.
+  a = new Array(20);
+  var count = 0;
+  a[2] = 2;
+  a[15] = 2;
+  a[17] = 4;
+  var a = a.filter(function(n) { count++; return n == 2; });
+  assertEquals(3, count);
+  for (var i in a) assertEquals(2, a[i]);
+
+})();
+
+
+//
+// Array.prototype.forEach
+//
+(function() {
+  // Simple use.
+  var a = [0,1];
+  var count = 0;
+  a.forEach(function(n) { count++; });
+  assertEquals(2, count);
+
+  // Use specified object as this object when calling the function.
+  var o = { value: 42 }
+  var result = [];
+  a.forEach(function(n) { result.push(this.value); }, o);
+  assertArrayEquals([42,42], result);
+
+  // Modify original array.
+  a = [0,1];
+  count = 0;
+  a.forEach(function(n, index, array) { array[index] = n + 1; count++; });
+  assertEquals(2, count);
+  assertArrayEquals([1,2], a);
+
+  // Only loop through initial part of array eventhough elements are
+  // added.
+  a = [1,1];
+  count = 0;
+  a.forEach(function(n, index, array) { array.push(n+1); count++; });
+  assertEquals(2, count);
+  assertArrayEquals([1,1,2,2], a);
+
+  // Respect holes.
+  a = new Array(20);
+  count = 0;
+  a[15] = 2;
+  a.forEach(function(n) { count++; });
+  assertEquals(1, count);
+
+})();
+
+
+//
+// Array.prototype.every
+//
+(function() {
+  // Simple use.
+  var a = [0,1];
+  assertFalse(a.every(function(n) { return n == 0 }));
+  a = [0,0];
+  assertTrue(a.every(function(n) { return n == 0 }));
+  assertTrue([].every(function(n) { return n == 0}));
+
+  // Use specified object as this object when calling the function.
+  var o = { value: 42 }
+  a = [0];
+  assertFalse(a.every(function(n) { return this.value == n; }, o));
+  a = [42];
+  assertTrue(a.every(function(n) { return this.value == n; }, o));
+
+  // Modify original array.
+  a = [0,1];
+  assertFalse(a.every(function(n, index, array) { array[index] = n + 1; return n == 1;}));
+  assertArrayEquals([1,1], a);
+  
+  // Only loop through initial part of array eventhough elements are
+  // added.
+  a = [1,1];
+  assertTrue(a.every(function(n, index, array) { array.push(n + 1); return n == 1;}));
+  assertArrayEquals([1,1,2,2], a);
+
+  // Respect holes.
+  a = new Array(20);
+  var count = 0;
+  a[2] = 2;
+  a[15] = 2;
+  assertTrue(a.every(function(n) { count++; return n == 2; }));
+  assertEquals(2, count);
+
+})();
+
+//
+// Array.prototype.map
+//
+(function() {
+  var a = [0,1,2,3,4];
+  
+  // Simple use.
+  var result = [1,2,3,4,5];
+  assertArrayEquals(result, a.map(function(n) { return n + 1; }));
+  assertEquals(a, a);
+  
+  // Use specified object as this object when calling the function.
+  var o = { delta: 42 }
+  result = [42,43,44,45,46];
+  assertArrayEquals(result, a.map(function(n) { return this.delta + n; }, o));
+  
+  // Modify original array.
+  a = [0,1,2,3,4];
+  result = [1,2,3,4,5];
+  assertArrayEquals(result, a.map(function(n, index, array) { array[index] = n + 1; return n + 1;}));
+  assertArrayEquals(result, a);
+  
+  // Only loop through initial part of array eventhough elements are
+  // added.
+  a = [0,1,2,3,4];
+  result = [1,2,3,4,5];
+  assertArrayEquals(result, a.map(function(n, index, array) { array.push(n); return n + 1;}));
+  assertArrayEquals([0,1,2,3,4,0,1,2,3,4], a);
+
+  // Respect holes.
+  a = new Array(20);
+  a[15] = 2;
+  a = a.map(function(n) { return 2*n; });
+  for (var i in a) assertEquals(4, a[i]);
+
+})();
+
+//
+// Array.prototype.some
+//
+(function() {
+  var a = [0,1,2,3,4];
+
+  // Simple use.
+  assertTrue(a.some(function(n) { return n == 3}));
+  assertFalse(a.some(function(n) { return n == 5}));
+  
+  // Use specified object as this object when calling the function.
+  var o = { element: 42 };
+  a = [1,42,3];
+  assertTrue(a.some(function(n) { return this.element == n; }, o));
+  a = [1];
+  assertFalse(a.some(function(n) { return this.element == n; }, o));
+
+  // Modify original array.
+  a = [0,1,2,3];
+  assertTrue(a.some(function(n, index, array) { array[index] = n + 1; return n == 2; }));
+  assertArrayEquals([1,2,3,3], a);
+
+  // Only loop through initial part when elements are added.
+  a = [0,1,2];
+  assertFalse(a.some(function(n, index, array) { array.push(42); return n == 42; }));
+  assertArrayEquals([0,1,2,42,42,42], a);
+
+  // Respect holes.
+  a = new Array(20);
+  var count = 0;
+  a[2] = 42;
+  a[10] = 2;
+  a[15] = 42;
+  assertTrue(a.some(function(n) { count++; return n == 2; }));
+  assertEquals(2, count);
+
+})();
+
diff --git a/regexp2000/test/mjsunit/array-join.js b/regexp2000/test/mjsunit/array-join.js
new file mode 100644 (file)
index 0000000..c66e462
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that array join calls toString on subarrays.
+var a = [[1,2],3,4,[5,6]];
+assertEquals('1,2*3*4*5,6', a.join('*'));
+
+// Create a cycle.
+a.push(a);
+assertEquals('1,2*3*4*5,6*', a.join('*'));
+
+// Replace array.prototype.toString.
+Array.prototype.toString = function() { return "array"; }
+assertEquals('array*3*4*array*array', a.join('*'));
+
+Array.prototype.toString = function() { throw 42; }
+assertThrows("a.join('*')");
+
+Array.prototype.toString = function() { return "array"; }
+assertEquals('array*3*4*array*array', a.join('*'));
+
diff --git a/regexp2000/test/mjsunit/array-length.js b/regexp2000/test/mjsunit/array-length.js
new file mode 100644 (file)
index 0000000..9731e7a
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var a = [0,1,2,3];
+a.length = 0;
+
+assertEquals('undefined', typeof a[0]);
+assertEquals('undefined', typeof a[1]);
+assertEquals('undefined', typeof a[2]);
+assertEquals('undefined', typeof a[3]);
+
+
+var a = [0,1,2,3];
+a.length = 2;
+
+assertEquals(0, a[0]);
+assertEquals(1, a[1]);
+assertEquals('undefined', typeof a[2]);
+assertEquals('undefined', typeof a[3]);
+
+
+var a = new Array();
+a[0] = 0;
+a[1000] = 1000;
+a[1000000] = 1000000;
+a[2000000] = 2000000;
+
+assertEquals(2000001, a.length);
+a.length = 0;
+assertEquals(0, a.length);
+assertEquals('undefined', typeof a[0]);
+assertEquals('undefined', typeof a[1000]);
+assertEquals('undefined', typeof a[1000000]);
+assertEquals('undefined', typeof a[2000000]);
+
+
+var a = new Array();
+a[0] = 0;
+a[1000] = 1000;
+a[1000000] = 1000000;
+a[2000000] = 2000000;
+
+assertEquals(2000001, a.length);
+a.length = 2000;
+assertEquals(2000, a.length);
+assertEquals(0, a[0]);
+assertEquals(1000, a[1000]);
+assertEquals('undefined', typeof a[1000000]);
+assertEquals('undefined', typeof a[2000000]);
+
+
+var a = new Array();
+a[Math.pow(2,31)-1] = 0;
+a[Math.pow(2,30)-1] = 0;
+assertEquals(Math.pow(2,31), a.length);
+
+
+var a = new Array();
+a[0] = 0;
+a[1000] = 1000;
+a[Math.pow(2,30)-1] = Math.pow(2,30)-1;
+a[Math.pow(2,31)-1] = Math.pow(2,31)-1;
+a[Math.pow(2,32)-2] = Math.pow(2,32)-2;
+
+assertEquals(Math.pow(2,30)-1, a[Math.pow(2,30)-1]);
+assertEquals(Math.pow(2,31)-1, a[Math.pow(2,31)-1]);
+assertEquals(Math.pow(2,32)-2, a[Math.pow(2,32)-2]);
+
+assertEquals(Math.pow(2,32)-1, a.length);
+a.length = Math.pow(2,30)+1;  // not a smi!
+assertEquals(Math.pow(2,30)+1, a.length);
+
+assertEquals(0, a[0]);
+assertEquals(1000, a[1000]);
+assertEquals(Math.pow(2,30)-1, a[Math.pow(2,30)-1]);
+assertEquals('undefined', typeof a[Math.pow(2,31)-1]);
+assertEquals('undefined', typeof a[Math.pow(2,32)-2], "top");
+
+
+var a = new Array();
+a.length = new Number(12);
+assertEquals(12, a.length);
+
+
+var o = { length: -23 };
+Array.prototype.pop.apply(o);
+assertEquals(4294967272, o.length);
diff --git a/regexp2000/test/mjsunit/array-sort.js b/regexp2000/test/mjsunit/array-sort.js
new file mode 100644 (file)
index 0000000..dfa4590
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Test array sort.
+
+// Test counter-intuitive default number sorting.
+function TestNumberSort() {
+  var a = [ 200, 45, 7 ];
+
+  // Default sort converts each element to string and orders
+  // lexicographically.
+  a.sort();
+  assertArrayEquals([ 200, 45, 7 ], a);
+  // Sort numbers by value using a compare functions.
+  a.sort(function(x, y) { return x - y; });
+  assertArrayEquals([ 7, 45, 200 ], a);
+
+  // Default sort on negative numbers.
+  a = [-12345,-123,-1234,-123456];
+  a.sort();
+  assertArrayEquals([-123,-1234,-12345,-123456], a);
+
+  // Default sort on negative and non-negative numbers.
+  a = [123456,0,-12345,-123,123,1234,-1234,0,12345,-123456];
+  a.sort();
+  assertArrayEquals([-123,-1234,-12345,-123456,0,0,123,1234,12345,123456], a);
+
+  // Tricky case avoiding integer overflow in Runtime_SmiLexicographicCompare.
+  a = [9, 1000000000].sort();
+  assertArrayEquals([1000000000, 9], a);
+  a = [1000000000, 1].sort();
+  assertArrayEquals([1, 1000000000], a);
+  a = [1000000000, 0].sort();
+  assertArrayEquals([0, 1000000000], a);
+
+  // One string is a prefix of the other.
+  a = [1230, 123].sort();
+  assertArrayEquals([123, 1230], a);
+  a = [1231, 123].sort();
+  assertArrayEquals([123, 1231], a);
+
+  // Default sort on Smis and non-Smis.
+  a = [1000000000, 10000000000, 1000000001, -1000000000, -10000000000, -1000000001];
+  a.sort();
+  assertArrayEquals([-1000000000, -10000000000, -1000000001, 1000000000, 10000000000, 1000000001], a);
+
+
+  for (var xb = 1; xb <= 1000 * 1000 * 1000; xb *= 10) {
+    for (var xf = 0; xf <= 9; xf++) {
+      for (var xo = -1; xo <= 1; xo++) {
+        for (var yb = 1; yb <= 1000 * 1000 * 1000; yb *= 10) {
+          for (var yf = 0; yf <= 9; yf++) {
+            for (var yo = -1; yo <= 1; yo++) {
+              var x = xb * xf + xo;
+              var y = yb * yf + yo;
+              if (!%_IsSmi(x)) continue;
+              if (!%_IsSmi(y)) continue;
+              var lex = %SmiLexicographicCompare(x, y);
+              if (lex < 0) lex = -1;
+              if (lex > 0) lex = 1;
+              assertEquals(lex, (x == y) ? 0 : ((x + "") < (y + "") ? -1 : 1), x + " < " + y);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+TestNumberSort();
+
+
+// Test lexicographical string sorting.
+function TestStringSort() {
+  var a = [ "cc", "c", "aa", "a", "bb", "b", "ab", "ac" ];
+  a.sort();
+  assertArrayEquals([ "a", "aa", "ab", "ac", "b", "bb", "c", "cc" ], a);
+}
+
+TestStringSort();
+
+
+// Test object sorting.  Calls toString on each element and sorts
+// lexicographically.
+function TestObjectSort() {
+  var obj0 = { toString: function() { return "a"; } };
+  var obj1 = { toString: function() { return "b"; } };
+  var obj2 = { toString: function() { return "c"; } };
+  var a = [ obj2, obj0, obj1 ];
+  a.sort();
+  assertArrayEquals([ obj0, obj1, obj2 ], a);
+}
+
+TestObjectSort();
+
+// Test array sorting with holes in the array.
+function TestArraySortingWithHoles() {
+  var a = [];
+  a[4] = "18";
+  a[10] = "12";
+  a.sort();
+  assertEquals(11, a.length);
+  assertEquals("12", a[0]);
+  assertEquals("18", a[1]);
+}
+
+TestArraySortingWithHoles();
+
+// Test array sorting with undefined elemeents in the array.
+function TestArraySortingWithUndefined() {
+  var a = [ 3, void 0, 2 ];
+  a.sort();
+  assertArrayEquals([ 2, 3, void 0 ], a);
+}
+
+TestArraySortingWithUndefined();
+
+// Test that sorting using an unsound comparison function still gives a
+// sane result, i.e. it terminates without error and retains the elements
+// in the array.
+function TestArraySortingWithUnsoundComparisonFunction() {
+  var a = [ 3, void 0, 2 ];
+  a.sort(function(x, y) { return 1; });
+  a.sort();
+  assertArrayEquals([ 2, 3, void 0 ], a);
+}
+
+TestArraySortingWithUnsoundComparisonFunction();
diff --git a/regexp2000/test/mjsunit/array-splice-webkit.js b/regexp2000/test/mjsunit/array-splice-webkit.js
new file mode 100644 (file)
index 0000000..113a56a
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Simple splice tests based on webkit layout tests.
+var arr = ['a','b','c','d'];
+assertArrayEquals(['a','b','c','d'], arr);
+assertArrayEquals(['c','d'], arr.splice(2));
+assertArrayEquals(['a','b'], arr);
+assertArrayEquals(['a','b'], arr.splice(0));
+assertArrayEquals([], arr)
+
+arr = ['a','b','c','d'];
+assertEquals(undefined, arr.splice())
+assertArrayEquals(['a','b','c','d'], arr);
+assertArrayEquals(['a','b','c','d'], arr.splice(undefined))
+assertArrayEquals([], arr);
+
+arr = ['a','b','c','d'];
+assertArrayEquals(['a','b','c','d'], arr.splice(null))
+assertArrayEquals([], arr);
+
+arr = ['a','b','c','d'];
+assertArrayEquals([], arr.splice(100))
+assertArrayEquals(['a','b','c','d'], arr);
+assertArrayEquals(['d'], arr.splice(-1))
+assertArrayEquals(['a','b','c'], arr);
+
+assertArrayEquals([], arr.splice(2, undefined))
+assertArrayEquals([], arr.splice(2, null))
+assertArrayEquals([], arr.splice(2, -1))
+assertArrayEquals([], arr.splice(2, 0))
+assertArrayEquals(['a','b','c'], arr);
+assertArrayEquals(['c'], arr.splice(2, 100))
+assertArrayEquals(['a','b'], arr);
+
+
diff --git a/regexp2000/test/mjsunit/array-splice.js b/regexp2000/test/mjsunit/array-splice.js
new file mode 100644 (file)
index 0000000..b5e85c6
--- /dev/null
@@ -0,0 +1,313 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Test splice, shift, unshift, slice and join on small
+ * and large arrays.  Some of these methods are specified such that they
+ * should work on other objects too, so we test that too.
+ */
+
+var LARGE = 40000000;
+var VERYLARGE = 4000000000;
+
+// Nicer for firefox 1.5.  Unless you uncomment the following two lines,
+// smjs will appear to hang on this file.
+//var LARGE = 40000;
+//var VERYLARGE = 40000;
+
+var fourhundredth = LARGE/400;
+
+function PseudoArray() {
+};
+
+for (var use_real_arrays = 0; use_real_arrays <= 1; use_real_arrays++) {
+  var poses = [0, 140, 40000, VERYLARGE];
+  var the_prototype;
+  var new_function;
+  var push_function;
+  var concat_function;
+  var slice_function;
+  var splice_function;
+  var splice_function_2;
+  var unshift_function;
+  var unshift_function_2;
+  var shift_function;
+  if (use_real_arrays) {
+    new_function = function(length) {
+      return new Array(length);
+    };
+    the_prototype = Array.prototype;
+    push_function = function(array, elt) {
+      return array.push(elt);
+    };
+    concat_function = function(array, other) {
+      return array.concat(other);
+    };
+    slice_function = function(array, start, len) {
+      return array.slice(start, len);
+    };
+    splice_function = function(array, start, len) {
+      return array.splice(start, len);
+    };
+    splice_function_2 = function(array, start, len, elt) {
+      return array.splice(start, len, elt);
+    };
+    unshift_function = function(array, elt) {
+      return array.unshift(elt);
+    };
+    unshift_function_2 = function(array, elt1, elt2) {
+      return array.unshift(elt1, elt2);
+    };
+    shift_function = function(array) {
+      return array.shift();
+    };
+  } else {
+    // Don't run largest size on non-arrays or we'll be here for ever.
+    poses.pop();
+    new_function = function(length) {
+      var obj = new PseudoArray();
+      obj.length = length;
+      return obj;
+    };
+    the_prototype = PseudoArray.prototype;
+    push_function = function(array, elt) {
+      array[array.length] = elt;
+      array.length++;
+    };
+    concat_function = function(array, other) {
+      return Array.prototype.concat.call(array, other);
+    };
+    slice_function = function(array, start, len) {
+      return Array.prototype.slice.call(array, start, len);
+    };
+    splice_function = function(array, start, len) {
+      return Array.prototype.splice.call(array, start, len);
+    };
+    splice_function_2 = function(array, start, len, elt) {
+      return Array.prototype.splice.call(array, start, len, elt);
+    };
+    unshift_function = function(array, elt) {
+      return Array.prototype.unshift.call(array, elt);
+    };
+    unshift_function_2 = function(array, elt1, elt2) {
+      return Array.prototype.unshift.call(array, elt1, elt2);
+    };
+    shift_function = function(array) {
+      return Array.prototype.shift.call(array);
+    };
+  }
+
+  for (var pos_pos = 0; pos_pos < poses.length; pos_pos++) {
+    var pos = poses[pos_pos];
+    if (pos > 100) {
+      var a = new_function(pos);
+      assertEquals(pos, a.length);
+      push_function(a, 'foo');
+      assertEquals(pos + 1, a.length);
+      var b = ['bar'];
+      // Delete a huge number of holes.
+      var c = splice_function(a, 10, pos - 20);
+      assertEquals(pos - 20, c.length);
+      assertEquals(21, a.length);
+    }
+
+    // Add a numeric property to the prototype of the array class.  This
+    // allows us to test some borderline stuff relative to the standard.
+    the_prototype["" + (pos + 1)] = 'baz';
+
+    if (use_real_arrays) {
+      // It seems quite clear from ECMAScript spec 15.4.4.5.  Just call Get on
+      // every integer in the range.
+      // IE, Safari get this right.
+      // FF, Opera get this wrong.
+      var a = ['zero', ,'two'];
+      if (pos == 0) {
+        assertEquals("zero,baz,two", a.join(","));
+      }
+
+      // Concat only applies to real arrays, unlike most of the other methods.
+      var a = new_function(pos);
+      push_function(a, "con");
+      assertEquals("con", a[pos]);
+      assertEquals(pos + 1, a.length);
+      var b = new_function(0);
+      push_function(b, "cat");
+      assertEquals("cat", b[0]);
+      var ab = concat_function(a, b);
+      assertEquals("con", ab[pos]);
+      assertEquals(pos + 2, ab.length);
+      assertEquals("cat", ab[pos + 1]);
+      var ba = concat_function(b, a);
+      assertEquals("con", ba[pos + 1]);
+      assertEquals(pos + 2, ba.length);
+      assertEquals("cat", ba[0]);
+
+      // Join with '' as separator.
+      var join = a.join('');
+      assertEquals("con", join);
+      join = b.join('');
+      assertEquals("cat", join);
+      join = ab.join('');
+      assertEquals("concat", join);
+      join = ba.join('');
+      assertEquals("catcon", join);
+
+      var sparse = [];
+      sparse[pos + 1000] = 'is ';
+      sparse[pos + 271828] = 'time ';
+      sparse[pos + 31415] = 'the ';
+      sparse[pos + 012260199] = 'all ';
+      sparse[-1] = 'foo';
+      sparse[pos + 22591927] = 'good ';
+      sparse[pos + 1618033] = 'for ';
+      sparse[pos + 91] = ': Now ';
+      sparse[pos + 86720199] = 'men.';
+      sparse.hest = 'fisk';
+
+      assertEquals("baz: Now is the time for all good men.", sparse.join(''));
+    }
+
+    a = new_function(pos);
+    push_function(a, 'zero');
+    push_function(a, void 0);
+    push_function(a, 'two');
+
+    // Splice works differently from join.
+    // IE, Safari get this wrong.
+    // FF, Opera get this right.
+    // 15.4.4.12 line 24 says the object itself has to have the property...
+    var zero = splice_function(a, pos, 1);
+    assertEquals("undefined", typeof(a[pos]));
+    assertEquals("two", a[pos+1], "pos1:" + pos);
+    assertEquals(pos + 2, a.length, "a length");
+    assertEquals(1, zero.length, "zero length");
+    assertEquals("zero", zero[0]);
+
+    // 15.4.4.12 line 41 says the object itself has to have the property...
+    a = new_function(pos);
+    push_function(a, 'zero');
+    push_function(a, void 0);
+    push_function(a, 'two');
+    var nothing = splice_function_2(a, pos, 0, 'minus1');
+    assertEquals("minus1", a[pos]);
+    assertEquals("zero", a[pos+1]);
+    assertEquals("undefined", typeof(a[pos+2]), "toot!");
+    assertEquals("two", a[pos+3], "pos3");
+    assertEquals(pos + 4, a.length);
+    assertEquals(1, zero.length);
+    assertEquals("zero", zero[0]);
+
+    // 15.4.4.12 line 10 says the object itself has to have the property...
+    a = new_function(pos);
+    push_function(a, 'zero');
+    push_function(a, void 0);
+    push_function(a, 'two');
+    var one = splice_function(a, pos + 1, 1);
+    assertEquals("", one.join(","));
+    assertEquals(pos + 2, a.length);
+    assertEquals("zero", a[pos]);
+    assertEquals("two", a[pos+1]);
+
+    // Set things back to the way they were.
+    the_prototype[pos + 1] = undefined;
+
+    // Unshift.
+    var a = new_function(pos);
+    push_function(a, "foo");
+    assertEquals("foo", a[pos]);
+    assertEquals(pos + 1, a.length);
+    unshift_function(a, "bar");
+    assertEquals("foo", a[pos+1]);
+    assertEquals(pos + 2, a.length);
+    assertEquals("bar", a[0]);
+    unshift_function_2(a, "baz", "boo");
+    assertEquals("foo", a[pos+3]);
+    assertEquals(pos + 4, a.length);
+    assertEquals("baz", a[0]);
+    assertEquals("boo", a[1]);
+    assertEquals("bar", a[2]);
+
+    // Shift.
+    var baz = shift_function(a);
+    assertEquals("baz", baz);
+    assertEquals("boo", a[0]);
+    assertEquals(pos + 3, a.length);
+    assertEquals("foo", a[pos + 2]);
+
+    // Slice.
+    var bar = slice_function(a, 1, 0);  // don't throw an exception please.
+    bar = slice_function(a, 1, 2);
+    assertEquals("bar", bar[0]);
+    assertEquals(1, bar.length);
+    assertEquals("bar", a[1]);
+
+  }
+}
+
+// Lets see if performance is reasonable.
+
+var a = new Array(LARGE + 10);
+for (var i = 0; i < a.length; i += 1000) {
+  a[i] = i;
+}
+
+// Take something near the end of the array.
+for (var i = 0; i < 100; i++) {
+  var top = a.splice(LARGE, 5);
+  assertEquals(5, top.length);
+  assertEquals(LARGE, top[0]);
+  assertEquals("undefined", typeof(top[1]));
+  assertEquals(LARGE + 5, a.length);
+  a.splice(LARGE, 0, LARGE);
+  a.length = LARGE + 10;
+}
+
+var a = new Array(LARGE + 10);
+for (var i = 0; i < a.length; i += fourhundredth) {
+  a[i] = i;
+}
+
+// Take something near the middle of the array.
+for (var i = 0; i < 10; i++) {
+  var top = a.splice(LARGE >> 1, 5);
+  assertEquals(5, top.length);
+  assertEquals(LARGE >> 1, top[0]);
+  assertEquals("undefined", typeof(top[1]));
+  assertEquals(LARGE + 5, a.length);
+  a.splice(LARGE >> 1, 0, LARGE >> 1, void 0, void 0, void 0, void 0);
+}
+
+
+// Test http://b/issue?id=1202711
+arr = [0];
+arr.length = 2;
+Array.prototype[1] = 1;
+assertEquals(1, arr.pop());
+assertEquals(0, arr.pop());
+Array.prototype[1] = undefined;
+
+
diff --git a/regexp2000/test/mjsunit/array_length.js b/regexp2000/test/mjsunit/array_length.js
new file mode 100644 (file)
index 0000000..11808af
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A reduced test case from Acid3 test 95.
+// When an object is assigned to an array length field,
+// it is converted to a number.
+
+function CheckSetArrayLength(x, expected) {
+  var a = [];
+  a.length = x;
+
+  assertEquals("number", typeof a.length);
+  assertEquals(expected, a.length);
+}
+
+CheckSetArrayLength(2147483648, 2147483648);
+CheckSetArrayLength("2147483648", 2147483648);
+CheckSetArrayLength(null, 0);
+CheckSetArrayLength(false, 0);
+CheckSetArrayLength(true, 1);
+CheckSetArrayLength({valueOf : function() { return 42; }}, 42);
+CheckSetArrayLength({toString : function() { return '42'; }}, 42);
+
+// Test invalid values
+assertThrows("var y = []; y.length = 'abc';");
+assertThrows("var y = []; y.length = undefined;");
+assertThrows("var y = []; y.length = {};");
+assertThrows("var y = []; y.length = -1;");
+assertThrows("var y = []; y.length = {valueOf:function() { throw new Error(); }};");
diff --git a/regexp2000/test/mjsunit/ascii-regexp-subject.js b/regexp2000/test/mjsunit/ascii-regexp-subject.js
new file mode 100644 (file)
index 0000000..01d0697
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Check that an initial ^ will result in a faster match fail.
+ */
+
+
+var s = "foo";
+var i;
+
+for (i = 0; i < 18; i++) {
+  s = s + s;
+}
+
+var re = /^bar/;
+
+for (i = 0; i < 1000; i++) {
+  re.test(s);
+  re = new RegExp("^bar");
+}
diff --git a/regexp2000/test/mjsunit/binary-operation-overwrite.js b/regexp2000/test/mjsunit/binary-operation-overwrite.js
new file mode 100644 (file)
index 0000000..8d217c5
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ensure that literals are not overwritten.
+function f1() { return (1.2, 3.4) + 5.6; }
+function f2() { return (1, 2) + 3; }
+function f3() { return (1.2 || 3.4) + 5.6; }
+function f4() { return (1 || 2) + 3; }
+assertTrue(f1() === f1());
+assertTrue(f2() === f2());
+assertTrue(f3() === f3());
+assertTrue(f4() === f4());
diff --git a/regexp2000/test/mjsunit/body-not-visible.js b/regexp2000/test/mjsunit/body-not-visible.js
new file mode 100644 (file)
index 0000000..c681ab3
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure we cannot see the local variables in NewFunction when
+// compiling functions using new Function().
+
+var caught = false;
+try {
+  (new Function("return body;"))();
+  assertTrue(false);
+} catch (e) {
+  caught = true;
+  assertTrue(e instanceof ReferenceError);
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/bugs/bug-1231206.js b/regexp2000/test/mjsunit/bugs/bug-1231206.js
new file mode 100644 (file)
index 0000000..04b296b
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// When calling user-defined functions on strings, booleans or
+// numbers, we should create a wrapper object.
+
+function TypeOfThis() { return typeof this; }
+
+String.prototype.TypeOfThis = TypeOfThis;
+Boolean.prototype.TypeOfThis = TypeOfThis;
+Number.prototype.TypeOfThis = TypeOfThis;
+
+assertEquals('object', 'xxx'.TypeOfThis());
+assertEquals('object', true.TypeOfThis());
+assertEquals('object', (42).TypeOfThis());
diff --git a/regexp2000/test/mjsunit/bugs/bug-1344252.js b/regexp2000/test/mjsunit/bugs/bug-1344252.js
new file mode 100644 (file)
index 0000000..1723834
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that setter accessors added to the prototype chain are called
+// when setting properties.
+
+// Test that accessors added to the prototype chain are called
+// eventhough there are inline caches for setting the property
+
+function F() {
+  this.x = 42;
+  this.y = 87;
+}
+
+// Force the inline caches to monomorphic state.
+new F(); new F();
+
+// Add a setter for x to Object.prototype and make sure it gets
+// called.
+var result_x;
+Object.prototype.__defineSetter__('x', function(value) { result_x = value; });
+var f = new F();
+assertEquals(42, result_x);
+assertTrue(typeof f.x == 'undefined');
+
+// Add a setter for y by changing the prototype of f and make sure
+// that gets called too.
+var result_y;
+var proto = new Object();
+proto.__defineSetter__('y', function (value) { result_y = value; });
+var f = new F();
+f.y = undefined;
+f.__proto__ = proto;
+F.call(f);
+assertEquals(87, result_y);
+assertTrue(typeof f.y == 'undefined');
+
+
+// Test the same issue in the runtime system.  Make sure that
+// accessors added to the prototype chain are called instead of
+// following map transitions.
+//
+// Create two objects.
+var result_z;
+var o1 = new Object();
+var o2 = new Object();
+// Add a z property to o1 to create a map transition.
+o1.z = 32;
+// Add a z accessor in the prototype chain for o1 and o2.
+Object.prototype.__defineSetter__('z', function(value) { result_z = value; });
+// The accessor should be called for o2.
+o2.z = 27;
+assertEquals(27, result_z);
+assertTrue(typeof o2.z == 'undefined');
+
diff --git a/regexp2000/test/mjsunit/bugs/bug-87.js b/regexp2000/test/mjsunit/bugs/bug-87.js
new file mode 100644 (file)
index 0000000..a467bba
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertTrue((/(?:)/g).global);
+assertTrue((/(?:)/\u0067).global);
diff --git a/regexp2000/test/mjsunit/bugs/bug-900066.js b/regexp2000/test/mjsunit/bugs/bug-900066.js
new file mode 100644 (file)
index 0000000..3b7cc3f
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// When a property of the arguments array is deleted, it
+// must be "disconnected" from the corresponding parameter.
+// Re-introducing the property does not connect to the parameter.
+
+function f(x) {
+  delete arguments[0];
+  arguments[0] = 100;
+  return x;
+}
+
+assertEquals(10, f(10));
diff --git a/regexp2000/test/mjsunit/bugs/bug-941049.js b/regexp2000/test/mjsunit/bugs/bug-941049.js
new file mode 100644 (file)
index 0000000..f68c37a
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This test fails because we copy the arguments array on indirect
+// access
+
+function g(f) {
+  assertEquals(100, f.arguments = 100);  // read-only
+  assertEquals(3, f.arguments.length);
+  assertEquals(1, f.arguments[0]);
+  assertEquals(2, f.arguments[1]);
+  assertEquals(3, f.arguments[2]);
+  f.arguments[0] = 999;
+  f.arguments.extra = 'kallevip';
+}
+
+function h(f) {
+  assertEquals('kallevip', f.arguments.extra);
+  return f.arguments;
+}
+
+// Test function with a materialized arguments array.
+function f0() {
+  g(f0);
+  var result = h(f0);
+  var a = arguments;
+  assertEquals(999, a[0]);
+  return result;
+}
+
+
+// Test function without a materialized arguments array.
+function f1(x) {
+  g(f1);
+  var result = h(f1);
+  assertEquals(999, x);
+  return result;
+}
+
+
+function test(f) {
+  assertTrue(null === f.arguments);
+  var args = f(1,2,3);
+  assertTrue(null === f.arguments);
+
+  assertEquals(3, args.length);
+  assertEquals(999, args[0]);
+  assertEquals(2, args[1]);
+  assertEquals(3, args[2]);
+  assertEquals('kallevip', args.extra);
+}
+
+test(f0);
+test(f1);
+
+
+
+
+function w() {
+  return q.arguments;
+}
+
+function q(x, y) {
+  x = 2;
+  var result = w();
+  y = 3;
+  return result;
+}
+
+var a = q(0, 1);
+// x is set locally *before* the last use of arguments before the
+// activation of q is popped from the stack.
+assertEquals(2, a[0]);
+// y is set locally *after* the last use of arguments before the
+// activation of q is popped from the stack.
+assertEquals(1, a[1]);
diff --git a/regexp2000/test/mjsunit/call-non-function-call.js b/regexp2000/test/mjsunit/call-non-function-call.js
new file mode 100644 (file)
index 0000000..6088fc3
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Throw exception when invoking Function.prototype.call with a
+// non-function receiver.
+var caught = false;
+try {
+  Function.prototype.call.call({});
+  assertTrue(false);
+} catch (e) {
+  caught = true;
+  assertTrue(e instanceof TypeError);
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/call-non-function.js b/regexp2000/test/mjsunit/call-non-function.js
new file mode 100644 (file)
index 0000000..8ed5ccb
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function TryCall(x) {
+  var caught = [];
+  try {
+    x();
+  } catch (e) {
+    caught.push(e);
+  }
+
+  try {
+    new x();
+  } catch (e) {
+    caught.push(e);
+  }
+
+  assertTrue(caught[0] instanceof TypeError);
+  assertTrue(caught[1] instanceof TypeError);
+};
+
+
+TryCall(this);
+TryCall(Math);
+TryCall(true);
+TryCall(1234);
+TryCall("hest");
+
+
+
diff --git a/regexp2000/test/mjsunit/call.js b/regexp2000/test/mjsunit/call.js
new file mode 100644 (file)
index 0000000..b873d7d
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f0() {
+  return this;
+}
+
+assertTrue(this === f0.call(), "1");
+
+assertTrue(this === f0.call(this), "w");
+assertTrue(this === f0.call(this, 1), "w");
+assertTrue(this === f0.call(this, 1, 2), "w");
+
+assertTrue(this === f0.call(null), "3a");
+assertTrue(this === f0.call(null, 1), "3b");
+assertTrue(this === f0.call(null, 1, 2), "3c");
+
+assertTrue(this === f0.call(void 0), "4a");
+assertTrue(this === f0.call(void 0, 1), "4b");
+assertTrue(this === f0.call(void 0, 1, 2), "4c");
+
+var x = {};
+assertTrue(x === f0.call(x));
+assertTrue(x === f0.call(x, 1));
+assertTrue(x === f0.call(x, 1, 2));
+
+
+function f1(a) {
+  a = a || 'i';
+  return this[a];
+}
+
+assertEquals(1, f1.call({i:1}));
+assertEquals(42, f1.call({i:42}, 'i'));
+assertEquals(87, f1.call({j:87}, 'j', 1));
+assertEquals(99, f1.call({k:99}, 'k', 1, 2));
+
+
+function f2(a, b) {
+  a = a || 'n';
+  b = b || 2;
+  return this[a] + b;
+}
+
+var x = {n: 1};
+assertEquals(3, f2.call(x));
+assertEquals(14, f2.call({i:12}, 'i'));
+assertEquals(42, f2.call(x, 'n', 41));
+assertEquals(87, f2.call(x, 'n', 86, 1));
+assertEquals(99, f2.call(x, 'n', 98, 1, 2));
+
+
+function fn() {
+  return arguments.length;
+}
+
+assertEquals(0, fn.call());
+assertEquals(0, fn.call(this));
+assertEquals(0, fn.call(null));
+assertEquals(0, fn.call(void 0));
+assertEquals(1, fn.call(this, 1));
+assertEquals(2, fn.call(this, 1, 2));
+assertEquals(3, fn.call(this, 1, 2, 3));
diff --git a/regexp2000/test/mjsunit/char-escape.js b/regexp2000/test/mjsunit/char-escape.js
new file mode 100644 (file)
index 0000000..a1b3429
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Check that character escapes are understood as one char
+var escapes = ["\b", "\t", "\n", "\v", "\f", "\r", "\"", "\'", "\\", "\x4a", "\u005f"];
+for (var i = 0; i < escapes.length; i++) {
+  var str = escapes[i];
+  assertEquals(1, str.length);
+  assertEquals(str, str.charAt(0));
+}
+
+function code(str) {
+  return str.charCodeAt(0);
+}
+
+// Do the single escape chars have the right value?
+assertEquals(0x08, code("\b"));
+assertEquals(0x09, code("\t"));
+assertEquals(0x0A, code("\n"));
+assertEquals(0x0B, code("\v"));
+assertEquals(0x0C, code("\f"));
+assertEquals(0x0D, code("\r"));
+assertEquals(0x22, code("\""));
+assertEquals(0x27, code("\'"));
+assertEquals(0x5c, code("\\"));
+
+// Do the hex and unicode escape chars have the right value?
+assertEquals(0x4a, code("\x4a"));
+assertEquals(0x5f, code("\u005f"));
diff --git a/regexp2000/test/mjsunit/class-of-builtins.js b/regexp2000/test/mjsunit/class-of-builtins.js
new file mode 100644 (file)
index 0000000..40c958c
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The [[Class]] property of (instances of) builtin functions must be
+// correctly set.
+var funs = {
+  Object:   [ Object ],
+  Function: [ Function ],
+  Array:    [ Array ],
+  String:   [ String ],
+  Boolean:  [ Boolean ],
+  Number:   [ Number ],
+  Date:     [ Date ],
+  RegExp:   [ RegExp ],  
+  Error:    [ Error, TypeError, RangeError, SyntaxError, ReferenceError, EvalError, URIError ]
+}
+for (f in funs) {
+  for (i in funs[f]) {
+    assertEquals("[object " + f + "]",
+                 Object.prototype.toString.call(new funs[f][i]),
+                 funs[f][i]);
+    assertEquals("[object Function]",
+                 Object.prototype.toString.call(funs[f][i]),
+                 funs[f][i]);
+  }
+}
diff --git a/regexp2000/test/mjsunit/closure.js b/regexp2000/test/mjsunit/closure.js
new file mode 100644 (file)
index 0000000..b1460d3
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This test is lifted an old bug (ic_context_bug.js).
+
+function f(n) {
+  return function () { return n; }
+}
+
+for (var i = 0; i < 10; i++) {
+  var a = f(i);
+  assertEquals(i, a());
+}
diff --git a/regexp2000/test/mjsunit/compare-nan.js b/regexp2000/test/mjsunit/compare-nan.js
new file mode 100644 (file)
index 0000000..29818c8
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var a = [NaN, -1, 0, 1, 1.2, -7.9, true, false, 'foo', '0', 'NaN' ];
+for (var i in a) {
+  var x = a[i];
+  assertFalse(NaN == x); 
+  assertFalse(NaN === x); 
+  assertFalse(NaN < x);
+  assertFalse(NaN > x);
+  assertFalse(NaN <= x);
+  assertFalse(NaN >= x);
+
+  assertFalse(x == NaN); 
+  assertFalse(x === NaN); 
+  assertFalse(x < NaN);
+  assertFalse(x > NaN);
+  assertFalse(x <= NaN);
+  assertFalse(x >= NaN);
+}
diff --git a/regexp2000/test/mjsunit/const-redecl.js b/regexp2000/test/mjsunit/const-redecl.js
new file mode 100644 (file)
index 0000000..26d765b
--- /dev/null
@@ -0,0 +1,220 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test for const semantics.
+
+
+function CheckException(e) {
+  var string = e.toString();
+  var index = string.indexOf(':');
+  assertTrue(index >= 0);
+  var name = string.slice(0, index);
+  assertTrue(string.indexOf("has already been declared") >= 0 ||
+             string.indexOf("redeclaration") >= 0);
+  if (name == 'SyntaxError') return 'TypeError';
+  return name;
+}
+
+
+function TestLocal(s,e) {
+  try {
+    return eval("(function(){" + s + ";return " + e + "})")();
+  } catch (x) {
+    return CheckException(x);
+  }
+}
+
+
+// NOTE: TestGlobal usually only tests the given string in the context
+// of a global object in dictionary mode. This is because we use
+// delete to get rid of any added properties.
+function TestGlobal(s,e) {
+  // Collect the global properties before the call.
+  var properties = [];
+  for (var key in this) properties.push(key); 
+  // Compute the result.
+  var result;
+  try {
+    var code = s + (e ? "; $$$result=" + e : "");
+    if (this.execScript) {
+      execScript(code);
+    } else {
+      this.eval(code);
+    }
+    // Avoid issues if $$$result is not defined by
+    // reading it through this.
+    result = this.$$$result;
+  } catch (x) {
+    result = CheckException(x);
+  }
+  // Get rid of any introduced global properties before
+  // returning the result.
+  for (var key in this) {
+    if (properties.indexOf(key) == -1) delete this[key];
+  }
+  return result;
+}
+
+
+function TestContext(s,e) {
+  try {
+    // Use a with-statement to force the system to do dynamic
+    // declarations of the introduced variables or constants.
+    with ({}) {
+      return eval(s + ";" + e);
+    }
+  } catch (x) {
+    return CheckException(x);
+  }
+}
+
+
+function TestAll(expected,s,opt_e) {
+  var e = "";
+  var msg = s;
+  if (opt_e) { e = opt_e; msg += "; " + opt_e; }
+  assertEquals(expected, TestLocal(s,e), "local:'" + msg + "'");
+  assertEquals(expected, TestGlobal(s,e), "global:'" + msg + "'");
+  assertEquals(expected, TestContext(s,e), "context:'" + msg + "'");
+}
+
+
+function TestConflict(def0, def1) {
+  // No eval.
+  TestAll("TypeError", def0 +'; ' + def1);
+  // Eval everything.
+  TestAll("TypeError", 'eval("' + def0 + '; ' + def1 + '")');
+  // Eval first definition.
+  TestAll("TypeError", 'eval("' + def0 +'"); ' + def1);
+  // Eval second definition.
+  TestAll("TypeError", def0 + '; eval("' + def1 + '")');
+  // Eval both definitions separately.
+  TestAll("TypeError", 'eval("' + def0 +'"); eval("' + def1 + '")');  
+}
+
+
+// Test conflicting definitions.
+TestConflict("const x", "var x");
+TestConflict("const x = 0", "var x");
+TestConflict("const x", "var x = 0");
+TestConflict("const x = 0", "var x = 0");
+
+TestConflict("var x", "const x");
+TestConflict("var x = 0", "const x");
+TestConflict("var x", "const x = 0");
+TestConflict("var x = 0", "const x = 0");
+
+TestConflict("const x = undefined", "var x");
+TestConflict("const x", "var x = undefined");
+TestConflict("const x = undefined", "var x = undefined");
+
+TestConflict("var x = undefined", "const x");
+TestConflict("var x", "const x = undefined");
+TestConflict("var x = undefined", "const x = undefined");
+
+TestConflict("const x = undefined", "var x = 0");
+TestConflict("const x = 0", "var x = undefined");
+
+TestConflict("var x = undefined", "const x = 0");
+TestConflict("var x = 0", "const x = undefined");
+
+TestConflict("const x", "function x() { }");
+TestConflict("const x = 0", "function x() { }");
+TestConflict("const x = undefined", "function x() { }");
+
+TestConflict("function x() { }", "const x");
+TestConflict("function x() { }", "const x = 0");
+TestConflict("function x() { }", "const x = undefined");
+
+TestConflict("const x, y", "var x");
+TestConflict("const x, y", "var y");
+TestConflict("const x = 0, y", "var x");
+TestConflict("const x = 0, y", "var y");
+TestConflict("const x, y = 0", "var x");
+TestConflict("const x, y = 0", "var y");
+TestConflict("const x = 0, y = 0", "var x");
+TestConflict("const x = 0, y = 0", "var y");
+
+TestConflict("var x", "const x, y");
+TestConflict("var y", "const x, y");
+TestConflict("var x", "const x = 0, y");
+TestConflict("var y", "const x = 0, y");
+TestConflict("var x", "const x, y = 0");
+TestConflict("var y", "const x, y = 0");
+TestConflict("var x", "const x = 0, y = 0");
+TestConflict("var y", "const x = 0, y = 0");
+
+
+// Test that multiple conflicts do not cause issues.
+TestConflict("var x, y", "const x, y");
+
+
+// Test that repeated const declarations throw redeclaration errors.
+TestConflict("const x", "const x");
+TestConflict("const x = 0", "const x");
+TestConflict("const x", "const x = 0");
+TestConflict("const x = 0", "const x = 0");
+
+TestConflict("const x = undefined", "const x");
+TestConflict("const x", "const x = undefined");
+TestConflict("const x = undefined", "const x = undefined");
+
+TestConflict("const x = undefined", "const x = 0");
+TestConflict("const x = 0", "const x = undefined");
+
+TestConflict("const x, y", "const x");
+TestConflict("const x, y", "const y");
+TestConflict("const x = 0, y", "const x");
+TestConflict("const x = 0, y", "const y");
+TestConflict("const x, y = 0", "const x");
+TestConflict("const x, y = 0", "const y");
+TestConflict("const x = 0, y = 0", "const x");
+TestConflict("const x = 0, y = 0", "const y");
+
+TestConflict("const x", "const x, y");
+TestConflict("const y", "const x, y");
+TestConflict("const x", "const x = 0, y");
+TestConflict("const y", "const x = 0, y");
+TestConflict("const x", "const x, y = 0");
+TestConflict("const y", "const x, y = 0");
+TestConflict("const x", "const x = 0, y = 0");
+TestConflict("const y", "const x = 0, y = 0");
+
+
+// Test that multiple const conflicts do not cause issues.
+TestConflict("const x, y", "const x, y");
+
+
+// Test that const inside loop behaves correctly.
+var loop = "for (var i = 0; i < 3; i++) { const x = i; }";
+TestAll(0, loop, "x");
+TestAll(0, "var a,b,c,d,e,f,g,h; " + loop, "x");
+
+
+// Test that const inside with behaves correctly.
+TestAll(87, "with ({x:42}) { const x = 87; }", "x");
+TestAll(undefined, "with ({x:42}) { const x; }", "x");
diff --git a/regexp2000/test/mjsunit/const.js b/regexp2000/test/mjsunit/const.js
new file mode 100644 (file)
index 0000000..5ad0c9c
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test const properties and pre/postfix operation.
+function f() {
+  const x = 1;
+  x++;
+  assertEquals(1, x);
+  x--;
+  assertEquals(1, x);
+  ++x;
+  assertEquals(1, x);
+  --x;
+  assertEquals(1, x);
+  assertEquals(1, x++);
+  assertEquals(1, x--);
+  assertEquals(2, ++x);
+  assertEquals(0, --x);
+}
+
+f();
+
+// Test that the value is read eventhough assignment is disallowed.
+// Spidermonkey does not do this, but it seems like the right thing to
+// do so that 'o++' is equivalent to 'o = o + 1'.
+var valueOfCount = 0;
+
+function g() {
+  const o = { valueOf: function() { valueOfCount++; return 42; } }
+  assertEquals(42, o);
+  assertEquals(0, valueOfCount);
+  o++;
+  assertEquals(42, o);
+  assertEquals(1, valueOfCount);
+  ++o;
+  assertEquals(42, o);
+  assertEquals(2, valueOfCount);
+  o--;
+  assertEquals(42, o);
+  assertEquals(3, valueOfCount);
+  --o;
+  assertEquals(42, o);
+  assertEquals(4, valueOfCount);
+}
diff --git a/regexp2000/test/mjsunit/context-variable-assignments.js b/regexp2000/test/mjsunit/context-variable-assignments.js
new file mode 100644 (file)
index 0000000..930b969
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function foo() {
+  var a, b;
+  var bar = function() {
+    a = b = "hello world";
+  }
+  bar();
+  return a;
+}
+
+assertEquals("hello world", foo());
diff --git a/regexp2000/test/mjsunit/cyclic-array-to-string.js b/regexp2000/test/mjsunit/cyclic-array-to-string.js
new file mode 100644 (file)
index 0000000..0a2d6e3
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test printing of cyclic arrays.
+
+var a1 = [1,2];
+assertEquals("1,2", a1.toString());
+assertEquals("1,2", a1.toLocaleString());
+assertEquals("1,2", a1.join());
+a1.push(a1);
+assertEquals("1,2,", a1.toString());
+assertEquals("1,2,", a1.toLocaleString());
+assertEquals("1,2,", a1.join());
+a1.push(1);
+assertEquals("1,2,,1", a1.toString());
+assertEquals("1,2,,1", a1.toLocaleString());
+assertEquals("1,2,,1", a1.join());
+a1.push(a1);
+assertEquals("1,2,,1,", a1.toString());
+assertEquals("1,2,,1,", a1.toLocaleString());
+assertEquals("1,2,,1,", a1.join());
+
+a1 = [1,2];
+var a2 = [3,4];
+a1.push(a2);
+a1.push(a2);
+assertEquals("1,2,3,4,3,4", a1.toString());
+assertEquals("1,2,3,4,3,4", a1.toLocaleString());
+assertEquals("1,2,3,4,3,4", a1.join());
+a2.push(a1);
+assertEquals("1,2,3,4,,3,4,", a1.toString());
+assertEquals("1,2,3,4,,3,4,", a1.toLocaleString());
+assertEquals("1,2,3,4,,3,4,", a1.join());
+
+a1 = [];
+a2 = [a1];
+a1.push(a2);
+assertEquals("", a1.toString());
+assertEquals("", a1.toLocaleString());
+assertEquals("", a1.join());
+
diff --git a/regexp2000/test/mjsunit/date-parse.js b/regexp2000/test/mjsunit/date-parse.js
new file mode 100644 (file)
index 0000000..1e09db5
--- /dev/null
@@ -0,0 +1,265 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that we can parse dates in all the different formats that we
+// have to support.
+//
+// These formats are all supported by KJS but a lot of them are not
+// supported by Spidermonkey.
+
+function testDateParse(string) {
+  var d = Date.parse(string);
+  assertEquals(946713600000, d, string);
+};
+
+
+// For local time we just test that parsing returns non-NaN positive
+// number of milliseconds to make it timezone independent.
+function testDateParseLocalTime(string) {
+  var d = Date.parse(string);
+  assertTrue(d > 0 && !isNaN(d));
+};
+
+
+function testDateParseMisc(array) {
+  assertTrue(array.length == 2);
+  var string = array[0];
+  var expected = array[1];
+  var d = Date.parse(string);
+  assertEquals(expected, d, string);
+}
+
+
+//
+// Test all the formats in UT timezone.
+//
+var testCasesUT = [
+    'Sat, 01-Jan-2000 08:00:00 UT',
+    'Sat, 01 Jan 2000 08:00:00 UT',
+    'Jan 01 2000 08:00:00 UT',
+    'Jan 01 08:00:00 UT 2000',
+    'Saturday, 01-Jan-00 08:00:00 UT',
+    '01 Jan 00 08:00 +0000',
+    // Ignore weekdays.
+    'Mon, 01 Jan 2000 08:00:00 UT',
+    'Tue, 01 Jan 2000 08:00:00 UT',
+    // Ignore prefix that is not part of a date.
+    '[Saturday] Jan 01 08:00:00 UT 2000',
+    'Ignore all of this stuff because it is annoying 01 Jan 2000 08:00:00 UT',
+    '[Saturday] Jan 01 2000 08:00:00 UT',
+    'All of this stuff is really annnoying, so it will be ignored Jan 01 2000 08:00:00 UT',
+    // If the three first letters of the month is a
+    // month name we are happy - ignore the rest.
+    'Sat, 01-Janisamonth-2000 08:00:00 UT',
+    'Sat, 01 Janisamonth 2000 08:00:00 UT',
+    'Janisamonth 01 2000 08:00:00 UT',
+    'Janisamonth 01 08:00:00 UT 2000',
+    'Saturday, 01-Janisamonth-00 08:00:00 UT',
+    '01 Janisamonth 00 08:00 +0000',
+    // Allow missing space between month and day.
+    'Janisamonthandtherestisignored01 2000 08:00:00 UT',
+    'Jan01 2000 08:00:00 UT',
+    // Allow year/month/day format.
+    'Sat, 2000/01/01 08:00:00 UT',
+    // Allow month/day/year format.
+    'Sat, 01/01/2000 08:00:00 UT',
+    // Allow month/day year format.
+    'Sat, 01/01 2000 08:00:00 UT',
+    // Allow comma instead of space after day, month and year.
+    'Sat, 01,Jan,2000,08:00:00 UT',
+    // Seconds are optional.
+    'Sat, 01-Jan-2000 08:00 UT',
+    'Sat, 01 Jan 2000 08:00 UT',
+    'Jan 01 2000 08:00 UT',
+    'Jan 01 08:00 UT 2000',
+    'Saturday, 01-Jan-00 08:00 UT',
+    '01 Jan 00 08:00 +0000',
+    // Allow AM/PM after the time.
+    'Sat, 01-Jan-2000 08:00 AM UT',
+    'Sat, 01 Jan 2000 08:00 AM UT',
+    'Jan 01 2000 08:00 AM UT',
+    'Jan 01 08:00 AM UT 2000',
+    'Saturday, 01-Jan-00 08:00 AM UT',
+    '01 Jan 00 08:00 AM +0000',
+    // White space and stuff in parenthesis is
+    // apparently allowed in most places where white
+    // space is allowed.
+    '   Sat,   01-Jan-2000   08:00:00   UT  ',
+    '  Sat,   01   Jan   2000   08:00:00   UT  ',
+    '  Saturday,   01-Jan-00   08:00:00   UT  ',
+    '  01    Jan   00    08:00   +0000   ',
+    ' ()(Sat, 01-Jan-2000)  Sat,   01-Jan-2000   08:00:00   UT  ',
+    '  Sat()(Sat, 01-Jan-2000)01   Jan   2000   08:00:00   UT  ',
+    '  Sat,(02)01   Jan   2000   08:00:00   UT  ',
+    '  Sat,  01(02)Jan   2000   08:00:00   UT  ',
+    '  Sat,  01  Jan  2000 (2001)08:00:00   UT  ',
+    '  Sat,  01  Jan  2000 (01)08:00:00   UT  ',
+    '  Sat,  01  Jan  2000 (01:00:00)08:00:00   UT  ',
+    '  Sat,  01  Jan  2000  08:00:00 (CDT)UT  ',
+    '  Sat,  01  Jan  2000  08:00:00  UT((((CDT))))',
+    '  Saturday,   01-Jan-00 ()(((asfd)))(Sat, 01-Jan-2000)08:00:00   UT  ',
+    '  01    Jan   00    08:00 ()(((asdf)))(Sat, 01-Jan-2000)+0000   ',
+    '  01    Jan   00    08:00   +0000()((asfd)(Sat, 01-Jan-2000)) '];
+
+//
+// Test that we do the right correction for different time zones.
+// I'll assume that we can handle the same formats as for UT and only
+// test a few formats for each of the timezones.
+//
+
+// GMT = UT
+var testCasesGMT = [
+    'Sat, 01-Jan-2000 08:00:00 GMT',
+    'Sat, 01-Jan-2000 08:00:00 GMT+0',
+    'Sat, 01-Jan-2000 08:00:00 GMT+00',
+    'Sat, 01-Jan-2000 08:00:00 GMT+000',
+    'Sat, 01-Jan-2000 08:00:00 GMT+0000',
+    'Sat, 01-Jan-2000 08:00:00 GMT+00:00', // Interestingly, KJS cannot handle this.
+    'Sat, 01 Jan 2000 08:00:00 GMT',
+    'Saturday, 01-Jan-00 08:00:00 GMT',
+    '01 Jan 00 08:00 -0000',
+    '01 Jan 00 08:00 +0000'];
+
+// EST = UT minus 5 hours.
+var testCasesEST = [
+    'Sat, 01-Jan-2000 03:00:00 UTC-0500',
+    'Sat, 01-Jan-2000 03:00:00 UTC-05:00', // Interestingly, KJS cannot handle this.
+    'Sat, 01-Jan-2000 03:00:00 EST',
+    'Sat, 01 Jan 2000 03:00:00 EST',
+    'Saturday, 01-Jan-00 03:00:00 EST',
+    '01 Jan 00 03:00 -0500'];
+
+// EDT = UT minus 4 hours.
+var testCasesEDT = [
+    'Sat, 01-Jan-2000 04:00:00 EDT',
+    'Sat, 01 Jan 2000 04:00:00 EDT',
+    'Saturday, 01-Jan-00 04:00:00 EDT',
+    '01 Jan 00 04:00 -0400'];
+
+// CST = UT minus 6 hours.
+var testCasesCST = [
+    'Sat, 01-Jan-2000 02:00:00 CST',
+    'Sat, 01 Jan 2000 02:00:00 CST',
+    'Saturday, 01-Jan-00 02:00:00 CST',
+    '01 Jan 00 02:00 -0600'];
+
+// CDT = UT minus 5 hours.
+var testCasesCDT = [
+    'Sat, 01-Jan-2000 03:00:00 CDT',
+    'Sat, 01 Jan 2000 03:00:00 CDT',
+    'Saturday, 01-Jan-00 03:00:00 CDT',
+    '01 Jan 00 03:00 -0500'];
+
+// MST = UT minus 7 hours.
+var testCasesMST = [
+    'Sat, 01-Jan-2000 01:00:00 MST',
+    'Sat, 01 Jan 2000 01:00:00 MST',
+    'Saturday, 01-Jan-00 01:00:00 MST',
+    '01 Jan 00 01:00 -0700'];
+
+// MDT = UT minus 6 hours.
+var testCasesMDT = [
+    'Sat, 01-Jan-2000 02:00:00 MDT',
+    'Sat, 01 Jan 2000 02:00:00 MDT',
+    'Saturday, 01-Jan-00 02:00:00 MDT',
+    '01 Jan 00 02:00 -0600'];
+
+// PST = UT minus 8 hours.
+var testCasesPST = [
+    'Sat, 01-Jan-2000 00:00:00 PST',
+    'Sat, 01 Jan 2000 00:00:00 PST',
+    'Saturday, 01-Jan-00 00:00:00 PST',
+    '01 Jan 00 00:00 -0800',
+    // Allow missing time.
+    'Sat, 01-Jan-2000 PST'];
+
+// PDT = UT minus 7 hours.
+var testCasesPDT = [
+    'Sat, 01-Jan-2000 01:00:00 PDT',
+    'Sat, 01 Jan 2000 01:00:00 PDT',
+    'Saturday, 01-Jan-00 01:00:00 PDT',
+    '01 Jan 00 01:00 -0700'];
+
+
+// Local time cases.
+var testCasesLocalTime = [
+    // Allow timezone ommision.
+    'Sat, 01-Jan-2000 08:00:00',
+    'Sat, 01 Jan 2000 08:00:00',
+    'Jan 01 2000 08:00:00',
+    'Jan 01 08:00:00 2000',
+    'Saturday, 01-Jan-00 08:00:00',
+    '01 Jan 00 08:00'];
+
+
+// Misc. test cases that result in a different time value.
+var testCasesMisc = [
+    // Special handling for years in the [0, 100) range.
+    ['Sat, 01 Jan 0 08:00:00 UT', 946713600000], // year 2000
+    ['Sat, 01 Jan 49 08:00:00 UT', 2493100800000], // year 2049
+    ['Sat, 01 Jan 50 08:00:00 UT', -631123200000], // year 1950
+    ['Sat, 01 Jan 99 08:00:00 UT', 915177600000], // year 1999
+    ['Sat, 01 Jan 100 08:00:00 UT', -59011430400000], // year 100
+    // Test PM after time.
+    ['Sat, 01-Jan-2000 08:00 PM UT', 946756800000],
+    ['Sat, 01 Jan 2000 08:00 PM UT', 946756800000],
+    ['Jan 01 2000 08:00 PM UT', 946756800000],
+    ['Jan 01 08:00 PM UT 2000', 946756800000],
+    ['Saturday, 01-Jan-00 08:00 PM UT', 946756800000],
+    ['01 Jan 00 08:00 PM +0000', 946756800000]];
+
+
+// Run all the tests.
+testCasesUT.forEach(testDateParse);
+testCasesGMT.forEach(testDateParse);
+testCasesEST.forEach(testDateParse);
+testCasesEDT.forEach(testDateParse);
+testCasesCST.forEach(testDateParse);
+testCasesCDT.forEach(testDateParse);
+testCasesMST.forEach(testDateParse);
+testCasesMDT.forEach(testDateParse);
+testCasesPST.forEach(testDateParse);
+testCasesPDT.forEach(testDateParse);
+testCasesLocalTime.forEach(testDateParseLocalTime);
+testCasesMisc.forEach(testDateParseMisc);
+
+
+// Test that we can parse our own date format.
+// (Dates from 1970 to ~2070 with 95h steps.)
+for (var i = 0; i < 24 * 365 * 100; i += 95) {
+  var ms = i * (3600 * 1000);
+  var s = (new Date(ms)).toString();
+  assertEquals(ms, Date.parse(s), s);
+}
+
+// Negative tests.
+var testCasesNegative = [
+    'May 25 2008 1:30 (PM)) UTC',
+    'May 25 2008 1:30( )AM (PM)',
+    'May 25 2008 AAA (GMT)'];
+
+testCasesNegative.forEach(function (s) { assertTrue(isNaN(Date.parse(s))); });
diff --git a/regexp2000/test/mjsunit/date.js b/regexp2000/test/mjsunit/date.js
new file mode 100644 (file)
index 0000000..342ace7
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test date construction from other dates.
+var date0 = new Date(1111);
+var date1 = new Date(date0);
+assertEquals(1111, date0.getTime());
+assertEquals(date0.getTime(), date1.getTime());
+var date2 = new Date(date0.toString());
+assertEquals(1000, date2.getTime());
+
+// Test that dates may contain commas.
+var date0 = Date.parse("Dec 25 1995 1:30");
+var date1 = Date.parse("Dec 25, 1995 1:30");
+var date2 = Date.parse("Dec 25 1995, 1:30");
+var date3 = Date.parse("Dec 25, 1995, 1:30");
+assertEquals(date0, date1);
+assertEquals(date1, date2);
+assertEquals(date2, date3);
+
+
+// Tests inspired by js1_5/Date/regress-346363.js
+
+// Year
+var a = new Date();
+a.setFullYear();
+a.setFullYear(2006);
+assertEquals(2006, a.getFullYear());
+
+var b = new Date();
+b.setUTCFullYear();
+b.setUTCFullYear(2006);
+assertEquals(2006, b.getUTCFullYear());
+
+// Month
+var c = new Date();
+c.setMonth();
+c.setMonth(2);
+assertTrue(isNaN(c.getMonth()));
+
+var d = new Date();
+d.setUTCMonth();
+d.setUTCMonth(2);
+assertTrue(isNaN(d.getUTCMonth()));
+
+// Date
+var e = new Date();
+e.setDate();
+e.setDate(2);
+assertTrue(isNaN(e.getDate()));
+
+var f = new Date();
+f.setUTCDate();
+f.setUTCDate(2);
+assertTrue(isNaN(f.getUTCDate()));
+
+// Hours
+var g = new Date();
+g.setHours();
+g.setHours(2);
+assertTrue(isNaN(g.getHours()));
+
+var h = new Date();
+h.setUTCHours();
+h.setUTCHours(2);
+assertTrue(isNaN(h.getUTCHours()));
+
+// Minutes
+var g = new Date();
+g.setMinutes();
+g.setMinutes(2);
+assertTrue(isNaN(g.getMinutes()));
+
+var h = new Date();
+h.setUTCHours();
+h.setUTCHours(2);
+assertTrue(isNaN(h.getUTCHours()));
+
+
+// Seconds
+var i = new Date();
+i.setSeconds();
+i.setSeconds(2);
+assertTrue(isNaN(i.getSeconds()));
+
+var j = new Date();
+j.setUTCSeconds();
+j.setUTCSeconds(2);
+assertTrue(isNaN(j.getUTCSeconds()));
+
+
+// Milliseconds
+var k = new Date();
+k.setMilliseconds();
+k.setMilliseconds(2);
+assertTrue(isNaN(k.getMilliseconds()));
+
+var l = new Date();
+l.setUTCMilliseconds();
+l.setUTCMilliseconds(2);
+assertTrue(isNaN(l.getUTCMilliseconds()));
+
+// Test that toLocaleTimeString only returns the time portion of the
+// date without the timezone information.
+function testToLocaleTimeString() {
+  var d = new Date();
+  var s = d.toLocaleTimeString();
+  assertEquals(8, s.length);
+}
+
+testToLocaleTimeString();
diff --git a/regexp2000/test/mjsunit/debug-backtrace-text.js b/regexp2000/test/mjsunit/debug-backtrace-text.js
new file mode 100644 (file)
index 0000000..d1acdab
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+
+// The functions used for testing backtraces.
+function Point(x, y) {
+  this.x = x;
+  this.y = y;
+};
+
+Point.prototype.distanceTo = function(p) {
+  debugger;
+  return Math.sqrt(Math.pow(Math.abs(this.x - p.x), 2) + Math.pow(Math.abs(this.y - p.y), 2))
+}
+
+p1 = new Point(1,1);
+p2 = new Point(2,2);
+
+p1.distanceTo = function(p) {
+  return p.distanceTo(this);
+}
+
+function distance(p, q) {
+  return p.distanceTo(q);
+}
+
+function createPoint(x, y) {
+  return new Point(x, y);
+}
+
+a=[1,2,distance];
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+testConstructor = false;  // Flag to control which part of the test is run.
+listenerCalled = false;
+exception = false;
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    return undefined;
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break)
+  {
+    if (!testConstructor) {
+      // The expected backtrace is
+      // 0: Call distance on Point where distance is a property on the prototype
+      // 1: Call distance on Point where distance is a direct property
+      // 2: Call on function an array element 2
+      // 3: [anonymous]
+      assertEquals("#<a Point>.distanceTo(p=#<a Point>)", exec_state.frame(0).invocationText());
+      assertEquals("#<a Point>.distanceTo(p=#<a Point>)", exec_state.frame(1).invocationText());
+      assertEquals("#<an Array>[2](aka distance)(p=#<a Point>, q=#<a Point>)", exec_state.frame(2).invocationText());
+      assertEquals("[anonymous]()", exec_state.frame(3).invocationText());
+      listenerCalled = true;
+    } else {
+      // The expected backtrace is
+      // 0: Call Point constructor
+      // 1: Call on global function createPoint
+      // 2: [anonymous]
+      assertEquals("new Point(x=0, y=0)", exec_state.frame(0).invocationText());
+      assertEquals("createPoint(x=0, y=0)", exec_state.frame(1).invocationText());
+      assertEquals("[anonymous]()", exec_state.frame(2).invocationText());
+      listenerCalled = true;
+    }
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Set a break point and call to invoke the debug event listener.
+a[2](p1, p2)
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerCalled);
+assertFalse(exception, "exception in listener")
+
+// Set a break point and call to invoke the debug event listener.
+listenerCalled = false;
+testConstructor = true;
+Debug.setBreakPoint(Point, 0, 0);
+createPoint(0, 0);
+
+// Make sure that the debug event listener vas invoked (again).
+assertTrue(listenerCalled);
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-backtrace.js b/regexp2000/test/mjsunit/debug-backtrace.js
new file mode 100644 (file)
index 0000000..91e1476
--- /dev/null
@@ -0,0 +1,194 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// The functions used for testing backtraces. They are at the top to make the
+// testing of source line/column easier.
+function f(x, y) {
+  a=1;
+};
+
+function g() {
+  new f(1);
+};
+
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerCalled = false;
+exception = false;
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    return undefined;
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break)
+  {
+    // The expected backtrace is
+    // 0: f
+    // 1: g
+    // 2: [anonymous]
+    
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Get the backtrace.
+    var json;
+    json = '{"seq":0,"type":"request","command":"backtrace"}'
+    var backtrace = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(0, backtrace.fromFrame);
+    assertEquals(3, backtrace.toFrame);
+    assertEquals(3, backtrace.totalFrames);
+    var frames = backtrace.frames;
+    assertEquals(3, frames.length);
+    for (var i = 0; i < frames.length; i++) {
+      assertEquals('frame', frames[i].type);
+    }
+    assertEquals(0, frames[0].index);
+    assertEquals("f", frames[0].func.name);
+    assertEquals(1, frames[1].index);
+    assertEquals("g", frames[1].func.name);
+    assertEquals(2, frames[2].index);
+    assertEquals("", frames[2].func.name);
+
+    // Get backtrace with two frames.
+    json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":1,"toFrame":3}}'
+    var backtrace = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(1, backtrace.fromFrame);
+    assertEquals(3, backtrace.toFrame);
+    assertEquals(3, backtrace.totalFrames);
+    var frames = backtrace.frames;
+    assertEquals(2, frames.length);
+    for (var i = 0; i < frames.length; i++) {
+      assertEquals('frame', frames[i].type);
+    }
+    assertEquals(1, frames[0].index);
+    assertEquals("g", frames[0].func.name);
+    assertEquals(2, frames[1].index);
+    assertEquals("", frames[1].func.name);
+
+    // Get the individual frames.
+    var frame;
+    json = '{"seq":0,"type":"request","command":"frame"}'
+    frame = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(0, frame.index);
+    assertEquals("f", frame.func.name);
+    assertTrue(frame.constructCall);
+    assertEquals(31, frame.line);
+    assertEquals(3, frame.column);
+    assertEquals(2, frame.arguments.length);
+    assertEquals('x', frame.arguments[0].name);
+    assertEquals('number', frame.arguments[0].value.type);
+    assertEquals(1, frame.arguments[0].value.value);
+    assertEquals('y', frame.arguments[1].name);
+    assertEquals('undefined', frame.arguments[1].value.type);
+
+    json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":0}}'
+    frame = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(0, frame.index);
+    assertEquals("f", frame.func.name);
+    assertEquals(31, frame.line);
+    assertEquals(3, frame.column);
+    assertEquals(2, frame.arguments.length);
+    assertEquals('x', frame.arguments[0].name);
+    assertEquals('number', frame.arguments[0].value.type);
+    assertEquals(1, frame.arguments[0].value.value);
+    assertEquals('y', frame.arguments[1].name);
+    assertEquals('undefined', frame.arguments[1].value.type);
+
+    json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":1}}'
+    frame = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(1, frame.index);
+    assertEquals("g", frame.func.name);
+    assertFalse(frame.constructCall);
+    assertEquals(35, frame.line);
+    assertEquals(2, frame.column);
+    assertEquals(0, frame.arguments.length);
+
+    json = '{"seq":0,"type":"request","command":"frame","arguments":{"number":2}}'
+    frame = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(2, frame.index);
+    assertEquals("", frame.func.name);
+
+    // Source slices for the individual frames (they all refer to this script).
+    json = '{"seq":0,"type":"request","command":"source",' +
+            '"arguments":{"frame":0,"fromLine":30,"toLine":32}}'
+    source = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals("function f(x, y) {", source.source.substring(0, 18));
+    assertEquals(30, source.fromLine);
+    assertEquals(32, source.toLine);
+    
+    json = '{"seq":0,"type":"request","command":"source",' +
+            '"arguments":{"frame":1,"fromLine":31,"toLine":32}}'
+    source = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals("  a=1;", source.source.substring(0, 6));
+    assertEquals(31, source.fromLine);
+    assertEquals(32, source.toLine);
+    
+    json = '{"seq":0,"type":"request","command":"source",' +
+            '"arguments":{"frame":2,"fromLine":35,"toLine":36}}'
+    source = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals("  new f(1);", source.source.substring(0, 11));
+    assertEquals(35, source.fromLine);
+    assertEquals(36, source.toLine);
+    
+    // Test line interval way beyond this script will result in an error.
+    json = '{"seq":0,"type":"request","command":"source",' +
+            '"arguments":{"frame":0,"fromLine":10000,"toLine":20000}}'
+    response = safeEval(dcp.processDebugJSONRequest(json));
+    assertFalse(response.success);
+    
+    // Test without arguments.
+    json = '{"seq":0,"type":"request","command":"source"}'
+    source = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(Debug.findScript(f).source, source.source);
+    
+    listenerCalled = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Set a break point and call to invoke the debug event listener.
+Debug.setBreakPoint(f, 0, 0);
+g();
+
+// Make sure that the debug event listener vas invoked.
+assertFalse(exception, "exception in listener");
+assertTrue(listenerCalled);
+
diff --git a/regexp2000/test/mjsunit/debug-breakpoints.js b/regexp2000/test/mjsunit/debug-breakpoints.js
new file mode 100644 (file)
index 0000000..c332f1e
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+function f() {a=1;b=2};
+function g() {
+  a=1;
+  b=2;
+}
+
+bp = Debug.setBreakPoint(f, 0, 0);
+assertEquals("() {[B0]a=1;b=2}", Debug.showBreakPoints(f));
+Debug.clearBreakPoint(bp);
+assertEquals("() {a=1;b=2}", Debug.showBreakPoints(f));
+bp1 = Debug.setBreakPoint(f, 0, 8);
+assertEquals("() {a=1;[B0]b=2}", Debug.showBreakPoints(f));
+bp2 = Debug.setBreakPoint(f, 0, 4);
+assertEquals("() {[B0]a=1;[B1]b=2}", Debug.showBreakPoints(f));
+bp3 = Debug.setBreakPoint(f, 0, 12);
+assertEquals("() {[B0]a=1;[B1]b=2}[B2]", Debug.showBreakPoints(f));
+Debug.clearBreakPoint(bp1);
+assertEquals("() {[B0]a=1;b=2}[B1]", Debug.showBreakPoints(f));
+Debug.clearBreakPoint(bp2);
+assertEquals("() {a=1;b=2}[B0]", Debug.showBreakPoints(f));
+Debug.clearBreakPoint(bp3);
+assertEquals("() {a=1;b=2}", Debug.showBreakPoints(f));
+
+// The following test checks that the Debug.showBreakPoints(g) produces output
+// like follows when changein breakpoints.
+//
+// function g() {
+//   [BX]a=1;
+//   [BX]b=2;
+// }[BX]
+
+// Test set and clear breakpoint at the first possible location (line 0,
+// position 0).
+bp = Debug.setBreakPoint(g, 0, 0);
+// function g() {
+//   [B0]a=1;
+//   b=2;
+// }
+assertTrue(Debug.showBreakPoints(g).indexOf("[B0]a=1;") > 0);
+Debug.clearBreakPoint(bp);
+// function g() {
+//   a=1;
+//   b=2;
+// }
+assertTrue(Debug.showBreakPoints(g).indexOf("[B0]") < 0);
+
+// Second test set and clear breakpoints on lines 1, 2 and 3 (position = 0).
+bp1 = Debug.setBreakPoint(g, 2, 0);
+// function g() {
+//   a=1;
+//   [B0]b=2;
+// }
+assertTrue(Debug.showBreakPoints(g).indexOf("[B0]b=2;") > 0);
+bp2 = Debug.setBreakPoint(g, 1, 0);
+// function g() {
+//   [B0]a=1;
+//   [B1]b=2;
+// }
+assertTrue(Debug.showBreakPoints(g).indexOf("[B0]a=1;") > 0);
+assertTrue(Debug.showBreakPoints(g).indexOf("[B1]b=2;") > 0);
+bp3 = Debug.setBreakPoint(g, 3, 0);
+// function g() {
+//   [B0]a=1;
+//   [B1]b=2;
+// }[B2]
+assertTrue(Debug.showBreakPoints(g).indexOf("[B0]a=1;") > 0);
+assertTrue(Debug.showBreakPoints(g).indexOf("[B1]b=2;") > 0);
+assertTrue(Debug.showBreakPoints(g).indexOf("}[B2]") > 0);
+Debug.clearBreakPoint(bp1);
+// function g() {
+//   [B0]a=1;
+//   b=2;
+// }[B1]
+assertTrue(Debug.showBreakPoints(g).indexOf("[B0]a=1;") > 0);
+assertTrue(Debug.showBreakPoints(g).indexOf("}[B1]") > 0);
+assertTrue(Debug.showBreakPoints(g).indexOf("[B2]") < 0);
+Debug.clearBreakPoint(bp2);
+// function g() {
+//   a=1;
+//   b=2;
+// }[B0]
+assertTrue(Debug.showBreakPoints(g).indexOf("}[B0]") > 0);
+assertTrue(Debug.showBreakPoints(g).indexOf("[B1]") < 0);
+Debug.clearBreakPoint(bp3);
+// function g() {
+//   a=1;
+//   b=2;
+// }
+assertTrue(Debug.showBreakPoints(g).indexOf("[B0]") < 0);
diff --git a/regexp2000/test/mjsunit/debug-changebreakpoint.js b/regexp2000/test/mjsunit/debug-changebreakpoint.js
new file mode 100644 (file)
index 0000000..e830082
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which stores the last debug event.
+listenerComplete = false;
+exception = false;
+
+var base_request = '"seq":0,"type":"request","command":"changebreakpoint"'
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+function testArguments(dcp, arguments, success) {
+  var request = '{' + base_request + ',"arguments":' + arguments + '}'
+  var json_response = dcp.processDebugJSONRequest(request);
+  var response = safeEval(json_response);
+  if (success) {
+    assertTrue(response.success, json_response);
+  } else {
+    assertFalse(response.success, json_response);
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break) {
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Test some illegal clearbreakpoint requests.
+    var request = '{' + base_request + '}'
+    var response = safeEval(dcp.processDebugJSONRequest(request));
+    assertFalse(response.success);
+
+    testArguments(dcp, '{}', false);
+    testArguments(dcp, '{"breakpoint":0,"condition":"false"}', false);
+    // TODO(1241036) change this to 2 when break points have been restructured.
+    testArguments(dcp, '{"breakpoint":3,"condition":"false"}', false);
+    testArguments(dcp, '{"breakpoint":"xx","condition":"false"}', false);
+
+    // Test some legal clearbreakpoint requests.
+    testArguments(dcp, '{"breakpoint":1}', true);
+    testArguments(dcp, '{"breakpoint":1,"enabled":"true"}', true);
+    testArguments(dcp, '{"breakpoint":1,"enabled":"false"}', true);
+    testArguments(dcp, '{"breakpoint":1,"condition":"1==2"}', true);
+    testArguments(dcp, '{"breakpoint":1,"condition":"false"}', true);
+    testArguments(dcp, '{"breakpoint":1,"ignoreCount":7}', true);
+    testArguments(dcp, '{"breakpoint":1,"ignoreCount":0}', true);
+    testArguments(
+        dcp,
+        '{"breakpoint":1,"enabled":"true","condition":"false","ignoreCount":0}',
+        true);
+
+    // Indicate that all was processed.
+    listenerComplete = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function g() {};
+
+// Set a break point and call to invoke the debug event listener.
+bp = Debug.setBreakPoint(g, 0, 0);
+assertEquals(1, bp);
+g();
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-clearbreakpoint.js b/regexp2000/test/mjsunit/debug-clearbreakpoint.js
new file mode 100644 (file)
index 0000000..fd8b2cf
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which stores the last debug event.
+listenerComplete = false;
+exception = false;
+
+var base_request = '"seq":0,"type":"request","command":"clearbreakpoint"'
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+function testArguments(dcp, arguments, success) {
+  var request = '{' + base_request + ',"arguments":' + arguments + '}'
+  var json_response = dcp.processDebugJSONRequest(request);
+  var response = safeEval(json_response);
+  if (success) {
+    assertTrue(response.success, json_response);
+  } else {
+    assertFalse(response.success, json_response);
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break) {
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Test some illegal clearbreakpoint requests.
+    var request = '{' + base_request + '}'
+    var response = safeEval(dcp.processDebugJSONRequest(request));
+    assertFalse(response.success);
+
+    testArguments(dcp, '{}', false);
+    testArguments(dcp, '{"breakpoint":0}', false);
+    // TODO(1241036) change this to 2 when break points have been restructured.
+    testArguments(dcp, '{"breakpoint":3}', false);
+    testArguments(dcp, '{"breakpoint":"xx"}', false);
+
+    // Test some legal clearbreakpoint requests.
+    testArguments(dcp, '{"breakpoint":1}', true);
+
+    // Cannot clear the same break point twice.
+    testArguments(dcp, '{"breakpoint":1}', false);
+
+    // Indicate that all was processed.
+    listenerComplete = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function g() {};
+
+// Set a break point and call to invoke the debug event listener.
+bp = Debug.setBreakPoint(g, 0, 0);
+assertEquals(1, bp);
+g();
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-conditional-breakpoints.js b/regexp2000/test/mjsunit/debug-conditional-breakpoints.js
new file mode 100644 (file)
index 0000000..b2be625
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple debug event handler which just counts the number of break points hit.
+var break_point_hit_count;
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) {
+    break_point_hit_count++;
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test functions.
+count = 0;
+function f() {};
+function g() {h(count++)};
+function h(x) {var a=x;};
+
+
+// Conditional breakpoint which syntax error.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(f, 0, 0, '{{{');
+f();
+assertEquals(0, break_point_hit_count);
+assertEquals(0, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Conditional breakpoint which evaluates to false.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(f, 0, 0, 'false');
+f();
+assertEquals(0, break_point_hit_count);
+assertEquals(0, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Conditional breakpoint which evaluates to true.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(f, 0, 0, 'true');
+f();
+assertEquals(1, break_point_hit_count);
+assertEquals(1, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Conditional breakpoint which different types of quotes.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(f, 0, 0, '"a" == "a"');
+f();
+assertEquals(1, break_point_hit_count);
+assertEquals(1, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(f, 0, 0, "'a' == 'a'");
+f();
+assertEquals(1, break_point_hit_count);
+assertEquals(1, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Changing condition.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(f, 0, 0, '"ab".indexOf("b") > 0');
+f();
+assertEquals(1, break_point_hit_count);
+assertEquals(1, Debug.findBreakPoint(bp, false).hit_count());
+Debug.changeBreakPointCondition(bp, 'Math.sin(Math.PI/2) > 1');
+f();
+assertEquals(1, break_point_hit_count);
+assertEquals(1, Debug.findBreakPoint(bp, false).hit_count());
+Debug.changeBreakPointCondition(bp, '1==1');
+f();
+assertEquals(2, break_point_hit_count);
+assertEquals(2, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Conditional breakpoint which checks global variable.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(f, 0, 0, 'x==1');
+f();
+assertEquals(0, break_point_hit_count);
+assertEquals(0, Debug.findBreakPoint(bp, false).hit_count());
+x=1;
+f();
+assertEquals(1, break_point_hit_count);
+assertEquals(1, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Conditional breakpoint which checks global variable.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(g, 0, 0, 'count % 2 == 0');
+for (var i = 0; i < 10; i++) {
+  g();
+}
+assertEquals(5, break_point_hit_count);
+assertEquals(5, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Conditional breakpoint which checks a parameter.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(h, 0, 0, 'x % 2 == 0');
+for (var i = 0; i < 10; i++) {
+  g();
+}
+assertEquals(5, break_point_hit_count);
+assertEquals(5, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Conditional breakpoint which checks a local variable.
+break_point_hit_count = 0;
+bp = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
+for (var i = 0; i < 10; i++) {
+  g();
+}
+assertEquals(5, break_point_hit_count);
+assertEquals(5, Debug.findBreakPoint(bp, false).hit_count());
+Debug.clearBreakPoint(bp);
+
+// Multiple conditional breakpoint which the same condition.
+break_point_hit_count = 0;
+bp1 = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
+bp2 = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
+for (var i = 0; i < 10; i++) {
+  g();
+}
+assertEquals(5, break_point_hit_count);
+assertEquals(5, Debug.findBreakPoint(bp1, false).hit_count());
+assertEquals(5, Debug.findBreakPoint(bp2, false).hit_count());
+Debug.clearBreakPoint(bp1);
+Debug.clearBreakPoint(bp2);
+
+// Multiple conditional breakpoint which different conditions.
+break_point_hit_count = 0;
+bp1 = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
+bp2 = Debug.setBreakPoint(h, 0, 0, '(a + 1) % 2 == 0');
+for (var i = 0; i < 10; i++) {
+  g();
+}
+assertEquals(10, break_point_hit_count);
+assertEquals(5, Debug.findBreakPoint(bp1, false).hit_count());
+assertEquals(5, Debug.findBreakPoint(bp2, false).hit_count());
+Debug.clearBreakPoint(bp1);
+Debug.clearBreakPoint(bp2);
diff --git a/regexp2000/test/mjsunit/debug-constructed-by.js b/regexp2000/test/mjsunit/debug-constructed-by.js
new file mode 100644 (file)
index 0000000..c904e25
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple constructor.
+function Point(x,y) {}
+
+// Create mirror for the constructor.
+var ctor = debug.MakeMirror(Point);
+
+// Initially no instances.
+assertEquals(0, ctor.constructedBy().length);
+assertEquals(0, ctor.constructedBy(0).length);
+assertEquals(0, ctor.constructedBy(1).length);
+assertEquals(0, ctor.constructedBy(10).length);
+
+// Create an instance.
+var p = new Point();
+assertEquals(1, ctor.constructedBy().length);
+assertEquals(1, ctor.constructedBy(0).length);
+assertEquals(1, ctor.constructedBy(1).length);
+assertEquals(1, ctor.constructedBy(10).length);
+
+
+// Create 10 more instances making for 11.
+ps = [];
+for (var i = 0; i < 10; i++) {
+  ps.push(new Point());
+}
+assertEquals(11, ctor.constructedBy().length);
+assertEquals(11, ctor.constructedBy(0).length);
+assertEquals(1, ctor.constructedBy(1).length);
+assertEquals(10, ctor.constructedBy(10).length);
diff --git a/regexp2000/test/mjsunit/debug-constructor.js b/regexp2000/test/mjsunit/debug-constructor.js
new file mode 100644 (file)
index 0000000..12520f4
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which collects a simple call graph.
+var call_graph = "";
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break)
+  {
+    call_graph += exec_state.frame().func().name();
+    exec_state.prepareStep();
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test debug event for constructor.
+function a() {
+  new c();
+}
+
+function b() {
+  x = 1;
+  new c();
+}
+
+function c() {
+  this.x = 1;
+  d();
+}
+
+function d() {
+}
+
+// Break point stops on "new c()" and steps into c.
+Debug.setBreakPoint(a, 1);
+call_graph = "";
+a();
+Debug.clearStepping();  // Clear stepping as the listener leaves it on.
+assertEquals("accdca", call_graph);
+
+// Break point stops on "x = 1" and steps to "new c()" and then into c.
+Debug.setBreakPoint(b, 1);
+call_graph = "";
+b();
+Debug.clearStepping();  // Clear stepping as the listener leaves it on.
+assertEquals("bbccdcb", call_graph);
+
+// Get rid of the debug event listener.
+Debug.removeListener(listener);
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/debug-continue.js b/regexp2000/test/mjsunit/debug-continue.js
new file mode 100644 (file)
index 0000000..e01885c
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which stores the last debug event.
+listenerComplete = false;
+exception = false;
+
+var base_request = '"seq":0,"type":"request","command":"continue"'
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+function testArguments(dcp, arguments, success) {
+  // Generate request with the supplied arguments
+  var request;
+  if (arguments) {
+    request = '{' + base_request + ',"arguments":' + arguments + '}';
+  } else {
+    request = '{' + base_request + '}'
+  }
+  var response = safeEval(dcp.processDebugJSONRequest(request));
+  if (success) {
+    assertTrue(response.success, request + ' -> ' + response.message);
+    assertTrue(response.running, request + ' -> expected running');
+  } else {
+    assertFalse(response.success, request + ' -> ' + response.message);
+    assertFalse(response.running, request + ' -> expected not running');
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break) {
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Test simple continue request.
+    testArguments(dcp, void 0, true);
+
+    // Test some illegal continue requests.
+    testArguments(dcp, '{"stepaction":"maybe"}', false);
+    testArguments(dcp, '{"stepcount":-1}', false);
+
+    // Test some legal continue requests.
+    testArguments(dcp, '{"stepaction":"in"}', true);
+    testArguments(dcp, '{"stepaction":"min"}', true);
+    testArguments(dcp, '{"stepaction":"next"}', true);
+    testArguments(dcp, '{"stepaction":"out"}', true);
+    testArguments(dcp, '{"stepcount":1}', true);
+    testArguments(dcp, '{"stepcount":10}', true);
+    testArguments(dcp, '{"stepcount":"10"}', true);
+    testArguments(dcp, '{"stepaction":"next","stepcount":10}', true);
+
+    // Indicate that all was processed.
+    listenerComplete = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function f() {
+  a=1
+};
+
+function g() {
+  f();
+};
+
+// Set a break point and call to invoke the debug event listener.
+Debug.setBreakPoint(g, 0, 0);
+g();
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-enable-disable-breakpoints.js b/regexp2000/test/mjsunit/debug-enable-disable-breakpoints.js
new file mode 100644 (file)
index 0000000..02bfc9e
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple debug event handler which just counts the number of break points hit.
+var break_point_hit_count;
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) {
+    break_point_hit_count++;
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test function.
+function f() {a=1;b=2;};
+
+// This tests enabeling and disabling of break points including the case
+// with several break points in the same location.
+break_point_hit_count = 0;
+
+// Set a breakpoint in f.
+bp1 = Debug.setBreakPoint(f);
+f();
+assertEquals(1, break_point_hit_count);
+
+// Disable the breakpoint.
+Debug.disableBreakPoint(bp1);
+f();
+assertEquals(1, break_point_hit_count);
+
+// Enable the breakpoint.
+Debug.enableBreakPoint(bp1);
+f();
+assertEquals(2, break_point_hit_count);
+
+// Set another breakpoint in f at the same place.
+bp2 = Debug.setBreakPoint(f);
+f();
+assertEquals(3, break_point_hit_count);
+
+// Disable the second breakpoint.
+Debug.disableBreakPoint(bp2);
+f();
+assertEquals(4, break_point_hit_count);
+
+// Disable the first breakpoint.
+Debug.disableBreakPoint(bp1);
+f();
+assertEquals(4, break_point_hit_count);
+
+// Enable both breakpoints.
+Debug.enableBreakPoint(bp1);
+Debug.enableBreakPoint(bp2);
+f();
+assertEquals(5, break_point_hit_count);
+
+// Disable the first breakpoint.
+Debug.disableBreakPoint(bp1);
+f();
+assertEquals(6, break_point_hit_count);
diff --git a/regexp2000/test/mjsunit/debug-evaluate-arguments.js b/regexp2000/test/mjsunit/debug-evaluate-arguments.js
new file mode 100644 (file)
index 0000000..730e9ca
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerComplete = false;
+exception = false;
+
+function checkArguments(frame, names, values) {
+  var argc = Math.max(names.length, values.length);
+  assertEquals(argc, frame.argumentCount());
+  for (var i = 0; i < argc; i++) {
+    if (i < names.length) {
+      assertEquals(names[i], frame.argumentName(i));
+    } else {
+      assertEquals(void 0, frame.argumentName(i));
+    }
+
+    if (i < values.length) {
+      assertEquals(values[i], frame.argumentValue(i).value());
+    } else {
+      assertEquals(void 0, frame.argumentValue(i).value());
+    }
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break)
+    {
+      // Frame 0 - called with less parameters than arguments.
+      checkArguments(exec_state.frame(0), ['x', 'y'], [1]);
+
+      // Frame 1 - called with more parameters than arguments.
+      checkArguments(exec_state.frame(1), ['x', 'y'], [1, 2, 3]);
+
+      // Frame 2 - called with same number of parameters than arguments.
+      checkArguments(exec_state.frame(2), ['x', 'y', 'z'], [1, 2, 3]);
+
+      // Indicate that all was processed.
+      listenerComplete = true;
+    }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function h(x, y) {
+  debugger;  // Breakpoint.
+};
+
+function g(x, y) {
+  h(x);
+};
+
+function f(x, y, z) {
+  g.apply(null, [x, y, z]);
+};
+
+f(1, 2, 3);
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete);
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-evaluate-locals.js b/regexp2000/test/mjsunit/debug-evaluate-locals.js
new file mode 100644 (file)
index 0000000..501e34a
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerComplete = false;
+exception = false;
+
+
+function checkFrame0(name, value) {
+  assertTrue(name == 'a' || name == 'b');
+  if (name == 'a') {
+    assertEquals(1, value);
+  }
+  if (name == 'b') {
+    assertEquals(2, value);
+  }
+}
+
+
+function checkFrame1(name, value) {
+  assertTrue(name == '.arguments' || name == 'a');
+  if (name == 'a') {
+    assertEquals(3, value);
+  }
+}
+
+
+function checkFrame2(name, value) {
+  assertTrue(name == '.arguments' || name == 'a' ||
+             name == 'arguments' || name == 'b');
+  if (name == 'a') {
+    assertEquals(5, value);
+  }
+  if (name == 'b') {
+    assertEquals(0, value);
+  }
+}
+
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break)
+    {
+      // Frame 0 has normal variables a and b.
+      var frame0 = exec_state.frame(0);
+      checkFrame0(frame0.localName(0), frame0.localValue(0).value());
+      checkFrame0(frame0.localName(1), frame0.localValue(1).value());
+
+      // Frame 1 has normal variable a (and the .arguments variable).
+      var frame1 = exec_state.frame(1);
+      checkFrame1(frame1.localName(0), frame1.localValue(0).value());
+      checkFrame1(frame1.localName(1), frame1.localValue(1).value());
+
+      // Frame 2 has normal variables a and b (and both the .arguments and
+      // arguments variable).
+      var frame2 = exec_state.frame(2);
+      checkFrame2(frame2.localName(0), frame2.localValue(0).value());
+      checkFrame2(frame2.localName(1), frame2.localValue(1).value());
+      checkFrame2(frame2.localName(2), frame2.localValue(2).value());
+      checkFrame2(frame2.localName(3), frame2.localValue(3).value());
+
+      // Evaluating a and b on frames 0, 1 and 2 produces 1, 2, 3, 4, 5 and 6.
+      assertEquals(1, exec_state.frame(0).evaluate('a').value());
+      assertEquals(2, exec_state.frame(0).evaluate('b').value());
+      assertEquals(3, exec_state.frame(1).evaluate('a').value());
+      assertEquals(4, exec_state.frame(1).evaluate('b').value());
+      assertEquals(5, exec_state.frame(2).evaluate('a').value());
+      assertEquals(6, exec_state.frame(2).evaluate('b').value());
+
+      // Indicate that all was processed.
+      listenerComplete = true;
+    }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function h() {
+  var a = 1;
+  var b = 2;
+  debugger;  // Breakpoint.
+};
+
+function g() {
+  var a = 3;
+  eval("var b = 4;");
+  h();
+};
+
+function f() {
+  var a = 5;
+  var b = 0;
+  with ({b:6}) {
+    g();
+  }
+};
+
+f();
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete);
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-evaluate-recursive.js b/regexp2000/test/mjsunit/debug-evaluate-recursive.js
new file mode 100644 (file)
index 0000000..85631c1
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerComplete = false;
+exception = false;
+
+// The base part of all evaluate requests.
+var base_request = '"seq":0,"type":"request","command":"evaluate"'
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+function testRequest(dcp, arguments, success, result) {
+  // Generate request with the supplied arguments.
+  var request;
+  if (arguments) {
+    request = '{' + base_request + ',"arguments":' + arguments + '}';
+  } else {
+    request = '{' + base_request + '}'
+  }
+  var response = safeEval(dcp.processDebugJSONRequest(request));
+  if (success) {
+    assertTrue(response.success, request + ' -> ' + response.message);
+    assertEquals(result, response.body.value);
+  } else {
+    assertFalse(response.success, request + ' -> ' + response.message);
+  }
+  assertFalse(response.running, request + ' -> expected not running');
+}
+
+
+// Event listener which evaluates with break disabled.
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break)
+    {
+      // Call functions with break using the FrameMirror directly.
+      assertEquals(1, exec_state.evaluateGlobal('f()', true).value());
+      assertEquals(2, exec_state.evaluateGlobal('g()', true).value());
+      assertEquals(1, exec_state.frame(0).evaluate('f()', true).value());
+      assertEquals(2, exec_state.frame(0).evaluate('g()', true).value());
+
+      // Get the debug command processor.
+      var dcp = exec_state.debugCommandProcessor();
+
+      // Call functions with break using the JSON protocol. Tests that argument
+      // disable_break is default true.
+      testRequest(dcp, '{"expression":"f()"}', true, 1);
+      testRequest(dcp, '{"expression":"f()","frame":0}',  true, 1);
+      testRequest(dcp, '{"expression":"g()"}', true, 2);
+      testRequest(dcp, '{"expression":"g()","frame":0}',  true, 2);
+
+      // Call functions with break using the JSON protocol. Tests passing
+      // argument disable_break is default true.
+      testRequest(dcp, '{"expression":"f()","disable_break":true}', true, 1);
+      testRequest(dcp, '{"expression":"f()","frame":0,"disable_break":true}',
+                  true, 1);
+      testRequest(dcp, '{"expression":"g()","disable_break":true}', true, 2);
+      testRequest(dcp, '{"expression":"g()","frame":0,"disable_break":true}',
+                  true, 2);
+
+      // Indicate that all was processed.
+      listenerComplete = true;
+    }
+  } catch (e) {
+    exception = e
+  };
+};
+
+
+// Event listener which evaluates with break enabled one time and the second
+// time evaluates with break disabled.
+var break_count = 0;
+function listener_recurse(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break)
+    {
+      break_count++;
+      
+      // Call functions with break using the FrameMirror directly.
+      if (break_count == 1) {
+        // First break event evaluates with break enabled.
+        assertEquals(1, exec_state.frame(0).evaluate('f()', false).value());
+        listenerComplete = true;
+      } else {
+        // Second break event evaluates with break disabled.
+        assertEquals(2, break_count);
+        assertFalse(listenerComplete);
+        assertEquals(1, exec_state.frame(0).evaluate('f()', true).value());
+      }
+    }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test functions - one with break point and one with debugger statement.
+function f() {
+  return 1;
+};
+
+function g() {
+  debugger;
+  return 2;
+};
+
+Debug.setBreakPoint(f, 2, 0);
+
+// Cause a debug break event.
+debugger;
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete);
+assertFalse(exception, "exception in listener")
+
+// Remove the debug event listener.
+Debug.removeListener(listener);
+
+// Add debug event listener wich uses recursive breaks.
+listenerComplete = false;
+Debug.addListener(listener_recurse);
+
+debugger;
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete);
+assertFalse(exception, "exception in listener")
+assertEquals(2, break_count);
diff --git a/regexp2000/test/mjsunit/debug-evaluate-with.js b/regexp2000/test/mjsunit/debug-evaluate-with.js
new file mode 100644 (file)
index 0000000..e746ab2
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerComplete = false;
+exception = false;
+breakPointCount = 0;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break)
+    {
+      breakPointCount++;
+      if (breakPointCount == 1) {
+        // Break point in first with block.
+        assertEquals(2, exec_state.frame(0).evaluate('a').value());
+        assertEquals(2, exec_state.frame(0).evaluate('b').value());
+      } else {
+        // Break point in second with block.
+        assertEquals(3, exec_state.frame(0).evaluate('a').value());
+        assertEquals(1, exec_state.frame(0).evaluate('b').value());
+
+        // Indicate that all was processed.
+        listenerComplete = true;
+      }
+    }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function f() {
+  var a = 1;
+  var b = 2;
+  with ({a:2}) {
+    debugger;  // Breakpoint.
+    x = {a:3,b:1};
+    with (x) {
+      debugger;  // Breakpoint.
+    }
+  }
+};
+
+f();
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete);
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-evaluate.js b/regexp2000/test/mjsunit/debug-evaluate.js
new file mode 100644 (file)
index 0000000..9a1e427
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerComplete = false;
+exception = false;
+
+// The base part of all evaluate requests.
+var base_request = '"seq":0,"type":"request","command":"evaluate"'
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+function testRequest(dcp, arguments, success, result) {
+  // Generate request with the supplied arguments.
+  var request;
+  if (arguments) {
+    request = '{' + base_request + ',"arguments":' + arguments + '}';
+  } else {
+    request = '{' + base_request + '}'
+  }
+  var response = safeEval(dcp.processDebugJSONRequest(request));
+  if (success) {
+    assertTrue(response.success, request + ' -> ' + response.message);
+    assertEquals(result, response.body.value);
+  } else {
+    assertFalse(response.success, request + ' -> ' + response.message);
+  }
+  assertFalse(response.running, request + ' -> expected not running');
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break) {
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Test some illegal evaluate requests.
+    testRequest(dcp, void 0, false);
+    testRequest(dcp, '{"expression":"1","global"=true}', false);
+    testRequest(dcp, '{"expression":"a","frame":4}', false);
+
+    // Test some legal evaluate requests.
+    testRequest(dcp, '{"expression":"1+2"}', true, 3);
+    testRequest(dcp, '{"expression":"a+2"}', true, 5);
+    testRequest(dcp, '{"expression":"({\\"a\\":1,\\"b\\":2}).b+2"}', true, 4);
+
+    // Test evaluation of a in the stack frames and the global context.
+    testRequest(dcp, '{"expression":"a"}', true, 3);
+    testRequest(dcp, '{"expression":"a","frame":0}', true, 3);
+    testRequest(dcp, '{"expression":"a","frame":1}', true, 2);
+    testRequest(dcp, '{"expression":"a","frame":2}', true, 1);
+    testRequest(dcp, '{"expression":"a","global":true}', true, 1);
+    testRequest(dcp, '{"expression":"this.a","global":true}', true, 1);
+
+    // Indicate that all was processed.
+    listenerComplete = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function f() {
+  var a = 3;
+};
+
+function g() {
+  var a = 2;
+  f();
+};
+
+a = 1;
+
+// Set a break point at return in f and invoke g to hit the breakpoint.
+Debug.setBreakPoint(f, 2, 0);
+g();
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-event-listener.js b/regexp2000/test/mjsunit/debug-event-listener.js
new file mode 100644 (file)
index 0000000..2d9d428
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which stores the last debug event.
+lastDebugEvent = new Object();
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break ||
+      event == Debug.DebugEvent.Exception)
+  {
+    lastDebugEvent.event = event;
+    lastDebugEvent.frameFuncName = exec_state.frame().func().name();
+    lastDebugEvent.event_data = event_data;
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+// Get events from handled exceptions.
+Debug.setBreakOnException();
+
+// Test debug event for handled exception.
+(function f(){
+  try {
+    x();
+  } catch(e) {
+    // Do nothing. Ignore exception.
+  }
+})();
+assertTrue(lastDebugEvent.event == Debug.DebugEvent.Exception);
+assertEquals(lastDebugEvent.frameFuncName, "f");
+assertFalse(lastDebugEvent.event_data.uncaught());
+Debug.clearBreakOnException();
+
+// Test debug event for break point.
+function a() {
+  x = 1;
+  y = 2;
+  z = 3;
+};
+Debug.setBreakPoint(a, 1);
+a();
+assertTrue(lastDebugEvent.event == Debug.DebugEvent.Break);
+assertEquals(lastDebugEvent.frameFuncName, "a");
+
+Debug.removeListener(listener);
diff --git a/regexp2000/test/mjsunit/debug-ignore-breakpoints.js b/regexp2000/test/mjsunit/debug-ignore-breakpoints.js
new file mode 100644 (file)
index 0000000..e71e4fb
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple debug event handler which just counts the number of break points hit.
+var break_point_hit_count;
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) {
+    break_point_hit_count++;
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test function.
+function f() {};
+
+// This tests ignore of break points including the case with several
+// break points in the same location.
+break_point_hit_count = 0;
+
+// Set a breakpoint in f.
+bp1 = Debug.setBreakPoint(f);
+
+// Try ignore count of 1.
+Debug.changeBreakPointIgnoreCount(bp1, 1);
+f();
+assertEquals(0, break_point_hit_count);
+f();
+assertEquals(1, break_point_hit_count);
+
+// Set another breakpoint in f at the same place.
+bp2 = Debug.setBreakPoint(f);
+f();
+assertEquals(2, break_point_hit_count);
+
+// Set different ignore counts.
+Debug.changeBreakPointIgnoreCount(bp1, 2);
+Debug.changeBreakPointIgnoreCount(bp2, 4);
+f();
+assertEquals(2, break_point_hit_count);
+f();
+assertEquals(2, break_point_hit_count);
+f();
+assertEquals(3, break_point_hit_count);
+f();
+assertEquals(4, break_point_hit_count);
+
+// Set different ignore counts (opposite).
+Debug.changeBreakPointIgnoreCount(bp1, 4);
+Debug.changeBreakPointIgnoreCount(bp2, 2);
+f();
+assertEquals(4, break_point_hit_count);
+f();
+assertEquals(4, break_point_hit_count);
+f();
+assertEquals(5, break_point_hit_count);
+f();
+assertEquals(6, break_point_hit_count);
+
diff --git a/regexp2000/test/mjsunit/debug-multiple-breakpoints.js b/regexp2000/test/mjsunit/debug-multiple-breakpoints.js
new file mode 100644 (file)
index 0000000..2bdff57
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple debug event handler which just counts the number of break points hit.
+var break_point_hit_count;
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) {
+    break_point_hit_count++;
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test functions
+function f() {a=1;b=2;};
+function g() {f();}
+function h() {}
+
+// This test sets several break points at the same place and checks that
+// several break points at the same place only makes one debug break event
+// and that when the last break point is removed no more debug break events
+// occours.
+break_point_hit_count = 0;
+
+// Set a breakpoint in f.
+bp1 = Debug.setBreakPoint(f);
+f();
+assertEquals(1, break_point_hit_count);
+
+// Set another breakpoint in f at the same place.
+bp2 = Debug.setBreakPoint(f);
+f();
+assertEquals(2, break_point_hit_count);
+
+// Remove one of the break points.
+Debug.clearBreakPoint(bp1);
+f();
+assertEquals(3, break_point_hit_count);
+
+// Remove the second break point.
+Debug.clearBreakPoint(bp2);
+f();
+assertEquals(3, break_point_hit_count);
+
+// Perform the same test using function g (this time removing the break points
+// in the another order).
+break_point_hit_count = 0;
+bp1 = Debug.setBreakPoint(g);
+g();
+assertEquals(1, break_point_hit_count);
+bp2 = Debug.setBreakPoint(g);
+g();
+assertEquals(2, break_point_hit_count);
+Debug.clearBreakPoint(bp2);
+g();
+assertEquals(3, break_point_hit_count);
+Debug.clearBreakPoint(bp1);
+g();
+assertEquals(3, break_point_hit_count);
+
+// Finally test with many break points.
+test_count = 100;
+bps = new Array(test_count);
+break_point_hit_count = 0;
+for (var i = 0; i < test_count; i++) {
+  bps[i] = Debug.setBreakPoint(h);
+  h();
+}
+for (var i = 0; i < test_count; i++) {
+  h();
+  Debug.clearBreakPoint(bps[i]);
+}
+assertEquals(test_count * 2, break_point_hit_count);
+h();
+assertEquals(test_count * 2, break_point_hit_count);
diff --git a/regexp2000/test/mjsunit/debug-referenced-by.js b/regexp2000/test/mjsunit/debug-referenced-by.js
new file mode 100644 (file)
index 0000000..2b35a9c
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple object.
+var a = {};
+
+// Create mirror for the object.
+var mirror = debug.MakeMirror(a);
+
+// Initially one reference from the global object.
+assertEquals(1, mirror.referencedBy().length);
+assertEquals(1, mirror.referencedBy(0).length);
+assertEquals(1, mirror.referencedBy(1).length);
+assertEquals(1, mirror.referencedBy(10).length);
+
+// Add some more references from simple objects and arrays.
+var b = {}
+b.a = a;
+assertEquals(2, mirror.referencedBy().length);
+var c = {}
+c.a = a;
+c.aa = a;
+c.aaa = a;
+assertEquals(3, mirror.referencedBy().length);
+function d(){};
+d.a = a
+assertEquals(4, mirror.referencedBy().length);
+e = [a,b,c,d];
+assertEquals(5, mirror.referencedBy().length);
+
+
+// Simple closure.
+function closure_simple(p) {
+  return function() { p = null; };
+}
+
+// This adds a reference (function context).
+f = closure_simple(a);
+assertEquals(6, mirror.referencedBy().length);
+// This clears the reference (in function context).
+f()
+assertEquals(5, mirror.referencedBy().length);
+
+// Use closure with eval - creates arguments array.
+function closure_eval(p, s) {
+  if (s) {
+    eval(s);
+  }
+  return function e(s) { eval(s); };
+}
+
+// This adds a references (function context).
+g = closure_eval(a);
+assertEquals(6, mirror.referencedBy().length);
+
+// Dynamically create a variable. This should create a context extension.
+h = closure_eval(null, "var x_");
+assertEquals(6, mirror.referencedBy().length);
+// Adds a reference when set.
+h("x_ = a");
+var x = mirror.referencedBy();
+// TODO(1323070) This should be 7 and not 8. 8 is caused by the context
+// extension object beeing part of the result.
+assertEquals(8, mirror.referencedBy().length);
+// Removes a reference when cleared.
+h("x_ = null");
+assertEquals(6, mirror.referencedBy().length);
+
+// Check circular references.
+x = {}
+mirror = debug.MakeMirror(x);
+assertEquals(1, mirror.referencedBy().length);
+x.x = x;
+assertEquals(2, mirror.referencedBy().length);
+x = null;
+assertEquals(0, mirror.referencedBy().length);
+
+// Check many references.
+y = {}
+mirror = debug.MakeMirror(y);
+refs = [];
+for (var i = 0; i < 200; i++) {
+  refs[i] = {'y': y};
+}
+y = null;
+assertEquals(200, mirror.referencedBy().length);
diff --git a/regexp2000/test/mjsunit/debug-script-breakpoints.js b/regexp2000/test/mjsunit/debug-script-breakpoints.js
new file mode 100644 (file)
index 0000000..28c8018
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Set and remove a script break point.
+var sbp = Debug.setScriptBreakPoint("1", 2, 3);
+assertEquals(1, Debug.scriptBreakPoints().length);
+assertEquals("1", Debug.scriptBreakPoints()[0].script_name());
+assertEquals(2, Debug.scriptBreakPoints()[0].line());
+assertEquals(3, Debug.scriptBreakPoints()[0].column());
+Debug.clearBreakPoint(sbp);
+assertEquals(0, Debug.scriptBreakPoints().length);
+
+// Set three script break points.
+var sbp1 = Debug.setScriptBreakPoint("1", 2, 3);
+var sbp2 = Debug.setScriptBreakPoint("2", 3, 4);
+var sbp3 = Debug.setScriptBreakPoint("3", 4, 5);
+
+// Check the content of the script break points.
+assertEquals(3, Debug.scriptBreakPoints().length);
+for (var i = 0; i < Debug.scriptBreakPoints().length; i++) {
+  var x = Debug.scriptBreakPoints()[i];
+  if ("1" == x.script_name()) {
+    assertEquals(2, x.line());
+    assertEquals(3, x.column());
+  } else if ("2" == x.script_name()) {
+    assertEquals(3, x.line());
+    assertEquals(4, x.column());
+  } else if ("3" == x.script_name()) {
+    assertEquals(4, x.line());
+    assertEquals(5, x.column());
+  } else {
+    assertUnreachable("unecpected script_data " + x.script_data());
+  }
+}
+
+// Remove script break points (in another order than they where added).
+assertEquals(3, Debug.scriptBreakPoints().length);
+Debug.clearBreakPoint(sbp1);
+assertEquals(2, Debug.scriptBreakPoints().length);
+Debug.clearBreakPoint(sbp3);
+assertEquals(1, Debug.scriptBreakPoints().length);
+Debug.clearBreakPoint(sbp2);
+assertEquals(0, Debug.scriptBreakPoints().length);
diff --git a/regexp2000/test/mjsunit/debug-script.js b/regexp2000/test/mjsunit/debug-script.js
new file mode 100644 (file)
index 0000000..4a77c3c
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --expose-gc
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+Date();
+RegExp();
+
+// Count script types.
+var native_count = 0;
+var extension_count = 0;
+var normal_count = 0;
+var scripts = Debug.scripts();
+for (i = 0; i < scripts.length; i++) {
+  if (scripts[i].type == Debug.ScriptType.Native) {
+    native_count++;
+  } else if (scripts[i].type == Debug.ScriptType.Extension) {
+    extension_count++;
+  } else if (scripts[i].type == Debug.ScriptType.Normal) {
+    if (!scripts[i].name) print("X" + scripts[i].source + "X"); // empty script
+    else {
+      print(scripts[i].name);
+      normal_count++;
+      }
+  } else {
+    assertUnreachable('Unexpected type ' + scripts[i].type);
+  }
+}
+
+// This has to be updated if the number of native scripts change.
+assertEquals(12, native_count);
+// If no snapshot is used, only the 'gc' extension is loaded.
+// If snapshot is used, all extensions are cached in the snapshot.
+assertTrue(extension_count == 1 || extension_count == 5);
+assertEquals(2, normal_count);  // This script and mjsunit.js.
+
+// Test a builtins script.
+var math_script = Debug.findScript('native math.js');
+assertEquals('native math.js', math_script.name);
+assertEquals(Debug.ScriptType.Native, math_script.type);
+
+// Test a builtins delay loaded script.
+var date_delay_script = Debug.findScript('native date.js');
+assertEquals('native date.js', date_delay_script.name);
+assertEquals(Debug.ScriptType.Native, date_delay_script.type);
+
+// Test a debugger script.
+var debug_delay_script = Debug.findScript('native debug.js');
+assertEquals('native debug.js', debug_delay_script.name);
+assertEquals(Debug.ScriptType.Native, debug_delay_script.type);
+
+// Test an extension script.
+var extension_gc_script = Debug.findScript('v8/gc');
+if (extension_gc_script) {
+  assertEquals('v8/gc', extension_gc_script.name);
+  assertEquals(Debug.ScriptType.Extension, extension_gc_script.type);
+}
+
+// Test a normal script.
+var mjsunit_js_script = Debug.findScript(/mjsunit.js/);
+assertTrue(/mjsunit.js/.test(mjsunit_js_script.name));
+assertEquals(Debug.ScriptType.Normal, mjsunit_js_script.type);
+
+// Check a nonexistent script.
+var dummy_script = Debug.findScript('dummy.js');
+assertTrue(typeof dummy_script == 'undefined');
diff --git a/regexp2000/test/mjsunit/debug-scripts-request.js b/regexp2000/test/mjsunit/debug-scripts-request.js
new file mode 100644 (file)
index 0000000..0fc857a
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// State to check that the listener code was invoked and that no exceptions
+// occoured.
+listenerComplete = false;
+exception = false;
+
+var base_request = '"seq":0,"type":"request","command":"scripts"'
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+function testArguments(dcp, arguments, success) {
+  var request = '{' + base_request + ',"arguments":' + arguments + '}'
+  var json_response = dcp.processDebugJSONRequest(request);
+  var response = safeEval(json_response);
+  if (success) {
+    assertTrue(response.success, json_response);
+  } else {
+    assertFalse(response.success, json_response);
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break) {
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Test illegal scripts requests.
+    testArguments(dcp, '{"types":"xx"}', false);
+
+    // Test legal scripts requests.
+    var request = '{' + base_request + '}'
+    var response = safeEval(dcp.processDebugJSONRequest(request));
+    assertTrue(response.success);
+    testArguments(dcp, '{}', true);
+    testArguments(dcp, '{"types":1}', true);
+    testArguments(dcp, '{"types":2}', true);
+    testArguments(dcp, '{"types":4}', true);
+    testArguments(dcp, '{"types":7}', true);
+    testArguments(dcp, '{"types":0xFF}', true);
+
+    // Indicate that all was processed.
+    listenerComplete = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Call debugger to invoke the debug event listener.
+debugger;
+
+// Make sure that the debug event listener vas invoked with no exceptions.
+assertTrue(listenerComplete, "listener did not run to completion");
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-setbreakpoint.js b/regexp2000/test/mjsunit/debug-setbreakpoint.js
new file mode 100644 (file)
index 0000000..faf8036
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which stores the last debug event.
+listenerComplete = false;
+exception = false;
+
+var base_request = '"seq":0,"type":"request","command":"setbreakpoint"'
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  }
+}
+
+function testArguments(dcp, arguments, success, type) {
+  var request = '{' + base_request + ',"arguments":' + arguments + '}'
+  var json_response = dcp.processDebugJSONRequest(request);
+  var response = safeEval(json_response);
+  if (success) {
+    assertTrue(response.success, json_response);
+    assertEquals(type ? type : 'script', response.body.type, json_response);
+  } else {
+    assertFalse(response.success, json_response);
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Break) {
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Test some illegal setbreakpoint requests.
+    var request = '{' + base_request + '}'
+    var response = safeEval(dcp.processDebugJSONRequest(request));
+    assertFalse(response.success);
+
+    testArguments(dcp, '{}', false);
+    testArguments(dcp, '{"type":"xx"}', false);
+    testArguments(dcp, '{"type":"function"}', false);
+    testArguments(dcp, '{"type":"script"}', false);
+    testArguments(dcp, '{"target":"f"}', false);
+    testArguments(dcp, '{"type":"xx","target":"xx"}', false);
+    testArguments(dcp, '{"type":"function","target":1}', false);
+    testArguments(dcp, '{"type":"function","target":"f","line":-1}', false);
+    testArguments(dcp, '{"type":"function","target":"f","column":-1}', false);
+    testArguments(dcp, '{"type":"function","target":"f","ignoreCount":-1}', false);
+
+    // Test some legal setbreakpoint requests.
+    testArguments(dcp, '{"type":"function","target":"f"}', true);
+    testArguments(dcp, '{"type":"function","target":"h"}', true, 'function');
+    testArguments(dcp, '{"type":"function","target":"f","line":1}', true);
+    testArguments(dcp, '{"type":"function","target":"f","position":1}', true);
+    testArguments(dcp, '{"type":"function","target":"f","condition":"i == 1"}', true);
+    testArguments(dcp, '{"type":"function","target":"f","enabled":true}', true);
+    testArguments(dcp, '{"type":"function","target":"f","enabled":false}', true);
+    testArguments(dcp, '{"type":"function","target":"f","ignoreCount":7}', true);
+    testArguments(dcp, '{"type":"script","target":"test"}', true);
+    testArguments(dcp, '{"type":"script","target":"test"}', true);
+    testArguments(dcp, '{"type":"script","target":"test","line":1}', true);
+    testArguments(dcp, '{"type":"script","target":"test","column":1}', true);
+
+    // Indicate that all was processed.
+    listenerComplete = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function f() {
+  a=1
+};
+
+function g() {
+  f();
+};
+
+eval('function h(){}');
+
+// Set a break point and call to invoke the debug event listener.
+Debug.setBreakPoint(g, 0, 0);
+g();
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/debug-sourceinfo.js b/regexp2000/test/mjsunit/debug-sourceinfo.js
new file mode 100644 (file)
index 0000000..2bad07a
--- /dev/null
@@ -0,0 +1,276 @@
+// Copyright 2008 the V8 project authors. All rights reserved.\r
+// Redistribution and use in source and binary forms, with or without\r
+// modification, are permitted provided that the following conditions are\r
+// met:\r
+//\r
+//     * Redistributions of source code must retain the above copyright\r
+//       notice, this list of conditions and the following disclaimer.\r
+//     * Redistributions in binary form must reproduce the above\r
+//       copyright notice, this list of conditions and the following\r
+//       disclaimer in the documentation and/or other materials provided\r
+//       with the distribution.\r
+//     * Neither the name of Google Inc. nor the names of its\r
+//       contributors may be used to endorse or promote products derived\r
+//       from this software without specific prior written permission.\r
+//\r
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+\r
+// Flags: --expose-debug-as debug\r
+// For this test to work this file MUST have CR LF line endings.\r
+function a() { b(); };\r
+function    b() {\r
+  c(true);\r
+};\r
+  function c(x) {\r
+    if (x) {\r
+      return 1;\r
+    } else {\r
+      return 1;\r
+    }\r
+  };\r
+\r
+// Get the Debug object exposed from the debug context global object.\r
+Debug = debug.Debug\r
+\r
+// This is the number of comment lines above the first test function.\r
+var comment_lines = 29;\r
+\r
+// This magic number is the length or the first line comment (actually number\r
+// of characters before 'function a(...'.\r
+var comment_line_length = 1726;\r
+var start_a = 10 + comment_line_length;\r
+var start_b = 37 + comment_line_length;\r
+var start_c = 71 + comment_line_length;\r
+\r
+assertEquals(start_a, Debug.sourcePosition(a));\r
+assertEquals(start_b, Debug.sourcePosition(b));\r
+assertEquals(start_c, Debug.sourcePosition(c));\r
+\r
+var script = Debug.findScript(a);\r
+assertTrue(script.data === Debug.findScript(b).data);\r
+assertTrue(script.data === Debug.findScript(c).data);\r
+assertTrue(script.source === Debug.findScript(b).source);\r
+assertTrue(script.source === Debug.findScript(c).source);\r
+\r
+// Test that when running through source positions the position, line and\r
+// column progresses as expected.\r
+var position;\r
+var line;\r
+var column;\r
+for (var p = 0; p < 100; p++) {\r
+  var location = script.locationFromPosition(p);\r
+  if (p > 0) {\r
+    assertEquals(position + 1, location.position);\r
+    if (line == location.line) {\r
+      assertEquals(column + 1, location.column);\r
+    } else {\r
+      assertEquals(line + 1, location.line);\r
+      assertEquals(0, location.column);\r
+    }\r
+  } else {\r
+    assertEquals(0, location.position);\r
+    assertEquals(0, location.line);\r
+    assertEquals(0, location.column);\r
+  }\r
+\r
+  // Remember the location.\r
+  position = location.position;\r
+  line = location.line;\r
+  column = location.column;\r
+}\r
+\r
+// Test first position.\r
+assertEquals(0, script.locationFromPosition(0).position);\r
+assertEquals(0, script.locationFromPosition(0).line);\r
+assertEquals(0, script.locationFromPosition(0).column);\r
+\r
+// Test second position.\r
+assertEquals(1, script.locationFromPosition(1).position);\r
+assertEquals(0, script.locationFromPosition(1).line);\r
+assertEquals(1, script.locationFromPosition(1).column);\r
+\r
+// Test first position in finction a.\r
+assertEquals(start_a, script.locationFromPosition(start_a).position);\r
+assertEquals(0, script.locationFromPosition(start_a).line - comment_lines);\r
+assertEquals(10, script.locationFromPosition(start_a).column);\r
+\r
+// Test first position in finction b.\r
+assertEquals(start_b, script.locationFromPosition(start_b).position);\r
+assertEquals(1, script.locationFromPosition(start_b).line - comment_lines);\r
+assertEquals(13, script.locationFromPosition(start_b).column);\r
+\r
+// Test first position in finction b.\r
+assertEquals(start_c, script.locationFromPosition(start_c).position);\r
+assertEquals(4, script.locationFromPosition(start_c).line - comment_lines);\r
+assertEquals(12, script.locationFromPosition(start_c).column);\r
+\r
+// Test first line.\r
+assertEquals(0, script.locationFromLine().position);\r
+assertEquals(0, script.locationFromLine().line);\r
+assertEquals(0, script.locationFromLine().column);\r
+assertEquals(0, script.locationFromLine(0).position);\r
+assertEquals(0, script.locationFromLine(0).line);\r
+assertEquals(0, script.locationFromLine(0).column);\r
+\r
+// Test first line column 1\r
+assertEquals(1, script.locationFromLine(0, 1).position);\r
+assertEquals(0, script.locationFromLine(0, 1).line);\r
+assertEquals(1, script.locationFromLine(0, 1).column);\r
+\r
+// Test first line offset 1\r
+assertEquals(1, script.locationFromLine(0, 0, 1).position);\r
+assertEquals(0, script.locationFromLine(0, 0, 1).line);\r
+assertEquals(1, script.locationFromLine(0, 0, 1).column);\r
+\r
+// Test offset function a\r
+assertEquals(start_a, script.locationFromLine(void 0, void 0, start_a).position);\r
+assertEquals(0, script.locationFromLine(void 0, void 0, start_a).line - comment_lines);\r
+assertEquals(10, script.locationFromLine(void 0, void 0, start_a).column);\r
+assertEquals(start_a, script.locationFromLine(0, void 0, start_a).position);\r
+assertEquals(0, script.locationFromLine(0, void 0, start_a).line - comment_lines);\r
+assertEquals(10, script.locationFromLine(0, void 0, start_a).column);\r
+assertEquals(start_a, script.locationFromLine(0, 0, start_a).position);\r
+assertEquals(0, script.locationFromLine(0, 0, start_a).line - comment_lines);\r
+assertEquals(10, script.locationFromLine(0, 0, start_a).column);\r
+\r
+// Test second line offset function a\r
+assertEquals(start_a + 14, script.locationFromLine(1, 0, start_a).position);\r
+assertEquals(1, script.locationFromLine(1, 0, start_a).line - comment_lines);\r
+assertEquals(0, script.locationFromLine(1, 0, start_a).column);\r
+\r
+// Test second line column 2 offset function a\r
+assertEquals(start_a + 14 + 2, script.locationFromLine(1, 2, start_a).position);\r
+assertEquals(1, script.locationFromLine(1, 2, start_a).line - comment_lines);\r
+assertEquals(2, script.locationFromLine(1, 2, start_a).column);\r
+\r
+// Test offset function b\r
+assertEquals(start_b, script.locationFromLine(0, 0, start_b).position);\r
+assertEquals(1, script.locationFromLine(0, 0, start_b).line - comment_lines);\r
+assertEquals(13, script.locationFromLine(0, 0, start_b).column);\r
+\r
+// Test second line offset function b\r
+assertEquals(start_b + 6, script.locationFromLine(1, 0, start_b).position);\r
+assertEquals(2, script.locationFromLine(1, 0, start_b).line - comment_lines);\r
+assertEquals(0, script.locationFromLine(1, 0, start_b).column);\r
+\r
+// Test second line column 11 offset function b\r
+assertEquals(start_b + 6 + 11, script.locationFromLine(1, 11, start_b).position);\r
+assertEquals(2, script.locationFromLine(1, 11, start_b).line - comment_lines);\r
+assertEquals(11, script.locationFromLine(1, 11, start_b).column);\r
+\r
+// Test second line column 12 offset function b. Second line in b is 11 long\r
+// using column 12 wraps to next line.\r
+assertEquals(start_b + 6 + 12, script.locationFromLine(1, 12, start_b).position);\r
+assertEquals(3, script.locationFromLine(1, 12, start_b).line - comment_lines);\r
+assertEquals(0, script.locationFromLine(1, 12, start_b).column);\r
+\r
+// Test the Debug.findSourcePosition which wraps SourceManager.\r
+assertEquals(0 + start_a, Debug.findFunctionSourcePosition(a, 0, 0));\r
+assertEquals(0 + start_b, Debug.findFunctionSourcePosition(b, 0, 0));\r
+assertEquals(6 + start_b, Debug.findFunctionSourcePosition(b, 1, 0));\r
+assertEquals(8 + start_b, Debug.findFunctionSourcePosition(b, 1, 2));\r
+assertEquals(18 + start_b, Debug.findFunctionSourcePosition(b, 2, 0));\r
+assertEquals(0 + start_c, Debug.findFunctionSourcePosition(c, 0, 0));\r
+assertEquals(7 + start_c, Debug.findFunctionSourcePosition(c, 1, 0));\r
+assertEquals(21 + start_c, Debug.findFunctionSourcePosition(c, 2, 0));\r
+assertEquals(38 + start_c, Debug.findFunctionSourcePosition(c, 3, 0));\r
+assertEquals(52 + start_c, Debug.findFunctionSourcePosition(c, 4, 0));\r
+assertEquals(69 + start_c, Debug.findFunctionSourcePosition(c, 5, 0));\r
+assertEquals(76 + start_c, Debug.findFunctionSourcePosition(c, 6, 0));\r
+\r
+// Test source line and restriction. All the following tests start from line 1\r
+// column 2 in function b, which is the call to c.\r
+//   c(true);\r
+//   ^\r
+\r
+var location;\r
+\r
+location = script.locationFromLine(1, 0, start_b);\r
+assertEquals('  c(true);', location.sourceText());\r
+\r
+result = ['c', ' c', ' c(', '  c(', '  c(t']\r
+for (var i = 1; i <= 5; i++) {\r
+  location = script.locationFromLine(1, 2, start_b);\r
+  location.restrict(i);\r
+  assertEquals(result[i - 1], location.sourceText());\r
+}\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(1, 0);\r
+assertEquals('c', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(2, 0);\r
+assertEquals('c(', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(2, 1);\r
+assertEquals(' c', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(2, 2);\r
+assertEquals(' c', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(2, 3);\r
+assertEquals(' c', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(3, 1);\r
+assertEquals(' c(', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(5, 0);\r
+assertEquals('c(tru', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(5, 2);\r
+assertEquals('  c(t', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 2, start_b);\r
+location.restrict(5, 4);\r
+assertEquals('  c(t', location.sourceText());\r
+\r
+// All the following tests start from line 1 column 10 in function b, which is\r
+// the final character.\r
+//   c(true);\r
+//          ^\r
+\r
+location = script.locationFromLine(1, 10, start_b);\r
+location.restrict(5, 0);\r
+assertEquals('rue);', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 10, start_b);\r
+location.restrict(7, 0);\r
+assertEquals('(true);', location.sourceText());\r
+\r
+// All the following tests start from line 1 column 0 in function b, which is\r
+// the first character.\r
+//   c(true);\r
+//^\r
+\r
+location = script.locationFromLine(1, 0, start_b);\r
+location.restrict(5, 0);\r
+assertEquals('  c(t', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 0, start_b);\r
+location.restrict(5, 4);\r
+assertEquals('  c(t', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 0, start_b);\r
+location.restrict(7, 0);\r
+assertEquals('  c(tru', location.sourceText());\r
+\r
+location = script.locationFromLine(1, 0, start_b);\r
+location.restrict(7, 6);\r
+assertEquals('  c(tru', location.sourceText());\r
diff --git a/regexp2000/test/mjsunit/debug-sourceslice.js b/regexp2000/test/mjsunit/debug-sourceslice.js
new file mode 100644 (file)
index 0000000..db9a3e7
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Source lines for test.
+var lines = [ 'function a() { b(); };\n',
+              'function    b() {\n',
+              '  c(true);\n',
+              '};\n',
+              '  function c(x) {\n',
+              '    if (x) {\n',
+              '      return 1;\n',
+              '    } else {\n',
+              '      return 1;\n',
+              '    }\n',
+              '  };\n' ];
+
+// Build source by putting all lines together
+var source = '';
+for (var i = 0; i < lines.length; i++) {
+  source += lines[i];
+}
+eval(source);
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Get the script object from one of the functions in the source.
+var script = Debug.findScript(a);
+
+// Make sure that the source is as expected.
+assertEquals(source, script.source);
+assertEquals(source, script.sourceSlice().sourceText());
+
+// Try all possible line interval slices.
+for (var slice_size = 0; slice_size < lines.length; slice_size++) {
+  for (var n = 0; n < lines.length - slice_size; n++) {
+    var slice = script.sourceSlice(n, n + slice_size);
+    assertEquals(n, slice.from_line);
+    assertEquals(n + slice_size, slice.to_line);
+
+    var text = slice.sourceText();
+    var expected = '';
+    for (var i = 0; i < slice_size; i++) {
+      expected += lines[n + i];
+    }
+    assertEquals(expected, text);
+  }
+}
diff --git a/regexp2000/test/mjsunit/debug-step-stub-callfunction.js b/regexp2000/test/mjsunit/debug-step-stub-callfunction.js
new file mode 100644 (file)
index 0000000..991c62e
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple debug event handler which counts the number of breaks hit and steps.
+var break_break_point_hit_count = 0;
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) {
+    break_break_point_hit_count++;
+    // Continue stepping until returned to bottom frame.
+    if (exec_state.frameCount() > 1) {
+      exec_state.prepareStep(Debug.StepAction.StepIn);
+    }
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Use 'eval' to ensure that the call to print is through CodeStub CallFunction.
+// See Ia32CodeGenerator::VisitCall and Ia32CodeGenerator::CallWithArguments.
+function f() {
+  debugger;
+  eval('');
+  print('Hello, world!');
+};
+
+break_break_point_hit_count = 0;
+f();
+assertEquals(5, break_break_point_hit_count);
+
+// Use an inner function to ensure that the function call is through CodeStub
+// CallFunction see Ia32CodeGenerator::VisitCall and
+// Ia32CodeGenerator::CallWithArguments.
+function g() {
+  function h() {}
+  debugger;
+  h();
+};
+
+break_break_point_hit_count = 0;
+g();
+assertEquals(4, break_break_point_hit_count);
+
+// Get rid of the debug event listener.
+Debug.removeListener(listener);
diff --git a/regexp2000/test/mjsunit/debug-step.js b/regexp2000/test/mjsunit/debug-step.js
new file mode 100644 (file)
index 0000000..1c0b383
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple debug event handler which first time hit will perform 1000 steps and
+// second time hit will evaluate and store the value of "i". If requires that
+// the global property "state" is initially zero.
+
+var bp1, bp2;
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break)
+  {
+    if (state == 0) {
+      exec_state.prepareStep(Debug.StepAction.StepIn, 1000);
+      state = 1;
+    } else if (state == 1) {
+      result = exec_state.frame().evaluate("i").value();
+      // Clear the break point on line 2 if set.
+      if (bp2) {
+        Debug.clearBreakPoint(bp2);
+      }
+    }
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test debug event for break point.
+function f() {
+  for (i = 0; i < 1000; i++) {  //  Line 1.
+    x = 1;                      //  Line 2.
+  }
+};
+
+// Set a breakpoint on the for statement (line 1).
+bp1 = Debug.setBreakPoint(f, 1);
+
+// Check that performing 1000 steps will make i 499.
+state = 0;
+result = -1;
+f();
+print(state);
+assertEquals(499, result);
+
+// Check that performing 1000 steps with a break point on the statement in the
+// for loop (line 2) will only make i 0 as a real break point breaks even when
+// multiple steps have been requested.
+state = 0;
+result = -1;
+bp2 = Debug.setBreakPoint(f, 2);
+f();
+assertEquals(0, result);
+
+// Get rid of the debug event listener.
+Debug.removeListener(listener);
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/debug-stepin-constructor.js b/regexp2000/test/mjsunit/debug-stepin-constructor.js
new file mode 100644 (file)
index 0000000..ecd1283
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple debug event handler which counts the number of breaks hit and steps.
+var break_break_point_hit_count = 0;
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) {
+    break_break_point_hit_count++;
+    // Continue stepping until returned to bottom frame.
+    if (exec_state.frameCount() > 1) {
+      exec_state.prepareStep(Debug.StepAction.StepIn);
+    }
+    
+    // Test that there is a script.
+    assertTrue(typeof(event_data.func().script()) == 'object');
+  }
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Test step into constructor with simple constructor.
+function X() {
+}
+
+function f() {
+  debugger;
+  new X();
+};
+
+break_break_point_hit_count = 0;
+f();
+assertEquals(5, break_break_point_hit_count);
+
+// Test step into constructor with builtin constructor.
+function g() {
+  debugger;
+  new Date();
+};
+
+break_break_point_hit_count = 0;
+g();
+assertEquals(5, break_break_point_hit_count);
+
+// Get rid of the debug event listener.
+Debug.removeListener(listener);
diff --git a/regexp2000/test/mjsunit/declare-locally.js b/regexp2000/test/mjsunit/declare-locally.js
new file mode 100644 (file)
index 0000000..93fcb85
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure that we're not overwriting global
+// properties defined in the prototype chain too
+// early when shadowing them with var/const
+// declarations.
+
+// This exercises the code in runtime.cc in
+// DeclareGlobal...Locally().
+
+this.__proto__.foo = 42;
+this.__proto__.bar = 87;
+
+eval("assertEquals(42, foo); var foo = 87;");
+assertEquals(87, foo);
+
+eval("assertEquals(87, bar); const bar = 42;");
+assertEquals(42, bar);
diff --git a/regexp2000/test/mjsunit/deep-recursion.js b/regexp2000/test/mjsunit/deep-recursion.js
new file mode 100644 (file)
index 0000000..a8093eb
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Check that flattening deep trees of cons strings does not
+ * cause stack overflows.
+ */
+
+var depth = 110000;
+
+function newdeep(start) {
+  var d = start;
+  for (var i = 0; i < depth; i++) {
+    d = d + "f";
+  }
+  return d;
+}
+
+var deep = newdeep("foo");
+assertEquals('f', deep[0]);
+
+var cmp1 = newdeep("a");
+var cmp2 = newdeep("b");
+
+assertEquals(-1, cmp1.localeCompare(cmp2), "ab");
+
+var cmp2empty = newdeep("c");
+assertTrue(cmp2empty.localeCompare("") > 0, "c");
+
+var cmp3empty = newdeep("d");
+assertTrue("".localeCompare(cmp3empty) < 0), "d";
+
+var slicer = newdeep("slice");
+
+for (i = 0; i < depth + 4; i += 2) {
+  slicer =  slicer.slice(1, -1);
+}
+
+assertEquals("f", slicer[0]);
+assertEquals(1, slicer.length);
diff --git a/regexp2000/test/mjsunit/delay-syntax-error.js b/regexp2000/test/mjsunit/delay-syntax-error.js
new file mode 100644 (file)
index 0000000..4fcb143
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// To be compatible with KJS syntax errors for illegal return, break
+// and continue should be delayed to runtime.
+
+// Do not throw syntax errors for illegal return, break and continue
+// at compile time.
+assertDoesNotThrow("if (false) return;");
+assertDoesNotThrow("if (false) break;");
+assertDoesNotThrow("if (false) continue;");
+
+// Throw syntax errors for illegal return, break and continue at
+// compile time.
+assertThrows("return;");
+assertThrows("break;");
+assertThrows("continue;");
diff --git a/regexp2000/test/mjsunit/delete-global-properties.js b/regexp2000/test/mjsunit/delete-global-properties.js
new file mode 100644 (file)
index 0000000..b3813dc
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Global properties declared with 'var' or 'function' should not be
+// deleteable.
+var tmp;
+assertFalse(delete tmp);  // should be DONT_DELETE
+assertTrue("tmp" in this);
+function f() { return 1; }
+assertFalse(delete f);  // should be DONT_DELETE
+assertEquals(1, f());  
+
+/* Perhaps related to bugs/11? */
diff --git a/regexp2000/test/mjsunit/delete-in-eval.js b/regexp2000/test/mjsunit/delete-in-eval.js
new file mode 100644 (file)
index 0000000..9278013
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Should be able to delete properties in the context through eval().
+tmp = 0;
+assertTrue(eval("delete XXX"));  // non-existing
+assertTrue(eval("delete tmp"));  // existing
+assertFalse("tmp" in this);
diff --git a/regexp2000/test/mjsunit/delete-in-with.js b/regexp2000/test/mjsunit/delete-in-with.js
new file mode 100644 (file)
index 0000000..1efc18d
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// It should be possible to delete properties of 'with' context
+// objects from within 'with' statements.
+(function(){
+  var tmp = { x: 12 };
+  with (tmp) { assertTrue(delete x); }  
+  assertFalse("x" in tmp);
+})();
diff --git a/regexp2000/test/mjsunit/delete-vars-from-eval.js b/regexp2000/test/mjsunit/delete-vars-from-eval.js
new file mode 100644 (file)
index 0000000..a457466
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Variable declarations in eval() must introduce delete-able vars;
+// even when they are local to a function.
+(function() {
+  eval("var tmp0 = 0");
+  assertEquals(0, tmp0);
+  assertTrue(delete tmp0);
+  assertTrue(typeof(tmp0) == 'undefined');
+})();
+
+eval("var tmp1 = 1");
+assertEquals(1, tmp1);
+assertTrue(delete tmp1);
+assertTrue(typeof(tmp1) == 'undefined');
diff --git a/regexp2000/test/mjsunit/delete.js b/regexp2000/test/mjsunit/delete.js
new file mode 100644 (file)
index 0000000..6fc15e9
--- /dev/null
@@ -0,0 +1,163 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// We use the has() function to avoid relying on a functioning
+// implementation of 'in'.
+function has(o, k) { return typeof o[k] !== 'undefined'; }
+
+assertTrue(delete null);
+assertTrue(delete 2);
+assertTrue(delete 'foo');
+assertTrue(delete Number(7));
+assertTrue(delete new Number(8));
+
+assertTrue(delete {}.x);
+assertTrue(delete {}.y);
+assertTrue(delete {}.toString);
+
+x = 42;
+assertEquals(42, x);
+assertTrue(delete x);
+assertTrue(typeof x === 'undefined', "x is gone");
+
+/**** 
+ * This test relies on DontDelete attributes. This is not 
+ * working yet.
+
+var y = 87; // should have DontDelete attribute
+assertEquals(87, y);
+assertFalse(delete y, "don't delete");
+assertFalse(typeof y === 'undefined');
+assertEquals(87, y);
+*/
+
+var o = { x: 42, y: 87 };
+assertTrue(has(o, 'x'));
+assertTrue(has(o, 'y'));
+assertTrue(delete o.x);
+assertFalse(has(o, 'x'));
+assertTrue(has(o, 'y'));
+assertTrue(delete o['y']);
+assertFalse(has(o, 'x'));
+assertFalse(has(o, 'y'));
+
+
+var o = {};
+for (var i = 0x0020; i < 0x02ff; i+=2) {
+  o[String.fromCharCode(i)] = i;
+  o[String.fromCharCode(i+1)] = i+1;
+}
+for (var i = 0x0020; i < 0x02ff; i+=2) {
+  assertTrue(delete o[String.fromCharCode(i)]);
+}
+for (var i = 0x0020; i < 0x02ff; i+=2) {
+  assertFalse(has(o, String.fromCharCode(i)), "deleted (" + i + ")");
+  assertTrue(has(o, String.fromCharCode(i+1)), "still here (" + i + ")");
+}
+
+
+var a = [0,1,2];
+assertTrue(has(a, 0));
+assertTrue(delete a[0]);
+assertFalse(has(a, 0), "delete 0");
+assertEquals(1, a[1]);
+assertEquals(2, a[2]);
+assertTrue(delete a[100], "delete 100");
+assertTrue(delete a[Math.pow(2,31)-1], "delete 2^31-1");
+assertFalse(has(a, 0), "delete 0");
+assertEquals(1, a[1]);
+assertEquals(2, a[2]);
+
+
+var a = [0,1,2];
+assertEquals(3, a.length);
+assertTrue(delete a[2]);
+assertEquals(3, a.length);
+assertTrue(delete a[0]);
+assertEquals(3, a.length);
+assertTrue(delete a[1]);
+assertEquals(3, a.length);
+
+
+var o = {};
+o[Math.pow(2,30)-1] = 0;
+o[Math.pow(2,31)-1] = 0;
+o[1] = 0;
+assertTrue(delete o[0]);
+assertTrue(delete o[Math.pow(2,30)]);
+assertFalse(has(o, 0), "delete 0");
+assertFalse(has(o, Math.pow(2,30)));
+assertTrue(has(o, 1));
+assertTrue(has(o, Math.pow(2,30)-1));
+assertTrue(has(o, Math.pow(2,31)-1));
+
+assertTrue(delete o[Math.pow(2,30)-1]);
+assertTrue(has(o, 1));
+assertFalse(has(o, Math.pow(2,30)-1), "delete 2^30-1");
+assertTrue(has(o, Math.pow(2,31)-1));
+
+assertTrue(delete o[1]);
+assertFalse(has(o, 1), "delete 1");
+assertFalse(has(o, Math.pow(2,30)-1), "delete 2^30-1");
+assertTrue(has(o, Math.pow(2,31)-1));
+
+assertTrue(delete o[Math.pow(2,31)-1]);
+assertFalse(has(o, 1), "delete 1");
+assertFalse(has(o, Math.pow(2,30)-1), "delete 2^30-1");
+assertFalse(has(o, Math.pow(2,31)-1), "delete 2^31-1");
+
+
+var a = [];
+a[Math.pow(2,30)-1] = 0;
+a[Math.pow(2,31)-1] = 0;
+a[1] = 0;
+assertTrue(delete a[0]);
+assertTrue(delete a[Math.pow(2,30)]);
+assertFalse(has(a, 0), "delete 0");
+assertFalse(has(a, Math.pow(2,30)), "delete 2^30");
+assertTrue(has(a, 1));
+assertTrue(has(a, Math.pow(2,30)-1));
+assertTrue(has(a, Math.pow(2,31)-1));
+assertEquals(Math.pow(2,31), a.length);
+
+assertTrue(delete a[Math.pow(2,30)-1]);
+assertTrue(has(a, 1));
+assertFalse(has(a, Math.pow(2,30)-1), "delete 2^30-1");
+assertTrue(has(a, Math.pow(2,31)-1));
+assertEquals(Math.pow(2,31), a.length);
+
+assertTrue(delete a[1]);
+assertFalse(has(a, 1), "delete 1");
+assertFalse(has(a, Math.pow(2,30)-1), "delete 2^30-1");
+assertTrue(has(a, Math.pow(2,31)-1));
+assertEquals(Math.pow(2,31), a.length);
+
+assertTrue(delete a[Math.pow(2,31)-1]);
+assertFalse(has(a, 1), "delete 1");
+assertFalse(has(a, Math.pow(2,30)-1), "delete 2^30-1");
+assertFalse(has(a, Math.pow(2,31)-1), "delete 2^31-1");
+assertEquals(Math.pow(2,31), a.length);
diff --git a/regexp2000/test/mjsunit/do-not-strip-fc.js b/regexp2000/test/mjsunit/do-not-strip-fc.js
new file mode 100644 (file)
index 0000000..1aef28c
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure we do not remove unicode format-control characters
+// from string literals.
+assertEquals(7, eval("'foo\u200dbar'").length);
+assertEquals(7, eval("'foo\u200cbar'").length);
diff --git a/regexp2000/test/mjsunit/dont-enum-array-holes.js b/regexp2000/test/mjsunit/dont-enum-array-holes.js
new file mode 100644 (file)
index 0000000..4761dc4
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not enum holes in arrays.
+var count = 0;
+for (var i in [,1,,3]) count++;
+assertEquals(2, count);
+
+count = 0;
+for (var i in new Array(10)) count++;
+assertEquals(0, count);
diff --git a/regexp2000/test/mjsunit/dont-reinit-global-var.js b/regexp2000/test/mjsunit/dont-reinit-global-var.js
new file mode 100644 (file)
index 0000000..1e3c1a0
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var foo = 'fisk';
+assertEquals('fisk', foo);
+var foo;
+assertEquals('fisk', foo);
+var foo = 'hest';
+assertEquals('hest', foo);
+
+this.bar = 'fisk';
+assertEquals('fisk', bar);
+var bar;
+assertEquals('fisk', bar);
+var bar = 'hest';
+assertEquals('hest', bar);
+
+this.baz = 'fisk';
+assertEquals('fisk', baz);
+eval('var baz;');
+assertEquals('fisk', baz);
+eval('var baz = "hest";');
+assertEquals('hest', baz);
diff --git a/regexp2000/test/mjsunit/double-equals.js b/regexp2000/test/mjsunit/double-equals.js
new file mode 100644 (file)
index 0000000..a68d7ea
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * This test uses assert{True,False}(... == ...) instead of
+ * assertEquals(..., ...) to not rely on the details of the
+ * implementation of assertEquals.
+ */
+
+assertTrue (void 0 == void 0, "void 0 == void 0");
+assertTrue (null == null,     "null == null");
+assertFalse(NaN == NaN,       "NaN == NaN");
+assertFalse(NaN == 0,         "NaN == 0");
+assertFalse(0 == NaN,         "0 == NaN");
+assertFalse(NaN == Infinity,  "NaN == Inf");
+assertFalse(Infinity == NaN,  "Inf == NaN");
+
+assertTrue(Number.MAX_VALUE == Number.MAX_VALUE, "MAX == MAX");
+assertTrue(Number.MIN_VALUE == Number.MIN_VALUE, "MIN == MIN");
+assertTrue(Infinity == Infinity,                 "Inf == Inf");
+assertTrue(-Infinity == -Infinity,               "-Inf == -Inf");
+
+assertTrue(0 == 0,   "0 == 0");
+assertTrue(0 == -0,  "0 == -0");
+assertTrue(-0 == 0,  "-0 == 0");
+assertTrue(-0 == -0, "-0 == -0");
+
+assertFalse(0.9 == 1,             "0.9 == 1");
+assertFalse(0.999999 == 1,        "0.999999 == 1");
+assertFalse(0.9999999999 == 1,    "0.9999999999 == 1");
+assertFalse(0.9999999999999 == 1, "0.9999999999999 == 1");
+
+assertTrue('hello' == 'hello', "'hello' == 'hello'");
+
+assertTrue (true == true,   "true == true");
+assertTrue (false == false, "false == false");
+assertFalse(true == false,  "true == false");
+assertFalse(false == true,  "false == true");
+
+assertFalse(new Wrapper(null) == new Wrapper(null),   "new Wrapper(null) == new Wrapper(null)");
+assertFalse(new Boolean(true) == new Boolean(true),   "new Boolean(true) == new Boolean(true)");
+assertFalse(new Boolean(false) == new Boolean(false), "new Boolean(false) == new Boolean(false)");
+
+(function () {
+  var x = new Wrapper(null);
+  var y = x, z = x;
+  assertTrue(y == x);
+})();
+
+(function () {
+  var x = new Boolean(true);
+  var y = x, z = x;
+  assertTrue(y == x);
+})();
+
+(function () {
+  var x = new Boolean(false);
+  var y = x, z = x;
+  assertTrue(y == x);
+})();
+
+assertTrue(null == void 0,             "null == void 0");
+assertTrue(void 0 == null,             "void 0 == null");
+assertFalse(new Wrapper(null) == null, "new Wrapper(null) == null");
+assertFalse(null == new Wrapper(null), "null == new Wrapper(null)");
+
+assertTrue(1 == '1',       "1 == '1");
+assertTrue(255 == '0xff',  "255 == '0xff'");
+assertTrue(0 == '\r',      "0 == '\\r'");
+assertTrue(1e19 == '1e19', "1e19 == '1e19'");
+
+assertTrue(new Boolean(true) == true,   "new Boolean(true) == true");
+assertTrue(new Boolean(false) == false, "new Boolean(false) == false");
+assertTrue(true == new Boolean(true),   "true == new Boolean(true)");
+assertTrue(false == new Boolean(false), "false == new Boolean(false)");
+
+assertTrue(Boolean(true) == true,   "Boolean(true) == true");
+assertTrue(Boolean(false) == false, "Boolean(false) == false");
+assertTrue(true == Boolean(true),   "true == Boolean(true)");
+assertTrue(false == Boolean(false), "false == Boolean(false)");
+
+assertTrue(new Wrapper(true) == true,   "new Wrapper(true) == true");
+assertTrue(new Wrapper(false) == false, "new Wrapper(false) == false");
+assertTrue(true == new Wrapper(true),   "true = new Wrapper(true)");
+assertTrue(false == new Wrapper(false), "false = new Wrapper(false)");
+
+function Wrapper(value) {
+  this.value = value;
+  this.valueOf = function () { return this.value; };
+}
diff --git a/regexp2000/test/mjsunit/dtoa.js b/regexp2000/test/mjsunit/dtoa.js
new file mode 100644 (file)
index 0000000..80167b7
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// dtoa.c used to contain a bogus assertions that got triggered when
+// passed very small numbers.  This test therefore used to fail in
+// debug mode.
+
+assertEquals(0, 1e-500);
diff --git a/regexp2000/test/mjsunit/enumeration_order.js b/regexp2000/test/mjsunit/enumeration_order.js
new file mode 100644 (file)
index 0000000..699a636
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function check_enumeration_order(obj)  {
+  var value = 0; 
+  for (var name in obj) assertTrue(value < obj[name]);
+  value = obj[name];
+}
+
+function make_object(size)  {
+  var a = new Object();
+  
+  for (var i = 0; i < size; i++) a["a_" + i] = i + 1;
+  check_enumeration_order(a);
+  
+  for (var i = 0; i < size; i +=3) delete a["a_" + i];
+  check_enumeration_order(a);
+}
+
+// Validate the enumeration order for object up to 100 named properties.
+for (var j = 1; j< 100; j++) make_object(j);
+
+
+function make_literal_object(size)  {
+  var code = "{ ";
+  for (var i = 0; i < size-1; i++) code += " a_" + i + " : " + (i + 1) + ", ";
+  code += "a_" + (size - 1) + " : " + size;
+  code += " }";
+  eval("var a = " + code);
+  check_enumeration_order(a);  
+}
+
+// Validate the enumeration order for object literals up to 100 named properties.
+for (var j = 1; j< 100; j++) make_literal_object(j);
+
diff --git a/regexp2000/test/mjsunit/escape.js b/regexp2000/test/mjsunit/escape.js
new file mode 100644 (file)
index 0000000..5732ce3
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Check that the global escape and unescape functions work
+ * right.
+ */
+
+// Section B.2.1 of ECMAScript 3
+var unescaped = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./";
+
+// Check the unescape chars are not escaped
+assertEquals(unescaped, escape(unescaped));
+// Check spaces are escaped
+assertEquals("%20/%20", escape(" / "));
+// Check that null chars are escaped and do not terminate the string
+assertEquals("%000", escape("\0" + "0"));
+// Check a unicode escape
+assertEquals("A%20B%u1234%00%20C", escape(String.fromCharCode(0x41, 0x20, 0x42, 0x1234, 0, 0x20, 0x43)));
+// Check unicode escapes have a leading zero to pad to 4 digits
+assertEquals("%u0123", escape(String.fromCharCode(0x123)));
+// Check escapes are upper case
+assertEquals("%uABCD", escape(String.fromCharCode(0xabcd)));
+assertEquals("%AB", escape(String.fromCharCode(0xab)));
+assertEquals("%0A", escape("\n"));
+
+// Check first 1000 chars individually for escaped/not escaped
+for (var i = 0; i < 1000; i++) {
+  var s = String.fromCharCode(i);
+  if (unescaped.indexOf(s, 0) == -1) {
+    assertFalse(s == escape(s));
+  } else {
+    assertTrue(s == escape(s));
+  }
+}
+
+// Check all chars up to 1000 in groups of 10 using unescape as a check
+for (var i = 0; i < 1000; i += 10) {
+  var s = String.fromCharCode(i, i+1, i+2, i+3, i+4, i+5, i+6, i+7, i+8, i+9);
+  assertEquals(s, unescape(escape(s)));
+}
+
+// Benchmark
+var example = "Now is the time for all good men to come to the aid of the party.";
+example = example + String.fromCharCode(267, 0x1234, 0x6667, 0xabcd);
+example = example + " The quick brown fox jumps over the lazy dog."
+example = example + String.fromCharCode(171, 172, 173, 174, 175, 176, 178, 179);
+
+for (var i = 0; i < 3000; i++) {
+  assertEquals(example, unescape(escape(example)));
+}
+
+// Check unescape can cope with upper and lower case
+assertEquals(unescape("%41%4A%4a"), "AJJ");
+
+// Check upper case U
+assertEquals("%U1234", unescape("%U1234"));
+
+// Check malformed unescapes
+assertEquals("%", unescape("%"));
+assertEquals("%4", unescape("%4"));
+assertEquals("%u", unescape("%u"));
+assertEquals("%u4", unescape("%u4"));
+assertEquals("%u44", unescape("%u44"));
+assertEquals("%u444", unescape("%u444"));
+assertEquals("%4z", unescape("%4z"));
+assertEquals("%uzzzz", unescape("%uzzzz"));
+assertEquals("%u4zzz", unescape("%u4zzz"));
+assertEquals("%u44zz", unescape("%u44zz"));
+assertEquals("%u444z", unescape("%u444z"));
+assertEquals("%4<", unescape("%4<"));
+assertEquals("%u<<<<", unescape("%u<<<<"));
+assertEquals("%u4<<<", unescape("%u4<<<"));
+assertEquals("%u44<<", unescape("%u44<<"));
+assertEquals("%u444<", unescape("%u444<"));
+assertEquals("foo%4<", unescape("foo%4<"));
+assertEquals("foo%u<<<<", unescape("foo%u<<<<"));
+assertEquals("foo%u4<<<", unescape("foo%u4<<<"));
+assertEquals("foo%u44<<", unescape("foo%u44<<"));
+assertEquals("foo%u444<", unescape("foo%u444<"));
+assertEquals("foo%4<bar", unescape("foo%4<bar"));
+assertEquals("foo%u<<<<bar", unescape("foo%u<<<<bar"));
+assertEquals("foo%u4<<<bar", unescape("foo%u4<<<bar"));
+assertEquals("foo%u44<<bar", unescape("foo%u44<<bar"));
+assertEquals("foo%u444<bar", unescape("foo%u444<bar"));
+assertEquals("% ", unescape("%%20"));
+assertEquals("%% ", unescape("%%%20"));
+
+// Unescape stress
+var eexample = escape(example);
+
+for (var i = 1; i < 3000; i++) {
+  assertEquals(example, unescape(eexample));
+}
diff --git a/regexp2000/test/mjsunit/eval-typeof-non-existing.js b/regexp2000/test/mjsunit/eval-typeof-non-existing.js
new file mode 100644 (file)
index 0000000..3513767
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Typeof expression must resolve to undefined when it used on a
+// non-existing property. It is *not* allowed to throw a
+// ReferenceError.
+assertEquals('undefined', typeof xxx);
+assertEquals('undefined', eval('typeof xxx'));
diff --git a/regexp2000/test/mjsunit/execScript-case-insensitive.js b/regexp2000/test/mjsunit/execScript-case-insensitive.js
new file mode 100644 (file)
index 0000000..468d657
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var x  = 0;
+execScript('x = 1', 'javascript');
+assertEquals(1, x);
+
+execScript('x = 2', 'JavaScript');
+assertEquals(2, x);
+
diff --git a/regexp2000/test/mjsunit/extra-arguments.js b/regexp2000/test/mjsunit/extra-arguments.js
new file mode 100644 (file)
index 0000000..186277a
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() {
+  return g();
+};
+
+function g() {
+  var result = 0;
+  var array = f.arguments;
+  for (var i = 0; i < array.length; i++) {
+    result += array[i];
+  }
+  return result;
+};
+
+
+// Make sure we can pass any number of arguments to f and read them
+// from g.
+for (var i = 0; i < 25; i++) {
+  var array = new Array(i);
+  var expected = 0;
+  for (var j = 0; j < i; j++) {
+    expected += j;
+    array[j] = j;
+  }
+  assertEquals(expected, f.apply(null, array), String(i));
+}
+
+
diff --git a/regexp2000/test/mjsunit/extra-commas.js b/regexp2000/test/mjsunit/extra-commas.js
new file mode 100644 (file)
index 0000000..6fed04c
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function assertSyntaxError(x) {
+  var caught = false;
+  try {
+    eval(x);
+  } catch (e) {
+    caught = true;
+    assertTrue(e instanceof SyntaxError, "is syntax error");
+  }
+  assertTrue(caught, "throws exception");
+};
+
+
+assertSyntaxError("f(,)");
+assertSyntaxError("f(1,)");
+assertSyntaxError("f(1,2,)");
+
+assertSyntaxError("function f(,) {}");
+assertSyntaxError("function f(1,) {}");
+assertSyntaxError("function f(1,2,) {}");
diff --git a/regexp2000/test/mjsunit/for-in-null-or-undefined.js b/regexp2000/test/mjsunit/for-in-null-or-undefined.js
new file mode 100644 (file)
index 0000000..b12d1b0
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// At least Spidermonkey and IE allow for-in iteration over null and
+// undefined. They never executed the statement block.
+var count = 0;
+for (var p in null) { count++; }
+for (var p in void 0) { count++; }
+assertEquals(0, count);
diff --git a/regexp2000/test/mjsunit/for-in-special-cases.js b/regexp2000/test/mjsunit/for-in-special-cases.js
new file mode 100644 (file)
index 0000000..3c54256
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+function for_in_null() {
+  try {
+    for (var x in null) {
+      return false;
+    }
+  } catch(e) {
+    return false;
+  }
+  return true;
+}
+
+function for_in_undefined() {
+  try {
+    for (var x in undefined) {
+      return false;
+    }
+  } catch(e) {
+    return false;
+  }
+  return true;
+}
+
+for (var i = 0; i < 10; ++i) {
+  assertTrue(for_in_null());
+  gc();
+}
+
+for (var j = 0; j < 10; ++j) {
+  assertTrue(for_in_undefined());
+  gc();
+}
+
+assertEquals(10, i);
+assertEquals(10, j);
+
diff --git a/regexp2000/test/mjsunit/for-in.js b/regexp2000/test/mjsunit/for-in.js
new file mode 100644 (file)
index 0000000..dfe721d
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function props(x) {
+  var array = [];
+  for (var p in x) array.push(p);
+  return array.sort();
+}
+
+assertEquals(0, props({}).length);
+assertEquals(1, props({x:1}).length);
+assertEquals(2, props({x:1, y:2}).length);
+
+assertArrayEquals(["x"], props({x:1}));
+assertArrayEquals(["x", "y"], props({x:1, y:2}));
+assertArrayEquals(["x", "y", "zoom"], props({x:1, y:2, zoom:3}));
+
+assertEquals(0, props([]).length);
+assertEquals(1, props([1]).length);
+assertEquals(2, props([1,2]).length);
+
+assertArrayEquals(["0"], props([1]));
+assertArrayEquals(["0", "1"], props([1,2]));
+assertArrayEquals(["0", "1", "2"], props([1,2,3]));
+
+var o = {};
+var a = [];
+for (var i = 0x0020; i < 0x01ff; i+=2) {
+  var s = 'char:' + String.fromCharCode(i);
+  a.push(s);
+  o[s] = i;
+}
+assertArrayEquals(a, props(o));
+
+var a = [];
+assertEquals(0, props(a).length);
+a[Math.pow(2,30)-1] = 0;
+assertEquals(1, props(a).length);
+a[Math.pow(2,31)-1] = 0;
+assertEquals(2, props(a).length);
+a[1] = 0;
+assertEquals(3, props(a).length);
+
+for (var hest = 'hest' in {}) { }
+assertEquals('hest', hest);
+
+var result = '';
+for (var p in {a : [0], b : 1}) { result += p; }
+assertEquals('ab', result);
+
+var result = '';
+for (var p in {a : {v:1}, b : 1}) { result += p; }
+assertEquals('ab', result);
+
+var result = '';
+for (var p in { get a() {}, b : 1}) { result += p; }
+assertEquals('ab', result);
+
+var result = '';
+for (var p in { get a() {}, set a(x) {}, b : 1}) { result += p; }
+assertEquals('ab', result);
+
diff --git a/regexp2000/test/mjsunit/fun-as-prototype.js b/regexp2000/test/mjsunit/fun-as-prototype.js
new file mode 100644 (file)
index 0000000..fbe995a
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var x = 0;
+function Funky(a, b, c) { return 7; }
+Number.prototype.__proto__ = Funky;
+assertEquals(3, x.length);
+assertEquals("Funky", x.name);
+assertEquals(Funky.prototype, x.prototype);
+
+Number.prototype.__proto__ = [1, 2, 3];
+assertEquals(3, x.length);
diff --git a/regexp2000/test/mjsunit/fun_name.js b/regexp2000/test/mjsunit/fun_name.js
new file mode 100644 (file)
index 0000000..676daaa
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function strip(s) {
+  return s.replace(/\s/g, '');
+}
+
+assertEquals('function(){}', strip((function () { }).toString()));
+assertEquals('functionanonymous(){}', strip(new Function().toString()));
+
diff --git a/regexp2000/test/mjsunit/function-arguments-null.js b/regexp2000/test/mjsunit/function-arguments-null.js
new file mode 100644 (file)
index 0000000..21e542f
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The arguments property of functions should be null when not
+// executing inside the function.
+assertTrue(toString.arguments === null);
diff --git a/regexp2000/test/mjsunit/function-caller.js b/regexp2000/test/mjsunit/function-caller.js
new file mode 100644 (file)
index 0000000..f749346
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f(match) {
+  g(match);
+}
+
+function g(match) {
+  assertEquals(f, g.caller);
+  assertEquals(match, f.caller);
+}
+
+// Check called from function.
+function h() {
+  f(h);
+}
+h();
+
+// Check called from top-level.
+f(null);
+
+// Check called from eval.
+eval('f(eval)');
+
diff --git a/regexp2000/test/mjsunit/function-names.js b/regexp2000/test/mjsunit/function-names.js
new file mode 100644 (file)
index 0000000..c083f18
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+function TestFunctionNames(object, names) {
+  for (var i = 0; i < names.length; i++) {
+    assertEquals(names[i], object[names[i]].name);
+  }
+}
+
+
+// Array.prototype functions.
+var arrayPrototypeFunctions = [
+    "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse",
+    "shift", "unshift", "slice", "splice", "sort", "filter", "forEach",
+    "some", "every", "map", "indexOf", "lastIndexOf"];
+
+TestFunctionNames(Array.prototype, arrayPrototypeFunctions);
+
+
+// Boolean prototype functions.
+var booleanPrototypeFunctions = [ "toString", "valueOf" ];
+
+TestFunctionNames(Boolean.prototype, booleanPrototypeFunctions);
+
+
+// Date functions.
+var dateFunctions = ["UTC", "parse", "now"];
+
+TestFunctionNames(Date, dateFunctions);
+
+
+// Date.prototype functions.
+var datePrototypeFunctions = [
+    "toString", "toDateString", "toTimeString", "toLocaleString",
+    "toLocaleDateString", "toLocaleTimeString", "valueOf", "getTime",
+    "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth",
+    "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours",
+    "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds",
+    "getUTCSeconds", "getMilliseconds", "getUTCMilliseconds",
+    "getTimezoneOffset", "setTime", "setMilliseconds",
+    "setUTCMilliseconds", "setSeconds", "setUTCSeconds", "setMinutes",
+    "setUTCMinutes", "setHours", "setUTCHours", "setDate", "setUTCDate",
+    "setMonth", "setUTCMonth", "setFullYear", "setUTCFullYear", "toGMTString",
+    "toUTCString", "getYear", "setYear"];
+
+TestFunctionNames(Date.prototype, datePrototypeFunctions);
+
+
+// Function.prototype functions.
+var functionPrototypeFunctions = [ "toString", "apply", "call" ];
+
+TestFunctionNames(Function.prototype, functionPrototypeFunctions);
+
+// Math functions.
+var mathFunctions = [
+    "random", "abs", "acos", "asin", "atan", "ceil", "cos", "exp", "floor",
+    "log", "round", "sin", "sqrt", "tan", "atan2", "pow", "max", "min"];
+
+TestFunctionNames(Math, mathFunctions);
+
+
+// Number.prototype functions.
+var numberPrototypeFunctions = [
+    "toString", "toLocaleString", "valueOf", "toFixed", "toExponential",
+    "toPrecision"];
+
+TestFunctionNames(Number.prototype, numberPrototypeFunctions);
+
+// Object.prototype functions.
+var objectPrototypeFunctions = [
+    "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf",
+    "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__",
+    "__defineSetter__", "__lookupSetter__"];
+
+TestFunctionNames(Object.prototype, objectPrototypeFunctions);
+
+// RegExp.prototype functions.
+var regExpPrototypeFunctions = ["exec", "test", "toString", "compile"];
+
+TestFunctionNames(RegExp.prototype, regExpPrototypeFunctions);
+
+// String functions.
+var stringFunctions = ["fromCharCode"];
+
+TestFunctionNames(String, stringFunctions);
+
+
+// String.prototype functions.
+var stringPrototypeFunctions = [
+    "toString", "valueOf", "charAt", "charCodeAt", "concat", "indexOf",
+    "lastIndexOf", "localeCompare", "match", "replace", "search", "slice",
+    "split", "substring", "substr", "toLowerCase", "toLocaleLowerCase",
+    "toUpperCase", "toLocaleUpperCase", "link", "anchor", "fontcolor",
+    "fontsize", "big", "blink", "bold", "fixed", "italics", "small",
+    "strike", "sub", "sup"];
+
+TestFunctionNames(String.prototype, stringPrototypeFunctions);
+
+
+// Global functions.
+var globalFunctions = [
+    "escape", "unescape", "decodeURI", "decodeURIComponent",
+    "encodeURI", "encodeURIComponent", "Error", "TypeError",
+    "RangeError", "SyntaxError", "ReferenceError", "EvalError",
+    "URIError", "isNaN", "isFinite", "parseInt", "parseFloat",
+    "eval", "execScript"];
+
+TestFunctionNames(this, globalFunctions);
diff --git a/regexp2000/test/mjsunit/function-property.js b/regexp2000/test/mjsunit/function-property.js
new file mode 100644 (file)
index 0000000..a657f64
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() { };
+assertEquals(5, f = 5);
diff --git a/regexp2000/test/mjsunit/function-prototype.js b/regexp2000/test/mjsunit/function-prototype.js
new file mode 100644 (file)
index 0000000..371311e
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that we can set function prototypes to non-object values.  The
+// prototype used for instances in that case should be the initial
+// object prototype.  ECMA-262 13.2.2.
+function TestNonObjectPrototype(value) {
+  function F() {};
+  F.prototype = value;
+  var f = new F();
+  assertEquals(value, F.prototype);
+  assertEquals(Object.prototype, f.__proto__);
+}
+
+var values = [123, "asdf", true];
+
+values.forEach(TestNonObjectPrototype);
+
+
+// Test moving between non-object and object values.
+function F() {};
+var f = new F();
+assertEquals(f.__proto__, F.prototype);
+F.prototype = 42;
+f = new F();
+assertEquals(Object.prototype, f.__proto__);
+assertEquals(42, F.prototype);
+F.prototype = { a: 42 };
+f = new F();
+assertEquals(42, F.prototype.a);
+assertEquals(f.__proto__, F.prototype);
+
+
+// Test that the fast case optimizations can handle non-functions,
+// functions with no prototypes (yet), non-object prototypes,
+// functions without initial maps, and the fully initialized
+// functions.
+function GetPrototypeOf(f) {
+  return f.prototype;
+};
+
+// Seed the GetPrototypeOf function to enable the fast case
+// optimizations.
+var p = GetPrototypeOf(GetPrototypeOf);
+
+// Check that getting the prototype of a tagged integer works.
+assertTrue(typeof GetPrototypeOf(1) == 'undefined');
+
+function NoPrototypeYet() { }
+var p = GetPrototypeOf(NoPrototypeYet);
+assertEquals(NoPrototypeYet.prototype, p);
+
+function NonObjectPrototype() { }
+NonObjectPrototype.prototype = 42;
+assertEquals(42, GetPrototypeOf(NonObjectPrototype));
+
+function NoInitialMap() { }
+var p = NoInitialMap.prototype;
+assertEquals(p, GetPrototypeOf(NoInitialMap));
+
+// Check the standard fast case.
+assertEquals(F.prototype, GetPrototypeOf(F));
+
+// Check that getting the prototype of a non-function works. This must
+// be the last thing we do because this will clobber the optimizations
+// in GetPrototypeOf and go to a monomorphic IC load instead.
+assertEquals(87, GetPrototypeOf({prototype:87}));
+
+// Check the prototype is enumerable as specified in ECMA262, 15.3.5.2
+var foo = new Function("return x");
+var result  = ""
+for (var n in foo) result += n;
+assertEquals(result, "prototype");
diff --git a/regexp2000/test/mjsunit/function-source.js b/regexp2000/test/mjsunit/function-source.js
new file mode 100644 (file)
index 0000000..7525775
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Check that the script source for all functions in a script is the same.
+function f() {
+  function h() {
+    assertEquals(Debug.scriptSource(f), Debug.scriptSource(h));
+  }
+  h();
+}
+  
+function g() {
+  function h() {
+    assertEquals(Debug.scriptSource(f), Debug.scriptSource(h));
+  }
+  h();
+}
+
+assertEquals(Debug.scriptSource(f), Debug.scriptSource(g));
+f();
+g();
diff --git a/regexp2000/test/mjsunit/function.js b/regexp2000/test/mjsunit/function.js
new file mode 100644 (file)
index 0000000..b5e83db
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var f = Function();
+assertTrue(typeof f() == 'undefined');
+f = new Function();
+assertTrue(typeof f() == 'undefined');
+
+f = Function('return 1');
+assertEquals(1, f());
+f = new Function('return 1');
+assertEquals(1, f());
+
+f = Function('return true');
+assertTrue(f());
+f = new Function('return true');
+assertTrue(f());
+
+f = Function('x', 'return x');
+assertEquals(1, f(1));
+assertEquals('bar', f('bar'));
+assertTrue(typeof f() == 'undefined');
+var x = {};
+assertTrue(x === f(x));
+
+f = Function('x', 'return x // comment');
+assertEquals(1, f(1));
+
+f = Function('return typeof anonymous');
+assertEquals('undefined', f());
+
+var anonymous = 42;
+f = Function('return anonymous;');
+assertEquals(42, f());
+
+f = new Function('x', 'return x')
+assertEquals(1, f(1));
+assertEquals('bar', f('bar'));
+assertTrue(typeof f() == 'undefined');
+var x = {};
+assertTrue(x === f(x));
+
+f = Function('x', 'y', 'return x+y');
+assertEquals(5, f(2, 3));
+assertEquals('foobar', f('foo', 'bar'));
+f = new Function('x', 'y', 'return x+y');
+assertEquals(5, f(2, 3));
+assertEquals('foobar', f('foo', 'bar'));
+
+var x = {}; x.toString = function() { return 'x'; };
+var y = {}; y.toString = function() { return 'y'; };
+var z = {}; z.toString = function() { return 'return x*y'; }
+var f = Function(x, y, z);
+assertEquals(25, f(5, 5));
+assertEquals(42, f(2, 21));
+f = new Function(x, y, z);
+assertEquals(25, f(5, 5));
+assertEquals(42, f(2, 21));
+
diff --git a/regexp2000/test/mjsunit/fuzz-accessors.js b/regexp2000/test/mjsunit/fuzz-accessors.js
new file mode 100644 (file)
index 0000000..f3602cc
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var builtInPropertyNames = [
+  'prototype', 'length', 'caller', 0, 1, '$1', 'arguments', 'name', 'message', 'constructor'
+];
+
+function getAnException() {
+  try {
+    ("str")();
+  } catch (e) {
+    return e;
+  }
+}
+
+function getSpecialObjects() {
+  return [
+    function () { },
+    [1, 2, 3],
+    /xxx/,
+    RegExp,
+    "blah",
+    9,
+    new Date(),
+    getAnException()
+  ];
+}
+
+var object = { };
+var fun = function () { };
+var someException = getAnException();
+var someDate = new Date();
+
+var objects = [
+  [1, Number.prototype],
+  ["foo", String.prototype],
+  [true, Boolean.prototype],
+  [object, object],
+  [fun, fun],
+  [someException, someException],
+  [someDate, someDate]
+];
+
+function runTest(fun) {
+  for (var i in objects) {
+    var obj = objects[i][0];
+    var chain = objects[i][1];
+    var specialObjects = getSpecialObjects();
+    for (var j in specialObjects) {
+      var special = specialObjects[j];
+      chain.__proto__ = special;
+      for (var k in builtInPropertyNames) {
+        var propertyName = builtInPropertyNames[k];
+        fun(obj, propertyName);
+      }
+    }
+  }
+}
+
+runTest(function (obj, name) { return obj[name]; });
+runTest(function (obj, name) { return obj[name] = { }; });
diff --git a/regexp2000/test/mjsunit/fuzz-natives.js b/regexp2000/test/mjsunit/fuzz-natives.js
new file mode 100644 (file)
index 0000000..315270c
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+function makeArguments() {
+  var result = [ ];
+  result.push(17);
+  result.push(-31);
+  result.push(Number.MAX_VALUE);
+  result.push(new Array(5003));
+  result.push(Number.MIN_VALUE);
+  result.push("whoops");
+  result.push("x");
+  result.push({"x": 1, "y": 2});
+  var slowCaseObj = {"a": 3, "b": 4, "c": 5};
+  delete slowCaseObj.c;
+  result.push(slowCaseObj);
+  result.push(function () { return 8; });
+  return result;
+}
+
+var kArgObjects = makeArguments().length;
+
+function makeFunction(name, argc) {
+  var args = [];
+  for (var i = 0; i < argc; i++)
+    args.push("x" + i);
+  var argsStr = args.join(", ");
+  return new Function(args.join(", "), "return %" + name + "(" + argsStr + ");");
+}
+
+function testArgumentCount(name) {
+  for (var i = 0; i < 10; i++) {
+    var func = makeFunction(name, i);
+    var args = [ ];
+    for (var j = 0; j < i; j++)
+      args.push(0);
+    try {
+      func.apply(void 0, args);
+    } catch (e) {
+      // we don't care what happens as long as we don't crash
+    }
+  }
+}
+
+function testArgumentTypes(name, argc) {
+  var type = 0;
+  var hasMore = true;
+  var func = makeFunction(name, argc);
+  while (hasMore) {
+    var argPool = makeArguments();
+    var current = type;
+    var hasMore = false;
+    var argList = [ ];
+    for (var i = 0; i < argc; i++) {
+      var index = current % kArgObjects;
+      current = (current / kArgObjects) << 0;
+      if (index != (kArgObjects - 1))
+        hasMore = true;
+      argList.push(argPool[index]);
+    }
+    try {
+      func.apply(void 0, argList);
+    } catch (e) {
+      // we don't care what happens as long as we don't crash
+    }
+    type++;
+  }
+}
+
+var knownProblems = {
+  "Abort": true,
+  
+  // These functions use pseudo-stack-pointers and are not robust
+  // to unexpected integer values.
+  "DebugEvaluate": true,
+
+  // These functions do nontrivial error checking in recursive calls,
+  // which means that we have to propagate errors back.
+  "SetFunctionBreakPoint": true,
+  "SetScriptBreakPoint": true,
+  "ChangeBreakOnException": true,
+  "PrepareStep": true,
+  
+  // These functions should not be callable as runtime functions.
+  "NewContext": true,
+  "NewArgumentsFast": true,
+  "PushContext": true,
+  "LazyCompile": true,
+  "CreateObjectLiteralBoilerplate": true,
+  "CloneObjectLiteralBoilerplate": true,
+  "IS_VAR": true
+};
+
+var currentlyUncallable = {
+  // We need to find a way to test this without breaking the system.
+  "SystemBreak": true
+};
+
+function testNatives() {
+  var allNatives = %ListNatives();
+  for (var i = 0; i < allNatives.length; i++) {
+    var nativeInfo = allNatives[i];
+    var name = nativeInfo[0];
+    if (name in knownProblems || name in currentlyUncallable)
+      continue;
+    print(name);
+    var argc = nativeInfo[1];
+    testArgumentCount(name);
+    testArgumentTypes(name, argc);
+  }
+}
+
+testNatives();
diff --git a/regexp2000/test/mjsunit/getter-in-value-prototype.js b/regexp2000/test/mjsunit/getter-in-value-prototype.js
new file mode 100644 (file)
index 0000000..b55320a
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that getters can be defined and called on value prototypes.
+//
+// This used to fail because of an invalid cast of the receiver to a
+// JSObject.
+
+String.prototype.__defineGetter__('x', function() { return this; });
+assertEquals('asdf', 'asdf'.x);
+
diff --git a/regexp2000/test/mjsunit/global-const-var-conflicts.js b/regexp2000/test/mjsunit/global-const-var-conflicts.js
new file mode 100644 (file)
index 0000000..d38d0ee
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Check that dynamically introducing conflicting consts/vars
+// leads to exceptions.
+
+var caught = 0;
+
+eval("const a");
+try { eval("var a"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertTrue(typeof a == 'undefined');
+try { eval("var a = 1"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertTrue(typeof a == 'undefined');
+
+eval("const b = 0");
+try { eval("var b"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertEquals(0, b);
+try { eval("var b = 1"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertEquals(0, b);
+
+eval("var c");
+try { eval("const c"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertTrue(typeof c == 'undefined');
+try { eval("const c = 1"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertTrue(typeof c == 'undefined');
+
+eval("var d = 0");
+try { eval("const d"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertEquals(0, d);
+try { eval("const d = 1"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
+assertEquals(0, d);
+
+assertEquals(8, caught);
diff --git a/regexp2000/test/mjsunit/global-vars-eval.js b/regexp2000/test/mjsunit/global-vars-eval.js
new file mode 100644 (file)
index 0000000..900f7be
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+eval("" + "");
+this.bar = 'fisk';
+assertEquals('fisk', bar, "1");
+var bar;
+assertEquals('fisk', bar, "2");
+var bar = 'hest';
+assertEquals('hest', bar, "3");
diff --git a/regexp2000/test/mjsunit/global-vars-with.js b/regexp2000/test/mjsunit/global-vars-with.js
new file mode 100644 (file)
index 0000000..05ca6b6
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+with ({}) { }
+this.bar = 'fisk';
+assertEquals('fisk', bar);
+var bar;
+assertEquals('fisk', bar);
+var bar = 'hest';
+assertEquals('hest', bar);
+
+with ({}) {
+  this.baz = 'fisk';
+  assertEquals('fisk', baz);
+  var baz;
+  assertEquals('fisk', baz);
+  var baz = 'hest';
+  assertEquals('hest', baz);
+}
diff --git a/regexp2000/test/mjsunit/greedy.js b/regexp2000/test/mjsunit/greedy.js
new file mode 100644 (file)
index 0000000..d357f0c
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --gc-greedy
+
+function IterativeFib(n) {
+  var f0 = 0, f1 = 1;
+  for (; n > 0; --n) {
+    var f2 = f0 + f1;
+    f0 = f1; f1 = f2;
+  }
+  return f0;
+}
+
+function RecursiveFib(n) {
+  if (n <= 1) return n;
+  return RecursiveFib(n - 1) + RecursiveFib(n - 2);
+}
+
+function Check(n, expected) {
+  var i = IterativeFib(n);
+  var r = RecursiveFib(n);
+  assertEquals(i, expected);
+  assertEquals(r, expected);
+}
+
+Check(0, 0);
+Check(1, 1);
+Check(2, 1);
+Check(3, 1 + 1);
+Check(4, 2 + 1);
+Check(5, 3 + 2);
+Check(10, 55);
+Check(15, 610);
+Check(20, 6765);
+assertEquals(IterativeFib(75), 2111485077978050);
diff --git a/regexp2000/test/mjsunit/has-own-property.js b/regexp2000/test/mjsunit/has-own-property.js
new file mode 100644 (file)
index 0000000..5ff8db5
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Check for objects.
+assertTrue({x:12}.hasOwnProperty('x'));
+assertFalse({x:12}.hasOwnProperty('y'));
+
+// Check for strings.
+assertTrue(''.hasOwnProperty('length'));
+assertTrue(Object.prototype.hasOwnProperty.call('', 'length'));
+
+// Check for numbers.
+assertFalse((123).hasOwnProperty('length'));
+assertFalse(Object.prototype.hasOwnProperty.call(123, 'length'));
diff --git a/regexp2000/test/mjsunit/html-comments.js b/regexp2000/test/mjsunit/html-comments.js
new file mode 100644 (file)
index 0000000..f39271a
--- /dev/null
@@ -0,0 +1,57 @@
+--> must work at beginning of file!
+
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var x = 1;
+--> this must be ignored...
+   --> so must this...
+       --> and this.
+x-->0;
+assertEquals(0, x);
+
+
+var x = 0; x <!-- x
+assertEquals(0, x);
+
+var x = 1; x <!--x
+assertEquals(1, x);
+
+var x = 2; x <!-- x; x = 42;
+assertEquals(2, x);
+
+var x = 1; x <! x--;
+assertEquals(0, x);
+
+var x = 1; x <!- x--;
+assertEquals(0, x);
+
+var b = true <! true;
+assertFalse(b);
+
+var b = true <!- true;
+assertFalse(b);
diff --git a/regexp2000/test/mjsunit/html-string-funcs.js b/regexp2000/test/mjsunit/html-string-funcs.js
new file mode 100644 (file)
index 0000000..213b7f3
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Spidermonkey and IE has some string functions useable for building
+// HTML.
+function CheckSimple(f, tag) {
+  assertEquals('<' + tag + '>foo</' + tag + '>',
+               "foo"[f]().toLowerCase()); 
+};
+var simple = { big: 'big', blink: 'blink', bold: 'b',
+               fixed: 'tt', italics: 'i', small: 'small',
+               strike: 'strike', sub: 'sub', sup: 'sup' };
+for (var i in simple) CheckSimple(i, simple[i]);
+
+
+function CheckCompound(f, tag, att) {
+  assertEquals('<' + tag + ' ' + att + '="bar">foo</' + tag + '>',
+               "foo"[f]("bar").toLowerCase());
+};
+CheckCompound('anchor', 'a', 'name');
+CheckCompound('link', 'a', 'href');
+CheckCompound('fontcolor', 'font', 'color');
+CheckCompound('fontsize', 'font', 'size');
diff --git a/regexp2000/test/mjsunit/if-in-undefined.js b/regexp2000/test/mjsunit/if-in-undefined.js
new file mode 100644 (file)
index 0000000..5bfa42e
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ECMA-252 11.8.7
+//
+// If the ShiftExpression is not an object, should throw an TypeError.
+// Should throw an exception, but not crash VM.
+
+assertThrows("if ('p' in undefined) { }");
+assertThrows("if ('p' in null) { }")
+assertThrows("if ('p' in true) { }");
+assertThrows("if ('p' in 5) { }");
diff --git a/regexp2000/test/mjsunit/in.js b/regexp2000/test/mjsunit/in.js
new file mode 100644 (file)
index 0000000..f98db42
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ----------------
+// Check fast objects
+
+var o = { };
+assertFalse(0 in o);
+assertFalse('x' in o);
+assertFalse('y' in o);
+assertTrue('toString' in o, "toString");
+
+var o = { x: 12 };
+assertFalse(0 in o);
+assertTrue('x' in o);
+assertFalse('y' in o);
+assertTrue('toString' in o, "toString");
+
+var o = { x: 12, y: 15 };
+assertFalse(0 in o);
+assertTrue('x' in o);
+assertTrue('y' in o);
+assertTrue('toString' in o, "toString");
+
+
+// ----------------
+// Check dense arrays
+
+var a = [ ];
+assertFalse(0 in a);
+assertFalse(1 in a);
+assertFalse('0' in a);
+assertFalse('1' in a);
+assertTrue('toString' in a, "toString");
+
+var a = [ 1 ];
+assertTrue(0 in a);
+assertFalse(1 in a);
+assertTrue('0' in a);
+assertFalse('1' in a);
+assertTrue('toString' in a, "toString");
+
+var a = [ 1, 2 ];
+assertTrue(0 in a);
+assertTrue(1 in a);
+assertTrue('0' in a);
+assertTrue('1' in a);
+assertTrue('toString' in a, "toString");
+
+var a = [ 1, 2 ];
+assertFalse(0.001 in a);
+assertTrue(-0 in a);
+assertTrue(+0 in a);
+assertFalse('0.0' in a);
+assertFalse('1.0' in a);
+assertFalse(NaN in a);
+assertFalse(Infinity in a);
+assertFalse(-Infinity in a);
+
+var a = [];
+a[1] = 2;
+assertFalse(0 in a);
+assertTrue(1 in a);
+assertFalse(2 in a);
+assertFalse('0' in a); 
+assertTrue('1' in a);
+assertFalse('2' in a);
+assertTrue('toString' in a, "toString");
+
+
+// ----------------
+// Check dictionary ("normalized") objects
+
+var o = {};
+for (var i = 0x0020; i < 0x02ff; i += 2) {
+  o['char:' + String.fromCharCode(i)] = i;
+}
+for (var i = 0x0020; i < 0x02ff; i += 2) {
+  assertTrue('char:' + String.fromCharCode(i) in o);
+  assertFalse('char:' + String.fromCharCode(i + 1) in o);
+}
+assertTrue('toString' in o, "toString");
+
+var o = {};
+o[Math.pow(2,30)-1] = 0;
+o[Math.pow(2,31)-1] = 0;
+o[1] = 0;
+assertFalse(0 in o);
+assertTrue(1 in o);
+assertFalse(2 in o);
+assertFalse(Math.pow(2,30)-2 in o);
+assertTrue(Math.pow(2,30)-1 in o);
+assertFalse(Math.pow(2,30)-0 in o);
+assertTrue(Math.pow(2,31)-1 in o);
+assertFalse(0.001 in o);
+assertFalse('0.0' in o);
+assertFalse('1.0' in o);
+assertFalse(NaN in o);
+assertFalse(Infinity in o);
+assertFalse(-Infinity in o);
+assertFalse(-0 in o);
+assertFalse(+0 in o);
+assertTrue('toString' in o, "toString");
+
+
+// ----------------
+// Check sparse arrays
+
+var a = [];
+a[Math.pow(2,30)-1] = 0;
+a[Math.pow(2,31)-1] = 0;
+a[1] = 0;
+assertFalse(0 in a, "0 in a");
+assertTrue(1 in a, "1 in a");
+assertFalse(2 in a, "2 in a");
+assertFalse(Math.pow(2,30)-2 in a, "Math.pow(2,30)-2 in a");
+assertTrue(Math.pow(2,30)-1 in a, "Math.pow(2,30)-1 in a");
+assertFalse(Math.pow(2,30)-0 in a, "Math.pow(2,30)-0 in a");
+assertTrue(Math.pow(2,31)-1 in a, "Math.pow(2,31)-1 in a");
+assertFalse(0.001 in a, "0.001 in a");
+assertFalse('0.0' in a,"'0.0' in a");
+assertFalse('1.0' in a,"'1.0' in a");
+assertFalse(NaN in a,"NaN in a");
+assertFalse(Infinity in a,"Infinity in a");
+assertFalse(-Infinity in a,"-Infinity in a");
+assertFalse(-0 in a,"-0 in a");
+assertFalse(+0 in a,"+0 in a");
+assertTrue('toString' in a, "toString");
+
+// -------------
+// Check negative indices in arrays.
+var a = [];
+assertFalse(-1 in a);
+a[-1] = 43;
+assertTrue(-1 in a);
diff --git a/regexp2000/test/mjsunit/instanceof.js b/regexp2000/test/mjsunit/instanceof.js
new file mode 100644 (file)
index 0000000..01ea426
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertTrue({} instanceof Object);
+assertTrue([] instanceof Object);
+
+assertFalse({} instanceof Array);
+assertTrue([] instanceof Array);
+
+function TestChains() {
+  var A = {};
+  var B = {};
+  var C = {};
+  B.__proto__ = A;
+  C.__proto__ = B;
+
+  function F() { }
+  F.prototype = A;
+  assertTrue(C instanceof F);
+  assertTrue(B instanceof F);
+  assertFalse(A instanceof F);
+
+  F.prototype = B;
+  assertTrue(C instanceof F);
+  assertFalse(B instanceof F);
+  assertFalse(A instanceof F);
+
+  F.prototype = C;
+  assertFalse(C instanceof F);
+  assertFalse(B instanceof F);
+  assertFalse(A instanceof F);
+}
+
+TestChains();
+
+
+function TestExceptions() {
+  function F() { }
+  var items = [ 1, new Number(42), 
+                true, 
+                'string', new String('hest'),
+                {}, [], 
+                F, new F(),
+                Object, String ];
+
+  var exceptions = 0;
+  var instanceofs = 0;
+
+  for (var i = 0; i < items.length; i++) {
+    for (var j = 0; j < items.length; j++) {
+      try {
+        if (items[i] instanceof items[j]) instanceofs++;
+      } catch (e) {
+        assertTrue(e instanceof TypeError);
+        exceptions++;
+      }
+    }
+  }
+  assertEquals(10, instanceofs);
+  assertEquals(88, exceptions);
+
+  // Make sure to throw an exception if the function prototype
+  // isn't a proper JavaScript object.
+  function G() { }
+  G.prototype = undefined;
+  assertThrows("({} instanceof G)");
+}
+
+TestExceptions();
diff --git a/regexp2000/test/mjsunit/integer-to-string.js b/regexp2000/test/mjsunit/integer-to-string.js
new file mode 100644 (file)
index 0000000..3076bc4
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function TestIntToString() {
+  for (var i = -1000; i < 1000; i++)
+    assertEquals(i, parseInt(""+i));
+  for (var i = -5e9; i < 5e9; i += (1e6 - 1))
+    assertEquals(i, parseInt(""+i));
+}
+
+TestIntToString();
diff --git a/regexp2000/test/mjsunit/invalid-lhs.js b/regexp2000/test/mjsunit/invalid-lhs.js
new file mode 100644 (file)
index 0000000..bbd19f2
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that we get exceptions for invalid left-hand sides.  Also
+// tests that if the invalid left-hand side is a function call, the
+// exception is delayed until runtime.
+
+// Normal assignments:
+assertThrows("12 = 12");
+assertThrows("x++ = 12");
+assertThrows("eval('var x') = 12");
+assertDoesNotThrow("if (false) eval('var x') = 12");
+
+// Pre- and post-fix operations:
+assertThrows("12++");
+assertThrows("12--");
+assertThrows("--12");
+assertThrows("++12");
+assertThrows("++(eval('12'))");
+assertThrows("(eval('12'))++");
+assertDoesNotThrow("if (false) ++(eval('12'))");
+assertDoesNotThrow("if (false) (eval('12'))++");
+
+// For in:
+assertThrows("for (12 in [1]) print(12);");
+assertThrows("for (eval('var x') in [1]) print(12);");
+assertDoesNotThrow("if (false) for (eval('var x') in [1]) print(12);");
+
+// For:
+assertThrows("for (12 = 1;;) print(12);");
+assertThrows("for (eval('var x') = 1;;) print(12);");
+assertDoesNotThrow("if (false) for (eval('var x') = 1;;) print(12);");
+
+// Assignments to 'this'.
+assertThrows("this = 42");
+assertThrows("function f() { this = 12; }");
+assertThrows("for (this in Array) ;");
+assertThrows("for (this = 0;;) ;");
+assertThrows("this++");
+assertThrows("++this");
+assertThrows("this--");
+assertThrows("--this");
+
+
diff --git a/regexp2000/test/mjsunit/keyed-ic.js b/regexp2000/test/mjsunit/keyed-ic.js
new file mode 100644 (file)
index 0000000..d37bd03
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This test attempts to test the inline caching for keyed access.
+
+// ----------------------------------------------------------------------
+// Prototype accessor.
+// ----------------------------------------------------------------------
+var runTest = function() {
+  var initial_P = 'prototype';
+  var P = initial_P;
+  var H = 'hasOwnProperty';
+
+  var f = function() {};
+
+  function prototypeTest(change_index) {
+    for (var i = 0; i < 10; i++) {
+      var property = f[P];
+      if (i <= change_index) {
+        assertEquals(f.prototype, property);
+      } else {
+        assertEquals(f.hasOwnProperty, property);
+      }
+      if (i == change_index) P = H;
+    }
+    P = initial_P;
+  }
+
+  for (var i = 0; i < 10; i++) prototypeTest(i);
+
+  f.prototype = 43;
+
+  for (var i = 0; i < 10; i++) prototypeTest(i);
+}
+
+runTest();
+
+// ----------------------------------------------------------------------
+// Array length accessor.
+// ----------------------------------------------------------------------
+runTest = function() {
+  var initial_L = 'length';
+  var L = initial_L;
+  var zero = '0';
+
+  var a = new Array(10);
+
+  function arrayLengthTest(change_index) {
+    for (var i = 0; i < 10; i++) {
+      var l = a[L];
+      if (i <= change_index) {
+        assertEquals(10, l);
+      } else {
+        assertEquals(undefined, l);
+      }
+      if (i == change_index) L = zero;
+    }
+    L = initial_L;
+  }
+
+  for (var i = 0; i < 10; i++) arrayLengthTest(i);
+}
+
+runTest();
+
+// ----------------------------------------------------------------------
+// String length accessor.
+// ----------------------------------------------------------------------
+runTest = function() {
+  var initial_L = 'length';
+  var L = initial_L;
+  var zero = '0';
+
+  var s = "asdf"
+
+  function stringLengthTest(change_index) {
+    for (var i = 0; i < 10; i++) {
+      var l = s[L];
+      if (i <= change_index) {
+        assertEquals(4, l);
+      } else {
+        assertEquals('a', l);
+      }
+      if (i == change_index) L = zero;
+    }
+    L = initial_L;
+  }
+
+  for (var i = 0; i < 10; i++) stringLengthTest(i);
+}
+
+runTest();
+
+// ----------------------------------------------------------------------
+// Field access.
+// ----------------------------------------------------------------------
+runTest = function() {
+  var o = { x: 42, y: 43 }
+
+  var initial_X = 'x';
+  var X = initial_X;
+  var Y = 'y';
+
+  function fieldTest(change_index) {
+    for (var i = 0; i < 10; i++) {
+      var property = o[X];
+      if (i <= change_index) {
+        assertEquals(42, property);
+      } else {
+        assertEquals(43, property);
+      }
+      if (i == change_index) X = Y;
+    }
+    X = initial_X;
+  };
+
+  for (var i = 0; i < 10; i++) fieldTest(i);
+}
+
+runTest();
+
+
+// ----------------------------------------------------------------------
+// Constant function access.
+// ----------------------------------------------------------------------
+runTest = function() {
+  function fun() { };
+
+  var o = new Object();
+  o.f = fun;
+  o.x = 42;
+
+  var initial_F = 'f';
+  var F = initial_F;
+  var X = 'x'
+
+  function constantFunctionTest(change_index) {
+    for (var i = 0; i < 10; i++) {
+      var property = o[F];
+      if (i <= change_index) {
+        assertEquals(fun, property);
+      } else {
+        assertEquals(42, property);
+      }
+      if (i == change_index) F = X;
+    }
+    F = initial_F;
+  };
+
+  for (var i = 0; i < 10; i++) constantFunctionTest(i);
+}
+
+runTest();
+
+// ----------------------------------------------------------------------
+// Keyed store field.
+// ----------------------------------------------------------------------
+
+runTest = function() {
+  var o = { x: 42, y: 43 }
+
+  var initial_X = 'x';
+  var X = initial_X;
+  var Y = 'y';
+
+  function fieldTest(change_index) {
+    for (var i = 0; i < 10; i++) {
+      o[X] = X;
+      var property = o[X];
+      if (i <= change_index) {
+        assertEquals('x', property);
+      } else {
+        assertEquals('y', property);
+      }
+      if (i == change_index) X = Y;
+    }
+    X = initial_X;
+  };
+
+  for (var i = 0; i < 10; i++) fieldTest(i);
+}
+
+runTest();
diff --git a/regexp2000/test/mjsunit/keyed-storage-extend.js b/regexp2000/test/mjsunit/keyed-storage-extend.js
new file mode 100644 (file)
index 0000000..04d2f04
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function F() { }
+
+function GrowNamed(o) {
+  o.a = 1;
+  o.b = 2;
+  o.c = 3;
+  o.d = 4;
+  o.e = 5;
+  o.f = 6;
+}
+
+function GrowKeyed(o) {
+  var names = ['a','b','c','d','e','f']; 
+  var i = 0;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+}
+
+GrowNamed(new F());
+GrowNamed(new F());
+GrowNamed(new F());
+GrowKeyed(new F());
+GrowKeyed(new F());
+GrowKeyed(new F());
diff --git a/regexp2000/test/mjsunit/large-object-allocation.js b/regexp2000/test/mjsunit/large-object-allocation.js
new file mode 100644 (file)
index 0000000..c2b717c
--- /dev/null
@@ -0,0 +1,300 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Allocate a very large object that is guaranteed to overflow the
+// instance_size field in the map resulting in an object that is smaller
+// than what was called for.
+function LargeObject(i) {
+  this.a = i;
+  this.b = i;
+  this.c = i;
+  this.d = i;
+  this.e = i;
+  this.f = i;
+  this.g = i;
+  this.h = i;
+  this.i = i;
+  this.j = i;
+  this.k = i;
+  this.l = i;
+  this.m = i;
+  this.n = i;
+  this.o = i;
+  this.p = i;
+  this.q = i;
+  this.r = i;
+  this.s = i;
+  this.t = i;
+  this.u = i;
+  this.v = i;
+  this.w = i;
+  this.x = i;
+  this.y = i;
+  this.z = i;
+  this.a1 = i;
+  this.b1 = i;
+  this.c1 = i;
+  this.d1 = i;
+  this.e1 = i;
+  this.f1 = i;
+  this.g1 = i;
+  this.h1 = i;
+  this.i1 = i;
+  this.j1 = i;
+  this.k1 = i;
+  this.l1 = i;
+  this.m1 = i;
+  this.n1 = i;
+  this.o1 = i;
+  this.p1 = i;
+  this.q1 = i;
+  this.r1 = i;
+  this.s1 = i;
+  this.t1 = i;
+  this.u1 = i;
+  this.v1 = i;
+  this.w1 = i;
+  this.x1 = i;
+  this.y1 = i;
+  this.z1 = i;
+  this.a2 = i;
+  this.b2 = i;
+  this.c2 = i;
+  this.d2 = i;
+  this.e2 = i;
+  this.f2 = i;
+  this.g2 = i;
+  this.h2 = i;
+  this.i2 = i;
+  this.j2 = i;
+  this.k2 = i;
+  this.l2 = i;
+  this.m2 = i;
+  this.n2 = i;
+  this.o2 = i;
+  this.p2 = i;
+  this.q2 = i;
+  this.r2 = i;
+  this.s2 = i;
+  this.t2 = i;
+  this.u2 = i;
+  this.v2 = i;
+  this.w2 = i;
+  this.x2 = i;
+  this.y2 = i;
+  this.z2 = i;
+  this.a3 = i;
+  this.b3 = i;
+  this.c3 = i;
+  this.d3 = i;
+  this.e3 = i;
+  this.f3 = i;
+  this.g3 = i;
+  this.h3 = i;
+  this.i3 = i;
+  this.j3 = i;
+  this.k3 = i;
+  this.l3 = i;
+  this.m3 = i;
+  this.n3 = i;
+  this.o3 = i;
+  this.p3 = i;
+  this.q3 = i;
+  this.r3 = i;
+  this.s3 = i;
+  this.t3 = i;
+  this.u3 = i;
+  this.v3 = i;
+  this.w3 = i;
+  this.x3 = i;
+  this.y3 = i;
+  this.z3 = i;
+  this.a4 = i;
+  this.b4 = i;
+  this.c4 = i;
+  this.d4 = i;
+  this.e4 = i;
+  this.f4 = i;
+  this.g4 = i;
+  this.h4 = i;
+  this.i4 = i;
+  this.j4 = i;
+  this.k4 = i;
+  this.l4 = i;
+  this.m4 = i;
+  this.n4 = i;
+  this.o4 = i;
+  this.p4 = i;
+  this.q4 = i;
+  this.r4 = i;
+  this.s4 = i;
+  this.t4 = i;
+  this.u4 = i;
+  this.v4 = i;
+  this.w4 = i;
+  this.x4 = i;
+  this.y4 = i;
+  this.z4 = i;
+  this.a5 = i;
+  this.b5 = i;
+  this.c5 = i;
+  this.d5 = i;
+  this.e5 = i;
+  this.f5 = i;
+  this.g5 = i;
+  this.h5 = i;
+  this.i5 = i;
+  this.j5 = i;
+  this.k5 = i;
+  this.l5 = i;
+  this.m5 = i;
+  this.n5 = i;
+  this.o5 = i;
+  this.p5 = i;
+  this.q5 = i;
+  this.r5 = i;
+  this.s5 = i;
+  this.t5 = i;
+  this.u5 = i;
+  this.v5 = i;
+  this.w5 = i;
+  this.x5 = i;
+  this.y5 = i;
+  this.z5 = i;
+  this.a6 = i;
+  this.b6 = i;
+  this.c6 = i;
+  this.d6 = i;
+  this.e6 = i;
+  this.f6 = i;
+  this.g6 = i;
+  this.h6 = i;
+  this.i6 = i;
+  this.j6 = i;
+  this.k6 = i;
+  this.l6 = i;
+  this.m6 = i;
+  this.n6 = i;
+  this.o6 = i;
+  this.p6 = i;
+  this.q6 = i;
+  this.r6 = i;
+  this.s6 = i;
+  this.t6 = i;
+  this.u6 = i;
+  this.v6 = i;
+  this.w6 = i;
+  this.x6 = i;
+  this.y6 = i;
+  this.z6 = i;
+  this.a7 = i;
+  this.b7 = i;
+  this.c7 = i;
+  this.d7 = i;
+  this.e7 = i;
+  this.f7 = i;
+  this.g7 = i;
+  this.h7 = i;
+  this.i7 = i;
+  this.j7 = i;
+  this.k7 = i;
+  this.l7 = i;
+  this.m7 = i;
+  this.n7 = i;
+  this.o7 = i;
+  this.p7 = i;
+  this.q7 = i;
+  this.r7 = i;
+  this.s7 = i;
+  this.t7 = i;
+  this.u7 = i;
+  this.v7 = i;
+  this.w7 = i;
+  this.x7 = i;
+  this.y7 = i;
+  this.z7 = i;
+  this.a8 = i;
+  this.b8 = i;
+  this.c8 = i;
+  this.d8 = i;
+  this.e8 = i;
+  this.f8 = i;
+  this.g8 = i;
+  this.h8 = i;
+  this.i8 = i;
+  this.j8 = i;
+  this.k8 = i;
+  this.l8 = i;
+  this.m8 = i;
+  this.n8 = i;
+  this.o8 = i;
+  this.p8 = i;
+  this.q8 = i;
+  this.r8 = i;
+  this.s8 = i;
+  this.t8 = i;
+  this.u8 = i;
+  this.v8 = i;
+  this.w8 = i;
+  this.x8 = i;
+  this.y8 = i;
+  this.z8 = i;
+  this.a9 = i;
+  this.b9 = i;
+  this.c9 = i;
+  this.d9 = i;
+  this.e9 = i;
+  this.f9 = i;
+  this.g9 = i;
+  this.h9 = i;
+  this.i9 = i;
+  this.j9 = i;
+  this.k9 = i;
+  this.l9 = i;
+  this.m9 = i;
+  this.n9 = i;
+  this.o9 = i;
+  this.p9 = i;
+  this.q9 = i;
+  // With this number of properties the object perfectly wraps around if the
+  // instance size is not checked when allocating the initial map for MultiProp.
+  // Meaning that the instance will be smaller than a minimal JSObject and we
+  // will suffer a bus error in the release build or an assertion in the debug
+  // build.
+}
+
+function ExpectAllFields(o, val) {
+  for (var x in o) {
+    assertEquals(o[x], val);
+  }
+}
+
+var a = new LargeObject(1);
+var b = new LargeObject(2);
+
+ExpectAllFields(a, 1);
+ExpectAllFields(b, 2);
diff --git a/regexp2000/test/mjsunit/large-object-literal.js b/regexp2000/test/mjsunit/large-object-literal.js
new file mode 100644 (file)
index 0000000..8118afe
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure that we can create large object literals.
+var nofProperties = 150;
+
+// Build large object literal string.
+var literal = "var o = { ";
+
+for (var i = 0; i < nofProperties; i++) {
+  if (i > 0) literal += ",";
+  literal += ("a" + i + ":" + i);
+}
+literal += "}";
+
+
+// Create the large object literal
+eval(literal);
+
+// Check that the properties have the expected values.
+for (var i = 0; i < nofProperties; i++) {
+  assertEquals(o["a"+i], i);
+}
+
+
diff --git a/regexp2000/test/mjsunit/lazy-load.js b/regexp2000/test/mjsunit/lazy-load.js
new file mode 100644 (file)
index 0000000..c384331
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test unusual way of accessing Date.
+var date0 = new this["Date"](1111);
+assertEquals(1111, date0.getTime());
+
+// Check that regexp literals use original RegExp (non-ECMA-262).
+RegExp = 42;
+var re = /test/;
diff --git a/regexp2000/test/mjsunit/leakcheck.js b/regexp2000/test/mjsunit/leakcheck.js
new file mode 100644 (file)
index 0000000..7cbb2e5
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * This test is run with leak detection when running special tests.
+ * Don't do too much work here or running it will take forever.
+ */
+
+function fac(n) {
+  if (n > 0) return fac(n - 1) * n;
+  else return 1;
+}
+
+function testFac() {
+  if (fac(6) != 720) throw "Error";
+}
+
+function testRegExp() {
+  var input = "123456789";
+  var result = input.replace(/[4-6]+/g, "xxx");
+  if (result != "123xxx789") throw "Error";
+}
+
+function main() {
+  testFac();
+  testRegExp();
+}
+
+main();
diff --git a/regexp2000/test/mjsunit/length.js b/regexp2000/test/mjsunit/length.js
new file mode 100644 (file)
index 0000000..3331564
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Assert we match ES3 and Safari.
+ */
+
+assertEquals(0, Array.prototype.length, "Array.prototype.length");
+assertEquals(1, Array.length, "Array.length");
+assertEquals(1, Array.prototype.concat.length, "Array.prototype.concat.length");
+assertEquals(1, Array.prototype.join.length, "Array.prototype.join.length");
+assertEquals(1, Array.prototype.push.length, "Array.prototype.push.length");
+assertEquals(1, Array.prototype.unshift.length, "Array.prototype.unshift.length");
+assertEquals(1, Boolean.length, "Boolean.length");
+assertEquals(1, Error.length, "Error.length");
+assertEquals(1, EvalError.length, "EvalError.length");
+assertEquals(1, Function.length, "Function.length");
+assertEquals(1, Function.prototype.call.length, "Function.prototype.call.length");
+assertEquals(1, Number.length, "Number.length");
+assertEquals(1, Number.prototype.toExponential.length, "Number.prototype.toExponential.length");
+assertEquals(1, Number.prototype.toFixed.length, "Number.prototype.toFixed.length");
+assertEquals(1, Number.prototype.toPrecision.length, "Number.prototype.toPrecision.length");
+assertEquals(1, Object.length, "Object.length");
+assertEquals(1, RangeError.length, "RangeError.length");
+assertEquals(1, ReferenceError.length, "ReferenceError.length");
+assertEquals(1, String.fromCharCode.length, "String.fromCharCode.length");
+assertEquals(1, String.length, "String.length");
+assertEquals(1, String.prototype.concat.length, "String.prototype.concat.length");
+assertEquals(1, String.prototype.indexOf.length, "String.prototype.indexOf.length");
+assertEquals(1, String.prototype.lastIndexOf.length, "String.prototype.lastIndexOf.length");
+assertEquals(1, SyntaxError.length, "SyntaxError.length");
+assertEquals(1, TypeError.length, "TypeError.length");
+assertEquals(2, Array.prototype.slice.length, "Array.prototype.slice.length");
+assertEquals(2, Array.prototype.splice.length, "Array.prototype.splice.length");
+assertEquals(2, Date.prototype.setMonth.length, "Date.prototype.setMonth.length");
+assertEquals(2, Date.prototype.setSeconds.length, "Date.prototype.setSeconds.length");
+assertEquals(2, Date.prototype.setUTCMonth.length, "Date.prototype.setUTCMonth.length");
+assertEquals(2, Date.prototype.setUTCSeconds.length, "Date.prototype.setUTCSeconds.length");
+assertEquals(2, Function.prototype.apply.length, "Function.prototype.apply.length");
+assertEquals(2, Math.max.length, "Math.max.length");
+assertEquals(2, Math.min.length, "Math.min.length");
+assertEquals(2, RegExp.length, "RegExp.length");
+assertEquals(2, String.prototype.slice.length, "String.prototype.slice.length");
+assertEquals(2, String.prototype.split.length, "String.prototype.split.length");
+assertEquals(2, String.prototype.substr.length, "String.prototype.substr.length");
+assertEquals(2, String.prototype.substring.length, "String.prototype.substring.length");
+assertEquals(3, Date.prototype.setFullYear.length, "Date.prototype.setFullYear.length");
+assertEquals(3, Date.prototype.setMinutes.length, "Date.prototype.setMinutes.length");
+assertEquals(3, Date.prototype.setUTCFullYear.length, "Date.prototype.setUTCFullYear.length");
+assertEquals(3, Date.prototype.setUTCMinutes.length, "Date.prototype.setUTCMinutes.length");
+assertEquals(4, Date.prototype.setHours.length, "Date.prototype.setHours.length");
+assertEquals(4, Date.prototype.setUTCHours.length, "Date.prototype.setUTCHours.length");
+assertEquals(7, Date.UTC.length, "Date.UTC.length");
+assertEquals(7, Date.length, "Date.length");
diff --git a/regexp2000/test/mjsunit/math-min-max.js b/regexp2000/test/mjsunit/math-min-max.js
new file mode 100644 (file)
index 0000000..0ed9912
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test Math.min().
+
+assertEquals(Number.POSITIVE_INFINITY, Math.min());
+assertEquals(1, Math.min(1));
+assertEquals(1, Math.min(1, 2));
+assertEquals(1, Math.min(2, 1));
+assertEquals(1, Math.min(1, 2, 3));
+assertEquals(1, Math.min(3, 2, 1));
+assertEquals(1, Math.min(2, 3, 1));
+
+var o = {};
+o.valueOf = function() { return 1; };
+assertEquals(1, Math.min(2, 3, '1'));
+assertEquals(1, Math.min(3, o, 2));
+assertEquals(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY / Math.min(-0, +0));
+assertEquals(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY / Math.min(+0, -0));
+assertEquals(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY / Math.min(+0, -0, 1));
+assertEquals(-1, Math.min(+0, -0, -1));
+assertEquals(-1, Math.min(-1, +0, -0));
+assertEquals(-1, Math.min(+0, -1, -0));
+assertEquals(-1, Math.min(-0, -1, +0));
+
+
+
+// Test Math.max().
+
+assertEquals(Number.NEGATIVE_INFINITY, Math.max());
+assertEquals(1, Math.max(1));
+assertEquals(2, Math.max(1, 2));
+assertEquals(2, Math.max(2, 1));
+assertEquals(3, Math.max(1, 2, 3));
+assertEquals(3, Math.max(3, 2, 1));
+assertEquals(3, Math.max(2, 3, 1));
+
+var o = {};
+o.valueOf = function() { return 3; };
+assertEquals(3, Math.max(2, '3', 1));
+assertEquals(3, Math.max(1, o, 2));
+assertEquals(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY / Math.max(-0, +0));
+assertEquals(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY / Math.max(+0, -0));
+assertEquals(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY / Math.max(+0, -0, -1));
+assertEquals(1, Math.max(+0, -0, +1));
+assertEquals(1, Math.max(+1, +0, -0));
+assertEquals(1, Math.max(+0, +1, -0));
+assertEquals(1, Math.max(-0, +1, +0));
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/megamorphic-callbacks.js b/regexp2000/test/mjsunit/megamorphic-callbacks.js
new file mode 100644 (file)
index 0000000..8829df0
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function load(o) {
+  return o.x;
+};
+
+function store(o) {
+  o.y = 42;
+};
+
+function call(o) {
+  return o.f();
+};
+
+// Create a slow-case object (with hashed properties).
+var o = { x: 42, f: function() { }, z: 100 };
+delete o.z;
+
+// Initialize IC stubs.
+load(o);
+store(o);
+call(o);
+
+
+// Create a new slow-case object (with hashed properties) and add
+// setter and getter properties to the object.
+var o = { z: 100 };
+delete o.z;
+o.__defineGetter__("x", function() { return 100; });
+o.__defineSetter__("y", function(value) { this.y_mirror = value; });
+o.__defineGetter__("f", function() { return function() { return 300; }});
+
+// Perform the load checks.
+assertEquals(100, o.x, "normal load");
+assertEquals(100, load(o), "ic load");
+
+// Perform the store checks.
+o.y = 200;
+assertEquals(200, o.y_mirror, "normal store");
+store(o);
+assertEquals(42, o.y_mirror, "ic store");
+
+// Perform the call checks.
+assertEquals(300, o.f(), "normal call");
+assertEquals(300, call(o), "ic call");
diff --git a/regexp2000/test/mjsunit/mirror-array.js b/regexp2000/test/mjsunit/mirror-array.js
new file mode 100644 (file)
index 0000000..25e64a6
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for objects
+
+function testArrayMirror(a, names) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(a);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.ObjectMirror);
+  assertTrue(mirror instanceof debug.ArrayMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isArray());
+  assertEquals('object', mirror.type());
+  assertFalse(mirror.isPrimitive());
+  assertEquals('Array', mirror.className());
+  assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror);
+  assertTrue(mirror.protoObject() instanceof debug.Mirror);
+  assertTrue(mirror.prototypeObject() instanceof debug.Mirror);
+  assertEquals(mirror.length(), a.length);
+  
+  var indexedValueMirrors = mirror.indexedPropertiesFromRange();
+  assertEquals(indexedValueMirrors.length, a.length);
+  for (var i = 0; i < indexedValueMirrors.length; i++) {
+    assertTrue(indexedValueMirrors[i] instanceof debug.Mirror);
+    if (a[i]) {
+      assertTrue(indexedValueMirrors[i] instanceof debug.PropertyMirror);
+    }
+  }
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('object', fromJSON.type);
+  assertEquals('Array', fromJSON.className);
+  assertEquals('function', fromJSON.constructorFunction.type);
+  assertEquals('Array', fromJSON.constructorFunction.name);
+  assertEquals(a.length, fromJSON.length);
+
+  // Check that the serialization contains all indexed properties.
+  for (var i = 0; i < fromJSON.indexedProperties.length; i++) {
+    var index = fromJSON.indexedProperties[i].name;
+    assertEquals(indexedValueMirrors[index].name(), index);
+    assertEquals(indexedValueMirrors[index].value().type(), fromJSON.indexedProperties[i].value.type, index);
+  }
+
+  // Check that the serialization contains all names properties.
+  if (names) {
+    for (var i = 0; i < names.length; i++) {
+      var found = false;
+      for (var j = 0; j < fromJSON.properties.length; j++) {
+        if (names[i] == fromJSON.properties[j].name) {
+          found = true; 
+        }
+      }
+      assertTrue(found, names[i])
+    }
+  } else {
+    assertEquals(1, fromJSON.properties.length)
+  }
+}
+
+
+// Test a number of different arrays.
+testArrayMirror([]);
+testArrayMirror([1]);
+testArrayMirror([1,2]);
+testArrayMirror(["a", function(){}, [1,2], 2, /[ab]/]);
+
+a=[1];
+a[100]=7;
+testArrayMirror(a);
+
+a=[1,2,3];
+a.x=2.2;
+a.y=function(){return null;}
+testArrayMirror(a, ['x','y']);
+
+var a = []; a.push(a);
+testArrayMirror(a);
diff --git a/regexp2000/test/mjsunit/mirror-boolean.js b/regexp2000/test/mjsunit/mirror-boolean.js
new file mode 100644 (file)
index 0000000..2147048
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for boolean values
+
+function testBooleanMirror(b) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(b);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.BooleanMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isBoolean());
+  assertEquals('boolean', mirror.type());
+  assertTrue(mirror.isPrimitive());
+
+  // Test text representation
+  assertEquals(b ? 'true' : 'false', mirror.toText());
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('boolean', fromJSON.type, json);
+  assertEquals(b, fromJSON.value, json);
+}
+
+
+// Test all boolean values.
+testBooleanMirror(true);
+testBooleanMirror(false);
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/mirror-date.js b/regexp2000/test/mjsunit/mirror-date.js
new file mode 100644 (file)
index 0000000..e96badc
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for boolean values
+
+function testDateMirror(d, iso8601) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(d);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.ObjectMirror);
+  assertTrue(mirror instanceof debug.DateMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isDate());
+  assertEquals('object', mirror.type());
+  assertFalse(mirror.isPrimitive());
+
+  // Test text representation
+  assertEquals(iso8601, mirror.toText());
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('object', fromJSON.type);
+  assertEquals('Date', fromJSON.className);
+  assertEquals(iso8601, fromJSON.value);
+}
+
+
+// Test Date values.
+testDateMirror(new Date(Date.parse("Dec 25, 1995 1:30 UTC")), "1995-12-25T01:30:00.000Z");
+d = new Date();
+d.setUTCFullYear(1967);
+d.setUTCMonth(0); // January.
+d.setUTCDate(17);
+d.setUTCHours(9);
+d.setUTCMinutes(22);
+d.setUTCSeconds(59);
+d.setUTCMilliseconds(0);
+testDateMirror(d, "1967-01-17T09:22:59.000Z");
+d.setUTCMilliseconds(1);
+testDateMirror(d, "1967-01-17T09:22:59.001Z");
+d.setUTCMilliseconds(12);
+testDateMirror(d, "1967-01-17T09:22:59.012Z");
+d.setUTCMilliseconds(123);
+testDateMirror(d, "1967-01-17T09:22:59.123Z");
diff --git a/regexp2000/test/mjsunit/mirror-error.js b/regexp2000/test/mjsunit/mirror-error.js
new file mode 100644 (file)
index 0000000..49eaaff
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for regular error objects
+
+function testErrorMirror(e) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(e);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.ObjectMirror);
+  assertTrue(mirror instanceof debug.ErrorMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isError());
+  assertEquals('error', mirror.type());
+  assertFalse(mirror.isPrimitive());
+  assertEquals(mirror.message(), e.message, 'source');
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('error', fromJSON.type);
+  assertEquals('Error', fromJSON.className);
+  assertEquals(fromJSON.message, e.message, 'message');
+  
+  // Check the formatted text (regress 1231579).
+  assertEquals(fromJSON.text, e.toString(), 'toString');
+}
+
+
+// Test Date values.
+testErrorMirror(new Error());
+testErrorMirror(new Error('This does not work'));
+testErrorMirror(new Error(123+456));
+testErrorMirror(new EvalError('EvalError'));
+testErrorMirror(new RangeError('RangeError'));
+testErrorMirror(new ReferenceError('ReferenceError'));
+testErrorMirror(new SyntaxError('SyntaxError'));
+testErrorMirror(new TypeError('TypeError'));
+testErrorMirror(new URIError('URIError'));
diff --git a/regexp2000/test/mjsunit/mirror-function.js b/regexp2000/test/mjsunit/mirror-function.js
new file mode 100644 (file)
index 0000000..c6e7a4e
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for functions.
+
+function testFunctionMirror(f) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(f);
+  print(mirror.toJSONProtocol(true));
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.ObjectMirror);
+  assertTrue(mirror instanceof debug.FunctionMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isFunction());
+  assertEquals('function', mirror.type());
+  assertFalse(mirror.isPrimitive());
+  assertEquals("Function", mirror.className());
+  assertEquals(f.name, mirror.name());
+  assertTrue(mirror.resolved());
+  assertEquals(f.toString(), mirror.source());
+  assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror);
+  assertTrue(mirror.protoObject() instanceof debug.Mirror);
+  assertTrue(mirror.prototypeObject() instanceof debug.Mirror);
+  
+  // Test text representation
+  assertEquals(f.toString(), mirror.toText());
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('function', fromJSON.type);
+  assertEquals('Function', fromJSON.className);
+  assertEquals('function', fromJSON.constructorFunction.type);
+  assertEquals('Function', fromJSON.constructorFunction.name);
+  assertTrue(fromJSON.resolved);
+  assertEquals(f.name, fromJSON.name);
+  assertEquals(f.toString(), fromJSON.source);
+
+  // Check the formatted text (regress 1142074).
+  assertEquals(f.toString(), fromJSON.text);
+}
+
+
+// Test a number of different functions.
+testFunctionMirror(function(){});
+testFunctionMirror(function a(){return 1;});
+testFunctionMirror(Math.sin);
diff --git a/regexp2000/test/mjsunit/mirror-null.js b/regexp2000/test/mjsunit/mirror-null.js
new file mode 100644 (file)
index 0000000..4233efa
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for null
+
+// Create mirror and JSON representation.
+var mirror = debug.MakeMirror(null);
+var json = mirror.toJSONProtocol(true);
+
+// Check the mirror hierachy.
+assertTrue(mirror instanceof debug.Mirror);
+assertTrue(mirror instanceof debug.NullMirror);
+
+// Check the mirror properties.
+assertTrue(mirror.isNull());
+assertEquals('null', mirror.type());
+assertTrue(mirror.isPrimitive());
+
+// Test text representation
+assertEquals('null', mirror.toText());
+
+// Parse JSON representation and check.
+var fromJSON = eval('(' + json + ')');
+assertEquals('null', fromJSON.type);
diff --git a/regexp2000/test/mjsunit/mirror-number.js b/regexp2000/test/mjsunit/mirror-number.js
new file mode 100644 (file)
index 0000000..20280c3
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for number values
+
+function testNumberMirror(n) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(n);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.NumberMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isNumber());
+  assertEquals('number', mirror.type());
+  assertTrue(mirror.isPrimitive());
+
+  // Test text representation
+  assertEquals(String(n), mirror.toText());
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('number', fromJSON.type);
+  if (!isNaN(n)) {
+    assertEquals(n, fromJSON.value);
+  } else {
+    assertTrue(isNaN(fromJSON.value));
+  }
+}
+
+
+// Test a number of different numbers.
+testNumberMirror(-7);
+testNumberMirror(-6.5);
+testNumberMirror(0);
+testNumberMirror(42);
+testNumberMirror(100.0002);
+testNumberMirror(Infinity);
+testNumberMirror(-Infinity);
+testNumberMirror(NaN);
diff --git a/regexp2000/test/mjsunit/mirror-object.js b/regexp2000/test/mjsunit/mirror-object.js
new file mode 100644 (file)
index 0000000..bbaf044
--- /dev/null
@@ -0,0 +1,178 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for objects
+
+function testObjectMirror(o, cls_name, ctor_name, hasSpecialProperties) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(o);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.ObjectMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isObject());
+  assertEquals('object', mirror.type());
+  assertFalse(mirror.isPrimitive());
+  assertEquals(cls_name, mirror.className());
+  assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror);
+  assertTrue(mirror.protoObject() instanceof debug.Mirror);
+  assertTrue(mirror.prototypeObject() instanceof debug.Mirror);
+  assertFalse(mirror.hasNamedInterceptor(), "hasNamedInterceptor()");
+  assertFalse(mirror.hasIndexedInterceptor(), "hasIndexedInterceptor()");
+
+  var names = mirror.propertyNames();
+  var properties = mirror.properties()
+  assertEquals(names.length, properties.length);
+  for (var i = 0; i < properties.length; i++) {
+    assertTrue(properties[i] instanceof debug.Mirror);
+    assertTrue(properties[i] instanceof debug.PropertyMirror);
+    assertEquals('property', properties[i].type());
+    assertEquals(names[i], properties[i].name());
+  }
+  
+  for (var p in o) {
+    var property_mirror = mirror.property(p);
+    assertTrue(property_mirror instanceof debug.PropertyMirror);
+    assertEquals(p, property_mirror.name());
+    // If the object has some special properties don't test for these.
+    if (!hasSpecialProperties) {
+      assertEquals(0, property_mirror.attributes(), property_mirror.name());
+      assertFalse(property_mirror.isReadOnly());
+      assertTrue(property_mirror.isEnum());
+      assertTrue(property_mirror.canDelete());
+    }
+  }
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('object', fromJSON.type);
+  assertEquals(cls_name, fromJSON.className);
+  assertEquals('function', fromJSON.constructorFunction.type);
+  if (ctor_name !== undefined)
+    assertEquals(ctor_name, fromJSON.constructorFunction.name);
+  assertEquals(void 0, fromJSON.namedInterceptor);
+  assertEquals(void 0, fromJSON.indexedInterceptor);
+
+  // For array the index properties are seperate from named properties.
+  if (!cls_name == 'Array') {
+    assertEquals(names.length, fromJSON.properties.length, 'Some properties missing in JSON');
+  }
+
+  // Check that the serialization contains all properties.
+  for (var i = 0; i < fromJSON.properties.length; i++) {
+    var name = fromJSON.properties[i].name;
+    if (!name) name = fromJSON.properties[i].index;
+    var found = false;
+    for (var j = 0; j < names.length; j++) {
+      if (names[j] == name) {
+        assertEquals(properties[i].value().type(), fromJSON.properties[i].value.type);
+        // If property type is normal nothing is serialized.
+        if (properties[i].propertyType() != debug.PropertyType.Normal) {
+          assertEquals(properties[i].propertyType(), fromJSON.properties[i].propertyType);
+        } else {
+          assertTrue(typeof(fromJSON.properties[i].propertyType) === 'undefined');
+        }
+        // If there are no attributes nothing is serialized.
+        if (properties[i].attributes() != debug.PropertyAttribute.None) {
+          assertEquals(properties[i].attributes(), fromJSON.properties[i].attributes);
+        } else {
+          assertTrue(typeof(fromJSON.properties[i].attributes) === 'undefined');
+        }
+        if (!properties[i].value() instanceof debug.AccessorMirror &&
+            properties[i].value().isPrimitive()) {
+          // NaN is not equal to NaN.
+          if (isNaN(properties[i].value().value())) {
+            assertTrue(isNaN(fromJSON.properties[i].value.value));
+          } else {
+            assertEquals(properties[i].value().value(), fromJSON.properties[i].value.value);
+          }
+        }
+        found = true;
+      }
+    }
+    assertTrue(found, '"' + name + '" not found');
+  }
+}
+
+
+function Point(x,y) {
+  this.x_ = x;
+  this.y_ = y;
+}
+
+
+// Test a number of different objects.
+testObjectMirror({}, 'Object', 'Object');
+testObjectMirror({'a':1,'b':2}, 'Object', 'Object');
+testObjectMirror({'1':void 0,'2':null,'f':function pow(x,y){return Math.pow(x,y);}}, 'Object', 'Object');
+testObjectMirror(new Point(-1.2,2.003), 'Object', 'Point');
+testObjectMirror(this, 'global', undefined, true);  // Global object has special properties
+testObjectMirror([], 'Array', 'Array');
+testObjectMirror([1,2], 'Array', 'Array');
+
+// Test that non enumerable properties are part of the mirror
+global_mirror = debug.MakeMirror(this);
+assertEquals('property', global_mirror.property("Math").type());
+assertFalse(global_mirror.property("Math").isEnum(), "Math is enumerable" + global_mirror.property("Math").attributes());
+
+math_mirror = global_mirror.property("Math").value();
+assertEquals('property', math_mirror.property("E").type());
+assertFalse(math_mirror.property("E").isEnum(), "Math.E is enumerable");
+assertTrue(math_mirror.property("E").isReadOnly());
+assertFalse(math_mirror.property("E").canDelete());
+
+// Test objects with JavaScript accessors.
+o = {}
+o.__defineGetter__('a', function(){throw 'a';})
+o.__defineSetter__('b', function(){throw 'b';})
+o.__defineGetter__('c', function(){throw 'c';})
+o.__defineSetter__('c', function(){throw 'c';})
+testObjectMirror(o, 'Object', 'Object');
+mirror = debug.MakeMirror(o);
+// a has getter but no setter.
+assertTrue(mirror.property('a').value() instanceof debug.AccessorMirror);
+assertEquals(debug.PropertyType.Callbacks, mirror.property('a').propertyType());
+// b has setter but no getter.
+assertTrue(mirror.property('b').value() instanceof debug.AccessorMirror);
+assertEquals(debug.PropertyType.Callbacks, mirror.property('b').propertyType());
+// c has both getter and setter.
+assertTrue(mirror.property('c').value() instanceof debug.AccessorMirror);
+assertEquals(debug.PropertyType.Callbacks, mirror.property('c').propertyType());
+
+// Test objects with native accessors.
+mirror = debug.MakeMirror(new String('abc'));
+assertTrue(mirror instanceof debug.ObjectMirror);
+assertTrue(mirror.property('length').value() instanceof debug.AccessorMirror);
+assertTrue(mirror.property('length').value().isNative());
+assertEquals('a', mirror.property(0).value().value());
+assertEquals('b', mirror.property(1).value().value());
+assertEquals('c', mirror.property(2).value().value());
diff --git a/regexp2000/test/mjsunit/mirror-regexp.js b/regexp2000/test/mjsunit/mirror-regexp.js
new file mode 100644 (file)
index 0000000..443caeb
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for regular expression values
+
+var all_attributes = debug.PropertyAttribute.ReadOnly |
+                     debug.PropertyAttribute.DontEnum |
+                     debug.PropertyAttribute.DontDelete;
+var expected_attributes = {
+  'source': all_attributes,
+  'global': all_attributes,
+  'ignoreCase': all_attributes,
+  'multiline': all_attributes,
+  'lastIndex': debug.PropertyAttribute.DontEnum | debug.PropertyAttribute.DontDelete
+};
+
+function testRegExpMirror(r) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(r);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.ObjectMirror);
+  assertTrue(mirror instanceof debug.RegExpMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isRegExp());
+  assertEquals('regexp', mirror.type());
+  assertFalse(mirror.isPrimitive());
+  assertEquals(mirror.source(), r.source, 'source');
+  assertEquals(mirror.global(), r.global, 'global');
+  assertEquals(mirror.ignoreCase(), r.ignoreCase, 'ignoreCase');
+  assertEquals(mirror.multiline(), r.multiline, 'multiline');
+  for (var p in expected_attributes) {
+    assertEquals(mirror.property(p).attributes(),
+                 expected_attributes[p],
+                 p + ' attributes');
+  }
+
+  // Test text representation
+  assertEquals('/' + r.source + '/', mirror.toText());
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('regexp', fromJSON.type);
+  assertEquals('RegExp', fromJSON.className);
+  assertEquals(fromJSON.source, r.source, 'source');
+  assertEquals(fromJSON.global, r.global, 'global');
+  assertEquals(fromJSON.ignoreCase, r.ignoreCase, 'ignoreCase');
+  assertEquals(fromJSON.multiline, r.multiline, 'multiline');
+  for (var p in expected_attributes) {
+    for (var i = 0; i < fromJSON.properties.length; i++) {
+      if (fromJSON.properties[i].name == p) {
+        assertEquals(fromJSON.properties[i].attributes,
+                     expected_attributes[p],
+                     p + ' attributes');
+      }
+    }
+  }
+}
+
+
+// Test Date values.
+testRegExpMirror(/x/);
+testRegExpMirror(/[abc]/);
+testRegExpMirror(/[\r\n]/g);
+testRegExpMirror(/a*b/gmi);
diff --git a/regexp2000/test/mjsunit/mirror-string.js b/regexp2000/test/mjsunit/mirror-string.js
new file mode 100644 (file)
index 0000000..451f8f1
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for string values
+
+function testStringMirror(s) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(s);
+  var json = mirror.toJSONProtocol(true);
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.StringMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isString());
+  assertEquals('string', mirror.type());
+  assertTrue(mirror.isPrimitive());
+
+  // Test text representation
+  assertEquals(s, mirror.toText());
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('string', fromJSON.type);
+  assertEquals(s, fromJSON.value);
+}
+
+Number =2;
+
+// Test a number of different strings.
+testStringMirror('');
+testStringMirror('abcdABCD');
+testStringMirror('1234');
+testStringMirror('"');
+testStringMirror('"""');
+testStringMirror("'");
+testStringMirror("'''");
+testStringMirror("'\"'");
+testStringMirror('\\');
+testStringMirror('\b\t\n\f\r');
+testStringMirror('\u0001\u0002\u001E\u001F');
+testStringMirror('"a":1,"b":2');
diff --git a/regexp2000/test/mjsunit/mirror-undefined.js b/regexp2000/test/mjsunit/mirror-undefined.js
new file mode 100644 (file)
index 0000000..fc35c8d
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for undefined
+
+// Create mirror and JSON representation.
+var mirror = debug.MakeMirror(void 0);
+var json = mirror.toJSONProtocol(true);
+
+// Check the mirror hierachy.
+assertTrue(mirror instanceof debug.Mirror);
+assertTrue(mirror instanceof debug.UndefinedMirror);
+
+// Check the mirror properties.
+assertTrue(mirror.isUndefined());
+assertEquals('undefined', mirror.type());
+assertTrue(mirror.isPrimitive());
+
+// Test text representation
+assertEquals('undefined', mirror.toText());
+
+// Parse JSON representation and check.
+var fromJSON = eval('(' + json + ')');
+assertEquals('undefined', fromJSON.type);
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/mirror-unresolved-function.js b/regexp2000/test/mjsunit/mirror-unresolved-function.js
new file mode 100644 (file)
index 0000000..ab49508
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for unresolved functions.
+
+var mirror = new debug.UnresolvedFunctionMirror("f");
+var json = mirror.toJSONProtocol(true);
+
+// Check the mirror hierachy for unresolved functions.
+assertTrue(mirror instanceof debug.Mirror);
+assertTrue(mirror instanceof debug.ValueMirror);
+assertTrue(mirror instanceof debug.ObjectMirror);
+assertTrue(mirror instanceof debug.FunctionMirror);
+
+// Check the mirror properties for unresolved functions.
+assertTrue(mirror.isUnresolvedFunction());
+assertEquals('function', mirror.type());
+assertFalse(mirror.isPrimitive());
+assertEquals("Function", mirror.className());
+assertEquals("f", mirror.name());
+assertFalse(mirror.resolved());
+assertEquals(void 0, mirror.source());
+assertEquals('undefined', mirror.constructorFunction().type());
+assertEquals('undefined', mirror.protoObject().type());
+assertEquals('undefined', mirror.prototypeObject().type());
+  
+// Parse JSON representation of unresolved functions and check.
+/*var fromJSON = eval('(' + json + ')');
+assertEquals('function', fromJSON.type);
+assertEquals('Function', fromJSON.className);
+assertEquals('undefined', fromJSON.constructorFunction.type);
+assertEquals('undefined', fromJSON.protoObject.type);
+assertEquals('undefined', fromJSON.prototypeObject.type);
+assertFalse(fromJSON.resolved);
+assertEquals("f", fromJSON.name);
+assertEquals(void 0, fromJSON.source);*/
diff --git a/regexp2000/test/mjsunit/mjsunit.js b/regexp2000/test/mjsunit/mjsunit.js
new file mode 100644 (file)
index 0000000..e7b47cd
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function MjsUnitAssertionError(message) {
+  this.message = message;
+}
+
+MjsUnitAssertionError.prototype.toString = function () {
+  return this.message;
+}
+
+/*
+ * This file is included in all mini jsunit test cases.  The test
+ * framework expects lines that signal failed tests to start with
+ * the f-word and ignore all other lines.
+ */
+
+function fail(expected, found, name_opt) {
+  var start;
+  if (name_opt) {
+    // Fix this when we ditch the old test runner.
+    start = "Fail" + "ure (" + name_opt + "): ";
+  } else {
+    start = "Fail" + "ure:";
+  }
+  throw new MjsUnitAssertionError(start + " expected <" + expected + "> found <" + found + ">");
+}
+
+
+function assertEquals(expected, found, name_opt) {
+  if (expected != found) {
+    fail(expected, found, name_opt);
+  }
+}
+
+
+function assertArrayEquals(expected, found, name_opt) {
+  var start = "";
+  if (name_opt) {
+    start = name_opt + " - ";
+  }
+  assertEquals(expected.length, found.length, start + "array length");
+  if (expected.length == found.length) {
+    for (var i = 0; i < expected.length; ++i) {
+      assertEquals(expected[i], found[i], start + "array element at index " + i);
+    }
+  }
+}
+
+
+function assertTrue(value, name_opt) {
+  assertEquals(true, value, name_opt);
+}
+
+
+function assertFalse(value, name_opt) {
+  assertEquals(false, value, name_opt);
+}
+
+
+function assertNaN(value, name_opt) {
+  if (!isNaN(value)) {
+    fail("NaN", value, name_opt);
+  }
+}
+
+
+function assertThrows(code) {
+  try {
+    eval(code);
+    assertTrue(false, "did not throw exception");
+  } catch (e) {
+    // Do nothing.
+  }
+}
+
+
+function assertInstanceof(obj, type) {
+  if (!(obj instanceof type)) {
+    assertTrue(false, "Object <" + obj + "> is not an instance of <" + type + ">");
+  }
+}
+
+
+function assertDoesNotThrow(code) {
+  try {
+    eval(code);
+  } catch (e) {
+    assertTrue(false, "threw an exception");
+  }
+}
+
+
+function assertUnreachable(name_opt) {
+  // Fix this when we ditch the old test runner.
+  var message = "Fail" + "ure: unreachable"
+  if (name_opt) {
+    message += " - " + name_opt;
+  }
+  throw new MjsUnitAssertionError(message);
+}
diff --git a/regexp2000/test/mjsunit/mjsunit.status b/regexp2000/test/mjsunit/mjsunit.status
new file mode 100644 (file)
index 0000000..6a97c7f
--- /dev/null
@@ -0,0 +1,63 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+prefix mjsunit
+
+# All tests in the bug directory are expected to fail.
+bugs: FAIL
+
+# This one uses a built-in that's only present in debug mode. It takes
+# too long to run in debug mode on ARM.
+fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm)
+
+[ $arch == arm ]
+
+# Slow tests which times out in debug mode.
+try: PASS, SKIP if $mode == debug
+debug-scripts-request: PASS, SKIP if $mode == debug
+
+# Bug number 1020483: Debug tests fail on ARM.
+debug-constructor: FAIL
+debug-continue: FAIL
+debug-backtrace-text: FAIL
+debug-backtrace: FAIL
+debug-evaluate-recursive: FAIL
+debug-changebreakpoint: FAIL
+debug-clearbreakpoint: FAIL
+debug-conditional-breakpoints: FAIL
+debug-enable-disable-breakpoints: FAIL
+debug-evaluate: FAIL
+debug-event-listener: FAIL
+debug-ignore-breakpoints: FAIL
+debug-multiple-breakpoints: FAIL
+debug-setbreakpoint: FAIL
+debug-step-stub-callfunction: FAIL
+debug-stepin-constructor: FAIL
+debug-step: FAIL
+debug-breakpoints: PASS || FAIL
+
+regress/regress-998565: FAIL
diff --git a/regexp2000/test/mjsunit/mul-exhaustive.js b/regexp2000/test/mjsunit/mul-exhaustive.js
new file mode 100644 (file)
index 0000000..452f933
--- /dev/null
@@ -0,0 +1,4511 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var x;
+var y;
+var a;
+
+function f(a, y) {
+  assertEquals(a, x * y);
+  assertEquals(a, -x * -y);
+  assertEquals(-a, -x * y);
+  assertEquals(-a, x * -y);
+  assertEquals(a, y * x);
+  assertEquals(a, -y * -x);
+  assertEquals(-a, y * -x);
+  assertEquals(-a, -y * x);
+}
+
+x = 1;
+f(1, 1);
+x = 2;
+f(2, 1);
+f(4, 2);
+x = 3;
+f(3, 1);
+f(6, 2);
+f(9, 3);
+x = 4;
+f(4, 1);
+f(8, 2);
+f(12, 3);
+f(16, 4);
+x = 5;
+f(5, 1);
+f(10, 2);
+f(15, 3);
+f(20, 4);
+f(25, 5);
+x = 7;
+f(7, 1);
+f(14, 2);
+f(21, 3);
+f(28, 4);
+f(35, 5);
+f(49, 7);
+x = 8;
+f(8, 1);
+f(16, 2);
+f(24, 3);
+f(32, 4);
+f(40, 5);
+f(56, 7);
+f(64, 8);
+x = 9;
+f(9, 1);
+f(18, 2);
+f(27, 3);
+f(36, 4);
+f(45, 5);
+f(63, 7);
+f(72, 8);
+f(81, 9);
+x = 15;
+f(15, 1);
+f(30, 2);
+f(45, 3);
+f(60, 4);
+f(75, 5);
+f(105, 7);
+f(120, 8);
+f(135, 9);
+f(225, 15);
+x = 16;
+f(16, 1);
+f(32, 2);
+f(48, 3);
+f(64, 4);
+f(80, 5);
+f(112, 7);
+f(128, 8);
+f(144, 9);
+f(240, 15);
+f(256, 16);
+x = 17;
+f(17, 1);
+f(34, 2);
+f(51, 3);
+f(68, 4);
+f(85, 5);
+f(119, 7);
+f(136, 8);
+f(153, 9);
+f(255, 15);
+f(272, 16);
+f(289, 17);
+x = 31;
+f(31, 1);
+f(62, 2);
+f(93, 3);
+f(124, 4);
+f(155, 5);
+f(217, 7);
+f(248, 8);
+f(279, 9);
+f(465, 15);
+f(496, 16);
+f(527, 17);
+f(961, 31);
+x = 32;
+f(32, 1);
+f(64, 2);
+f(96, 3);
+f(128, 4);
+f(160, 5);
+f(224, 7);
+f(256, 8);
+f(288, 9);
+f(480, 15);
+f(512, 16);
+f(544, 17);
+f(992, 31);
+f(1024, 32);
+x = 33;
+f(33, 1);
+f(66, 2);
+f(99, 3);
+f(132, 4);
+f(165, 5);
+f(231, 7);
+f(264, 8);
+f(297, 9);
+f(495, 15);
+f(528, 16);
+f(561, 17);
+f(1023, 31);
+f(1056, 32);
+f(1089, 33);
+x = 63;
+f(63, 1);
+f(126, 2);
+f(189, 3);
+f(252, 4);
+f(315, 5);
+f(441, 7);
+f(504, 8);
+f(567, 9);
+f(945, 15);
+f(1008, 16);
+f(1071, 17);
+f(1953, 31);
+f(2016, 32);
+f(2079, 33);
+f(3969, 63);
+x = 64;
+f(64, 1);
+f(128, 2);
+f(192, 3);
+f(256, 4);
+f(320, 5);
+f(448, 7);
+f(512, 8);
+f(576, 9);
+f(960, 15);
+f(1024, 16);
+f(1088, 17);
+f(1984, 31);
+f(2048, 32);
+f(2112, 33);
+f(4032, 63);
+f(4096, 64);
+x = 65;
+f(65, 1);
+f(130, 2);
+f(195, 3);
+f(260, 4);
+f(325, 5);
+f(455, 7);
+f(520, 8);
+f(585, 9);
+f(975, 15);
+f(1040, 16);
+f(1105, 17);
+f(2015, 31);
+f(2080, 32);
+f(2145, 33);
+f(4095, 63);
+f(4160, 64);
+f(4225, 65);
+x = 127;
+f(127, 1);
+f(254, 2);
+f(381, 3);
+f(508, 4);
+f(635, 5);
+f(889, 7);
+f(1016, 8);
+f(1143, 9);
+f(1905, 15);
+f(2032, 16);
+f(2159, 17);
+f(3937, 31);
+f(4064, 32);
+f(4191, 33);
+f(8001, 63);
+f(8128, 64);
+f(8255, 65);
+f(16129, 127);
+x = 128;
+f(128, 1);
+f(256, 2);
+f(384, 3);
+f(512, 4);
+f(640, 5);
+f(896, 7);
+f(1024, 8);
+f(1152, 9);
+f(1920, 15);
+f(2048, 16);
+f(2176, 17);
+f(3968, 31);
+f(4096, 32);
+f(4224, 33);
+f(8064, 63);
+f(8192, 64);
+f(8320, 65);
+f(16256, 127);
+f(16384, 128);
+x = 129;
+f(129, 1);
+f(258, 2);
+f(387, 3);
+f(516, 4);
+f(645, 5);
+f(903, 7);
+f(1032, 8);
+f(1161, 9);
+f(1935, 15);
+f(2064, 16);
+f(2193, 17);
+f(3999, 31);
+f(4128, 32);
+f(4257, 33);
+f(8127, 63);
+f(8256, 64);
+f(8385, 65);
+f(16383, 127);
+f(16512, 128);
+f(16641, 129);
+x = 255;
+f(255, 1);
+f(510, 2);
+f(765, 3);
+f(1020, 4);
+f(1275, 5);
+f(1785, 7);
+f(2040, 8);
+f(2295, 9);
+f(3825, 15);
+f(4080, 16);
+f(4335, 17);
+f(7905, 31);
+f(8160, 32);
+f(8415, 33);
+f(16065, 63);
+f(16320, 64);
+f(16575, 65);
+f(32385, 127);
+f(32640, 128);
+f(32895, 129);
+f(65025, 255);
+x = 256;
+f(256, 1);
+f(512, 2);
+f(768, 3);
+f(1024, 4);
+f(1280, 5);
+f(1792, 7);
+f(2048, 8);
+f(2304, 9);
+f(3840, 15);
+f(4096, 16);
+f(4352, 17);
+f(7936, 31);
+f(8192, 32);
+f(8448, 33);
+f(16128, 63);
+f(16384, 64);
+f(16640, 65);
+f(32512, 127);
+f(32768, 128);
+f(33024, 129);
+f(65280, 255);
+f(65536, 256);
+x = 257;
+f(257, 1);
+f(514, 2);
+f(771, 3);
+f(1028, 4);
+f(1285, 5);
+f(1799, 7);
+f(2056, 8);
+f(2313, 9);
+f(3855, 15);
+f(4112, 16);
+f(4369, 17);
+f(7967, 31);
+f(8224, 32);
+f(8481, 33);
+f(16191, 63);
+f(16448, 64);
+f(16705, 65);
+f(32639, 127);
+f(32896, 128);
+f(33153, 129);
+f(65535, 255);
+f(65792, 256);
+f(66049, 257);
+x = 511;
+f(511, 1);
+f(1022, 2);
+f(1533, 3);
+f(2044, 4);
+f(2555, 5);
+f(3577, 7);
+f(4088, 8);
+f(4599, 9);
+f(7665, 15);
+f(8176, 16);
+f(8687, 17);
+f(15841, 31);
+f(16352, 32);
+f(16863, 33);
+f(32193, 63);
+f(32704, 64);
+f(33215, 65);
+f(64897, 127);
+f(65408, 128);
+f(65919, 129);
+f(130305, 255);
+f(130816, 256);
+f(131327, 257);
+f(261121, 511);
+x = 512;
+f(512, 1);
+f(1024, 2);
+f(1536, 3);
+f(2048, 4);
+f(2560, 5);
+f(3584, 7);
+f(4096, 8);
+f(4608, 9);
+f(7680, 15);
+f(8192, 16);
+f(8704, 17);
+f(15872, 31);
+f(16384, 32);
+f(16896, 33);
+f(32256, 63);
+f(32768, 64);
+f(33280, 65);
+f(65024, 127);
+f(65536, 128);
+f(66048, 129);
+f(130560, 255);
+f(131072, 256);
+f(131584, 257);
+f(261632, 511);
+f(262144, 512);
+x = 513;
+f(513, 1);
+f(1026, 2);
+f(1539, 3);
+f(2052, 4);
+f(2565, 5);
+f(3591, 7);
+f(4104, 8);
+f(4617, 9);
+f(7695, 15);
+f(8208, 16);
+f(8721, 17);
+f(15903, 31);
+f(16416, 32);
+f(16929, 33);
+f(32319, 63);
+f(32832, 64);
+f(33345, 65);
+f(65151, 127);
+f(65664, 128);
+f(66177, 129);
+f(130815, 255);
+f(131328, 256);
+f(131841, 257);
+f(262143, 511);
+f(262656, 512);
+f(263169, 513);
+x = 1023;
+f(1023, 1);
+f(2046, 2);
+f(3069, 3);
+f(4092, 4);
+f(5115, 5);
+f(7161, 7);
+f(8184, 8);
+f(9207, 9);
+f(15345, 15);
+f(16368, 16);
+f(17391, 17);
+f(31713, 31);
+f(32736, 32);
+f(33759, 33);
+f(64449, 63);
+f(65472, 64);
+f(66495, 65);
+f(129921, 127);
+f(130944, 128);
+f(131967, 129);
+f(260865, 255);
+f(261888, 256);
+f(262911, 257);
+f(522753, 511);
+f(523776, 512);
+f(524799, 513);
+f(1046529, 1023);
+x = 1024;
+f(1024, 1);
+f(2048, 2);
+f(3072, 3);
+f(4096, 4);
+f(5120, 5);
+f(7168, 7);
+f(8192, 8);
+f(9216, 9);
+f(15360, 15);
+f(16384, 16);
+f(17408, 17);
+f(31744, 31);
+f(32768, 32);
+f(33792, 33);
+f(64512, 63);
+f(65536, 64);
+f(66560, 65);
+f(130048, 127);
+f(131072, 128);
+f(132096, 129);
+f(261120, 255);
+f(262144, 256);
+f(263168, 257);
+f(523264, 511);
+f(524288, 512);
+f(525312, 513);
+f(1047552, 1023);
+f(1048576, 1024);
+x = 1025;
+f(1025, 1);
+f(2050, 2);
+f(3075, 3);
+f(4100, 4);
+f(5125, 5);
+f(7175, 7);
+f(8200, 8);
+f(9225, 9);
+f(15375, 15);
+f(16400, 16);
+f(17425, 17);
+f(31775, 31);
+f(32800, 32);
+f(33825, 33);
+f(64575, 63);
+f(65600, 64);
+f(66625, 65);
+f(130175, 127);
+f(131200, 128);
+f(132225, 129);
+f(261375, 255);
+f(262400, 256);
+f(263425, 257);
+f(523775, 511);
+f(524800, 512);
+f(525825, 513);
+f(1048575, 1023);
+f(1049600, 1024);
+f(1050625, 1025);
+x = 2047;
+f(2047, 1);
+f(4094, 2);
+f(6141, 3);
+f(8188, 4);
+f(10235, 5);
+f(14329, 7);
+f(16376, 8);
+f(18423, 9);
+f(30705, 15);
+f(32752, 16);
+f(34799, 17);
+f(63457, 31);
+f(65504, 32);
+f(67551, 33);
+f(128961, 63);
+f(131008, 64);
+f(133055, 65);
+f(259969, 127);
+f(262016, 128);
+f(264063, 129);
+f(521985, 255);
+f(524032, 256);
+f(526079, 257);
+f(1046017, 511);
+f(1048064, 512);
+f(1050111, 513);
+f(2094081, 1023);
+f(2096128, 1024);
+f(2098175, 1025);
+f(4190209, 2047);
+x = 2048;
+f(2048, 1);
+f(4096, 2);
+f(6144, 3);
+f(8192, 4);
+f(10240, 5);
+f(14336, 7);
+f(16384, 8);
+f(18432, 9);
+f(30720, 15);
+f(32768, 16);
+f(34816, 17);
+f(63488, 31);
+f(65536, 32);
+f(67584, 33);
+f(129024, 63);
+f(131072, 64);
+f(133120, 65);
+f(260096, 127);
+f(262144, 128);
+f(264192, 129);
+f(522240, 255);
+f(524288, 256);
+f(526336, 257);
+f(1046528, 511);
+f(1048576, 512);
+f(1050624, 513);
+f(2095104, 1023);
+f(2097152, 1024);
+f(2099200, 1025);
+f(4192256, 2047);
+f(4194304, 2048);
+x = 2049;
+f(2049, 1);
+f(4098, 2);
+f(6147, 3);
+f(8196, 4);
+f(10245, 5);
+f(14343, 7);
+f(16392, 8);
+f(18441, 9);
+f(30735, 15);
+f(32784, 16);
+f(34833, 17);
+f(63519, 31);
+f(65568, 32);
+f(67617, 33);
+f(129087, 63);
+f(131136, 64);
+f(133185, 65);
+f(260223, 127);
+f(262272, 128);
+f(264321, 129);
+f(522495, 255);
+f(524544, 256);
+f(526593, 257);
+f(1047039, 511);
+f(1049088, 512);
+f(1051137, 513);
+f(2096127, 1023);
+f(2098176, 1024);
+f(2100225, 1025);
+f(4194303, 2047);
+f(4196352, 2048);
+f(4198401, 2049);
+x = 4095;
+f(4095, 1);
+f(8190, 2);
+f(12285, 3);
+f(16380, 4);
+f(20475, 5);
+f(28665, 7);
+f(32760, 8);
+f(36855, 9);
+f(61425, 15);
+f(65520, 16);
+f(69615, 17);
+f(126945, 31);
+f(131040, 32);
+f(135135, 33);
+f(257985, 63);
+f(262080, 64);
+f(266175, 65);
+f(520065, 127);
+f(524160, 128);
+f(528255, 129);
+f(1044225, 255);
+f(1048320, 256);
+f(1052415, 257);
+f(2092545, 511);
+f(2096640, 512);
+f(2100735, 513);
+f(4189185, 1023);
+f(4193280, 1024);
+f(4197375, 1025);
+f(8382465, 2047);
+f(8386560, 2048);
+f(8390655, 2049);
+f(16769025, 4095);
+x = 4096;
+f(4096, 1);
+f(8192, 2);
+f(12288, 3);
+f(16384, 4);
+f(20480, 5);
+f(28672, 7);
+f(32768, 8);
+f(36864, 9);
+f(61440, 15);
+f(65536, 16);
+f(69632, 17);
+f(126976, 31);
+f(131072, 32);
+f(135168, 33);
+f(258048, 63);
+f(262144, 64);
+f(266240, 65);
+f(520192, 127);
+f(524288, 128);
+f(528384, 129);
+f(1044480, 255);
+f(1048576, 256);
+f(1052672, 257);
+f(2093056, 511);
+f(2097152, 512);
+f(2101248, 513);
+f(4190208, 1023);
+f(4194304, 1024);
+f(4198400, 1025);
+f(8384512, 2047);
+f(8388608, 2048);
+f(8392704, 2049);
+f(16773120, 4095);
+f(16777216, 4096);
+x = 4097;
+f(4097, 1);
+f(8194, 2);
+f(12291, 3);
+f(16388, 4);
+f(20485, 5);
+f(28679, 7);
+f(32776, 8);
+f(36873, 9);
+f(61455, 15);
+f(65552, 16);
+f(69649, 17);
+f(127007, 31);
+f(131104, 32);
+f(135201, 33);
+f(258111, 63);
+f(262208, 64);
+f(266305, 65);
+f(520319, 127);
+f(524416, 128);
+f(528513, 129);
+f(1044735, 255);
+f(1048832, 256);
+f(1052929, 257);
+f(2093567, 511);
+f(2097664, 512);
+f(2101761, 513);
+f(4191231, 1023);
+f(4195328, 1024);
+f(4199425, 1025);
+f(8386559, 2047);
+f(8390656, 2048);
+f(8394753, 2049);
+f(16777215, 4095);
+f(16781312, 4096);
+f(16785409, 4097);
+x = 8191;
+f(8191, 1);
+f(16382, 2);
+f(24573, 3);
+f(32764, 4);
+f(40955, 5);
+f(57337, 7);
+f(65528, 8);
+f(73719, 9);
+f(122865, 15);
+f(131056, 16);
+f(139247, 17);
+f(253921, 31);
+f(262112, 32);
+f(270303, 33);
+f(516033, 63);
+f(524224, 64);
+f(532415, 65);
+f(1040257, 127);
+f(1048448, 128);
+f(1056639, 129);
+f(2088705, 255);
+f(2096896, 256);
+f(2105087, 257);
+f(4185601, 511);
+f(4193792, 512);
+f(4201983, 513);
+f(8379393, 1023);
+f(8387584, 1024);
+f(8395775, 1025);
+f(16766977, 2047);
+f(16775168, 2048);
+f(16783359, 2049);
+f(33542145, 4095);
+f(33550336, 4096);
+f(33558527, 4097);
+f(67092481, 8191);
+x = 8192;
+f(8192, 1);
+f(16384, 2);
+f(24576, 3);
+f(32768, 4);
+f(40960, 5);
+f(57344, 7);
+f(65536, 8);
+f(73728, 9);
+f(122880, 15);
+f(131072, 16);
+f(139264, 17);
+f(253952, 31);
+f(262144, 32);
+f(270336, 33);
+f(516096, 63);
+f(524288, 64);
+f(532480, 65);
+f(1040384, 127);
+f(1048576, 128);
+f(1056768, 129);
+f(2088960, 255);
+f(2097152, 256);
+f(2105344, 257);
+f(4186112, 511);
+f(4194304, 512);
+f(4202496, 513);
+f(8380416, 1023);
+f(8388608, 1024);
+f(8396800, 1025);
+f(16769024, 2047);
+f(16777216, 2048);
+f(16785408, 2049);
+f(33546240, 4095);
+f(33554432, 4096);
+f(33562624, 4097);
+f(67100672, 8191);
+f(67108864, 8192);
+x = 8193;
+f(8193, 1);
+f(16386, 2);
+f(24579, 3);
+f(32772, 4);
+f(40965, 5);
+f(57351, 7);
+f(65544, 8);
+f(73737, 9);
+f(122895, 15);
+f(131088, 16);
+f(139281, 17);
+f(253983, 31);
+f(262176, 32);
+f(270369, 33);
+f(516159, 63);
+f(524352, 64);
+f(532545, 65);
+f(1040511, 127);
+f(1048704, 128);
+f(1056897, 129);
+f(2089215, 255);
+f(2097408, 256);
+f(2105601, 257);
+f(4186623, 511);
+f(4194816, 512);
+f(4203009, 513);
+f(8381439, 1023);
+f(8389632, 1024);
+f(8397825, 1025);
+f(16771071, 2047);
+f(16779264, 2048);
+f(16787457, 2049);
+f(33550335, 4095);
+f(33558528, 4096);
+f(33566721, 4097);
+f(67108863, 8191);
+f(67117056, 8192);
+f(67125249, 8193);
+x = 16383;
+f(16383, 1);
+f(32766, 2);
+f(49149, 3);
+f(65532, 4);
+f(81915, 5);
+f(114681, 7);
+f(131064, 8);
+f(147447, 9);
+f(245745, 15);
+f(262128, 16);
+f(278511, 17);
+f(507873, 31);
+f(524256, 32);
+f(540639, 33);
+f(1032129, 63);
+f(1048512, 64);
+f(1064895, 65);
+f(2080641, 127);
+f(2097024, 128);
+f(2113407, 129);
+f(4177665, 255);
+f(4194048, 256);
+f(4210431, 257);
+f(8371713, 511);
+f(8388096, 512);
+f(8404479, 513);
+f(16759809, 1023);
+f(16776192, 1024);
+f(16792575, 1025);
+f(33536001, 2047);
+f(33552384, 2048);
+f(33568767, 2049);
+f(67088385, 4095);
+f(67104768, 4096);
+f(67121151, 4097);
+f(134193153, 8191);
+f(134209536, 8192);
+f(134225919, 8193);
+f(268402689, 16383);
+x = 16384;
+f(16384, 1);
+f(32768, 2);
+f(49152, 3);
+f(65536, 4);
+f(81920, 5);
+f(114688, 7);
+f(131072, 8);
+f(147456, 9);
+f(245760, 15);
+f(262144, 16);
+f(278528, 17);
+f(507904, 31);
+f(524288, 32);
+f(540672, 33);
+f(1032192, 63);
+f(1048576, 64);
+f(1064960, 65);
+f(2080768, 127);
+f(2097152, 128);
+f(2113536, 129);
+f(4177920, 255);
+f(4194304, 256);
+f(4210688, 257);
+f(8372224, 511);
+f(8388608, 512);
+f(8404992, 513);
+f(16760832, 1023);
+f(16777216, 1024);
+f(16793600, 1025);
+f(33538048, 2047);
+f(33554432, 2048);
+f(33570816, 2049);
+f(67092480, 4095);
+f(67108864, 4096);
+f(67125248, 4097);
+f(134201344, 8191);
+f(134217728, 8192);
+f(134234112, 8193);
+f(268419072, 16383);
+f(268435456, 16384);
+x = 16385;
+f(16385, 1);
+f(32770, 2);
+f(49155, 3);
+f(65540, 4);
+f(81925, 5);
+f(114695, 7);
+f(131080, 8);
+f(147465, 9);
+f(245775, 15);
+f(262160, 16);
+f(278545, 17);
+f(507935, 31);
+f(524320, 32);
+f(540705, 33);
+f(1032255, 63);
+f(1048640, 64);
+f(1065025, 65);
+f(2080895, 127);
+f(2097280, 128);
+f(2113665, 129);
+f(4178175, 255);
+f(4194560, 256);
+f(4210945, 257);
+f(8372735, 511);
+f(8389120, 512);
+f(8405505, 513);
+f(16761855, 1023);
+f(16778240, 1024);
+f(16794625, 1025);
+f(33540095, 2047);
+f(33556480, 2048);
+f(33572865, 2049);
+f(67096575, 4095);
+f(67112960, 4096);
+f(67129345, 4097);
+f(134209535, 8191);
+f(134225920, 8192);
+f(134242305, 8193);
+f(268435455, 16383);
+f(268451840, 16384);
+f(268468225, 16385);
+x = 32767;
+f(32767, 1);
+f(65534, 2);
+f(98301, 3);
+f(131068, 4);
+f(163835, 5);
+f(229369, 7);
+f(262136, 8);
+f(294903, 9);
+f(491505, 15);
+f(524272, 16);
+f(557039, 17);
+f(1015777, 31);
+f(1048544, 32);
+f(1081311, 33);
+f(2064321, 63);
+f(2097088, 64);
+f(2129855, 65);
+f(4161409, 127);
+f(4194176, 128);
+f(4226943, 129);
+f(8355585, 255);
+f(8388352, 256);
+f(8421119, 257);
+f(16743937, 511);
+f(16776704, 512);
+f(16809471, 513);
+f(33520641, 1023);
+f(33553408, 1024);
+f(33586175, 1025);
+f(67074049, 2047);
+f(67106816, 2048);
+f(67139583, 2049);
+f(134180865, 4095);
+f(134213632, 4096);
+f(134246399, 4097);
+f(268394497, 8191);
+f(268427264, 8192);
+f(268460031, 8193);
+f(536821761, 16383);
+f(536854528, 16384);
+f(536887295, 16385);
+f(1073676289, 32767);
+x = 32768;
+f(32768, 1);
+f(65536, 2);
+f(98304, 3);
+f(131072, 4);
+f(163840, 5);
+f(229376, 7);
+f(262144, 8);
+f(294912, 9);
+f(491520, 15);
+f(524288, 16);
+f(557056, 17);
+f(1015808, 31);
+f(1048576, 32);
+f(1081344, 33);
+f(2064384, 63);
+f(2097152, 64);
+f(2129920, 65);
+f(4161536, 127);
+f(4194304, 128);
+f(4227072, 129);
+f(8355840, 255);
+f(8388608, 256);
+f(8421376, 257);
+f(16744448, 511);
+f(16777216, 512);
+f(16809984, 513);
+f(33521664, 1023);
+f(33554432, 1024);
+f(33587200, 1025);
+f(67076096, 2047);
+f(67108864, 2048);
+f(67141632, 2049);
+f(134184960, 4095);
+f(134217728, 4096);
+f(134250496, 4097);
+f(268402688, 8191);
+f(268435456, 8192);
+f(268468224, 8193);
+f(536838144, 16383);
+f(536870912, 16384);
+f(536903680, 16385);
+f(1073709056, 32767);
+f(1073741824, 32768);
+x = 32769;
+f(32769, 1);
+f(65538, 2);
+f(98307, 3);
+f(131076, 4);
+f(163845, 5);
+f(229383, 7);
+f(262152, 8);
+f(294921, 9);
+f(491535, 15);
+f(524304, 16);
+f(557073, 17);
+f(1015839, 31);
+f(1048608, 32);
+f(1081377, 33);
+f(2064447, 63);
+f(2097216, 64);
+f(2129985, 65);
+f(4161663, 127);
+f(4194432, 128);
+f(4227201, 129);
+f(8356095, 255);
+f(8388864, 256);
+f(8421633, 257);
+f(16744959, 511);
+f(16777728, 512);
+f(16810497, 513);
+f(33522687, 1023);
+f(33555456, 1024);
+f(33588225, 1025);
+f(67078143, 2047);
+f(67110912, 2048);
+f(67143681, 2049);
+f(134189055, 4095);
+f(134221824, 4096);
+f(134254593, 4097);
+f(268410879, 8191);
+f(268443648, 8192);
+f(268476417, 8193);
+f(536854527, 16383);
+f(536887296, 16384);
+f(536920065, 16385);
+f(1073741823, 32767);
+f(1073774592, 32768);
+f(1073807361, 32769);
+x = 65535;
+f(65535, 1);
+f(131070, 2);
+f(196605, 3);
+f(262140, 4);
+f(327675, 5);
+f(458745, 7);
+f(524280, 8);
+f(589815, 9);
+f(983025, 15);
+f(1048560, 16);
+f(1114095, 17);
+f(2031585, 31);
+f(2097120, 32);
+f(2162655, 33);
+f(4128705, 63);
+f(4194240, 64);
+f(4259775, 65);
+f(8322945, 127);
+f(8388480, 128);
+f(8454015, 129);
+f(16711425, 255);
+f(16776960, 256);
+f(16842495, 257);
+f(33488385, 511);
+f(33553920, 512);
+f(33619455, 513);
+f(67042305, 1023);
+f(67107840, 1024);
+f(67173375, 1025);
+f(134150145, 2047);
+f(134215680, 2048);
+f(134281215, 2049);
+f(268365825, 4095);
+f(268431360, 4096);
+f(268496895, 4097);
+f(536797185, 8191);
+f(536862720, 8192);
+f(536928255, 8193);
+f(1073659905, 16383);
+f(1073725440, 16384);
+f(1073790975, 16385);
+f(2147385345, 32767);
+f(2147450880, 32768);
+f(2147516415, 32769);
+f(4294836225, 65535);
+x = 65536;
+f(65536, 1);
+f(131072, 2);
+f(196608, 3);
+f(262144, 4);
+f(327680, 5);
+f(458752, 7);
+f(524288, 8);
+f(589824, 9);
+f(983040, 15);
+f(1048576, 16);
+f(1114112, 17);
+f(2031616, 31);
+f(2097152, 32);
+f(2162688, 33);
+f(4128768, 63);
+f(4194304, 64);
+f(4259840, 65);
+f(8323072, 127);
+f(8388608, 128);
+f(8454144, 129);
+f(16711680, 255);
+f(16777216, 256);
+f(16842752, 257);
+f(33488896, 511);
+f(33554432, 512);
+f(33619968, 513);
+f(67043328, 1023);
+f(67108864, 1024);
+f(67174400, 1025);
+f(134152192, 2047);
+f(134217728, 2048);
+f(134283264, 2049);
+f(268369920, 4095);
+f(268435456, 4096);
+f(268500992, 4097);
+f(536805376, 8191);
+f(536870912, 8192);
+f(536936448, 8193);
+f(1073676288, 16383);
+f(1073741824, 16384);
+f(1073807360, 16385);
+f(2147418112, 32767);
+f(2147483648, 32768);
+f(2147549184, 32769);
+f(4294901760, 65535);
+f(4294967296, 65536);
+x = 65537;
+f(65537, 1);
+f(131074, 2);
+f(196611, 3);
+f(262148, 4);
+f(327685, 5);
+f(458759, 7);
+f(524296, 8);
+f(589833, 9);
+f(983055, 15);
+f(1048592, 16);
+f(1114129, 17);
+f(2031647, 31);
+f(2097184, 32);
+f(2162721, 33);
+f(4128831, 63);
+f(4194368, 64);
+f(4259905, 65);
+f(8323199, 127);
+f(8388736, 128);
+f(8454273, 129);
+f(16711935, 255);
+f(16777472, 256);
+f(16843009, 257);
+f(33489407, 511);
+f(33554944, 512);
+f(33620481, 513);
+f(67044351, 1023);
+f(67109888, 1024);
+f(67175425, 1025);
+f(134154239, 2047);
+f(134219776, 2048);
+f(134285313, 2049);
+f(268374015, 4095);
+f(268439552, 4096);
+f(268505089, 4097);
+f(536813567, 8191);
+f(536879104, 8192);
+f(536944641, 8193);
+f(1073692671, 16383);
+f(1073758208, 16384);
+f(1073823745, 16385);
+f(2147450879, 32767);
+f(2147516416, 32768);
+f(2147581953, 32769);
+f(4294967295, 65535);
+f(4295032832, 65536);
+f(4295098369, 65537);
+x = 131071;
+f(131071, 1);
+f(262142, 2);
+f(393213, 3);
+f(524284, 4);
+f(655355, 5);
+f(917497, 7);
+f(1048568, 8);
+f(1179639, 9);
+f(1966065, 15);
+f(2097136, 16);
+f(2228207, 17);
+f(4063201, 31);
+f(4194272, 32);
+f(4325343, 33);
+f(8257473, 63);
+f(8388544, 64);
+f(8519615, 65);
+f(16646017, 127);
+f(16777088, 128);
+f(16908159, 129);
+f(33423105, 255);
+f(33554176, 256);
+f(33685247, 257);
+f(66977281, 511);
+f(67108352, 512);
+f(67239423, 513);
+f(134085633, 1023);
+f(134216704, 1024);
+f(134347775, 1025);
+f(268302337, 2047);
+f(268433408, 2048);
+f(268564479, 2049);
+f(536735745, 4095);
+f(536866816, 4096);
+f(536997887, 4097);
+f(1073602561, 8191);
+f(1073733632, 8192);
+f(1073864703, 8193);
+f(2147336193, 16383);
+f(2147467264, 16384);
+f(2147598335, 16385);
+f(4294803457, 32767);
+f(4294934528, 32768);
+f(4295065599, 32769);
+f(8589737985, 65535);
+f(8589869056, 65536);
+f(8590000127, 65537);
+f(17179607041, 131071);
+x = 131072;
+f(131072, 1);
+f(262144, 2);
+f(393216, 3);
+f(524288, 4);
+f(655360, 5);
+f(917504, 7);
+f(1048576, 8);
+f(1179648, 9);
+f(1966080, 15);
+f(2097152, 16);
+f(2228224, 17);
+f(4063232, 31);
+f(4194304, 32);
+f(4325376, 33);
+f(8257536, 63);
+f(8388608, 64);
+f(8519680, 65);
+f(16646144, 127);
+f(16777216, 128);
+f(16908288, 129);
+f(33423360, 255);
+f(33554432, 256);
+f(33685504, 257);
+f(66977792, 511);
+f(67108864, 512);
+f(67239936, 513);
+f(134086656, 1023);
+f(134217728, 1024);
+f(134348800, 1025);
+f(268304384, 2047);
+f(268435456, 2048);
+f(268566528, 2049);
+f(536739840, 4095);
+f(536870912, 4096);
+f(537001984, 4097);
+f(1073610752, 8191);
+f(1073741824, 8192);
+f(1073872896, 8193);
+f(2147352576, 16383);
+f(2147483648, 16384);
+f(2147614720, 16385);
+f(4294836224, 32767);
+f(4294967296, 32768);
+f(4295098368, 32769);
+f(8589803520, 65535);
+f(8589934592, 65536);
+f(8590065664, 65537);
+f(17179738112, 131071);
+f(17179869184, 131072);
+x = 131073;
+f(131073, 1);
+f(262146, 2);
+f(393219, 3);
+f(524292, 4);
+f(655365, 5);
+f(917511, 7);
+f(1048584, 8);
+f(1179657, 9);
+f(1966095, 15);
+f(2097168, 16);
+f(2228241, 17);
+f(4063263, 31);
+f(4194336, 32);
+f(4325409, 33);
+f(8257599, 63);
+f(8388672, 64);
+f(8519745, 65);
+f(16646271, 127);
+f(16777344, 128);
+f(16908417, 129);
+f(33423615, 255);
+f(33554688, 256);
+f(33685761, 257);
+f(66978303, 511);
+f(67109376, 512);
+f(67240449, 513);
+f(134087679, 1023);
+f(134218752, 1024);
+f(134349825, 1025);
+f(268306431, 2047);
+f(268437504, 2048);
+f(268568577, 2049);
+f(536743935, 4095);
+f(536875008, 4096);
+f(537006081, 4097);
+f(1073618943, 8191);
+f(1073750016, 8192);
+f(1073881089, 8193);
+f(2147368959, 16383);
+f(2147500032, 16384);
+f(2147631105, 16385);
+f(4294868991, 32767);
+f(4295000064, 32768);
+f(4295131137, 32769);
+f(8589869055, 65535);
+f(8590000128, 65536);
+f(8590131201, 65537);
+f(17179869183, 131071);
+f(17180000256, 131072);
+f(17180131329, 131073);
+x = 262143;
+f(262143, 1);
+f(524286, 2);
+f(786429, 3);
+f(1048572, 4);
+f(1310715, 5);
+f(1835001, 7);
+f(2097144, 8);
+f(2359287, 9);
+f(3932145, 15);
+f(4194288, 16);
+f(4456431, 17);
+f(8126433, 31);
+f(8388576, 32);
+f(8650719, 33);
+f(16515009, 63);
+f(16777152, 64);
+f(17039295, 65);
+f(33292161, 127);
+f(33554304, 128);
+f(33816447, 129);
+f(66846465, 255);
+f(67108608, 256);
+f(67370751, 257);
+f(133955073, 511);
+f(134217216, 512);
+f(134479359, 513);
+f(268172289, 1023);
+f(268434432, 1024);
+f(268696575, 1025);
+f(536606721, 2047);
+f(536868864, 2048);
+f(537131007, 2049);
+f(1073475585, 4095);
+f(1073737728, 4096);
+f(1073999871, 4097);
+f(2147213313, 8191);
+f(2147475456, 8192);
+f(2147737599, 8193);
+f(4294688769, 16383);
+f(4294950912, 16384);
+f(4295213055, 16385);
+f(8589639681, 32767);
+f(8589901824, 32768);
+f(8590163967, 32769);
+f(17179541505, 65535);
+f(17179803648, 65536);
+f(17180065791, 65537);
+f(34359345153, 131071);
+f(34359607296, 131072);
+f(34359869439, 131073);
+f(68718952449, 262143);
+x = 262144;
+f(262144, 1);
+f(524288, 2);
+f(786432, 3);
+f(1048576, 4);
+f(1310720, 5);
+f(1835008, 7);
+f(2097152, 8);
+f(2359296, 9);
+f(3932160, 15);
+f(4194304, 16);
+f(4456448, 17);
+f(8126464, 31);
+f(8388608, 32);
+f(8650752, 33);
+f(16515072, 63);
+f(16777216, 64);
+f(17039360, 65);
+f(33292288, 127);
+f(33554432, 128);
+f(33816576, 129);
+f(66846720, 255);
+f(67108864, 256);
+f(67371008, 257);
+f(133955584, 511);
+f(134217728, 512);
+f(134479872, 513);
+f(268173312, 1023);
+f(268435456, 1024);
+f(268697600, 1025);
+f(536608768, 2047);
+f(536870912, 2048);
+f(537133056, 2049);
+f(1073479680, 4095);
+f(1073741824, 4096);
+f(1074003968, 4097);
+f(2147221504, 8191);
+f(2147483648, 8192);
+f(2147745792, 8193);
+f(4294705152, 16383);
+f(4294967296, 16384);
+f(4295229440, 16385);
+f(8589672448, 32767);
+f(8589934592, 32768);
+f(8590196736, 32769);
+f(17179607040, 65535);
+f(17179869184, 65536);
+f(17180131328, 65537);
+f(34359476224, 131071);
+f(34359738368, 131072);
+f(34360000512, 131073);
+f(68719214592, 262143);
+f(68719476736, 262144);
+x = 262145;
+f(262145, 1);
+f(524290, 2);
+f(786435, 3);
+f(1048580, 4);
+f(1310725, 5);
+f(1835015, 7);
+f(2097160, 8);
+f(2359305, 9);
+f(3932175, 15);
+f(4194320, 16);
+f(4456465, 17);
+f(8126495, 31);
+f(8388640, 32);
+f(8650785, 33);
+f(16515135, 63);
+f(16777280, 64);
+f(17039425, 65);
+f(33292415, 127);
+f(33554560, 128);
+f(33816705, 129);
+f(66846975, 255);
+f(67109120, 256);
+f(67371265, 257);
+f(133956095, 511);
+f(134218240, 512);
+f(134480385, 513);
+f(268174335, 1023);
+f(268436480, 1024);
+f(268698625, 1025);
+f(536610815, 2047);
+f(536872960, 2048);
+f(537135105, 2049);
+f(1073483775, 4095);
+f(1073745920, 4096);
+f(1074008065, 4097);
+f(2147229695, 8191);
+f(2147491840, 8192);
+f(2147753985, 8193);
+f(4294721535, 16383);
+f(4294983680, 16384);
+f(4295245825, 16385);
+f(8589705215, 32767);
+f(8589967360, 32768);
+f(8590229505, 32769);
+f(17179672575, 65535);
+f(17179934720, 65536);
+f(17180196865, 65537);
+f(34359607295, 131071);
+f(34359869440, 131072);
+f(34360131585, 131073);
+f(68719476735, 262143);
+f(68719738880, 262144);
+f(68720001025, 262145);
+x = 524287;
+f(524287, 1);
+f(1048574, 2);
+f(1572861, 3);
+f(2097148, 4);
+f(2621435, 5);
+f(3670009, 7);
+f(4194296, 8);
+f(4718583, 9);
+f(7864305, 15);
+f(8388592, 16);
+f(8912879, 17);
+f(16252897, 31);
+f(16777184, 32);
+f(17301471, 33);
+f(33030081, 63);
+f(33554368, 64);
+f(34078655, 65);
+f(66584449, 127);
+f(67108736, 128);
+f(67633023, 129);
+f(133693185, 255);
+f(134217472, 256);
+f(134741759, 257);
+f(267910657, 511);
+f(268434944, 512);
+f(268959231, 513);
+f(536345601, 1023);
+f(536869888, 1024);
+f(537394175, 1025);
+f(1073215489, 2047);
+f(1073739776, 2048);
+f(1074264063, 2049);
+f(2146955265, 4095);
+f(2147479552, 4096);
+f(2148003839, 4097);
+f(4294434817, 8191);
+f(4294959104, 8192);
+f(4295483391, 8193);
+f(8589393921, 16383);
+f(8589918208, 16384);
+f(8590442495, 16385);
+f(17179312129, 32767);
+f(17179836416, 32768);
+f(17180360703, 32769);
+f(34359148545, 65535);
+f(34359672832, 65536);
+f(34360197119, 65537);
+f(68718821377, 131071);
+f(68719345664, 131072);
+f(68719869951, 131073);
+f(137438167041, 262143);
+f(137438691328, 262144);
+f(137439215615, 262145);
+f(274876858369, 524287);
+x = 524288;
+f(524288, 1);
+f(1048576, 2);
+f(1572864, 3);
+f(2097152, 4);
+f(2621440, 5);
+f(3670016, 7);
+f(4194304, 8);
+f(4718592, 9);
+f(7864320, 15);
+f(8388608, 16);
+f(8912896, 17);
+f(16252928, 31);
+f(16777216, 32);
+f(17301504, 33);
+f(33030144, 63);
+f(33554432, 64);
+f(34078720, 65);
+f(66584576, 127);
+f(67108864, 128);
+f(67633152, 129);
+f(133693440, 255);
+f(134217728, 256);
+f(134742016, 257);
+f(267911168, 511);
+f(268435456, 512);
+f(268959744, 513);
+f(536346624, 1023);
+f(536870912, 1024);
+f(537395200, 1025);
+f(1073217536, 2047);
+f(1073741824, 2048);
+f(1074266112, 2049);
+f(2146959360, 4095);
+f(2147483648, 4096);
+f(2148007936, 4097);
+f(4294443008, 8191);
+f(4294967296, 8192);
+f(4295491584, 8193);
+f(8589410304, 16383);
+f(8589934592, 16384);
+f(8590458880, 16385);
+f(17179344896, 32767);
+f(17179869184, 32768);
+f(17180393472, 32769);
+f(34359214080, 65535);
+f(34359738368, 65536);
+f(34360262656, 65537);
+f(68718952448, 131071);
+f(68719476736, 131072);
+f(68720001024, 131073);
+f(137438429184, 262143);
+f(137438953472, 262144);
+f(137439477760, 262145);
+f(274877382656, 524287);
+f(274877906944, 524288);
+x = 524289;
+f(524289, 1);
+f(1048578, 2);
+f(1572867, 3);
+f(2097156, 4);
+f(2621445, 5);
+f(3670023, 7);
+f(4194312, 8);
+f(4718601, 9);
+f(7864335, 15);
+f(8388624, 16);
+f(8912913, 17);
+f(16252959, 31);
+f(16777248, 32);
+f(17301537, 33);
+f(33030207, 63);
+f(33554496, 64);
+f(34078785, 65);
+f(66584703, 127);
+f(67108992, 128);
+f(67633281, 129);
+f(133693695, 255);
+f(134217984, 256);
+f(134742273, 257);
+f(267911679, 511);
+f(268435968, 512);
+f(268960257, 513);
+f(536347647, 1023);
+f(536871936, 1024);
+f(537396225, 1025);
+f(1073219583, 2047);
+f(1073743872, 2048);
+f(1074268161, 2049);
+f(2146963455, 4095);
+f(2147487744, 4096);
+f(2148012033, 4097);
+f(4294451199, 8191);
+f(4294975488, 8192);
+f(4295499777, 8193);
+f(8589426687, 16383);
+f(8589950976, 16384);
+f(8590475265, 16385);
+f(17179377663, 32767);
+f(17179901952, 32768);
+f(17180426241, 32769);
+f(34359279615, 65535);
+f(34359803904, 65536);
+f(34360328193, 65537);
+f(68719083519, 131071);
+f(68719607808, 131072);
+f(68720132097, 131073);
+f(137438691327, 262143);
+f(137439215616, 262144);
+f(137439739905, 262145);
+f(274877906943, 524287);
+f(274878431232, 524288);
+f(274878955521, 524289);
+x = 1048575;
+f(1048575, 1);
+f(2097150, 2);
+f(3145725, 3);
+f(4194300, 4);
+f(5242875, 5);
+f(7340025, 7);
+f(8388600, 8);
+f(9437175, 9);
+f(15728625, 15);
+f(16777200, 16);
+f(17825775, 17);
+f(32505825, 31);
+f(33554400, 32);
+f(34602975, 33);
+f(66060225, 63);
+f(67108800, 64);
+f(68157375, 65);
+f(133169025, 127);
+f(134217600, 128);
+f(135266175, 129);
+f(267386625, 255);
+f(268435200, 256);
+f(269483775, 257);
+f(535821825, 511);
+f(536870400, 512);
+f(537918975, 513);
+f(1072692225, 1023);
+f(1073740800, 1024);
+f(1074789375, 1025);
+f(2146433025, 2047);
+f(2147481600, 2048);
+f(2148530175, 2049);
+f(4293914625, 4095);
+f(4294963200, 4096);
+f(4296011775, 4097);
+f(8588877825, 8191);
+f(8589926400, 8192);
+f(8590974975, 8193);
+f(17178804225, 16383);
+f(17179852800, 16384);
+f(17180901375, 16385);
+f(34358657025, 32767);
+f(34359705600, 32768);
+f(34360754175, 32769);
+f(68718362625, 65535);
+f(68719411200, 65536);
+f(68720459775, 65537);
+f(137437773825, 131071);
+f(137438822400, 131072);
+f(137439870975, 131073);
+f(274876596225, 262143);
+f(274877644800, 262144);
+f(274878693375, 262145);
+f(549754241025, 524287);
+f(549755289600, 524288);
+f(549756338175, 524289);
+f(1099509530625, 1048575);
+x = 1048576;
+f(1048576, 1);
+f(2097152, 2);
+f(3145728, 3);
+f(4194304, 4);
+f(5242880, 5);
+f(7340032, 7);
+f(8388608, 8);
+f(9437184, 9);
+f(15728640, 15);
+f(16777216, 16);
+f(17825792, 17);
+f(32505856, 31);
+f(33554432, 32);
+f(34603008, 33);
+f(66060288, 63);
+f(67108864, 64);
+f(68157440, 65);
+f(133169152, 127);
+f(134217728, 128);
+f(135266304, 129);
+f(267386880, 255);
+f(268435456, 256);
+f(269484032, 257);
+f(535822336, 511);
+f(536870912, 512);
+f(537919488, 513);
+f(1072693248, 1023);
+f(1073741824, 1024);
+f(1074790400, 1025);
+f(2146435072, 2047);
+f(2147483648, 2048);
+f(2148532224, 2049);
+f(4293918720, 4095);
+f(4294967296, 4096);
+f(4296015872, 4097);
+f(8588886016, 8191);
+f(8589934592, 8192);
+f(8590983168, 8193);
+f(17178820608, 16383);
+f(17179869184, 16384);
+f(17180917760, 16385);
+f(34358689792, 32767);
+f(34359738368, 32768);
+f(34360786944, 32769);
+f(68718428160, 65535);
+f(68719476736, 65536);
+f(68720525312, 65537);
+f(137437904896, 131071);
+f(137438953472, 131072);
+f(137440002048, 131073);
+f(274876858368, 262143);
+f(274877906944, 262144);
+f(274878955520, 262145);
+f(549754765312, 524287);
+f(549755813888, 524288);
+f(549756862464, 524289);
+f(1099510579200, 1048575);
+f(1099511627776, 1048576);
+x = 1048577;
+f(1048577, 1);
+f(2097154, 2);
+f(3145731, 3);
+f(4194308, 4);
+f(5242885, 5);
+f(7340039, 7);
+f(8388616, 8);
+f(9437193, 9);
+f(15728655, 15);
+f(16777232, 16);
+f(17825809, 17);
+f(32505887, 31);
+f(33554464, 32);
+f(34603041, 33);
+f(66060351, 63);
+f(67108928, 64);
+f(68157505, 65);
+f(133169279, 127);
+f(134217856, 128);
+f(135266433, 129);
+f(267387135, 255);
+f(268435712, 256);
+f(269484289, 257);
+f(535822847, 511);
+f(536871424, 512);
+f(537920001, 513);
+f(1072694271, 1023);
+f(1073742848, 1024);
+f(1074791425, 1025);
+f(2146437119, 2047);
+f(2147485696, 2048);
+f(2148534273, 2049);
+f(4293922815, 4095);
+f(4294971392, 4096);
+f(4296019969, 4097);
+f(8588894207, 8191);
+f(8589942784, 8192);
+f(8590991361, 8193);
+f(17178836991, 16383);
+f(17179885568, 16384);
+f(17180934145, 16385);
+f(34358722559, 32767);
+f(34359771136, 32768);
+f(34360819713, 32769);
+f(68718493695, 65535);
+f(68719542272, 65536);
+f(68720590849, 65537);
+f(137438035967, 131071);
+f(137439084544, 131072);
+f(137440133121, 131073);
+f(274877120511, 262143);
+f(274878169088, 262144);
+f(274879217665, 262145);
+f(549755289599, 524287);
+f(549756338176, 524288);
+f(549757386753, 524289);
+f(1099511627775, 1048575);
+f(1099512676352, 1048576);
+f(1099513724929, 1048577);
+x = 2097151;
+f(2097151, 1);
+f(4194302, 2);
+f(6291453, 3);
+f(8388604, 4);
+f(10485755, 5);
+f(14680057, 7);
+f(16777208, 8);
+f(18874359, 9);
+f(31457265, 15);
+f(33554416, 16);
+f(35651567, 17);
+f(65011681, 31);
+f(67108832, 32);
+f(69205983, 33);
+f(132120513, 63);
+f(134217664, 64);
+f(136314815, 65);
+f(266338177, 127);
+f(268435328, 128);
+f(270532479, 129);
+f(534773505, 255);
+f(536870656, 256);
+f(538967807, 257);
+f(1071644161, 511);
+f(1073741312, 512);
+f(1075838463, 513);
+f(2145385473, 1023);
+f(2147482624, 1024);
+f(2149579775, 1025);
+f(4292868097, 2047);
+f(4294965248, 2048);
+f(4297062399, 2049);
+f(8587833345, 4095);
+f(8589930496, 4096);
+f(8592027647, 4097);
+f(17177763841, 8191);
+f(17179860992, 8192);
+f(17181958143, 8193);
+f(34357624833, 16383);
+f(34359721984, 16384);
+f(34361819135, 16385);
+f(68717346817, 32767);
+f(68719443968, 32768);
+f(68721541119, 32769);
+f(137436790785, 65535);
+f(137438887936, 65536);
+f(137440985087, 65537);
+f(274875678721, 131071);
+f(274877775872, 131072);
+f(274879873023, 131073);
+f(549753454593, 262143);
+f(549755551744, 262144);
+f(549757648895, 262145);
+f(1099509006337, 524287);
+f(1099511103488, 524288);
+f(1099513200639, 524289);
+f(2199020109825, 1048575);
+f(2199022206976, 1048576);
+f(2199024304127, 1048577);
+f(4398042316801, 2097151);
+x = 2097152;
+f(2097152, 1);
+f(4194304, 2);
+f(6291456, 3);
+f(8388608, 4);
+f(10485760, 5);
+f(14680064, 7);
+f(16777216, 8);
+f(18874368, 9);
+f(31457280, 15);
+f(33554432, 16);
+f(35651584, 17);
+f(65011712, 31);
+f(67108864, 32);
+f(69206016, 33);
+f(132120576, 63);
+f(134217728, 64);
+f(136314880, 65);
+f(266338304, 127);
+f(268435456, 128);
+f(270532608, 129);
+f(534773760, 255);
+f(536870912, 256);
+f(538968064, 257);
+f(1071644672, 511);
+f(1073741824, 512);
+f(1075838976, 513);
+f(2145386496, 1023);
+f(2147483648, 1024);
+f(2149580800, 1025);
+f(4292870144, 2047);
+f(4294967296, 2048);
+f(4297064448, 2049);
+f(8587837440, 4095);
+f(8589934592, 4096);
+f(8592031744, 4097);
+f(17177772032, 8191);
+f(17179869184, 8192);
+f(17181966336, 8193);
+f(34357641216, 16383);
+f(34359738368, 16384);
+f(34361835520, 16385);
+f(68717379584, 32767);
+f(68719476736, 32768);
+f(68721573888, 32769);
+f(137436856320, 65535);
+f(137438953472, 65536);
+f(137441050624, 65537);
+f(274875809792, 131071);
+f(274877906944, 131072);
+f(274880004096, 131073);
+f(549753716736, 262143);
+f(549755813888, 262144);
+f(549757911040, 262145);
+f(1099509530624, 524287);
+f(1099511627776, 524288);
+f(1099513724928, 524289);
+f(2199021158400, 1048575);
+f(2199023255552, 1048576);
+f(2199025352704, 1048577);
+f(4398044413952, 2097151);
+f(4398046511104, 2097152);
+x = 2097153;
+f(2097153, 1);
+f(4194306, 2);
+f(6291459, 3);
+f(8388612, 4);
+f(10485765, 5);
+f(14680071, 7);
+f(16777224, 8);
+f(18874377, 9);
+f(31457295, 15);
+f(33554448, 16);
+f(35651601, 17);
+f(65011743, 31);
+f(67108896, 32);
+f(69206049, 33);
+f(132120639, 63);
+f(134217792, 64);
+f(136314945, 65);
+f(266338431, 127);
+f(268435584, 128);
+f(270532737, 129);
+f(534774015, 255);
+f(536871168, 256);
+f(538968321, 257);
+f(1071645183, 511);
+f(1073742336, 512);
+f(1075839489, 513);
+f(2145387519, 1023);
+f(2147484672, 1024);
+f(2149581825, 1025);
+f(4292872191, 2047);
+f(4294969344, 2048);
+f(4297066497, 2049);
+f(8587841535, 4095);
+f(8589938688, 4096);
+f(8592035841, 4097);
+f(17177780223, 8191);
+f(17179877376, 8192);
+f(17181974529, 8193);
+f(34357657599, 16383);
+f(34359754752, 16384);
+f(34361851905, 16385);
+f(68717412351, 32767);
+f(68719509504, 32768);
+f(68721606657, 32769);
+f(137436921855, 65535);
+f(137439019008, 65536);
+f(137441116161, 65537);
+f(274875940863, 131071);
+f(274878038016, 131072);
+f(274880135169, 131073);
+f(549753978879, 262143);
+f(549756076032, 262144);
+f(549758173185, 262145);
+f(1099510054911, 524287);
+f(1099512152064, 524288);
+f(1099514249217, 524289);
+f(2199022206975, 1048575);
+f(2199024304128, 1048576);
+f(2199026401281, 1048577);
+f(4398046511103, 2097151);
+f(4398048608256, 2097152);
+f(4398050705409, 2097153);
+x = 4194303;
+f(4194303, 1);
+f(8388606, 2);
+f(12582909, 3);
+f(16777212, 4);
+f(20971515, 5);
+f(29360121, 7);
+f(33554424, 8);
+f(37748727, 9);
+f(62914545, 15);
+f(67108848, 16);
+f(71303151, 17);
+f(130023393, 31);
+f(134217696, 32);
+f(138411999, 33);
+f(264241089, 63);
+f(268435392, 64);
+f(272629695, 65);
+f(532676481, 127);
+f(536870784, 128);
+f(541065087, 129);
+f(1069547265, 255);
+f(1073741568, 256);
+f(1077935871, 257);
+f(2143288833, 511);
+f(2147483136, 512);
+f(2151677439, 513);
+f(4290771969, 1023);
+f(4294966272, 1024);
+f(4299160575, 1025);
+f(8585738241, 2047);
+f(8589932544, 2048);
+f(8594126847, 2049);
+f(17175670785, 4095);
+f(17179865088, 4096);
+f(17184059391, 4097);
+f(34355535873, 8191);
+f(34359730176, 8192);
+f(34363924479, 8193);
+f(68715266049, 16383);
+f(68719460352, 16384);
+f(68723654655, 16385);
+f(137434726401, 32767);
+f(137438920704, 32768);
+f(137443115007, 32769);
+f(274873647105, 65535);
+f(274877841408, 65536);
+f(274882035711, 65537);
+f(549751488513, 131071);
+f(549755682816, 131072);
+f(549759877119, 131073);
+f(1099507171329, 262143);
+f(1099511365632, 262144);
+f(1099515559935, 262145);
+f(2199018536961, 524287);
+f(2199022731264, 524288);
+f(2199026925567, 524289);
+f(4398041268225, 1048575);
+f(4398045462528, 1048576);
+f(4398049656831, 1048577);
+f(8796086730753, 2097151);
+f(8796090925056, 2097152);
+f(8796095119359, 2097153);
+f(17592177655809, 4194303);
+x = 4194304;
+f(4194304, 1);
+f(8388608, 2);
+f(12582912, 3);
+f(16777216, 4);
+f(20971520, 5);
+f(29360128, 7);
+f(33554432, 8);
+f(37748736, 9);
+f(62914560, 15);
+f(67108864, 16);
+f(71303168, 17);
+f(130023424, 31);
+f(134217728, 32);
+f(138412032, 33);
+f(264241152, 63);
+f(268435456, 64);
+f(272629760, 65);
+f(532676608, 127);
+f(536870912, 128);
+f(541065216, 129);
+f(1069547520, 255);
+f(1073741824, 256);
+f(1077936128, 257);
+f(2143289344, 511);
+f(2147483648, 512);
+f(2151677952, 513);
+f(4290772992, 1023);
+f(4294967296, 1024);
+f(4299161600, 1025);
+f(8585740288, 2047);
+f(8589934592, 2048);
+f(8594128896, 2049);
+f(17175674880, 4095);
+f(17179869184, 4096);
+f(17184063488, 4097);
+f(34355544064, 8191);
+f(34359738368, 8192);
+f(34363932672, 8193);
+f(68715282432, 16383);
+f(68719476736, 16384);
+f(68723671040, 16385);
+f(137434759168, 32767);
+f(137438953472, 32768);
+f(137443147776, 32769);
+f(274873712640, 65535);
+f(274877906944, 65536);
+f(274882101248, 65537);
+f(549751619584, 131071);
+f(549755813888, 131072);
+f(549760008192, 131073);
+f(1099507433472, 262143);
+f(1099511627776, 262144);
+f(1099515822080, 262145);
+f(2199019061248, 524287);
+f(2199023255552, 524288);
+f(2199027449856, 524289);
+f(4398042316800, 1048575);
+f(4398046511104, 1048576);
+f(4398050705408, 1048577);
+f(8796088827904, 2097151);
+f(8796093022208, 2097152);
+f(8796097216512, 2097153);
+f(17592181850112, 4194303);
+f(17592186044416, 4194304);
+x = 4194305;
+f(4194305, 1);
+f(8388610, 2);
+f(12582915, 3);
+f(16777220, 4);
+f(20971525, 5);
+f(29360135, 7);
+f(33554440, 8);
+f(37748745, 9);
+f(62914575, 15);
+f(67108880, 16);
+f(71303185, 17);
+f(130023455, 31);
+f(134217760, 32);
+f(138412065, 33);
+f(264241215, 63);
+f(268435520, 64);
+f(272629825, 65);
+f(532676735, 127);
+f(536871040, 128);
+f(541065345, 129);
+f(1069547775, 255);
+f(1073742080, 256);
+f(1077936385, 257);
+f(2143289855, 511);
+f(2147484160, 512);
+f(2151678465, 513);
+f(4290774015, 1023);
+f(4294968320, 1024);
+f(4299162625, 1025);
+f(8585742335, 2047);
+f(8589936640, 2048);
+f(8594130945, 2049);
+f(17175678975, 4095);
+f(17179873280, 4096);
+f(17184067585, 4097);
+f(34355552255, 8191);
+f(34359746560, 8192);
+f(34363940865, 8193);
+f(68715298815, 16383);
+f(68719493120, 16384);
+f(68723687425, 16385);
+f(137434791935, 32767);
+f(137438986240, 32768);
+f(137443180545, 32769);
+f(274873778175, 65535);
+f(274877972480, 65536);
+f(274882166785, 65537);
+f(549751750655, 131071);
+f(549755944960, 131072);
+f(549760139265, 131073);
+f(1099507695615, 262143);
+f(1099511889920, 262144);
+f(1099516084225, 262145);
+f(2199019585535, 524287);
+f(2199023779840, 524288);
+f(2199027974145, 524289);
+f(4398043365375, 1048575);
+f(4398047559680, 1048576);
+f(4398051753985, 1048577);
+f(8796090925055, 2097151);
+f(8796095119360, 2097152);
+f(8796099313665, 2097153);
+f(17592186044415, 4194303);
+f(17592190238720, 4194304);
+f(17592194433025, 4194305);
+x = 8388607;
+f(8388607, 1);
+f(16777214, 2);
+f(25165821, 3);
+f(33554428, 4);
+f(41943035, 5);
+f(58720249, 7);
+f(67108856, 8);
+f(75497463, 9);
+f(125829105, 15);
+f(134217712, 16);
+f(142606319, 17);
+f(260046817, 31);
+f(268435424, 32);
+f(276824031, 33);
+f(528482241, 63);
+f(536870848, 64);
+f(545259455, 65);
+f(1065353089, 127);
+f(1073741696, 128);
+f(1082130303, 129);
+f(2139094785, 255);
+f(2147483392, 256);
+f(2155871999, 257);
+f(4286578177, 511);
+f(4294966784, 512);
+f(4303355391, 513);
+f(8581544961, 1023);
+f(8589933568, 1024);
+f(8598322175, 1025);
+f(17171478529, 2047);
+f(17179867136, 2048);
+f(17188255743, 2049);
+f(34351345665, 4095);
+f(34359734272, 4096);
+f(34368122879, 4097);
+f(68711079937, 8191);
+f(68719468544, 8192);
+f(68727857151, 8193);
+f(137430548481, 16383);
+f(137438937088, 16384);
+f(137447325695, 16385);
+f(274869485569, 32767);
+f(274877874176, 32768);
+f(274886262783, 32769);
+f(549747359745, 65535);
+f(549755748352, 65536);
+f(549764136959, 65537);
+f(1099503108097, 131071);
+f(1099511496704, 131072);
+f(1099519885311, 131073);
+f(2199014604801, 262143);
+f(2199022993408, 262144);
+f(2199031382015, 262145);
+f(4398037598209, 524287);
+f(4398045986816, 524288);
+f(4398054375423, 524289);
+f(8796083585025, 1048575);
+f(8796091973632, 1048576);
+f(8796100362239, 1048577);
+f(17592175558657, 2097151);
+f(17592183947264, 2097152);
+f(17592192335871, 2097153);
+f(35184359505921, 4194303);
+f(35184367894528, 4194304);
+f(35184376283135, 4194305);
+f(70368727400449, 8388607);
+x = 8388608;
+f(8388608, 1);
+f(16777216, 2);
+f(25165824, 3);
+f(33554432, 4);
+f(41943040, 5);
+f(58720256, 7);
+f(67108864, 8);
+f(75497472, 9);
+f(125829120, 15);
+f(134217728, 16);
+f(142606336, 17);
+f(260046848, 31);
+f(268435456, 32);
+f(276824064, 33);
+f(528482304, 63);
+f(536870912, 64);
+f(545259520, 65);
+f(1065353216, 127);
+f(1073741824, 128);
+f(1082130432, 129);
+f(2139095040, 255);
+f(2147483648, 256);
+f(2155872256, 257);
+f(4286578688, 511);
+f(4294967296, 512);
+f(4303355904, 513);
+f(8581545984, 1023);
+f(8589934592, 1024);
+f(8598323200, 1025);
+f(17171480576, 2047);
+f(17179869184, 2048);
+f(17188257792, 2049);
+f(34351349760, 4095);
+f(34359738368, 4096);
+f(34368126976, 4097);
+f(68711088128, 8191);
+f(68719476736, 8192);
+f(68727865344, 8193);
+f(137430564864, 16383);
+f(137438953472, 16384);
+f(137447342080, 16385);
+f(274869518336, 32767);
+f(274877906944, 32768);
+f(274886295552, 32769);
+f(549747425280, 65535);
+f(549755813888, 65536);
+f(549764202496, 65537);
+f(1099503239168, 131071);
+f(1099511627776, 131072);
+f(1099520016384, 131073);
+f(2199014866944, 262143);
+f(2199023255552, 262144);
+f(2199031644160, 262145);
+f(4398038122496, 524287);
+f(4398046511104, 524288);
+f(4398054899712, 524289);
+f(8796084633600, 1048575);
+f(8796093022208, 1048576);
+f(8796101410816, 1048577);
+f(17592177655808, 2097151);
+f(17592186044416, 2097152);
+f(17592194433024, 2097153);
+f(35184363700224, 4194303);
+f(35184372088832, 4194304);
+f(35184380477440, 4194305);
+f(70368735789056, 8388607);
+f(70368744177664, 8388608);
+x = 8388609;
+f(8388609, 1);
+f(16777218, 2);
+f(25165827, 3);
+f(33554436, 4);
+f(41943045, 5);
+f(58720263, 7);
+f(67108872, 8);
+f(75497481, 9);
+f(125829135, 15);
+f(134217744, 16);
+f(142606353, 17);
+f(260046879, 31);
+f(268435488, 32);
+f(276824097, 33);
+f(528482367, 63);
+f(536870976, 64);
+f(545259585, 65);
+f(1065353343, 127);
+f(1073741952, 128);
+f(1082130561, 129);
+f(2139095295, 255);
+f(2147483904, 256);
+f(2155872513, 257);
+f(4286579199, 511);
+f(4294967808, 512);
+f(4303356417, 513);
+f(8581547007, 1023);
+f(8589935616, 1024);
+f(8598324225, 1025);
+f(17171482623, 2047);
+f(17179871232, 2048);
+f(17188259841, 2049);
+f(34351353855, 4095);
+f(34359742464, 4096);
+f(34368131073, 4097);
+f(68711096319, 8191);
+f(68719484928, 8192);
+f(68727873537, 8193);
+f(137430581247, 16383);
+f(137438969856, 16384);
+f(137447358465, 16385);
+f(274869551103, 32767);
+f(274877939712, 32768);
+f(274886328321, 32769);
+f(549747490815, 65535);
+f(549755879424, 65536);
+f(549764268033, 65537);
+f(1099503370239, 131071);
+f(1099511758848, 131072);
+f(1099520147457, 131073);
+f(2199015129087, 262143);
+f(2199023517696, 262144);
+f(2199031906305, 262145);
+f(4398038646783, 524287);
+f(4398047035392, 524288);
+f(4398055424001, 524289);
+f(8796085682175, 1048575);
+f(8796094070784, 1048576);
+f(8796102459393, 1048577);
+f(17592179752959, 2097151);
+f(17592188141568, 2097152);
+f(17592196530177, 2097153);
+f(35184367894527, 4194303);
+f(35184376283136, 4194304);
+f(35184384671745, 4194305);
+f(70368744177663, 8388607);
+f(70368752566272, 8388608);
+f(70368760954881, 8388609);
+x = 16777215;
+f(16777215, 1);
+f(33554430, 2);
+f(50331645, 3);
+f(67108860, 4);
+f(83886075, 5);
+f(117440505, 7);
+f(134217720, 8);
+f(150994935, 9);
+f(251658225, 15);
+f(268435440, 16);
+f(285212655, 17);
+f(520093665, 31);
+f(536870880, 32);
+f(553648095, 33);
+f(1056964545, 63);
+f(1073741760, 64);
+f(1090518975, 65);
+f(2130706305, 127);
+f(2147483520, 128);
+f(2164260735, 129);
+f(4278189825, 255);
+f(4294967040, 256);
+f(4311744255, 257);
+f(8573156865, 511);
+f(8589934080, 512);
+f(8606711295, 513);
+f(17163090945, 1023);
+f(17179868160, 1024);
+f(17196645375, 1025);
+f(34342959105, 2047);
+f(34359736320, 2048);
+f(34376513535, 2049);
+f(68702695425, 4095);
+f(68719472640, 4096);
+f(68736249855, 4097);
+f(137422168065, 8191);
+f(137438945280, 8192);
+f(137455722495, 8193);
+f(274861113345, 16383);
+f(274877890560, 16384);
+f(274894667775, 16385);
+f(549739003905, 32767);
+f(549755781120, 32768);
+f(549772558335, 32769);
+f(1099494785025, 65535);
+f(1099511562240, 65536);
+f(1099528339455, 65537);
+f(2199006347265, 131071);
+f(2199023124480, 131072);
+f(2199039901695, 131073);
+f(4398029471745, 262143);
+f(4398046248960, 262144);
+f(4398063026175, 262145);
+f(8796075720705, 524287);
+f(8796092497920, 524288);
+f(8796109275135, 524289);
+f(17592168218625, 1048575);
+f(17592184995840, 1048576);
+f(17592201773055, 1048577);
+f(35184353214465, 2097151);
+f(35184369991680, 2097152);
+f(35184386768895, 2097153);
+f(70368723206145, 4194303);
+f(70368739983360, 4194304);
+f(70368756760575, 4194305);
+f(140737463189505, 8388607);
+f(140737479966720, 8388608);
+f(140737496743935, 8388609);
+f(281474943156225, 16777215);
+x = 16777216;
+f(16777216, 1);
+f(33554432, 2);
+f(50331648, 3);
+f(67108864, 4);
+f(83886080, 5);
+f(117440512, 7);
+f(134217728, 8);
+f(150994944, 9);
+f(251658240, 15);
+f(268435456, 16);
+f(285212672, 17);
+f(520093696, 31);
+f(536870912, 32);
+f(553648128, 33);
+f(1056964608, 63);
+f(1073741824, 64);
+f(1090519040, 65);
+f(2130706432, 127);
+f(2147483648, 128);
+f(2164260864, 129);
+f(4278190080, 255);
+f(4294967296, 256);
+f(4311744512, 257);
+f(8573157376, 511);
+f(8589934592, 512);
+f(8606711808, 513);
+f(17163091968, 1023);
+f(17179869184, 1024);
+f(17196646400, 1025);
+f(34342961152, 2047);
+f(34359738368, 2048);
+f(34376515584, 2049);
+f(68702699520, 4095);
+f(68719476736, 4096);
+f(68736253952, 4097);
+f(137422176256, 8191);
+f(137438953472, 8192);
+f(137455730688, 8193);
+f(274861129728, 16383);
+f(274877906944, 16384);
+f(274894684160, 16385);
+f(549739036672, 32767);
+f(549755813888, 32768);
+f(549772591104, 32769);
+f(1099494850560, 65535);
+f(1099511627776, 65536);
+f(1099528404992, 65537);
+f(2199006478336, 131071);
+f(2199023255552, 131072);
+f(2199040032768, 131073);
+f(4398029733888, 262143);
+f(4398046511104, 262144);
+f(4398063288320, 262145);
+f(8796076244992, 524287);
+f(8796093022208, 524288);
+f(8796109799424, 524289);
+f(17592169267200, 1048575);
+f(17592186044416, 1048576);
+f(17592202821632, 1048577);
+f(35184355311616, 2097151);
+f(35184372088832, 2097152);
+f(35184388866048, 2097153);
+f(70368727400448, 4194303);
+f(70368744177664, 4194304);
+f(70368760954880, 4194305);
+f(140737471578112, 8388607);
+f(140737488355328, 8388608);
+f(140737505132544, 8388609);
+f(281474959933440, 16777215);
+f(281474976710656, 16777216);
+x = 16777217;
+f(16777217, 1);
+f(33554434, 2);
+f(50331651, 3);
+f(67108868, 4);
+f(83886085, 5);
+f(117440519, 7);
+f(134217736, 8);
+f(150994953, 9);
+f(251658255, 15);
+f(268435472, 16);
+f(285212689, 17);
+f(520093727, 31);
+f(536870944, 32);
+f(553648161, 33);
+f(1056964671, 63);
+f(1073741888, 64);
+f(1090519105, 65);
+f(2130706559, 127);
+f(2147483776, 128);
+f(2164260993, 129);
+f(4278190335, 255);
+f(4294967552, 256);
+f(4311744769, 257);
+f(8573157887, 511);
+f(8589935104, 512);
+f(8606712321, 513);
+f(17163092991, 1023);
+f(17179870208, 1024);
+f(17196647425, 1025);
+f(34342963199, 2047);
+f(34359740416, 2048);
+f(34376517633, 2049);
+f(68702703615, 4095);
+f(68719480832, 4096);
+f(68736258049, 4097);
+f(137422184447, 8191);
+f(137438961664, 8192);
+f(137455738881, 8193);
+f(274861146111, 16383);
+f(274877923328, 16384);
+f(274894700545, 16385);
+f(549739069439, 32767);
+f(549755846656, 32768);
+f(549772623873, 32769);
+f(1099494916095, 65535);
+f(1099511693312, 65536);
+f(1099528470529, 65537);
+f(2199006609407, 131071);
+f(2199023386624, 131072);
+f(2199040163841, 131073);
+f(4398029996031, 262143);
+f(4398046773248, 262144);
+f(4398063550465, 262145);
+f(8796076769279, 524287);
+f(8796093546496, 524288);
+f(8796110323713, 524289);
+f(17592170315775, 1048575);
+f(17592187092992, 1048576);
+f(17592203870209, 1048577);
+f(35184357408767, 2097151);
+f(35184374185984, 2097152);
+f(35184390963201, 2097153);
+f(70368731594751, 4194303);
+f(70368748371968, 4194304);
+f(70368765149185, 4194305);
+f(140737479966719, 8388607);
+f(140737496743936, 8388608);
+f(140737513521153, 8388609);
+f(281474976710655, 16777215);
+f(281474993487872, 16777216);
+f(281475010265089, 16777217);
+x = 33554431;
+f(33554431, 1);
+f(67108862, 2);
+f(100663293, 3);
+f(134217724, 4);
+f(167772155, 5);
+f(234881017, 7);
+f(268435448, 8);
+f(301989879, 9);
+f(503316465, 15);
+f(536870896, 16);
+f(570425327, 17);
+f(1040187361, 31);
+f(1073741792, 32);
+f(1107296223, 33);
+f(2113929153, 63);
+f(2147483584, 64);
+f(2181038015, 65);
+f(4261412737, 127);
+f(4294967168, 128);
+f(4328521599, 129);
+f(8556379905, 255);
+f(8589934336, 256);
+f(8623488767, 257);
+f(17146314241, 511);
+f(17179868672, 512);
+f(17213423103, 513);
+f(34326182913, 1023);
+f(34359737344, 1024);
+f(34393291775, 1025);
+f(68685920257, 2047);
+f(68719474688, 2048);
+f(68753029119, 2049);
+f(137405394945, 4095);
+f(137438949376, 4096);
+f(137472503807, 4097);
+f(274844344321, 8191);
+f(274877898752, 8192);
+f(274911453183, 8193);
+f(549722243073, 16383);
+f(549755797504, 16384);
+f(549789351935, 16385);
+f(1099478040577, 32767);
+f(1099511595008, 32768);
+f(1099545149439, 32769);
+f(2198989635585, 65535);
+f(2199023190016, 65536);
+f(2199056744447, 65537);
+f(4398012825601, 131071);
+f(4398046380032, 131072);
+f(4398079934463, 131073);
+f(8796059205633, 262143);
+f(8796092760064, 262144);
+f(8796126314495, 262145);
+f(17592151965697, 524287);
+f(17592185520128, 524288);
+f(17592219074559, 524289);
+f(35184337485825, 1048575);
+f(35184371040256, 1048576);
+f(35184404594687, 1048577);
+f(70368708526081, 2097151);
+f(70368742080512, 2097152);
+f(70368775634943, 2097153);
+f(140737450606593, 4194303);
+f(140737484161024, 4194304);
+f(140737517715455, 4194305);
+f(281474934767617, 8388607);
+f(281474968322048, 8388608);
+f(281475001876479, 8388609);
+f(562949903089665, 16777215);
+f(562949936644096, 16777216);
+f(562949970198527, 16777217);
+f(1125899839733761, 33554431);
+x = 33554432;
+f(33554432, 1);
+f(67108864, 2);
+f(100663296, 3);
+f(134217728, 4);
+f(167772160, 5);
+f(234881024, 7);
+f(268435456, 8);
+f(301989888, 9);
+f(503316480, 15);
+f(536870912, 16);
+f(570425344, 17);
+f(1040187392, 31);
+f(1073741824, 32);
+f(1107296256, 33);
+f(2113929216, 63);
+f(2147483648, 64);
+f(2181038080, 65);
+f(4261412864, 127);
+f(4294967296, 128);
+f(4328521728, 129);
+f(8556380160, 255);
+f(8589934592, 256);
+f(8623489024, 257);
+f(17146314752, 511);
+f(17179869184, 512);
+f(17213423616, 513);
+f(34326183936, 1023);
+f(34359738368, 1024);
+f(34393292800, 1025);
+f(68685922304, 2047);
+f(68719476736, 2048);
+f(68753031168, 2049);
+f(137405399040, 4095);
+f(137438953472, 4096);
+f(137472507904, 4097);
+f(274844352512, 8191);
+f(274877906944, 8192);
+f(274911461376, 8193);
+f(549722259456, 16383);
+f(549755813888, 16384);
+f(549789368320, 16385);
+f(1099478073344, 32767);
+f(1099511627776, 32768);
+f(1099545182208, 32769);
+f(2198989701120, 65535);
+f(2199023255552, 65536);
+f(2199056809984, 65537);
+f(4398012956672, 131071);
+f(4398046511104, 131072);
+f(4398080065536, 131073);
+f(8796059467776, 262143);
+f(8796093022208, 262144);
+f(8796126576640, 262145);
+f(17592152489984, 524287);
+f(17592186044416, 524288);
+f(17592219598848, 524289);
+f(35184338534400, 1048575);
+f(35184372088832, 1048576);
+f(35184405643264, 1048577);
+f(70368710623232, 2097151);
+f(70368744177664, 2097152);
+f(70368777732096, 2097153);
+f(140737454800896, 4194303);
+f(140737488355328, 4194304);
+f(140737521909760, 4194305);
+f(281474943156224, 8388607);
+f(281474976710656, 8388608);
+f(281475010265088, 8388609);
+f(562949919866880, 16777215);
+f(562949953421312, 16777216);
+f(562949986975744, 16777217);
+f(1125899873288192, 33554431);
+f(1125899906842624, 33554432);
+x = 33554433;
+f(33554433, 1);
+f(67108866, 2);
+f(100663299, 3);
+f(134217732, 4);
+f(167772165, 5);
+f(234881031, 7);
+f(268435464, 8);
+f(301989897, 9);
+f(503316495, 15);
+f(536870928, 16);
+f(570425361, 17);
+f(1040187423, 31);
+f(1073741856, 32);
+f(1107296289, 33);
+f(2113929279, 63);
+f(2147483712, 64);
+f(2181038145, 65);
+f(4261412991, 127);
+f(4294967424, 128);
+f(4328521857, 129);
+f(8556380415, 255);
+f(8589934848, 256);
+f(8623489281, 257);
+f(17146315263, 511);
+f(17179869696, 512);
+f(17213424129, 513);
+f(34326184959, 1023);
+f(34359739392, 1024);
+f(34393293825, 1025);
+f(68685924351, 2047);
+f(68719478784, 2048);
+f(68753033217, 2049);
+f(137405403135, 4095);
+f(137438957568, 4096);
+f(137472512001, 4097);
+f(274844360703, 8191);
+f(274877915136, 8192);
+f(274911469569, 8193);
+f(549722275839, 16383);
+f(549755830272, 16384);
+f(549789384705, 16385);
+f(1099478106111, 32767);
+f(1099511660544, 32768);
+f(1099545214977, 32769);
+f(2198989766655, 65535);
+f(2199023321088, 65536);
+f(2199056875521, 65537);
+f(4398013087743, 131071);
+f(4398046642176, 131072);
+f(4398080196609, 131073);
+f(8796059729919, 262143);
+f(8796093284352, 262144);
+f(8796126838785, 262145);
+f(17592153014271, 524287);
+f(17592186568704, 524288);
+f(17592220123137, 524289);
+f(35184339582975, 1048575);
+f(35184373137408, 1048576);
+f(35184406691841, 1048577);
+f(70368712720383, 2097151);
+f(70368746274816, 2097152);
+f(70368779829249, 2097153);
+f(140737458995199, 4194303);
+f(140737492549632, 4194304);
+f(140737526104065, 4194305);
+f(281474951544831, 8388607);
+f(281474985099264, 8388608);
+f(281475018653697, 8388609);
+f(562949936644095, 16777215);
+f(562949970198528, 16777216);
+f(562950003752961, 16777217);
+f(1125899906842623, 33554431);
+f(1125899940397056, 33554432);
+f(1125899973951489, 33554433);
+x = 67108863;
+f(67108863, 1);
+f(134217726, 2);
+f(201326589, 3);
+f(268435452, 4);
+f(335544315, 5);
+f(469762041, 7);
+f(536870904, 8);
+f(603979767, 9);
+f(1006632945, 15);
+f(1073741808, 16);
+f(1140850671, 17);
+f(2080374753, 31);
+f(2147483616, 32);
+f(2214592479, 33);
+f(4227858369, 63);
+f(4294967232, 64);
+f(4362076095, 65);
+f(8522825601, 127);
+f(8589934464, 128);
+f(8657043327, 129);
+f(17112760065, 255);
+f(17179868928, 256);
+f(17246977791, 257);
+f(34292628993, 511);
+f(34359737856, 512);
+f(34426846719, 513);
+f(68652366849, 1023);
+f(68719475712, 1024);
+f(68786584575, 1025);
+f(137371842561, 2047);
+f(137438951424, 2048);
+f(137506060287, 2049);
+f(274810793985, 4095);
+f(274877902848, 4096);
+f(274945011711, 4097);
+f(549688696833, 8191);
+f(549755805696, 8192);
+f(549822914559, 8193);
+f(1099444502529, 16383);
+f(1099511611392, 16384);
+f(1099578720255, 16385);
+f(2198956113921, 32767);
+f(2199023222784, 32768);
+f(2199090331647, 32769);
+f(4397979336705, 65535);
+f(4398046445568, 65536);
+f(4398113554431, 65537);
+f(8796025782273, 131071);
+f(8796092891136, 131072);
+f(8796159999999, 131073);
+f(17592118673409, 262143);
+f(17592185782272, 262144);
+f(17592252891135, 262145);
+f(35184304455681, 524287);
+f(35184371564544, 524288);
+f(35184438673407, 524289);
+f(70368676020225, 1048575);
+f(70368743129088, 1048576);
+f(70368810237951, 1048577);
+f(140737419149313, 2097151);
+f(140737486258176, 2097152);
+f(140737553367039, 2097153);
+f(281474905407489, 4194303);
+f(281474972516352, 4194304);
+f(281475039625215, 4194305);
+f(562949877923841, 8388607);
+f(562949945032704, 8388608);
+f(562950012141567, 8388609);
+f(1125899822956545, 16777215);
+f(1125899890065408, 16777216);
+f(1125899957174271, 16777217);
+x = 67108864;
+f(67108864, 1);
+f(134217728, 2);
+f(201326592, 3);
+f(268435456, 4);
+f(335544320, 5);
+f(469762048, 7);
+f(536870912, 8);
+f(603979776, 9);
+f(1006632960, 15);
+f(1073741824, 16);
+f(1140850688, 17);
+f(2080374784, 31);
+f(2147483648, 32);
+f(2214592512, 33);
+f(4227858432, 63);
+f(4294967296, 64);
+f(4362076160, 65);
+f(8522825728, 127);
+f(8589934592, 128);
+f(8657043456, 129);
+f(17112760320, 255);
+f(17179869184, 256);
+f(17246978048, 257);
+f(34292629504, 511);
+f(34359738368, 512);
+f(34426847232, 513);
+f(68652367872, 1023);
+f(68719476736, 1024);
+f(68786585600, 1025);
+f(137371844608, 2047);
+f(137438953472, 2048);
+f(137506062336, 2049);
+f(274810798080, 4095);
+f(274877906944, 4096);
+f(274945015808, 4097);
+f(549688705024, 8191);
+f(549755813888, 8192);
+f(549822922752, 8193);
+f(1099444518912, 16383);
+f(1099511627776, 16384);
+f(1099578736640, 16385);
+f(2198956146688, 32767);
+f(2199023255552, 32768);
+f(2199090364416, 32769);
+f(4397979402240, 65535);
+f(4398046511104, 65536);
+f(4398113619968, 65537);
+f(8796025913344, 131071);
+f(8796093022208, 131072);
+f(8796160131072, 131073);
+f(17592118935552, 262143);
+f(17592186044416, 262144);
+f(17592253153280, 262145);
+f(35184304979968, 524287);
+f(35184372088832, 524288);
+f(35184439197696, 524289);
+f(70368677068800, 1048575);
+f(70368744177664, 1048576);
+f(70368811286528, 1048577);
+f(140737421246464, 2097151);
+f(140737488355328, 2097152);
+f(140737555464192, 2097153);
+f(281474909601792, 4194303);
+f(281474976710656, 4194304);
+f(281475043819520, 4194305);
+f(562949886312448, 8388607);
+f(562949953421312, 8388608);
+f(562950020530176, 8388609);
+f(1125899839733760, 16777215);
+f(1125899906842624, 16777216);
+f(1125899973951488, 16777217);
+x = 67108865;
+f(67108865, 1);
+f(134217730, 2);
+f(201326595, 3);
+f(268435460, 4);
+f(335544325, 5);
+f(469762055, 7);
+f(536870920, 8);
+f(603979785, 9);
+f(1006632975, 15);
+f(1073741840, 16);
+f(1140850705, 17);
+f(2080374815, 31);
+f(2147483680, 32);
+f(2214592545, 33);
+f(4227858495, 63);
+f(4294967360, 64);
+f(4362076225, 65);
+f(8522825855, 127);
+f(8589934720, 128);
+f(8657043585, 129);
+f(17112760575, 255);
+f(17179869440, 256);
+f(17246978305, 257);
+f(34292630015, 511);
+f(34359738880, 512);
+f(34426847745, 513);
+f(68652368895, 1023);
+f(68719477760, 1024);
+f(68786586625, 1025);
+f(137371846655, 2047);
+f(137438955520, 2048);
+f(137506064385, 2049);
+f(274810802175, 4095);
+f(274877911040, 4096);
+f(274945019905, 4097);
+f(549688713215, 8191);
+f(549755822080, 8192);
+f(549822930945, 8193);
+f(1099444535295, 16383);
+f(1099511644160, 16384);
+f(1099578753025, 16385);
+f(2198956179455, 32767);
+f(2199023288320, 32768);
+f(2199090397185, 32769);
+f(4397979467775, 65535);
+f(4398046576640, 65536);
+f(4398113685505, 65537);
+f(8796026044415, 131071);
+f(8796093153280, 131072);
+f(8796160262145, 131073);
+f(17592119197695, 262143);
+f(17592186306560, 262144);
+f(17592253415425, 262145);
+f(35184305504255, 524287);
+f(35184372613120, 524288);
+f(35184439721985, 524289);
+f(70368678117375, 1048575);
+f(70368745226240, 1048576);
+f(70368812335105, 1048577);
+f(140737423343615, 2097151);
+f(140737490452480, 2097152);
+f(140737557561345, 2097153);
+f(281474913796095, 4194303);
+f(281474980904960, 4194304);
+f(281475048013825, 4194305);
+f(562949894701055, 8388607);
+f(562949961809920, 8388608);
+f(562950028918785, 8388609);
+f(1125899856510975, 16777215);
+f(1125899923619840, 16777216);
+f(1125899990728705, 16777217);
+x = 134217727;
+f(134217727, 1);
+f(268435454, 2);
+f(402653181, 3);
+f(536870908, 4);
+f(671088635, 5);
+f(939524089, 7);
+f(1073741816, 8);
+f(1207959543, 9);
+f(2013265905, 15);
+f(2147483632, 16);
+f(2281701359, 17);
+f(4160749537, 31);
+f(4294967264, 32);
+f(4429184991, 33);
+f(8455716801, 63);
+f(8589934528, 64);
+f(8724152255, 65);
+f(17045651329, 127);
+f(17179869056, 128);
+f(17314086783, 129);
+f(34225520385, 255);
+f(34359738112, 256);
+f(34493955839, 257);
+f(68585258497, 511);
+f(68719476224, 512);
+f(68853693951, 513);
+f(137304734721, 1023);
+f(137438952448, 1024);
+f(137573170175, 1025);
+f(274743687169, 2047);
+f(274877904896, 2048);
+f(275012122623, 2049);
+f(549621592065, 4095);
+f(549755809792, 4096);
+f(549890027519, 4097);
+f(1099377401857, 8191);
+f(1099511619584, 8192);
+f(1099645837311, 8193);
+f(2198889021441, 16383);
+f(2199023239168, 16384);
+f(2199157456895, 16385);
+f(4397912260609, 32767);
+f(4398046478336, 32768);
+f(4398180696063, 32769);
+f(8795958738945, 65535);
+f(8796092956672, 65536);
+f(8796227174399, 65537);
+f(17592051695617, 131071);
+f(17592185913344, 131072);
+f(17592320131071, 131073);
+f(35184237608961, 262143);
+f(35184371826688, 262144);
+f(35184506044415, 262145);
+f(70368609435649, 524287);
+f(70368743653376, 524288);
+f(70368877871103, 524289);
+f(140737353089025, 1048575);
+f(140737487306752, 1048576);
+f(140737621524479, 1048577);
+f(281474840395777, 2097151);
+f(281474974613504, 2097152);
+f(281475108831231, 2097153);
+f(562949815009281, 4194303);
+f(562949949227008, 4194304);
+f(562950083444735, 4194305);
+f(1125899764236289, 8388607);
+f(1125899898454016, 8388608);
+f(1125900032671743, 8388609);
+x = 134217728;
+f(134217728, 1);
+f(268435456, 2);
+f(402653184, 3);
+f(536870912, 4);
+f(671088640, 5);
+f(939524096, 7);
+f(1073741824, 8);
+f(1207959552, 9);
+f(2013265920, 15);
+f(2147483648, 16);
+f(2281701376, 17);
+f(4160749568, 31);
+f(4294967296, 32);
+f(4429185024, 33);
+f(8455716864, 63);
+f(8589934592, 64);
+f(8724152320, 65);
+f(17045651456, 127);
+f(17179869184, 128);
+f(17314086912, 129);
+f(34225520640, 255);
+f(34359738368, 256);
+f(34493956096, 257);
+f(68585259008, 511);
+f(68719476736, 512);
+f(68853694464, 513);
+f(137304735744, 1023);
+f(137438953472, 1024);
+f(137573171200, 1025);
+f(274743689216, 2047);
+f(274877906944, 2048);
+f(275012124672, 2049);
+f(549621596160, 4095);
+f(549755813888, 4096);
+f(549890031616, 4097);
+f(1099377410048, 8191);
+f(1099511627776, 8192);
+f(1099645845504, 8193);
+f(2198889037824, 16383);
+f(2199023255552, 16384);
+f(2199157473280, 16385);
+f(4397912293376, 32767);
+f(4398046511104, 32768);
+f(4398180728832, 32769);
+f(8795958804480, 65535);
+f(8796093022208, 65536);
+f(8796227239936, 65537);
+f(17592051826688, 131071);
+f(17592186044416, 131072);
+f(17592320262144, 131073);
+f(35184237871104, 262143);
+f(35184372088832, 262144);
+f(35184506306560, 262145);
+f(70368609959936, 524287);
+f(70368744177664, 524288);
+f(70368878395392, 524289);
+f(140737354137600, 1048575);
+f(140737488355328, 1048576);
+f(140737622573056, 1048577);
+f(281474842492928, 2097151);
+f(281474976710656, 2097152);
+f(281475110928384, 2097153);
+f(562949819203584, 4194303);
+f(562949953421312, 4194304);
+f(562950087639040, 4194305);
+f(1125899772624896, 8388607);
+f(1125899906842624, 8388608);
+f(1125900041060352, 8388609);
+x = 134217729;
+f(134217729, 1);
+f(268435458, 2);
+f(402653187, 3);
+f(536870916, 4);
+f(671088645, 5);
+f(939524103, 7);
+f(1073741832, 8);
+f(1207959561, 9);
+f(2013265935, 15);
+f(2147483664, 16);
+f(2281701393, 17);
+f(4160749599, 31);
+f(4294967328, 32);
+f(4429185057, 33);
+f(8455716927, 63);
+f(8589934656, 64);
+f(8724152385, 65);
+f(17045651583, 127);
+f(17179869312, 128);
+f(17314087041, 129);
+f(34225520895, 255);
+f(34359738624, 256);
+f(34493956353, 257);
+f(68585259519, 511);
+f(68719477248, 512);
+f(68853694977, 513);
+f(137304736767, 1023);
+f(137438954496, 1024);
+f(137573172225, 1025);
+f(274743691263, 2047);
+f(274877908992, 2048);
+f(275012126721, 2049);
+f(549621600255, 4095);
+f(549755817984, 4096);
+f(549890035713, 4097);
+f(1099377418239, 8191);
+f(1099511635968, 8192);
+f(1099645853697, 8193);
+f(2198889054207, 16383);
+f(2199023271936, 16384);
+f(2199157489665, 16385);
+f(4397912326143, 32767);
+f(4398046543872, 32768);
+f(4398180761601, 32769);
+f(8795958870015, 65535);
+f(8796093087744, 65536);
+f(8796227305473, 65537);
+f(17592051957759, 131071);
+f(17592186175488, 131072);
+f(17592320393217, 131073);
+f(35184238133247, 262143);
+f(35184372350976, 262144);
+f(35184506568705, 262145);
+f(70368610484223, 524287);
+f(70368744701952, 524288);
+f(70368878919681, 524289);
+f(140737355186175, 1048575);
+f(140737489403904, 1048576);
+f(140737623621633, 1048577);
+f(281474844590079, 2097151);
+f(281474978807808, 2097152);
+f(281475113025537, 2097153);
+f(562949823397887, 4194303);
+f(562949957615616, 4194304);
+f(562950091833345, 4194305);
+f(1125899781013503, 8388607);
+f(1125899915231232, 8388608);
+f(1125900049448961, 8388609);
+x = 268435455;
+f(268435455, 1);
+f(536870910, 2);
+f(805306365, 3);
+f(1073741820, 4);
+f(1342177275, 5);
+f(1879048185, 7);
+f(2147483640, 8);
+f(2415919095, 9);
+f(4026531825, 15);
+f(4294967280, 16);
+f(4563402735, 17);
+f(8321499105, 31);
+f(8589934560, 32);
+f(8858370015, 33);
+f(16911433665, 63);
+f(17179869120, 64);
+f(17448304575, 65);
+f(34091302785, 127);
+f(34359738240, 128);
+f(34628173695, 129);
+f(68451041025, 255);
+f(68719476480, 256);
+f(68987911935, 257);
+f(137170517505, 511);
+f(137438952960, 512);
+f(137707388415, 513);
+f(274609470465, 1023);
+f(274877905920, 1024);
+f(275146341375, 1025);
+f(549487376385, 2047);
+f(549755811840, 2048);
+f(550024247295, 2049);
+f(1099243188225, 4095);
+f(1099511623680, 4096);
+f(1099780059135, 4097);
+f(2198754811905, 8191);
+f(2199023247360, 8192);
+f(2199291682815, 8193);
+f(4397778059265, 16383);
+f(4398046494720, 16384);
+f(4398314930175, 16385);
+f(8795824553985, 32767);
+f(8796092989440, 32768);
+f(8796361424895, 32769);
+f(17591917543425, 65535);
+f(17592185978880, 65536);
+f(17592454414335, 65537);
+f(35184103522305, 131071);
+f(35184371957760, 131072);
+f(35184640393215, 131073);
+f(70368475480065, 262143);
+f(70368743915520, 262144);
+f(70369012350975, 262145);
+f(140737219395585, 524287);
+f(140737487831040, 524288);
+f(140737756266495, 524289);
+f(281474707226625, 1048575);
+f(281474975662080, 1048576);
+f(281475244097535, 1048577);
+f(562949682888705, 2097151);
+f(562949951324160, 2097152);
+f(562950219759615, 2097153);
+f(1125899634212865, 4194303);
+f(1125899902648320, 4194304);
+f(1125900171083775, 4194305);
+x = 268435456;
+f(268435456, 1);
+f(536870912, 2);
+f(805306368, 3);
+f(1073741824, 4);
+f(1342177280, 5);
+f(1879048192, 7);
+f(2147483648, 8);
+f(2415919104, 9);
+f(4026531840, 15);
+f(4294967296, 16);
+f(4563402752, 17);
+f(8321499136, 31);
+f(8589934592, 32);
+f(8858370048, 33);
+f(16911433728, 63);
+f(17179869184, 64);
+f(17448304640, 65);
+f(34091302912, 127);
+f(34359738368, 128);
+f(34628173824, 129);
+f(68451041280, 255);
+f(68719476736, 256);
+f(68987912192, 257);
+f(137170518016, 511);
+f(137438953472, 512);
+f(137707388928, 513);
+f(274609471488, 1023);
+f(274877906944, 1024);
+f(275146342400, 1025);
+f(549487378432, 2047);
+f(549755813888, 2048);
+f(550024249344, 2049);
+f(1099243192320, 4095);
+f(1099511627776, 4096);
+f(1099780063232, 4097);
+f(2198754820096, 8191);
+f(2199023255552, 8192);
+f(2199291691008, 8193);
+f(4397778075648, 16383);
+f(4398046511104, 16384);
+f(4398314946560, 16385);
+f(8795824586752, 32767);
+f(8796093022208, 32768);
+f(8796361457664, 32769);
+f(17591917608960, 65535);
+f(17592186044416, 65536);
+f(17592454479872, 65537);
+f(35184103653376, 131071);
+f(35184372088832, 131072);
+f(35184640524288, 131073);
+f(70368475742208, 262143);
+f(70368744177664, 262144);
+f(70369012613120, 262145);
+f(140737219919872, 524287);
+f(140737488355328, 524288);
+f(140737756790784, 524289);
+f(281474708275200, 1048575);
+f(281474976710656, 1048576);
+f(281475245146112, 1048577);
+f(562949684985856, 2097151);
+f(562949953421312, 2097152);
+f(562950221856768, 2097153);
+f(1125899638407168, 4194303);
+f(1125899906842624, 4194304);
+f(1125900175278080, 4194305);
+x = 268435457;
+f(268435457, 1);
+f(536870914, 2);
+f(805306371, 3);
+f(1073741828, 4);
+f(1342177285, 5);
+f(1879048199, 7);
+f(2147483656, 8);
+f(2415919113, 9);
+f(4026531855, 15);
+f(4294967312, 16);
+f(4563402769, 17);
+f(8321499167, 31);
+f(8589934624, 32);
+f(8858370081, 33);
+f(16911433791, 63);
+f(17179869248, 64);
+f(17448304705, 65);
+f(34091303039, 127);
+f(34359738496, 128);
+f(34628173953, 129);
+f(68451041535, 255);
+f(68719476992, 256);
+f(68987912449, 257);
+f(137170518527, 511);
+f(137438953984, 512);
+f(137707389441, 513);
+f(274609472511, 1023);
+f(274877907968, 1024);
+f(275146343425, 1025);
+f(549487380479, 2047);
+f(549755815936, 2048);
+f(550024251393, 2049);
+f(1099243196415, 4095);
+f(1099511631872, 4096);
+f(1099780067329, 4097);
+f(2198754828287, 8191);
+f(2199023263744, 8192);
+f(2199291699201, 8193);
+f(4397778092031, 16383);
+f(4398046527488, 16384);
+f(4398314962945, 16385);
+f(8795824619519, 32767);
+f(8796093054976, 32768);
+f(8796361490433, 32769);
+f(17591917674495, 65535);
+f(17592186109952, 65536);
+f(17592454545409, 65537);
+f(35184103784447, 131071);
+f(35184372219904, 131072);
+f(35184640655361, 131073);
+f(70368476004351, 262143);
+f(70368744439808, 262144);
+f(70369012875265, 262145);
+f(140737220444159, 524287);
+f(140737488879616, 524288);
+f(140737757315073, 524289);
+f(281474709323775, 1048575);
+f(281474977759232, 1048576);
+f(281475246194689, 1048577);
+f(562949687083007, 2097151);
+f(562949955518464, 2097152);
+f(562950223953921, 2097153);
+f(1125899642601471, 4194303);
+f(1125899911036928, 4194304);
+f(1125900179472385, 4194305);
+x = 536870911;
+f(536870911, 1);
+f(1073741822, 2);
+f(1610612733, 3);
+f(2147483644, 4);
+f(2684354555, 5);
+f(3758096377, 7);
+f(4294967288, 8);
+f(4831838199, 9);
+f(8053063665, 15);
+f(8589934576, 16);
+f(9126805487, 17);
+f(16642998241, 31);
+f(17179869152, 32);
+f(17716740063, 33);
+f(33822867393, 63);
+f(34359738304, 64);
+f(34896609215, 65);
+f(68182605697, 127);
+f(68719476608, 128);
+f(69256347519, 129);
+f(136902082305, 255);
+f(137438953216, 256);
+f(137975824127, 257);
+f(274341035521, 511);
+f(274877906432, 512);
+f(275414777343, 513);
+f(549218941953, 1023);
+f(549755812864, 1024);
+f(550292683775, 1025);
+f(1098974754817, 2047);
+f(1099511625728, 2048);
+f(1100048496639, 2049);
+f(2198486380545, 4095);
+f(2199023251456, 4096);
+f(2199560122367, 4097);
+f(4397509632001, 8191);
+f(4398046502912, 8192);
+f(4398583373823, 8193);
+f(8795556134913, 16383);
+f(8796093005824, 16384);
+f(8796629876735, 16385);
+f(17591649140737, 32767);
+f(17592186011648, 32768);
+f(17592722882559, 32769);
+f(35183835152385, 65535);
+f(35184372023296, 65536);
+f(35184908894207, 65537);
+f(70368207175681, 131071);
+f(70368744046592, 131072);
+f(70369280917503, 131073);
+f(140736951222273, 262143);
+f(140737488093184, 262144);
+f(140738024964095, 262145);
+f(281474439315457, 524287);
+f(281474976186368, 524288);
+f(281475513057279, 524289);
+f(562949415501825, 1048575);
+f(562949952372736, 1048576);
+f(562950489243647, 1048577);
+f(1125899367874561, 2097151);
+f(1125899904745472, 2097152);
+f(1125900441616383, 2097153);
+x = 536870912;
+f(536870912, 1);
+f(1073741824, 2);
+f(1610612736, 3);
+f(2147483648, 4);
+f(2684354560, 5);
+f(3758096384, 7);
+f(4294967296, 8);
+f(4831838208, 9);
+f(8053063680, 15);
+f(8589934592, 16);
+f(9126805504, 17);
+f(16642998272, 31);
+f(17179869184, 32);
+f(17716740096, 33);
+f(33822867456, 63);
+f(34359738368, 64);
+f(34896609280, 65);
+f(68182605824, 127);
+f(68719476736, 128);
+f(69256347648, 129);
+f(136902082560, 255);
+f(137438953472, 256);
+f(137975824384, 257);
+f(274341036032, 511);
+f(274877906944, 512);
+f(275414777856, 513);
+f(549218942976, 1023);
+f(549755813888, 1024);
+f(550292684800, 1025);
+f(1098974756864, 2047);
+f(1099511627776, 2048);
+f(1100048498688, 2049);
+f(2198486384640, 4095);
+f(2199023255552, 4096);
+f(2199560126464, 4097);
+f(4397509640192, 8191);
+f(4398046511104, 8192);
+f(4398583382016, 8193);
+f(8795556151296, 16383);
+f(8796093022208, 16384);
+f(8796629893120, 16385);
+f(17591649173504, 32767);
+f(17592186044416, 32768);
+f(17592722915328, 32769);
+f(35183835217920, 65535);
+f(35184372088832, 65536);
+f(35184908959744, 65537);
+f(70368207306752, 131071);
+f(70368744177664, 131072);
+f(70369281048576, 131073);
+f(140736951484416, 262143);
+f(140737488355328, 262144);
+f(140738025226240, 262145);
+f(281474439839744, 524287);
+f(281474976710656, 524288);
+f(281475513581568, 524289);
+f(562949416550400, 1048575);
+f(562949953421312, 1048576);
+f(562950490292224, 1048577);
+f(1125899369971712, 2097151);
+f(1125899906842624, 2097152);
+f(1125900443713536, 2097153);
+x = 536870913;
+f(536870913, 1);
+f(1073741826, 2);
+f(1610612739, 3);
+f(2147483652, 4);
+f(2684354565, 5);
+f(3758096391, 7);
+f(4294967304, 8);
+f(4831838217, 9);
+f(8053063695, 15);
+f(8589934608, 16);
+f(9126805521, 17);
+f(16642998303, 31);
+f(17179869216, 32);
+f(17716740129, 33);
+f(33822867519, 63);
+f(34359738432, 64);
+f(34896609345, 65);
+f(68182605951, 127);
+f(68719476864, 128);
+f(69256347777, 129);
+f(136902082815, 255);
+f(137438953728, 256);
+f(137975824641, 257);
+f(274341036543, 511);
+f(274877907456, 512);
+f(275414778369, 513);
+f(549218943999, 1023);
+f(549755814912, 1024);
+f(550292685825, 1025);
+f(1098974758911, 2047);
+f(1099511629824, 2048);
+f(1100048500737, 2049);
+f(2198486388735, 4095);
+f(2199023259648, 4096);
+f(2199560130561, 4097);
+f(4397509648383, 8191);
+f(4398046519296, 8192);
+f(4398583390209, 8193);
+f(8795556167679, 16383);
+f(8796093038592, 16384);
+f(8796629909505, 16385);
+f(17591649206271, 32767);
+f(17592186077184, 32768);
+f(17592722948097, 32769);
+f(35183835283455, 65535);
+f(35184372154368, 65536);
+f(35184909025281, 65537);
+f(70368207437823, 131071);
+f(70368744308736, 131072);
+f(70369281179649, 131073);
+f(140736951746559, 262143);
+f(140737488617472, 262144);
+f(140738025488385, 262145);
+f(281474440364031, 524287);
+f(281474977234944, 524288);
+f(281475514105857, 524289);
+f(562949417598975, 1048575);
+f(562949954469888, 1048576);
+f(562950491340801, 1048577);
+f(1125899372068863, 2097151);
+f(1125899908939776, 2097152);
+f(1125900445810689, 2097153);
+x = 1073741823;
+f(1073741823, 1);
+f(2147483646, 2);
+f(3221225469, 3);
+f(4294967292, 4);
+f(5368709115, 5);
+f(7516192761, 7);
+f(8589934584, 8);
+f(9663676407, 9);
+f(16106127345, 15);
+f(17179869168, 16);
+f(18253610991, 17);
+f(33285996513, 31);
+f(34359738336, 32);
+f(35433480159, 33);
+f(67645734849, 63);
+f(68719476672, 64);
+f(69793218495, 65);
+f(136365211521, 127);
+f(137438953344, 128);
+f(138512695167, 129);
+f(273804164865, 255);
+f(274877906688, 256);
+f(275951648511, 257);
+f(548682071553, 511);
+f(549755813376, 512);
+f(550829555199, 513);
+f(1098437884929, 1023);
+f(1099511626752, 1024);
+f(1100585368575, 1025);
+f(2197949511681, 2047);
+f(2199023253504, 2048);
+f(2200096995327, 2049);
+f(4396972765185, 4095);
+f(4398046507008, 4096);
+f(4399120248831, 4097);
+f(8795019272193, 8191);
+f(8796093014016, 8192);
+f(8797166755839, 8193);
+f(17591112286209, 16383);
+f(17592186028032, 16384);
+f(17593259769855, 16385);
+f(35183298314241, 32767);
+f(35184372056064, 32768);
+f(35185445797887, 32769);
+f(70367670370305, 65535);
+f(70368744112128, 65536);
+f(70369817853951, 65537);
+f(140736414482433, 131071);
+f(140737488224256, 131072);
+f(140738561966079, 131073);
+f(281473902706689, 262143);
+f(281474976448512, 262144);
+f(281476050190335, 262145);
+f(562948879155201, 524287);
+f(562949952897024, 524288);
+f(562951026638847, 524289);
+f(1125898832052225, 1048575);
+f(1125899905794048, 1048576);
+f(1125900979535871, 1048577);
+x = 1073741824;
+f(1073741824, 1);
+f(2147483648, 2);
+f(3221225472, 3);
+f(4294967296, 4);
+f(5368709120, 5);
+f(7516192768, 7);
+f(8589934592, 8);
+f(9663676416, 9);
+f(16106127360, 15);
+f(17179869184, 16);
+f(18253611008, 17);
+f(33285996544, 31);
+f(34359738368, 32);
+f(35433480192, 33);
+f(67645734912, 63);
+f(68719476736, 64);
+f(69793218560, 65);
+f(136365211648, 127);
+f(137438953472, 128);
+f(138512695296, 129);
+f(273804165120, 255);
+f(274877906944, 256);
+f(275951648768, 257);
+f(548682072064, 511);
+f(549755813888, 512);
+f(550829555712, 513);
+f(1098437885952, 1023);
+f(1099511627776, 1024);
+f(1100585369600, 1025);
+f(2197949513728, 2047);
+f(2199023255552, 2048);
+f(2200096997376, 2049);
+f(4396972769280, 4095);
+f(4398046511104, 4096);
+f(4399120252928, 4097);
+f(8795019280384, 8191);
+f(8796093022208, 8192);
+f(8797166764032, 8193);
+f(17591112302592, 16383);
+f(17592186044416, 16384);
+f(17593259786240, 16385);
+f(35183298347008, 32767);
+f(35184372088832, 32768);
+f(35185445830656, 32769);
+f(70367670435840, 65535);
+f(70368744177664, 65536);
+f(70369817919488, 65537);
+f(140736414613504, 131071);
+f(140737488355328, 131072);
+f(140738562097152, 131073);
+f(281473902968832, 262143);
+f(281474976710656, 262144);
+f(281476050452480, 262145);
+f(562948879679488, 524287);
+f(562949953421312, 524288);
+f(562951027163136, 524289);
+f(1125898833100800, 1048575);
+f(1125899906842624, 1048576);
+f(1125900980584448, 1048577);
+x = 1073741825;
+f(1073741825, 1);
+f(2147483650, 2);
+f(3221225475, 3);
+f(4294967300, 4);
+f(5368709125, 5);
+f(7516192775, 7);
+f(8589934600, 8);
+f(9663676425, 9);
+f(16106127375, 15);
+f(17179869200, 16);
+f(18253611025, 17);
+f(33285996575, 31);
+f(34359738400, 32);
+f(35433480225, 33);
+f(67645734975, 63);
+f(68719476800, 64);
+f(69793218625, 65);
+f(136365211775, 127);
+f(137438953600, 128);
+f(138512695425, 129);
+f(273804165375, 255);
+f(274877907200, 256);
+f(275951649025, 257);
+f(548682072575, 511);
+f(549755814400, 512);
+f(550829556225, 513);
+f(1098437886975, 1023);
+f(1099511628800, 1024);
+f(1100585370625, 1025);
+f(2197949515775, 2047);
+f(2199023257600, 2048);
+f(2200096999425, 2049);
+f(4396972773375, 4095);
+f(4398046515200, 4096);
+f(4399120257025, 4097);
+f(8795019288575, 8191);
+f(8796093030400, 8192);
+f(8797166772225, 8193);
+f(17591112318975, 16383);
+f(17592186060800, 16384);
+f(17593259802625, 16385);
+f(35183298379775, 32767);
+f(35184372121600, 32768);
+f(35185445863425, 32769);
+f(70367670501375, 65535);
+f(70368744243200, 65536);
+f(70369817985025, 65537);
+f(140736414744575, 131071);
+f(140737488486400, 131072);
+f(140738562228225, 131073);
+f(281473903230975, 262143);
+f(281474976972800, 262144);
+f(281476050714625, 262145);
+f(562948880203775, 524287);
+f(562949953945600, 524288);
+f(562951027687425, 524289);
+f(1125898834149375, 1048575);
+f(1125899907891200, 1048576);
+f(1125900981633025, 1048577);
+x = 2147483647;
+f(2147483647, 1);
+f(4294967294, 2);
+f(6442450941, 3);
+f(8589934588, 4);
+f(10737418235, 5);
+f(15032385529, 7);
+f(17179869176, 8);
+f(19327352823, 9);
+f(32212254705, 15);
+f(34359738352, 16);
+f(36507221999, 17);
+f(66571993057, 31);
+f(68719476704, 32);
+f(70866960351, 33);
+f(135291469761, 63);
+f(137438953408, 64);
+f(139586437055, 65);
+f(272730423169, 127);
+f(274877906816, 128);
+f(277025390463, 129);
+f(547608329985, 255);
+f(549755813632, 256);
+f(551903297279, 257);
+f(1097364143617, 511);
+f(1099511627264, 512);
+f(1101659110911, 513);
+f(2196875770881, 1023);
+f(2199023254528, 1024);
+f(2201170738175, 1025);
+f(4395899025409, 2047);
+f(4398046509056, 2048);
+f(4400193992703, 2049);
+f(8793945534465, 4095);
+f(8796093018112, 4096);
+f(8798240501759, 4097);
+f(17590038552577, 8191);
+f(17592186036224, 8192);
+f(17594333519871, 8193);
+f(35182224588801, 16383);
+f(35184372072448, 16384);
+f(35186519556095, 16385);
+f(70366596661249, 32767);
+f(70368744144896, 32768);
+f(70370891628543, 32769);
+f(140735340806145, 65535);
+f(140737488289792, 65536);
+f(140739635773439, 65537);
+f(281472829095937, 131071);
+f(281474976579584, 131072);
+f(281477124063231, 131073);
+f(562947805675521, 262143);
+f(562949953159168, 262144);
+f(562952100642815, 262145);
+f(1125897758834689, 524287);
+f(1125899906318336, 524288);
+f(1125902053801983, 524289);
+x = 2147483648;
+f(2147483648, 1);
+f(4294967296, 2);
+f(6442450944, 3);
+f(8589934592, 4);
+f(10737418240, 5);
+f(15032385536, 7);
+f(17179869184, 8);
+f(19327352832, 9);
+f(32212254720, 15);
+f(34359738368, 16);
+f(36507222016, 17);
+f(66571993088, 31);
+f(68719476736, 32);
+f(70866960384, 33);
+f(135291469824, 63);
+f(137438953472, 64);
+f(139586437120, 65);
+f(272730423296, 127);
+f(274877906944, 128);
+f(277025390592, 129);
+f(547608330240, 255);
+f(549755813888, 256);
+f(551903297536, 257);
+f(1097364144128, 511);
+f(1099511627776, 512);
+f(1101659111424, 513);
+f(2196875771904, 1023);
+f(2199023255552, 1024);
+f(2201170739200, 1025);
+f(4395899027456, 2047);
+f(4398046511104, 2048);
+f(4400193994752, 2049);
+f(8793945538560, 4095);
+f(8796093022208, 4096);
+f(8798240505856, 4097);
+f(17590038560768, 8191);
+f(17592186044416, 8192);
+f(17594333528064, 8193);
+f(35182224605184, 16383);
+f(35184372088832, 16384);
+f(35186519572480, 16385);
+f(70366596694016, 32767);
+f(70368744177664, 32768);
+f(70370891661312, 32769);
+f(140735340871680, 65535);
+f(140737488355328, 65536);
+f(140739635838976, 65537);
+f(281472829227008, 131071);
+f(281474976710656, 131072);
+f(281477124194304, 131073);
+f(562947805937664, 262143);
+f(562949953421312, 262144);
+f(562952100904960, 262145);
+f(1125897759358976, 524287);
+f(1125899906842624, 524288);
+f(1125902054326272, 524289);
+x = 2147483649;
+f(2147483649, 1);
+f(4294967298, 2);
+f(6442450947, 3);
+f(8589934596, 4);
+f(10737418245, 5);
+f(15032385543, 7);
+f(17179869192, 8);
+f(19327352841, 9);
+f(32212254735, 15);
+f(34359738384, 16);
+f(36507222033, 17);
+f(66571993119, 31);
+f(68719476768, 32);
+f(70866960417, 33);
+f(135291469887, 63);
+f(137438953536, 64);
+f(139586437185, 65);
+f(272730423423, 127);
+f(274877907072, 128);
+f(277025390721, 129);
+f(547608330495, 255);
+f(549755814144, 256);
+f(551903297793, 257);
+f(1097364144639, 511);
+f(1099511628288, 512);
+f(1101659111937, 513);
+f(2196875772927, 1023);
+f(2199023256576, 1024);
+f(2201170740225, 1025);
+f(4395899029503, 2047);
+f(4398046513152, 2048);
+f(4400193996801, 2049);
+f(8793945542655, 4095);
+f(8796093026304, 4096);
+f(8798240509953, 4097);
+f(17590038568959, 8191);
+f(17592186052608, 8192);
+f(17594333536257, 8193);
+f(35182224621567, 16383);
+f(35184372105216, 16384);
+f(35186519588865, 16385);
+f(70366596726783, 32767);
+f(70368744210432, 32768);
+f(70370891694081, 32769);
+f(140735340937215, 65535);
+f(140737488420864, 65536);
+f(140739635904513, 65537);
+f(281472829358079, 131071);
+f(281474976841728, 131072);
+f(281477124325377, 131073);
+f(562947806199807, 262143);
+f(562949953683456, 262144);
+f(562952101167105, 262145);
+f(1125897759883263, 524287);
+f(1125899907366912, 524288);
+f(1125902054850561, 524289);
+x = 4294967295;
+f(4294967295, 1);
+f(8589934590, 2);
+f(12884901885, 3);
+f(17179869180, 4);
+f(21474836475, 5);
+f(30064771065, 7);
+f(34359738360, 8);
+f(38654705655, 9);
+f(64424509425, 15);
+f(68719476720, 16);
+f(73014444015, 17);
+f(133143986145, 31);
+f(137438953440, 32);
+f(141733920735, 33);
+f(270582939585, 63);
+f(274877906880, 64);
+f(279172874175, 65);
+f(545460846465, 127);
+f(549755813760, 128);
+f(554050781055, 129);
+f(1095216660225, 255);
+f(1099511627520, 256);
+f(1103806594815, 257);
+f(2194728287745, 511);
+f(2199023255040, 512);
+f(2203318222335, 513);
+f(4393751542785, 1023);
+f(4398046510080, 1024);
+f(4402341477375, 1025);
+f(8791798052865, 2047);
+f(8796093020160, 2048);
+f(8800387987455, 2049);
+f(17587891073025, 4095);
+f(17592186040320, 4096);
+f(17596481007615, 4097);
+f(35180077113345, 8191);
+f(35184372080640, 8192);
+f(35188667047935, 8193);
+f(70364449193985, 16383);
+f(70368744161280, 16384);
+f(70373039128575, 16385);
+f(140733193355265, 32767);
+f(140737488322560, 32768);
+f(140741783289855, 32769);
+f(281470681677825, 65535);
+f(281474976645120, 65536);
+f(281479271612415, 65537);
+f(562945658322945, 131071);
+f(562949953290240, 131072);
+f(562954248257535, 131073);
+f(1125895611613185, 262143);
+f(1125899906580480, 262144);
+f(1125904201547775, 262145);
+x = 4294967296;
+f(4294967296, 1);
+f(8589934592, 2);
+f(12884901888, 3);
+f(17179869184, 4);
+f(21474836480, 5);
+f(30064771072, 7);
+f(34359738368, 8);
+f(38654705664, 9);
+f(64424509440, 15);
+f(68719476736, 16);
+f(73014444032, 17);
+f(133143986176, 31);
+f(137438953472, 32);
+f(141733920768, 33);
+f(270582939648, 63);
+f(274877906944, 64);
+f(279172874240, 65);
+f(545460846592, 127);
+f(549755813888, 128);
+f(554050781184, 129);
+f(1095216660480, 255);
+f(1099511627776, 256);
+f(1103806595072, 257);
+f(2194728288256, 511);
+f(2199023255552, 512);
+f(2203318222848, 513);
+f(4393751543808, 1023);
+f(4398046511104, 1024);
+f(4402341478400, 1025);
+f(8791798054912, 2047);
+f(8796093022208, 2048);
+f(8800387989504, 2049);
+f(17587891077120, 4095);
+f(17592186044416, 4096);
+f(17596481011712, 4097);
+f(35180077121536, 8191);
+f(35184372088832, 8192);
+f(35188667056128, 8193);
+f(70364449210368, 16383);
+f(70368744177664, 16384);
+f(70373039144960, 16385);
+f(140733193388032, 32767);
+f(140737488355328, 32768);
+f(140741783322624, 32769);
+f(281470681743360, 65535);
+f(281474976710656, 65536);
+f(281479271677952, 65537);
+f(562945658454016, 131071);
+f(562949953421312, 131072);
+f(562954248388608, 131073);
+f(1125895611875328, 262143);
+f(1125899906842624, 262144);
+f(1125904201809920, 262145);
+x = 4294967297;
+f(4294967297, 1);
+f(8589934594, 2);
+f(12884901891, 3);
+f(17179869188, 4);
+f(21474836485, 5);
+f(30064771079, 7);
+f(34359738376, 8);
+f(38654705673, 9);
+f(64424509455, 15);
+f(68719476752, 16);
+f(73014444049, 17);
+f(133143986207, 31);
+f(137438953504, 32);
+f(141733920801, 33);
+f(270582939711, 63);
+f(274877907008, 64);
+f(279172874305, 65);
+f(545460846719, 127);
+f(549755814016, 128);
+f(554050781313, 129);
+f(1095216660735, 255);
+f(1099511628032, 256);
+f(1103806595329, 257);
+f(2194728288767, 511);
+f(2199023256064, 512);
+f(2203318223361, 513);
+f(4393751544831, 1023);
+f(4398046512128, 1024);
+f(4402341479425, 1025);
+f(8791798056959, 2047);
+f(8796093024256, 2048);
+f(8800387991553, 2049);
+f(17587891081215, 4095);
+f(17592186048512, 4096);
+f(17596481015809, 4097);
+f(35180077129727, 8191);
+f(35184372097024, 8192);
+f(35188667064321, 8193);
+f(70364449226751, 16383);
+f(70368744194048, 16384);
+f(70373039161345, 16385);
+f(140733193420799, 32767);
+f(140737488388096, 32768);
+f(140741783355393, 32769);
+f(281470681808895, 65535);
+f(281474976776192, 65536);
+f(281479271743489, 65537);
+f(562945658585087, 131071);
+f(562949953552384, 131072);
+f(562954248519681, 131073);
+f(1125895612137471, 262143);
+f(1125899907104768, 262144);
+f(1125904202072065, 262145);
+x = 8589934591;
+f(8589934591, 1);
+f(17179869182, 2);
+f(25769803773, 3);
+f(34359738364, 4);
+f(42949672955, 5);
+f(60129542137, 7);
+f(68719476728, 8);
+f(77309411319, 9);
+f(128849018865, 15);
+f(137438953456, 16);
+f(146028888047, 17);
+f(266287972321, 31);
+f(274877906912, 32);
+f(283467841503, 33);
+f(541165879233, 63);
+f(549755813824, 64);
+f(558345748415, 65);
+f(1090921693057, 127);
+f(1099511627648, 128);
+f(1108101562239, 129);
+f(2190433320705, 255);
+f(2199023255296, 256);
+f(2207613189887, 257);
+f(4389456576001, 511);
+f(4398046510592, 512);
+f(4406636445183, 513);
+f(8787503086593, 1023);
+f(8796093021184, 1024);
+f(8804682955775, 1025);
+f(17583596107777, 2047);
+f(17592186042368, 2048);
+f(17600775976959, 2049);
+f(35175782150145, 4095);
+f(35184372084736, 4096);
+f(35192962019327, 4097);
+f(70360154234881, 8191);
+f(70368744169472, 8192);
+f(70377334104063, 8193);
+f(140728898404353, 16383);
+f(140737488338944, 16384);
+f(140746078273535, 16385);
+f(281466386743297, 32767);
+f(281474976677888, 32768);
+f(281483566612479, 32769);
+f(562941363421185, 65535);
+f(562949953355776, 65536);
+f(562958543290367, 65537);
+f(1125891316776961, 131071);
+f(1125899906711552, 131072);
+f(1125908496646143, 131073);
+x = 8589934592;
+f(8589934592, 1);
+f(17179869184, 2);
+f(25769803776, 3);
+f(34359738368, 4);
+f(42949672960, 5);
+f(60129542144, 7);
+f(68719476736, 8);
+f(77309411328, 9);
+f(128849018880, 15);
+f(137438953472, 16);
+f(146028888064, 17);
+f(266287972352, 31);
+f(274877906944, 32);
+f(283467841536, 33);
+f(541165879296, 63);
+f(549755813888, 64);
+f(558345748480, 65);
+f(1090921693184, 127);
+f(1099511627776, 128);
+f(1108101562368, 129);
+f(2190433320960, 255);
+f(2199023255552, 256);
+f(2207613190144, 257);
+f(4389456576512, 511);
+f(4398046511104, 512);
+f(4406636445696, 513);
+f(8787503087616, 1023);
+f(8796093022208, 1024);
+f(8804682956800, 1025);
+f(17583596109824, 2047);
+f(17592186044416, 2048);
+f(17600775979008, 2049);
+f(35175782154240, 4095);
+f(35184372088832, 4096);
+f(35192962023424, 4097);
+f(70360154243072, 8191);
+f(70368744177664, 8192);
+f(70377334112256, 8193);
+f(140728898420736, 16383);
+f(140737488355328, 16384);
+f(140746078289920, 16385);
+f(281466386776064, 32767);
+f(281474976710656, 32768);
+f(281483566645248, 32769);
+f(562941363486720, 65535);
+f(562949953421312, 65536);
+f(562958543355904, 65537);
+f(1125891316908032, 131071);
+f(1125899906842624, 131072);
+f(1125908496777216, 131073);
+x = 8589934593;
+f(8589934593, 1);
+f(17179869186, 2);
+f(25769803779, 3);
+f(34359738372, 4);
+f(42949672965, 5);
+f(60129542151, 7);
+f(68719476744, 8);
+f(77309411337, 9);
+f(128849018895, 15);
+f(137438953488, 16);
+f(146028888081, 17);
+f(266287972383, 31);
+f(274877906976, 32);
+f(283467841569, 33);
+f(541165879359, 63);
+f(549755813952, 64);
+f(558345748545, 65);
+f(1090921693311, 127);
+f(1099511627904, 128);
+f(1108101562497, 129);
+f(2190433321215, 255);
+f(2199023255808, 256);
+f(2207613190401, 257);
+f(4389456577023, 511);
+f(4398046511616, 512);
+f(4406636446209, 513);
+f(8787503088639, 1023);
+f(8796093023232, 1024);
+f(8804682957825, 1025);
+f(17583596111871, 2047);
+f(17592186046464, 2048);
+f(17600775981057, 2049);
+f(35175782158335, 4095);
+f(35184372092928, 4096);
+f(35192962027521, 4097);
+f(70360154251263, 8191);
+f(70368744185856, 8192);
+f(70377334120449, 8193);
+f(140728898437119, 16383);
+f(140737488371712, 16384);
+f(140746078306305, 16385);
+f(281466386808831, 32767);
+f(281474976743424, 32768);
+f(281483566678017, 32769);
+f(562941363552255, 65535);
+f(562949953486848, 65536);
+f(562958543421441, 65537);
+f(1125891317039103, 131071);
+f(1125899906973696, 131072);
+f(1125908496908289, 131073);
+x = 17179869183;
+f(17179869183, 1);
+f(34359738366, 2);
+f(51539607549, 3);
+f(68719476732, 4);
+f(85899345915, 5);
+f(120259084281, 7);
+f(137438953464, 8);
+f(154618822647, 9);
+f(257698037745, 15);
+f(274877906928, 16);
+f(292057776111, 17);
+f(532575944673, 31);
+f(549755813856, 32);
+f(566935683039, 33);
+f(1082331758529, 63);
+f(1099511627712, 64);
+f(1116691496895, 65);
+f(2181843386241, 127);
+f(2199023255424, 128);
+f(2216203124607, 129);
+f(4380866641665, 255);
+f(4398046510848, 256);
+f(4415226380031, 257);
+f(8778913152513, 511);
+f(8796093021696, 512);
+f(8813272890879, 513);
+f(17575006174209, 1023);
+f(17592186043392, 1024);
+f(17609365912575, 1025);
+f(35167192217601, 2047);
+f(35184372086784, 2048);
+f(35201551955967, 2049);
+f(70351564304385, 4095);
+f(70368744173568, 4096);
+f(70385924042751, 4097);
+f(140720308477953, 8191);
+f(140737488347136, 8192);
+f(140754668216319, 8193);
+f(281457796825089, 16383);
+f(281474976694272, 16384);
+f(281492156563455, 16385);
+f(562932773519361, 32767);
+f(562949953388544, 32768);
+f(562967133257727, 32769);
+f(1125882726907905, 65535);
+f(1125899906777088, 65536);
+f(1125917086646271, 65537);
+x = 17179869184;
+f(17179869184, 1);
+f(34359738368, 2);
+f(51539607552, 3);
+f(68719476736, 4);
+f(85899345920, 5);
+f(120259084288, 7);
+f(137438953472, 8);
+f(154618822656, 9);
+f(257698037760, 15);
+f(274877906944, 16);
+f(292057776128, 17);
+f(532575944704, 31);
+f(549755813888, 32);
+f(566935683072, 33);
+f(1082331758592, 63);
+f(1099511627776, 64);
+f(1116691496960, 65);
+f(2181843386368, 127);
+f(2199023255552, 128);
+f(2216203124736, 129);
+f(4380866641920, 255);
+f(4398046511104, 256);
+f(4415226380288, 257);
+f(8778913153024, 511);
+f(8796093022208, 512);
+f(8813272891392, 513);
+f(17575006175232, 1023);
+f(17592186044416, 1024);
+f(17609365913600, 1025);
+f(35167192219648, 2047);
+f(35184372088832, 2048);
+f(35201551958016, 2049);
+f(70351564308480, 4095);
+f(70368744177664, 4096);
+f(70385924046848, 4097);
+f(140720308486144, 8191);
+f(140737488355328, 8192);
+f(140754668224512, 8193);
+f(281457796841472, 16383);
+f(281474976710656, 16384);
+f(281492156579840, 16385);
+f(562932773552128, 32767);
+f(562949953421312, 32768);
+f(562967133290496, 32769);
+f(1125882726973440, 65535);
+f(1125899906842624, 65536);
+f(1125917086711808, 65537);
+x = 17179869185;
+f(17179869185, 1);
+f(34359738370, 2);
+f(51539607555, 3);
+f(68719476740, 4);
+f(85899345925, 5);
+f(120259084295, 7);
+f(137438953480, 8);
+f(154618822665, 9);
+f(257698037775, 15);
+f(274877906960, 16);
+f(292057776145, 17);
+f(532575944735, 31);
+f(549755813920, 32);
+f(566935683105, 33);
+f(1082331758655, 63);
+f(1099511627840, 64);
+f(1116691497025, 65);
+f(2181843386495, 127);
+f(2199023255680, 128);
+f(2216203124865, 129);
+f(4380866642175, 255);
+f(4398046511360, 256);
+f(4415226380545, 257);
+f(8778913153535, 511);
+f(8796093022720, 512);
+f(8813272891905, 513);
+f(17575006176255, 1023);
+f(17592186045440, 1024);
+f(17609365914625, 1025);
+f(35167192221695, 2047);
+f(35184372090880, 2048);
+f(35201551960065, 2049);
+f(70351564312575, 4095);
+f(70368744181760, 4096);
+f(70385924050945, 4097);
+f(140720308494335, 8191);
+f(140737488363520, 8192);
+f(140754668232705, 8193);
+f(281457796857855, 16383);
+f(281474976727040, 16384);
+f(281492156596225, 16385);
+f(562932773584895, 32767);
+f(562949953454080, 32768);
+f(562967133323265, 32769);
+f(1125882727038975, 65535);
+f(1125899906908160, 65536);
+f(1125917086777345, 65537);
diff --git a/regexp2000/test/mjsunit/negate-zero.js b/regexp2000/test/mjsunit/negate-zero.js
new file mode 100644 (file)
index 0000000..31d460a
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function IsNegativeZero(x) {
+  assertEquals(0, x);
+  var y = 1 / x;
+  assertFalse(isFinite(y));
+  return y < 0;
+}
+
+var pz = 0;
+var nz = -0;
+
+assertTrue(IsNegativeZero(nz), "-0");
+assertFalse(IsNegativeZero(-nz), "-(-0)");
+
+assertFalse(IsNegativeZero(pz), "0");
+assertTrue(IsNegativeZero(-pz), "-(0)");
diff --git a/regexp2000/test/mjsunit/negate.js b/regexp2000/test/mjsunit/negate.js
new file mode 100644 (file)
index 0000000..3bf4111
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+const SMI_MAX = (1 << 30) - 1;
+const SMI_MIN = -(1 << 30);
+
+function testmulneg(a, b) {
+  var base = a * b;
+  assertEquals(-base, a * -b);
+  assertEquals(-base, -a * b);
+  assertEquals(base, -a * -b);
+}
+
+testmulneg(2, 3);
+testmulneg(SMI_MAX, 3);
+testmulneg(SMI_MIN, 3);
+testmulneg(3.2, 2.3);
+
+var x = { valueOf: function() { return 2; } };
+var y = { valueOf: function() { return 3; } };
+
+testmulneg(x, y);
+
+// The test below depends on the correct evaluation order, which is not
+// implemented by any of the known JS engines.
+var z;
+var v = { valueOf: function() { z+=2; return z; } };
+var w = { valueOf: function() { z+=3; return z; } };
+
+z = 0;
+var base = v * w;
+z = 0;
+assertEquals(-base, -v * w);
+z = 0;
+assertEquals(base, -v * -w);
diff --git a/regexp2000/test/mjsunit/nested-repetition-count-overflow.js b/regexp2000/test/mjsunit/nested-repetition-count-overflow.js
new file mode 100644 (file)
index 0000000..8f040c3
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var s = "a";
+for (var i = 0; i < 17; i++)
+    s += s;
+
+assertThrows('new RegExp(s);');
+
+assertThrows('/(([ab]){30}){3360}/');
+assertThrows('/(([ab]){30}){0,3360}/');
+assertThrows('/(([ab]){30}){10,3360}/');
+assertThrows('/(([ab]){0,30}){3360}/');
+assertThrows('/(([ab]){0,30}){0,3360}/');
+assertThrows('/(([ab]){0,30}){10,3360}/');
+assertThrows('/(([ab]){10,30}){3360}/');
+assertThrows('/(([ab]){10,30}){0,3360}/');
+assertThrows('/(([ab]){10,30}){10,3360}/');
+assertThrows('/(([ab]){12})(([ab]){65535}){1680}(([ab]){38}){722}([ab]){27}/');
diff --git a/regexp2000/test/mjsunit/new.js b/regexp2000/test/mjsunit/new.js
new file mode 100644 (file)
index 0000000..1062628
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function Construct(x) { return x; }
+
+assertFalse(null == new Construct(null));
+assertFalse(void 0 == new Construct(void 0));
+assertFalse(0 == new Construct(0));
+assertFalse(1 == new Construct(1));
+assertFalse(4.2 == new Construct(4.2));
+assertFalse('foo' == new Construct('foo'));
+assertFalse(true == new Construct(true));
+
+x = {};
+assertTrue(x === new Construct(x));
+assertFalse(x === new Construct(null));
+assertFalse(x === new Construct(void 0));
+assertFalse(x === new Construct(1));
+assertFalse(x === new Construct(3.2));
+assertFalse(x === new Construct(false));
+assertFalse(x === new Construct('bar'));
+x = [];
+assertTrue(x === new Construct(x));
+x = new Boolean(true);
+assertTrue(x === new Construct(x));
+x = new Number(42);
+assertTrue(x === new Construct(x));
+x = new String('foo');
+assertTrue(x === new Construct(x));
+x = function() { };
+assertTrue(x === new Construct(x));
+
diff --git a/regexp2000/test/mjsunit/newline-in-string.js b/regexp2000/test/mjsunit/newline-in-string.js
new file mode 100644 (file)
index 0000000..8c3ff86
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test multiline string literal.
+var str = 'asdf\
+\nasdf\
+\rasdf\
+\tasdf\
+\\\
+\
+';
+assertEquals('asdf\nasdf\rasdf\tasdf\\', str);
+
+// Allow CR+LF in multiline string literals.
+var code = "'asdf\\" + String.fromCharCode(0xD) + String.fromCharCode(0xA) + "asdf'";
+assertEquals('asdfasdf', eval(code));
+
+// Allow LF+CR in multiline string literals.
+code = "'asdf\\" + String.fromCharCode(0xA) + String.fromCharCode(0xD) + "asdf'";
+assertEquals('asdfasdf', eval(code));
+
+
diff --git a/regexp2000/test/mjsunit/no-branch-elimination.js b/regexp2000/test/mjsunit/no-branch-elimination.js
new file mode 100644 (file)
index 0000000..538039b
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Branch elimination on ARM build eliminate bl branches. It was wrong.
+
+if (1 & true) { }
+
+try {
+  throw "error";
+} catch (e) {
+  assertEquals("error", e);
+}
diff --git a/regexp2000/test/mjsunit/no-octal-constants-above-256.js b/regexp2000/test/mjsunit/no-octal-constants-above-256.js
new file mode 100644 (file)
index 0000000..1525d6a
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Octal constants above \377 should not be allowed; instead they
+// should parse as two-digit octals constants followed by digits.
+assertEquals(2, "\400".length);
+assertEquals("\40".charCodeAt(0), "\400".charCodeAt(0));
+assertEquals("0", "\400".charAt(1));
diff --git a/regexp2000/test/mjsunit/no-semicolon.js b/regexp2000/test/mjsunit/no-semicolon.js
new file mode 100644 (file)
index 0000000..fa6ccba
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Random tests to make sure you can leave out semicolons
+// in various places.
+
+function f() { return }
+
+function g() { 
+  return
+    4;
+}
+
+assertTrue(f() === void 0);
+assertTrue(g() === void 0);
+
+for (var i = 0; i < 10; i++) { break }
+assertEquals(0, i);
+
+for (var i = 0; i < 10; i++) { continue }
+assertEquals(10, i);
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/non-ascii-replace.js b/regexp2000/test/mjsunit/non-ascii-replace.js
new file mode 100644 (file)
index 0000000..9807412
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Regression test for bug #743664.
+assertEquals("\x60\x60".replace(/\x60/g, "u"), "uu");
+assertEquals("\xAB\xAB".replace(/\xAB/g, "u"), "uu");
diff --git a/regexp2000/test/mjsunit/nul-characters.js b/regexp2000/test/mjsunit/nul-characters.js
new file mode 100644 (file)
index 0000000..22da82d
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var a = [ '\0', '\u0000', '\x00' ]
+for (var i in a) {
+  assertEquals(1, a[i].length);
+  assertEquals(0, a[i].charCodeAt(0));
+}
+
+assertEquals(7, 'foo\0bar'.length);
+assertEquals(7, 'foo\x00bar'.length);
+assertEquals(7, 'foo\u0000bar'.length);
+
+assertEquals(2, ('\0' + '\0').length);
diff --git a/regexp2000/test/mjsunit/number-limits.js b/regexp2000/test/mjsunit/number-limits.js
new file mode 100644 (file)
index 0000000..1d9a1e5
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ensure that Number.MAX_VALUE and Number.MIN_VALUE are extreme.
+function testLimits() {
+  var i; var eps;
+  for (i = 0, eps = 1; i < 1100; i++, eps /= 2) {
+    var mulAboveMax = Number.MAX_VALUE * (1 + eps);
+    var addAboveMax = Number.MAX_VALUE + 1/eps;
+    var mulBelowMin = Number.MIN_VALUE * (1 - eps);
+    var addBelowMin = Number.MIN_VALUE - eps;
+    assertTrue(mulAboveMax == Number.MAX_VALUE || mulAboveMax == Infinity);
+    assertTrue(addAboveMax == Number.MAX_VALUE || addAboveMax == Infinity);
+    assertTrue(mulBelowMin == Number.MIN_VALUE || mulBelowMin <= 0);
+    assertTrue(addBelowMin == Number.MIN_VALUE || addBelowMin <= 0);
+  }
+}
+
+testLimits();
diff --git a/regexp2000/test/mjsunit/number-string-index-call.js b/regexp2000/test/mjsunit/number-string-index-call.js
new file mode 100644 (file)
index 0000000..6f540c0
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --call_regexp
+var callbacks = [ function() {return 'foo'}, "nonobject", /abc/ ];
+assertEquals('foo', callbacks['0']());
+assertThrows("callbacks['1']()");
+assertEquals('abc', callbacks['2']("abcdefg"));
diff --git a/regexp2000/test/mjsunit/number-tostring-small.js b/regexp2000/test/mjsunit/number-tostring-small.js
new file mode 100644 (file)
index 0000000..dbd2b59
--- /dev/null
@@ -0,0 +1,395 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is a concatenation of the number-tostring and
+// to-precision mjsunit tests where the mjsunit assert code has been
+// removed.
+
+// ----------------------------------------------------------------------
+// toString
+(NaN).toString();
+(1/0).toString();
+(-1/0).toString();
+(0).toString();
+(9).toString();
+(90).toString();
+(90.12).toString();
+(0.1).toString();
+(0.01).toString();
+(0.0123).toString();
+(111111111111111111111).toString();
+(1111111111111111111111).toString();
+(11111111111111111111111).toString();
+(0.00001).toString();
+(0.000001).toString();
+(0.0000001).toString();
+(0.00000012).toString();
+(0.000000123).toString();
+(0.00000001).toString();
+(0.000000012).toString();
+(0.0000000123).toString();
+
+(-0).toString();
+(-9).toString();
+(-90).toString();
+(-90.12).toString();
+(-0.1).toString();
+(-0.01).toString();
+(-0.0123).toString();
+(-111111111111111111111).toString();
+(-1111111111111111111111).toString();
+(-11111111111111111111111).toString();
+(-0.00001).toString();
+(-0.000001).toString();
+(-0.0000001).toString();
+(-0.00000012).toString();
+(-0.000000123).toString();
+(-0.00000001).toString();
+(-0.000000012).toString();
+(-0.0000000123).toString();
+
+(NaN).toString(16);
+(1/0).toString(16);
+(-1/0).toString(16);
+(0).toString(16);
+(9).toString(16);
+(90).toString(16);
+(90.12).toString(16);
+(0.1).toString(16);
+(0.01).toString(16);
+(0.0123).toString(16);
+(111111111111111111111).toString(16);
+(1111111111111111111111).toString(16);
+(11111111111111111111111).toString(16);
+(0.00001).toString(16);
+(0.000001).toString(16);
+(0.0000001).toString(16);
+(0.00000012).toString(16);
+(0.000000123).toString(16);
+(0.00000001).toString(16);
+(0.000000012).toString(16);
+(0.0000000123).toString(16);
+
+(-0).toString(16);
+(-9).toString(16);
+(-90).toString(16);
+(-90.12).toString(16);
+(-0.1).toString(16);
+(-0.01).toString(16);
+(-0.0123).toString(16);
+(-111111111111111111111).toString(16);
+(-1111111111111111111111).toString(16);
+(-11111111111111111111111).toString(16);
+(-0.00001).toString(16);
+(-0.000001).toString(16);
+(-0.0000001).toString(16);
+(-0.00000012).toString(16);
+(-0.000000123).toString(16);
+(-0.00000001).toString(16);
+(-0.000000012).toString(16);
+(-0.0000000123).toString(16);
+
+(2,32).toString();
+(Math.pow(2,32)-1).toString(16);
+(Math.pow(2,32)-1).toString(2);
+(10000007).toString(36);
+(0).toString(36);
+(0).toString(16);
+(0).toString(10);
+(0).toString(8);
+(0).toString(2);
+(2,32).toString(2);
+(Math.pow(2,32) + 1).toString(2);
+(0x100000000000081).toString(16);
+(-(-'0x1000000000000081')).toString(16);
+(0x100000000000081).toString(2);
+(-(Math.pow(2,32)-1)).toString(2);
+(-10000007).toString(36);
+(-Math.pow(2,32)).toString(2);
+(-(Math.pow(2,32) + 1)).toString(2);
+(-0x100000000000081).toString(16);
+(-0x100000000000081).toString(2);
+(1000).toString();
+(0.00001).toString();
+(1000000000000000128).toString();
+(1000000000000000012800).toString();
+(-1000000000000000012800).toString();
+(0.0000001).toString();
+(-0.0000001).toString();
+(1000000000000000128000).toString();
+(0.000001).toString();
+(0.0000001).toString();
+(8.5).toString(16);
+(-8.5).toString(16);
+
+// ----------------------------------------------------------------------
+// toFixed
+(NaN).toFixed(2);
+(1/0).toFixed(2);
+(-1/0).toFixed(2);
+
+(1111111111111111111111).toFixed(8);
+(0.1).toFixed(1);
+(0.1).toFixed(2);
+(0.1).toFixed(3);
+(0.01).toFixed(2);
+(0.01).toFixed(3);
+(0.01).toFixed(4);
+(0.001).toFixed(2);
+(0.001).toFixed(3);
+(0.001).toFixed(4);
+(1).toFixed(4);
+(1).toFixed(1);
+(1).toFixed(0);
+(12).toFixed(0);
+(1.1).toFixed(0);
+(12.1).toFixed(0);
+(1.12).toFixed(0);
+(12.12).toFixed(0);
+(0.0000006).toFixed(7);
+(0.00000006).toFixed(8);
+(0.00000006).toFixed(9);
+(0.00000006).toFixed(10);
+(0).toFixed(0);
+(0).toFixed(1);
+(0).toFixed(2);
+
+(-1111111111111111111111).toFixed(8);
+(-0.1).toFixed(1);
+(-0.1).toFixed(2);
+(-0.1).toFixed(3);
+(-0.01).toFixed(2);
+(-0.01).toFixed(3);
+(-0.01).toFixed(4);
+(-0.001).toFixed(2);
+(-0.001).toFixed(3);
+(-0.001).toFixed(4);
+(-1).toFixed(4);
+(-1).toFixed(1);
+(-1).toFixed(0);
+(-1.1).toFixed(0);
+(-12.1).toFixed(0);
+(-1.12).toFixed(0);
+(-12.12).toFixed(0);
+(-0.0000006).toFixed(7);
+(-0.00000006).toFixed(8);
+(-0.00000006).toFixed(9);
+(-0.00000006).toFixed(10);
+(-0).toFixed(0);
+(-0).toFixed(1);
+(-0).toFixed(2);
+
+(1000).toFixed();
+(0.00001).toFixed();
+(0.00001).toFixed(5);
+(0.0000000000000000001).toFixed(20);
+(0.00001).toFixed(17);
+(1).toFixed(17);
+(1000000000000000128).toFixed();
+(100000000000000128).toFixed(1);
+(10000000000000128).toFixed(2);
+(10000000000000128).toFixed(20);
+(0).toFixed();
+((-42).toFixed(3));
+(-1000000000000000128).toFixed();
+(-0.0000000000000000001).toFixed(20);
+(0.123123123123123).toFixed(20);
+// Test that we round up even when the last digit generated is even.
+// dtoa does not do this in its original form.
+(0.5).toFixed(0);
+(-0.5).toFixed(0);
+(1.25).toFixed(1);
+// This is bizare, but Spidermonkey and KJS behave the same.
+(234.20405).toFixed(4);
+(234.2040506).toFixed(4);
+
+// ----------------------------------------------------------------------
+// toExponential
+(1).toExponential();
+(11).toExponential();
+(112).toExponential();
+(1).toExponential(0);
+(11).toExponential(0);
+(112).toExponential(0);
+(1).toExponential(1);
+(11).toExponential(1);
+(112).toExponential(1);
+(1).toExponential(2);
+(11).toExponential(2);
+(112).toExponential(2);
+(1).toExponential(3);
+(11).toExponential(3);
+(112).toExponential(3);
+(0.1).toExponential();
+(0.11).toExponential();
+(0.112).toExponential();
+(0.1).toExponential(0);
+(0.11).toExponential(0);
+(0.112).toExponential(0);
+(0.1).toExponential(1);
+(0.11).toExponential(1);
+(0.112).toExponential(1);
+(0.1).toExponential(2);
+(0.11).toExponential(2);
+(0.112).toExponential(2);
+(0.1).toExponential(3);
+(0.11).toExponential(3);
+(0.112).toExponential(3);
+
+(-1).toExponential();
+(-11).toExponential();
+(-112).toExponential();
+(-1).toExponential(0);
+(-11).toExponential(0);
+(-112).toExponential(0);
+(-1).toExponential(1);
+(-11).toExponential(1);
+(-112).toExponential(1);
+(-1).toExponential(2);
+(-11).toExponential(2);
+(-112).toExponential(2);
+(-1).toExponential(3);
+(-11).toExponential(3);
+(-112).toExponential(3);
+(-0.1).toExponential();
+(-0.11).toExponential();
+(-0.112).toExponential();
+(-0.1).toExponential(0);
+(-0.11).toExponential(0);
+(-0.112).toExponential(0);
+(-0.1).toExponential(1);
+(-0.11).toExponential(1);
+(-0.112).toExponential(1);
+(-0.1).toExponential(2);
+(-0.11).toExponential(2);
+(-0.112).toExponential(2);
+(-0.1).toExponential(3);
+(-0.11).toExponential(3);
+(-0.112).toExponential(3);
+
+(NaN).toExponential(2);
+(Infinity).toExponential(2);
+(-Infinity).toExponential(2);
+(1).toExponential(0);
+(0).toExponential();
+(0).toExponential(2);
+(11.2356).toExponential(0);
+(11.2356).toExponential(4);
+(0.000112356).toExponential(4);
+(-0.000112356).toExponential(4);
+(0.000112356).toExponential();
+(-0.000112356).toExponential();
+
+// ----------------------------------------------------------------------
+// toPrecision
+(NaN).toPrecision(1);
+(Infinity).toPrecision(2);
+(-Infinity).toPrecision(2);
+(0.000555).toPrecision(15);
+(0.000000555).toPrecision(15);
+(-0.000000555).toPrecision(15);
+(123456789).toPrecision(1);
+(123456789).toPrecision(9);
+(123456789).toPrecision(8);
+(123456789).toPrecision(7);
+(-123456789).toPrecision(7);
+(-.0000000012345).toPrecision(2);
+(-.000000012345).toPrecision(2);
+(-.00000012345).toPrecision(2);
+(-.0000012345).toPrecision(2);
+(-.000012345).toPrecision(2);
+(-.00012345).toPrecision(2);
+(-.0012345).toPrecision(2);
+(-.012345).toPrecision(2);
+(-.12345).toPrecision(2);
+(-1.2345).toPrecision(2);
+(-12.345).toPrecision(2);
+(-123.45).toPrecision(2);
+(-1234.5).toPrecision(2);
+(-12345).toPrecision(2);
+(-12345.67).toPrecision(4);
+Number(-12344.67).toPrecision(4);
+// Test that we round up even when the last digit generated is even.
+// dtoa does not do this in its original form.
+(1.25).toPrecision(2);
+(1.35).toPrecision(2);
+
+// Test the exponential notation output.
+(1.2345e+27).toPrecision(1);
+(1.2345e+27).toPrecision(2);
+(1.2345e+27).toPrecision(3);
+(1.2345e+27).toPrecision(4);
+(1.2345e+27).toPrecision(5);
+(1.2345e+27).toPrecision(6);
+(1.2345e+27).toPrecision(7);
+
+(-1.2345e+27).toPrecision(1);
+(-1.2345e+27).toPrecision(2);
+(-1.2345e+27).toPrecision(3);
+(-1.2345e+27).toPrecision(4);
+(-1.2345e+27).toPrecision(5);
+(-1.2345e+27).toPrecision(6);
+(-1.2345e+27).toPrecision(7);
+
+
+// Test the fixed notation output.
+(7).toPrecision(1);
+(7).toPrecision(2);
+(7).toPrecision(3);
+
+(-7).toPrecision(1);
+(-7).toPrecision(2);
+(-7).toPrecision(3);
+
+(91).toPrecision(1);
+(91).toPrecision(2);
+(91).toPrecision(3);
+(91).toPrecision(4);
+
+(-91).toPrecision(1);
+(-91).toPrecision(2);
+(-91).toPrecision(3);
+(-91).toPrecision(4);
+
+(91.1234).toPrecision(1);
+(91.1234).toPrecision(2);
+(91.1234).toPrecision(3);
+(91.1234).toPrecision(4);
+(91.1234).toPrecision(5);
+(91.1234).toPrecision(6);
+(91.1234).toPrecision(7);
+(91.1234).toPrecision(8);
+
+(-91.1234).toPrecision(1);
+(-91.1234).toPrecision(2);
+(-91.1234).toPrecision(3);
+(-91.1234).toPrecision(4);
+(-91.1234).toPrecision(5);
+(-91.1234).toPrecision(6);
+(-91.1234).toPrecision(7);
+(-91.1234).toPrecision(8);
+
diff --git a/regexp2000/test/mjsunit/number-tostring.js b/regexp2000/test/mjsunit/number-tostring.js
new file mode 100644 (file)
index 0000000..04d027f
--- /dev/null
@@ -0,0 +1,338 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ----------------------------------------------------------------------
+// toString
+assertEquals("NaN", (NaN).toString());
+assertEquals("Infinity", (1/0).toString());
+assertEquals("-Infinity", (-1/0).toString());
+assertEquals("0", (0).toString());
+assertEquals("9", (9).toString());
+assertEquals("90", (90).toString());
+assertEquals("90.12", (90.12).toString());
+assertEquals("0.1", (0.1).toString());
+assertEquals("0.01", (0.01).toString());
+assertEquals("0.0123", (0.0123).toString());
+assertEquals("111111111111111110000", (111111111111111111111).toString());
+assertEquals("1.1111111111111111e+21", (1111111111111111111111).toString());
+assertEquals("1.1111111111111111e+22", (11111111111111111111111).toString());
+assertEquals("0.00001", (0.00001).toString());
+assertEquals("0.000001", (0.000001).toString());
+assertEquals("1e-7", (0.0000001).toString());
+assertEquals("1.2e-7", (0.00000012).toString());
+assertEquals("1.23e-7", (0.000000123).toString());
+assertEquals("1e-8", (0.00000001).toString());
+assertEquals("1.2e-8", (0.000000012).toString());
+assertEquals("1.23e-8", (0.0000000123).toString());
+
+assertEquals("0", (-0).toString());
+assertEquals("-9", (-9).toString());
+assertEquals("-90", (-90).toString());
+assertEquals("-90.12", (-90.12).toString());
+assertEquals("-0.1", (-0.1).toString());
+assertEquals("-0.01", (-0.01).toString());
+assertEquals("-0.0123", (-0.0123).toString())
+assertEquals("-111111111111111110000", (-111111111111111111111).toString());
+assertEquals("-1.1111111111111111e+21", (-1111111111111111111111).toString());
+assertEquals("-1.1111111111111111e+22", (-11111111111111111111111).toString());
+assertEquals("-0.00001", (-0.00001).toString());
+assertEquals("-0.000001", (-0.000001).toString());
+assertEquals("-1e-7", (-0.0000001).toString());
+assertEquals("-1.2e-7", (-0.00000012).toString());
+assertEquals("-1.23e-7", (-0.000000123).toString());
+assertEquals("-1e-8", (-0.00000001).toString());
+assertEquals("-1.2e-8", (-0.000000012).toString());
+assertEquals("-1.23e-8", (-0.0000000123).toString());
+
+assertEquals("NaN", (NaN).toString(16));
+assertEquals("Infinity", (1/0).toString(16));
+assertEquals("-Infinity", (-1/0).toString(16));
+assertEquals("0", (0).toString(16));
+assertEquals("9", (9).toString(16));
+assertEquals("5a", (90).toString(16));
+assertEquals("5a.1eb851eb852", (90.12).toString(16));
+assertEquals("0.1999999999999a", (0.1).toString(16));
+assertEquals("0.028f5c28f5c28f6", (0.01).toString(16));
+assertEquals("0.032617c1bda511a", (0.0123).toString(16));
+assertEquals("605f9f6dd18bc8000", (111111111111111111111).toString(16));
+assertEquals("3c3bc3a4a2f75c0000", (1111111111111111111111).toString(16));
+assertEquals("25a55a46e5da9a00000", (11111111111111111111111).toString(16));
+assertEquals("0.0000a7c5ac471b4788", (0.00001).toString(16));
+assertEquals("0.000010c6f7a0b5ed8d", (0.000001).toString(16));
+assertEquals("0.000001ad7f29abcaf48", (0.0000001).toString(16));
+assertEquals("0.000002036565348d256", (0.00000012).toString(16));
+assertEquals("0.0000021047ee22aa466", (0.000000123).toString(16));
+assertEquals("0.0000002af31dc4611874", (0.00000001).toString(16));
+assertEquals("0.000000338a23b87483be", (0.000000012).toString(16));
+assertEquals("0.00000034d3fe36aaa0a2", (0.0000000123).toString(16));
+
+assertEquals("0", (-0).toString(16));
+assertEquals("-9", (-9).toString(16));
+assertEquals("-5a", (-90).toString(16));
+assertEquals("-5a.1eb851eb852", (-90.12).toString(16));
+assertEquals("-0.1999999999999a", (-0.1).toString(16));
+assertEquals("-0.028f5c28f5c28f6", (-0.01).toString(16));
+assertEquals("-0.032617c1bda511a", (-0.0123).toString(16));
+assertEquals("-605f9f6dd18bc8000", (-111111111111111111111).toString(16));
+assertEquals("-3c3bc3a4a2f75c0000", (-1111111111111111111111).toString(16));
+assertEquals("-25a55a46e5da9a00000", (-11111111111111111111111).toString(16));
+assertEquals("-0.0000a7c5ac471b4788", (-0.00001).toString(16));
+assertEquals("-0.000010c6f7a0b5ed8d", (-0.000001).toString(16));
+assertEquals("-0.000001ad7f29abcaf48", (-0.0000001).toString(16));
+assertEquals("-0.000002036565348d256", (-0.00000012).toString(16));
+assertEquals("-0.0000021047ee22aa466", (-0.000000123).toString(16));
+assertEquals("-0.0000002af31dc4611874", (-0.00000001).toString(16));
+assertEquals("-0.000000338a23b87483be", (-0.000000012).toString(16));
+assertEquals("-0.00000034d3fe36aaa0a2", (-0.0000000123).toString(16));
+
+assertEquals("4294967296", Math.pow(2,32).toString());
+assertEquals("ffffffff", (Math.pow(2,32)-1).toString(16));
+assertEquals("11111111111111111111111111111111", (Math.pow(2,32)-1).toString(2));
+assertEquals("5yc1z", (10000007).toString(36));
+assertEquals("0", (0).toString(36));
+assertEquals("0", (0).toString(16));
+assertEquals("0", (0).toString(10));
+assertEquals("0", (0).toString(8));
+assertEquals("0", (0).toString(2));
+assertEquals("100000000000000000000000000000000", Math.pow(2,32).toString(2));
+assertEquals("100000000000000000000000000000001", (Math.pow(2,32) + 1).toString(2));
+assertEquals("100000000000080", (0x100000000000081).toString(16));
+assertEquals("1000000000000100", (-(-'0x1000000000000081')).toString(16));
+assertEquals("100000000000000000000000000000000000000000000000010000000", (0x100000000000081).toString(2));
+assertEquals("-11111111111111111111111111111111", (-(Math.pow(2,32)-1)).toString(2));
+assertEquals("-5yc1z", (-10000007).toString(36));
+assertEquals("-100000000000000000000000000000000", (-Math.pow(2,32)).toString(2));
+assertEquals("-100000000000000000000000000000001", (-(Math.pow(2,32) + 1)).toString(2));
+assertEquals("-100000000000080", (-0x100000000000081).toString(16));
+assertEquals("-100000000000000000000000000000000000000000000000010000000", (-0x100000000000081).toString(2));
+assertEquals("1000", (1000).toString());
+assertEquals("0.00001", (0.00001).toString());
+assertEquals("1000000000000000100", (1000000000000000128).toString());
+assertEquals("1e+21", (1000000000000000012800).toString());
+assertEquals("-1e+21", (-1000000000000000012800).toString());
+assertEquals("1e-7", (0.0000001).toString());
+assertEquals("-1e-7", (-0.0000001).toString());
+assertEquals("1.0000000000000001e+21", (1000000000000000128000).toString());
+assertEquals("0.000001", (0.000001).toString());
+assertEquals("1e-7", (0.0000001).toString());
+assertEquals("8.8", (8.5).toString(16));
+assertEquals("-8.8", (-8.5).toString(16));
+
+// ----------------------------------------------------------------------
+// toFixed
+assertEquals("NaN", (NaN).toFixed(2));
+assertEquals("Infinity", (1/0).toFixed(2));
+assertEquals("-Infinity", (-1/0).toFixed(2));
+
+assertEquals("1.1111111111111111e+21", (1111111111111111111111).toFixed(8));
+assertEquals("0.1", (0.1).toFixed(1));
+assertEquals("0.10", (0.1).toFixed(2));
+assertEquals("0.100", (0.1).toFixed(3));
+assertEquals("0.01", (0.01).toFixed(2));
+assertEquals("0.010", (0.01).toFixed(3));
+assertEquals("0.0100", (0.01).toFixed(4));
+assertEquals("0.00", (0.001).toFixed(2));
+assertEquals("0.001", (0.001).toFixed(3));
+assertEquals("0.0010", (0.001).toFixed(4));
+assertEquals("1.0000", (1).toFixed(4));
+assertEquals("1.0", (1).toFixed(1));
+assertEquals("1", (1).toFixed(0));
+assertEquals("12", (12).toFixed(0));
+assertEquals("1", (1.1).toFixed(0));
+assertEquals("12", (12.1).toFixed(0));
+assertEquals("1", (1.12).toFixed(0));
+assertEquals("12", (12.12).toFixed(0));
+assertEquals("0.0000006", (0.0000006).toFixed(7));
+assertEquals("0.00000006", (0.00000006).toFixed(8));
+assertEquals("0.000000060", (0.00000006).toFixed(9));
+assertEquals("0.0000000600", (0.00000006).toFixed(10));
+assertEquals("0", (0).toFixed(0));
+assertEquals("0.0", (0).toFixed(1));
+assertEquals("0.00", (0).toFixed(2));
+
+assertEquals("-1.1111111111111111e+21", (-1111111111111111111111).toFixed(8));
+assertEquals("-0.1", (-0.1).toFixed(1));
+assertEquals("-0.10", (-0.1).toFixed(2));
+assertEquals("-0.100", (-0.1).toFixed(3));
+assertEquals("-0.01", (-0.01).toFixed(2));
+assertEquals("-0.010", (-0.01).toFixed(3));
+assertEquals("-0.0100", (-0.01).toFixed(4));
+assertEquals("-0.00", (-0.001).toFixed(2));
+assertEquals("-0.001", (-0.001).toFixed(3));
+assertEquals("-0.0010", (-0.001).toFixed(4));
+assertEquals("-1.0000", (-1).toFixed(4));
+assertEquals("-1.0", (-1).toFixed(1));
+assertEquals("-1", (-1).toFixed(0));
+assertEquals("-1", (-1.1).toFixed(0));
+assertEquals("-12", (-12.1).toFixed(0));
+assertEquals("-1", (-1.12).toFixed(0));
+assertEquals("-12", (-12.12).toFixed(0));
+assertEquals("-0.0000006", (-0.0000006).toFixed(7));
+assertEquals("-0.00000006", (-0.00000006).toFixed(8));
+assertEquals("-0.000000060", (-0.00000006).toFixed(9));
+assertEquals("-0.0000000600", (-0.00000006).toFixed(10));
+assertEquals("0", (-0).toFixed(0));
+assertEquals("0.0", (-0).toFixed(1));
+assertEquals("0.00", (-0).toFixed(2));
+
+assertEquals("1000", (1000).toFixed());
+assertEquals("0", (0.00001).toFixed());
+assertEquals("0.00001", (0.00001).toFixed(5));
+assertEquals("0.00000000000000000010", (0.0000000000000000001).toFixed(20));
+assertEquals("0.00001000000000000", (0.00001).toFixed(17));
+assertEquals("1.00000000000000000", (1).toFixed(17));
+assertEquals("1000000000000000128", (1000000000000000128).toFixed());
+assertEquals("100000000000000128.0", (100000000000000128).toFixed(1));
+assertEquals("10000000000000128.00", (10000000000000128).toFixed(2));
+assertEquals("10000000000000128.00000000000000000000", (10000000000000128).toFixed(20));
+assertEquals("0", (0).toFixed());
+assertEquals("-42.000", ((-42).toFixed(3)));
+assertEquals("-1000000000000000128", (-1000000000000000128).toFixed());
+assertEquals("-0.00000000000000000010", (-0.0000000000000000001).toFixed(20));
+assertEquals("0.12312312312312299889", (0.123123123123123).toFixed(20));
+// Test that we round up even when the last digit generated is even.
+// dtoa does not do this in its original form.
+assertEquals("1", 0.5.toFixed(0), "0.5.toFixed(0)");
+assertEquals("-1", -0.5.toFixed(0), "-0.5.toFixed(0)");
+assertEquals("1.3", 1.25.toFixed(1), "1.25.toFixed(1)");
+// This is bizare, but Spidermonkey and KJS behave the same.
+assertEquals("234.2040", (234.20405).toFixed(4), "234.2040.toFixed(4)");
+assertEquals("234.2041", (234.2040506).toFixed(4));
+
+// ----------------------------------------------------------------------
+// toExponential
+assertEquals("1e+0", (1).toExponential());
+assertEquals("1.1e+1", (11).toExponential());
+assertEquals("1.12e+2", (112).toExponential());
+assertEquals("1e+0", (1).toExponential(0));
+assertEquals("1e+1", (11).toExponential(0));
+assertEquals("1e+2", (112).toExponential(0));
+assertEquals("1.0e+0", (1).toExponential(1));
+assertEquals("1.1e+1", (11).toExponential(1));
+assertEquals("1.1e+2", (112).toExponential(1));
+assertEquals("1.00e+0", (1).toExponential(2));
+assertEquals("1.10e+1", (11).toExponential(2));
+assertEquals("1.12e+2", (112).toExponential(2));
+assertEquals("1.000e+0", (1).toExponential(3));
+assertEquals("1.100e+1", (11).toExponential(3));
+assertEquals("1.120e+2", (112).toExponential(3));
+assertEquals("1e-1", (0.1).toExponential());
+assertEquals("1.1e-1", (0.11).toExponential());
+assertEquals("1.12e-1", (0.112).toExponential());
+assertEquals("1e-1", (0.1).toExponential(0));
+assertEquals("1e-1", (0.11).toExponential(0));
+assertEquals("1e-1", (0.112).toExponential(0));
+assertEquals("1.0e-1", (0.1).toExponential(1));
+assertEquals("1.1e-1", (0.11).toExponential(1));
+assertEquals("1.1e-1", (0.112).toExponential(1));
+assertEquals("1.00e-1", (0.1).toExponential(2));
+assertEquals("1.10e-1", (0.11).toExponential(2));
+assertEquals("1.12e-1", (0.112).toExponential(2));
+assertEquals("1.000e-1", (0.1).toExponential(3));
+assertEquals("1.100e-1", (0.11).toExponential(3));
+assertEquals("1.120e-1", (0.112).toExponential(3));
+
+assertEquals("-1e+0", (-1).toExponential());
+assertEquals("-1.1e+1", (-11).toExponential());
+assertEquals("-1.12e+2", (-112).toExponential());
+assertEquals("-1e+0", (-1).toExponential(0));
+assertEquals("-1e+1", (-11).toExponential(0));
+assertEquals("-1e+2", (-112).toExponential(0));
+assertEquals("-1.0e+0", (-1).toExponential(1));
+assertEquals("-1.1e+1", (-11).toExponential(1));
+assertEquals("-1.1e+2", (-112).toExponential(1));
+assertEquals("-1.00e+0", (-1).toExponential(2));
+assertEquals("-1.10e+1", (-11).toExponential(2));
+assertEquals("-1.12e+2", (-112).toExponential(2));
+assertEquals("-1.000e+0", (-1).toExponential(3));
+assertEquals("-1.100e+1", (-11).toExponential(3));
+assertEquals("-1.120e+2", (-112).toExponential(3));
+assertEquals("-1e-1", (-0.1).toExponential());
+assertEquals("-1.1e-1", (-0.11).toExponential());
+assertEquals("-1.12e-1", (-0.112).toExponential());
+assertEquals("-1e-1", (-0.1).toExponential(0));
+assertEquals("-1e-1", (-0.11).toExponential(0));
+assertEquals("-1e-1", (-0.112).toExponential(0));
+assertEquals("-1.0e-1", (-0.1).toExponential(1));
+assertEquals("-1.1e-1", (-0.11).toExponential(1));
+assertEquals("-1.1e-1", (-0.112).toExponential(1));
+assertEquals("-1.00e-1", (-0.1).toExponential(2));
+assertEquals("-1.10e-1", (-0.11).toExponential(2));
+assertEquals("-1.12e-1", (-0.112).toExponential(2));
+assertEquals("-1.000e-1", (-0.1).toExponential(3));
+assertEquals("-1.100e-1", (-0.11).toExponential(3));
+assertEquals("-1.120e-1", (-0.112).toExponential(3));
+
+assertEquals("NaN", (NaN).toExponential(2));
+assertEquals("Infinity", (Infinity).toExponential(2));
+assertEquals("-Infinity", (-Infinity).toExponential(2));
+assertEquals("1e+0", (1).toExponential(0));
+assertEquals("0e+0", (0).toExponential());
+assertEquals("0.00e+0", (0).toExponential(2));
+assertEquals("1e+1", (11.2356).toExponential(0));
+assertEquals("1.1236e+1", (11.2356).toExponential(4));
+assertEquals("1.1236e-4", (0.000112356).toExponential(4));
+assertEquals("-1.1236e-4", (-0.000112356).toExponential(4));
+assertEquals("1.12356e-4", (0.000112356).toExponential());
+assertEquals("-1.12356e-4", (-0.000112356).toExponential());
+
+// ----------------------------------------------------------------------
+// toPrecision
+assertEquals("NaN", (NaN).toPrecision(1));
+assertEquals("Infinity", (Infinity).toPrecision(2));
+assertEquals("-Infinity", (-Infinity).toPrecision(2));
+assertEquals("0.000555000000000000", (0.000555).toPrecision(15));
+assertEquals("5.55000000000000e-7", (0.000000555).toPrecision(15));
+assertEquals("-5.55000000000000e-7", (-0.000000555).toPrecision(15));
+assertEquals("1e+8", (123456789).toPrecision(1));
+assertEquals("123456789", (123456789).toPrecision(9));
+assertEquals("1.2345679e+8", (123456789).toPrecision(8));
+assertEquals("1.234568e+8", (123456789).toPrecision(7));
+assertEquals("-1.234568e+8", (-123456789).toPrecision(7));
+assertEquals("-1.2e-9", Number(-.0000000012345).toPrecision(2));
+assertEquals("-1.2e-8", Number(-.000000012345).toPrecision(2));
+assertEquals("-1.2e-7", Number(-.00000012345).toPrecision(2));
+assertEquals("-0.0000012", Number(-.0000012345).toPrecision(2));
+assertEquals("-0.000012", Number(-.000012345).toPrecision(2));
+assertEquals("-0.00012", Number(-.00012345).toPrecision(2));
+assertEquals("-0.0012", Number(-.0012345).toPrecision(2));
+assertEquals("-0.012", Number(-.012345).toPrecision(2));
+assertEquals("-0.12", Number(-.12345).toPrecision(2));
+assertEquals("-1.2", Number(-1.2345).toPrecision(2));
+assertEquals("-12", Number(-12.345).toPrecision(2));
+assertEquals("-1.2e+2", Number(-123.45).toPrecision(2));
+assertEquals("-1.2e+3", Number(-1234.5).toPrecision(2));
+assertEquals("-1.2e+4", Number(-12345).toPrecision(2));
+assertEquals("-1.235e+4", Number(-12345.67).toPrecision(4));
+assertEquals("-1.234e+4", Number(-12344.67).toPrecision(4));
+// Test that we round up even when the last digit generated is even.
+// dtoa does not do this in its original form.
+assertEquals("1.3", 1.25.toPrecision(2), "1.25.toPrecision(2)");
+assertEquals("1.4", 1.35.toPrecision(2), "1.35.toPrecision(2)");
+
+
+
diff --git a/regexp2000/test/mjsunit/obj-construct.js b/regexp2000/test/mjsunit/obj-construct.js
new file mode 100644 (file)
index 0000000..98e09b2
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var consCalled = false;
+
+function Object() {
+  consCalled = true;
+}
+
+function Array() {
+  consCalled = true;
+}
+
+assertFalse(consCalled);
+var x1 = { };
+assertFalse(consCalled);
+var x2 = { a: 3, b: 4 };
+assertFalse(consCalled);
+var x3 = [ ];
+assertFalse(consCalled);
+var x4 = [ 1, 2, 3 ];
+assertFalse(consCalled);
diff --git a/regexp2000/test/mjsunit/parse-int-float.js b/regexp2000/test/mjsunit/parse-int-float.js
new file mode 100644 (file)
index 0000000..ad2275e
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertEquals(0, parseInt('0'));
+assertEquals(0, parseInt(' 0'));
+assertEquals(0, parseInt(' 0 '));
+
+assertEquals(63, parseInt('077'));
+assertEquals(63, parseInt('  077'));
+assertEquals(63, parseInt('  077   '));
+assertEquals(-63, parseInt('  -077'));
+
+assertEquals(3, parseInt('11', 2));
+assertEquals(4, parseInt('11', 3));
+
+assertEquals(0x12, parseInt('0x12'));
+assertEquals(0x12, parseInt('0x12', 16));
+
+assertEquals(12, parseInt('12aaa'));
+
+assertEquals(0.1, parseFloat('0.1'));
+assertEquals(0.1, parseFloat('0.1aaa'));
+assertEquals(0, parseFloat('0x12'));
+assertEquals(77, parseFloat('077'));
+
+
+var i;
+var y = 10;
+
+for (i = 1; i < 21; i++) {
+  var x = eval("1.2e" + i);
+  assertEquals(Math.floor(x), parseInt(x));
+  x = eval("1e" + i);
+  assertEquals(x, y);
+  y *= 10;
+  assertEquals(Math.floor(x), parseInt(x));
+  x = eval("-1e" + i);
+  assertEquals(Math.ceil(x), parseInt(x));
+  x = eval("-1.2e" + i);
+  assertEquals(Math.ceil(x), parseInt(x));
+}
+
+for (i = 21; i < 53; i++) {
+  var x = eval("1e" + i);
+  assertEquals(1, parseInt(x));
+  x = eval("-1e" + i);
+  assertEquals(-1, parseInt(x));
+}
+
+assertTrue(isNaN(parseInt(0/0)));
+assertTrue(isNaN(parseInt(1/0)), "parseInt Infinity");
+assertTrue(isNaN(parseInt(-1/0)), "parseInt -Infinity");
+
+assertTrue(isNaN(parseFloat(0/0)));
+assertEquals(Infinity, parseFloat(1/0), "parseFloat Infinity");
+assertEquals(-Infinity, parseFloat(-1/0), "parseFloat -Infinity");
+
+
diff --git a/regexp2000/test/mjsunit/property-object-key.js b/regexp2000/test/mjsunit/property-object-key.js
new file mode 100644 (file)
index 0000000..5eb1e1b
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var key = { toString: function() { return 'baz'; } }
+var object = { baz: 42 };
+
+assertEquals(42, object[key]);
+object[key] = 87;
+assertEquals(87, object[key]);
+object[key]++;
+assertEquals(88, object[key]);
+
diff --git a/regexp2000/test/mjsunit/proto.js b/regexp2000/test/mjsunit/proto.js
new file mode 100644 (file)
index 0000000..faf98b2
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var o1 = { x: 12 };
+
+var o2 = { x: 12, y: 13 };
+delete o2.x;  // normalize
+
+assertTrue(o1.__proto__ === o2.__proto__);
diff --git a/regexp2000/test/mjsunit/prototype.js b/regexp2000/test/mjsunit/prototype.js
new file mode 100644 (file)
index 0000000..bfc1a79
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function A() { }
+function B() { }
+function C() { }
+
+function NewC() {
+  A.prototype = {};
+  B.prototype = new A();
+  C.prototype = new B();
+  var result = new C();
+  result.A = A.prototype;
+  result.B = B.prototype;
+  result.C = C.prototype;
+  return result;
+}
+
+// Check that we can read properties defined in prototypes.
+var c = NewC();
+c.A.x = 1;
+c.B.y = 2;
+c.C.z = 3;
+assertEquals(1, c.x);
+assertEquals(2, c.y);
+assertEquals(3, c.z);
+
+var c = NewC();
+c.A.x = 0;
+for (var i = 0; i < 2; i++) {
+  assertEquals(i, c.x);
+  c.B.x = 1;
+}
+
+
+// Regression test:
+// Make sure we preserve the prototype of an object in the face of map transitions.
+
+function D() {
+  this.d = 1;
+}
+var p = new Object();
+p.y = 1;
+new D();
+
+D.prototype = p
+assertEquals(1, (new D).y);
+
+
+// Regression test:
+// Make sure that arrays and functions in the prototype chain works;
+// check length.
+function X() { }
+function Y() { }
+
+X.prototype = function(a,b) { };
+Y.prototype = [1,2,3];
+
+assertEquals(2, (new X).length);
+assertEquals(3, (new Y).length);
+
+
+// Test setting the length of an object where the prototype is from an array.
+var test = new Object;
+test.__proto__ = (new Array()).__proto__;
+test.length = 14;
+assertEquals(14, test.length);
+
+
diff --git a/regexp2000/test/mjsunit/regexp-indexof.js b/regexp2000/test/mjsunit/regexp-indexof.js
new file mode 100644 (file)
index 0000000..9b064b0
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function CheckMatch(re, str, matches) {
+  assertEquals(matches.length > 0, re.test(str));
+  var result = str.match(re);
+  if (matches.length > 0) {
+    assertEquals(matches.length, result.length);
+    for (idx in matches) {
+      var from = matches[idx][0];
+      var length = matches[idx][1];
+      var expected = str.substr(from, length);
+      assertEquals(expected, result[idx]);
+    }
+    assertEquals(expected, RegExp.lastMatch);
+    assertEquals(str.substr(0, from), RegExp.leftContext);
+    assertEquals(str.substr(from + length), RegExp.rightContext);
+  } else {
+    assertTrue(result === null);
+  }
+}
+
+CheckMatch(/abc/, "xxxabcxxxabcxxx", [[3, 3]]);
+CheckMatch(/abc/g, "xxxabcxxxabcxxx", [[3, 3], [9, 3]]);
+CheckMatch(/abc/, "xxxabababcxxxabcxxx", [[7, 3]]);
+CheckMatch(/abc/g, "abcabcabc", [[0, 3], [3, 3], [6, 3]]);
+CheckMatch(/aba/g, "ababababa", [[0, 3], [4, 3]]);
+CheckMatch(/foo/g, "ofooofoooofofooofo", [[1, 3], [5, 3], [12, 3]]);
+CheckMatch(/foobarbaz/, "xx", []);
+CheckMatch(new RegExp(""), "xxx", [[0, 0]]);
+CheckMatch(/abc/, "abababa", []);
+
+assertEquals("xxxdefxxxdefxxx", "xxxabcxxxabcxxx".replace(/abc/g, "def"));
+assertEquals("o-o-oofo-ofo", "ofooofoooofofooofo".replace(/foo/g, "-"));
+assertEquals("deded", "deded".replace(/x/g, "-"));
+assertEquals("-a-b-c-d-e-f-", "abcdef".replace(new RegExp("", "g"), "-"));
diff --git a/regexp2000/test/mjsunit/regexp-multiline-stack-trace.js b/regexp2000/test/mjsunit/regexp-multiline-stack-trace.js
new file mode 100644 (file)
index 0000000..aa2de88
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --trace-calls --preallocate-message-memory
+
+/**
+ * @fileoverview Check that various regexp constructs work as intended.
+ * Particularly those regexps that use ^ and $.
+ */
+
+assertTrue(/^bar/.test("bar"));
+assertTrue(/^bar/.test("bar\nfoo"));
+assertFalse(/^bar/.test("foo\nbar"));
+assertTrue(/^bar/m.test("bar"));
+assertTrue(/^bar/m.test("bar\nfoo"));
+assertTrue(/^bar/m.test("foo\nbar"));
+
+assertTrue(/bar$/.test("bar"));
+assertFalse(/bar$/.test("bar\nfoo"));
+assertTrue(/bar$/.test("foo\nbar"));
+assertTrue(/bar$/m.test("bar"));
+assertTrue(/bar$/m.test("bar\nfoo"));
+assertTrue(/bar$/m.test("foo\nbar"));
+
+assertFalse(/^bxr/.test("bar"));
+assertFalse(/^bxr/.test("bar\nfoo"));
+assertFalse(/^bxr/m.test("bar"));
+assertFalse(/^bxr/m.test("bar\nfoo"));
+assertFalse(/^bxr/m.test("foo\nbar"));
+
+assertFalse(/bxr$/.test("bar"));
+assertFalse(/bxr$/.test("foo\nbar"));
+assertFalse(/bxr$/m.test("bar"));
+assertFalse(/bxr$/m.test("bar\nfoo"));
+assertFalse(/bxr$/m.test("foo\nbar"));
+
+
+assertTrue(/^.*$/.test(""));
+assertTrue(/^.*$/.test("foo"));
+assertFalse(/^.*$/.test("\n"));
+assertTrue(/^.*$/m.test("\n"));
+
+assertTrue(/^[\s]*$/.test(" "));
+assertTrue(/^[\s]*$/.test("\n"));
+
+assertTrue(/^[^]*$/.test(""));
+assertTrue(/^[^]*$/.test("foo"));
+assertTrue(/^[^]*$/.test("\n"));
+
+assertTrue(/^([()\s]|.)*$/.test("()\n()"));
+assertTrue(/^([()\n]|.)*$/.test("()\n()"));
+assertFalse(/^([()]|.)*$/.test("()\n()"));
+assertTrue(/^([()]|.)*$/m.test("()\n()"));
+assertTrue(/^([()]|.)*$/m.test("()\n"));
+assertTrue(/^[()]*$/m.test("()\n."));
+
+assertTrue(/^[\].]*$/.test("...]..."));
+
+
+function check_case(lc, uc) {
+  var a = new RegExp("^" + lc + "$");
+  assertFalse(a.test(uc));
+  a = new RegExp("^" + lc + "$", "i");
+  assertTrue(a.test(uc));
+
+  var A = new RegExp("^" + uc + "$");
+  assertFalse(A.test(lc));
+  A = new RegExp("^" + uc + "$", "i");
+  assertTrue(A.test(lc));
+
+  a = new RegExp("^[" + lc + "]$");
+  assertFalse(a.test(uc));
+  a = new RegExp("^[" + lc + "]$", "i");
+  assertTrue(a.test(uc));
+
+  A = new RegExp("^[" + uc + "]$");
+  assertFalse(A.test(lc));
+  A = new RegExp("^[" + uc + "]$", "i");
+  assertTrue(A.test(lc));
+}
+
+
+check_case("a", "A");
+// Aring
+check_case(String.fromCharCode(229), String.fromCharCode(197));
+// Russian G
+check_case(String.fromCharCode(0x413), String.fromCharCode(0x433));
+
+
+assertThrows("a = new RegExp('[z-a]');");
diff --git a/regexp2000/test/mjsunit/regexp-multiline.js b/regexp2000/test/mjsunit/regexp-multiline.js
new file mode 100644 (file)
index 0000000..32edf25
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Check that various regexp constructs work as intended.
+ * Particularly those regexps that use ^ and $.
+ */
+
+assertTrue(/^bar/.test("bar"));
+assertTrue(/^bar/.test("bar\nfoo"));
+assertFalse(/^bar/.test("foo\nbar"));
+assertTrue(/^bar/m.test("bar"));
+assertTrue(/^bar/m.test("bar\nfoo"));
+assertTrue(/^bar/m.test("foo\nbar"));
+
+assertTrue(/bar$/.test("bar"));
+assertFalse(/bar$/.test("bar\nfoo"));
+assertTrue(/bar$/.test("foo\nbar"));
+assertTrue(/bar$/m.test("bar"));
+assertTrue(/bar$/m.test("bar\nfoo"));
+assertTrue(/bar$/m.test("foo\nbar"));
+
+assertFalse(/^bxr/.test("bar"));
+assertFalse(/^bxr/.test("bar\nfoo"));
+assertFalse(/^bxr/m.test("bar"));
+assertFalse(/^bxr/m.test("bar\nfoo"));
+assertFalse(/^bxr/m.test("foo\nbar"));
+
+assertFalse(/bxr$/.test("bar"));
+assertFalse(/bxr$/.test("foo\nbar"));
+assertFalse(/bxr$/m.test("bar"));
+assertFalse(/bxr$/m.test("bar\nfoo"));
+assertFalse(/bxr$/m.test("foo\nbar"));
+
+
+assertTrue(/^.*$/.test(""));
+assertTrue(/^.*$/.test("foo"));
+assertFalse(/^.*$/.test("\n"));
+assertTrue(/^.*$/m.test("\n"));
+
+assertTrue(/^[\s]*$/.test(" "));
+assertTrue(/^[\s]*$/.test("\n"));
+
+assertTrue(/^[^]*$/.test(""));
+assertTrue(/^[^]*$/.test("foo"));
+assertTrue(/^[^]*$/.test("\n"));
+
+assertTrue(/^([()\s]|.)*$/.test("()\n()"));
+assertTrue(/^([()\n]|.)*$/.test("()\n()"));
+assertFalse(/^([()]|.)*$/.test("()\n()"));
+assertTrue(/^([()]|.)*$/m.test("()\n()"));
+assertTrue(/^([()]|.)*$/m.test("()\n"));
+assertTrue(/^[()]*$/m.test("()\n."));
+
+assertTrue(/^[\].]*$/.test("...]..."));
+
+
+function check_case(lc, uc) {
+  var a = new RegExp("^" + lc + "$");
+  assertFalse(a.test(uc));
+  a = new RegExp("^" + lc + "$", "i");
+  assertTrue(a.test(uc));
+
+  var A = new RegExp("^" + uc + "$");
+  assertFalse(A.test(lc));
+  A = new RegExp("^" + uc + "$", "i");
+  assertTrue(A.test(lc));
+
+  a = new RegExp("^[" + lc + "]$");
+  assertFalse(a.test(uc));
+  a = new RegExp("^[" + lc + "]$", "i");
+  assertTrue(a.test(uc));
+
+  A = new RegExp("^[" + uc + "]$");
+  assertFalse(A.test(lc));
+  A = new RegExp("^[" + uc + "]$", "i");
+  assertTrue(A.test(lc));
+}
+
+
+check_case("a", "A");
+// Aring
+check_case(String.fromCharCode(229), String.fromCharCode(197));
+// Russian G
+check_case(String.fromCharCode(0x413), String.fromCharCode(0x433));
+
+
+assertThrows("a = new RegExp('[z-a]');");
diff --git a/regexp2000/test/mjsunit/regexp-standalones.js b/regexp2000/test/mjsunit/regexp-standalones.js
new file mode 100644 (file)
index 0000000..4699754
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* Many of the Mozilla regexp tests used 'toSource' to test their
+ * results.  Since we don't currently support toSource, those tests
+ * are disabled and standalone versions are included here.
+ */
+
+// Tests from ecma_3/RegExp/regress-78156.js
+var string = 'aaa\n789\r\nccc\r\n345';
+var pattern = /^\d/gm;
+var result = string.match(pattern);
+assertEquals(2, result.length, "1");
+assertEquals('7', result[0], "2");
+assertEquals('3', result[1], "3");
+
+pattern = /\d$/gm;
+result = string.match(pattern);
+assertEquals(2, result.length, "4");
+assertEquals('9', result[0], "5");
+assertEquals('5', result[1], "6");
+
+string = 'aaa\n789\r\nccc\r\nddd';
+pattern = /^\d/gm;
+result = string.match(pattern);
+assertEquals(1, result.length, "7");
+assertEquals('7', result[0], "8");
+
+pattern = /\d$/gm;
+result = string.match(pattern);
+assertEquals(1, result.length, "9");
+assertEquals('9', result[0], "10");
+
+// Tests from ecma_3/RegExp/regress-72964.js
+pattern = /[\S]+/;
+string = '\u00BF\u00CD\u00BB\u00A7';
+result = string.match(pattern);
+assertEquals(1, result.length, "11");
+assertEquals(string, result[0], "12");
+
+string = '\u00BF\u00CD \u00BB\u00A7';
+result = string.match(pattern);
+assertEquals(1, result.length, "13");
+assertEquals('\u00BF\u00CD', result[0], "14");
+
+string = '\u4e00\uac00\u4e03\u4e00';
+result = string.match(pattern);
+assertEquals(1, result.length, "15");
+assertEquals(string, result[0], "16");
+
+string = '\u4e00\uac00 \u4e03\u4e00';
+result = string.match(pattern);
+assertEquals(1, result.length, "17");
+assertEquals('\u4e00\uac00', result[0], "18");
diff --git a/regexp2000/test/mjsunit/regexp-static.js b/regexp2000/test/mjsunit/regexp-static.js
new file mode 100644 (file)
index 0000000..73940d7
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test the (deprecated as of JS 1.5) properties of the RegExp function.
+var re = /((\d+)\.(\d+))/;
+var s = 'abc123.456def';
+
+re.exec(s);
+
+assertEquals(s, RegExp.input);
+assertEquals('123.456', RegExp.lastMatch);
+assertEquals('456', RegExp.lastParen);
+assertEquals('abc', RegExp.leftContext);
+assertEquals('def', RegExp.rightContext);
+
+assertEquals(s, RegExp['$_']);
+assertEquals('123.456', RegExp['$&']);
+assertEquals('456', RegExp['$+']);
+assertEquals('abc', RegExp['$`']);
+assertEquals('def', RegExp["$'"]);
+
+assertEquals('123.456', RegExp['$1']);
+assertEquals('123', RegExp['$2']);
+assertEquals('456', RegExp['$3']);
+for (var i = 4; i < 10; ++i) {
+  assertEquals('', RegExp['$' + i]);
+}
+
+// They should be read only.
+RegExp['$1'] = 'fisk';
+assertEquals('123.456', RegExp['$1']);
+
+// String.prototype.match and String.prototype.replace (when given a
+// regexp) and also RegExp.prototype.test should all behave as if
+// RegExp.prototype.exec were called.
+s = 'ghi789.012jkl';
+s.match(re);
+assertEquals(s, RegExp.input);
+assertEquals('789.012', RegExp.lastMatch);
+assertEquals('012', RegExp.lastParen);
+assertEquals('ghi', RegExp.leftContext);
+assertEquals('jkl', RegExp.rightContext);
+assertEquals(s, RegExp['$_']);
+assertEquals('789.012', RegExp['$&']);
+assertEquals('012', RegExp['$+']);
+assertEquals('ghi', RegExp['$`']);
+assertEquals('jkl', RegExp["$'"]);
+assertEquals('789.012', RegExp['$1']);
+assertEquals('789', RegExp['$2']);
+assertEquals('012', RegExp['$3']);
+for (var i = 4; i < 10; ++i) {
+  assertEquals('', RegExp['$' + i]);
+}
+
+s = 'abc123.456def';
+s.replace(re, 'whocares');
+assertEquals(s, RegExp.input);
+assertEquals('123.456', RegExp.lastMatch);
+assertEquals('456', RegExp.lastParen);
+assertEquals('abc', RegExp.leftContext);
+assertEquals('def', RegExp.rightContext);
+assertEquals(s, RegExp['$_']);
+assertEquals('123.456', RegExp['$&']);
+assertEquals('456', RegExp['$+']);
+assertEquals('abc', RegExp['$`']);
+assertEquals('def', RegExp["$'"]);
+assertEquals('123.456', RegExp['$1']);
+assertEquals('123', RegExp['$2']);
+assertEquals('456', RegExp['$3']);
+for (var i = 4; i < 10; ++i) {
+  assertEquals('', RegExp['$' + i]);
+}
+
+s = 'ghi789.012jkl';
+re.test(s);
+assertEquals(s, RegExp.input);
+assertEquals('789.012', RegExp.lastMatch);
+assertEquals('012', RegExp.lastParen);
+assertEquals('ghi', RegExp.leftContext);
+assertEquals('jkl', RegExp.rightContext);
+assertEquals(s, RegExp['$_']);
+assertEquals('789.012', RegExp['$&']);
+assertEquals('012', RegExp['$+']);
+assertEquals('ghi', RegExp['$`']);
+assertEquals('jkl', RegExp["$'"]);
+assertEquals('789.012', RegExp['$1']);
+assertEquals('789', RegExp['$2']);
+assertEquals('012', RegExp['$3']);
+for (var i = 4; i < 10; ++i) {
+  assertEquals('', RegExp['$' + i]);
+}
+
+// String.prototype.replace must interleave matching and replacing when a
+// global regexp is matched and replaced with the result of a function, in
+// case the function uses the static properties of the regexp constructor.
+re = /(.)/g;
+function f() { return RegExp.$1; };
+assertEquals('abcd', 'abcd'.replace(re, f));
diff --git a/regexp2000/test/mjsunit/regexp.js b/regexp2000/test/mjsunit/regexp.js
new file mode 100644 (file)
index 0000000..00f02e0
--- /dev/null
@@ -0,0 +1,243 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function testEscape(str, regex) {
+  assertEquals("foo:bar:baz", str.split(regex).join(":"));
+}
+
+testEscape("foo\nbar\nbaz", /\n/);
+testEscape("foo bar baz", /\s/);
+testEscape("foo\tbar\tbaz", /\s/);
+testEscape("foo-bar-baz", /\u002D/);
+
+// Test containing null char in regexp.
+var s = '[' + String.fromCharCode(0) + ']';
+var re = new RegExp(s);
+assertEquals(s.match(re).length, 1);
+assertEquals(s.match(re)[0], String.fromCharCode(0));
+
+// Test strings containing all line separators
+s = 'aA\nbB\rcC\r\ndD\u2028eE\u2029fF';
+re = /^./gm; // any non-newline character at the beginning of a line
+var result = s.match(re);
+assertEquals(result.length, 6);
+assertEquals(result[0], 'a');
+assertEquals(result[1], 'b');
+assertEquals(result[2], 'c');
+assertEquals(result[3], 'd');
+assertEquals(result[4], 'e');
+assertEquals(result[5], 'f');
+
+re = /.$/gm; // any non-newline character at the end of a line
+result = s.match(re);
+assertEquals(result.length, 6);
+assertEquals(result[0], 'A');
+assertEquals(result[1], 'B');
+assertEquals(result[2], 'C');
+assertEquals(result[3], 'D');
+assertEquals(result[4], 'E');
+assertEquals(result[5], 'F');
+
+re = /^[^]/gm; // *any* character at the beginning of a line
+result = s.match(re);
+assertEquals(result.length, 7);
+assertEquals(result[0], 'a');
+assertEquals(result[1], 'b');
+assertEquals(result[2], 'c');
+assertEquals(result[3], '\n');
+assertEquals(result[4], 'd');
+assertEquals(result[5], 'e');
+assertEquals(result[6], 'f');
+
+re = /[^]$/gm; // *any* character at the end of a line
+result = s.match(re);
+assertEquals(result.length, 7);
+assertEquals(result[0], 'A');
+assertEquals(result[1], 'B');
+assertEquals(result[2], 'C');
+assertEquals(result[3], '\r');
+assertEquals(result[4], 'D');
+assertEquals(result[5], 'E');
+assertEquals(result[6], 'F');
+
+// Some tests from the Mozilla tests, where our behavior differs from
+// SpiderMonkey.
+// From ecma_3/RegExp/regress-334158.js
+assertTrue(/\ca/.test( "\x01" ));
+assertFalse(/\ca/.test( "\\ca" ));
+assertTrue(/\c[a/]/.test( "\x1ba/]" ));
+
+// Test that we handle \s and \S correctly inside some bizarre
+// character classes.
+re = /[\s-:]/;
+assertTrue(re.test('-'));
+assertTrue(re.test(':'));
+assertTrue(re.test(' '));
+assertTrue(re.test('\t'));
+assertTrue(re.test('\n'));
+assertFalse(re.test('a'));
+assertFalse(re.test('Z'));
+
+re = /[\S-:]/;
+assertTrue(re.test('-'));
+assertTrue(re.test(':'));
+assertFalse(re.test(' '));
+assertFalse(re.test('\t'));
+assertFalse(re.test('\n'));
+assertTrue(re.test('a'));
+assertTrue(re.test('Z'));
+
+re = /[^\s-:]/;
+assertFalse(re.test('-'));
+assertFalse(re.test(':'));
+assertFalse(re.test(' '));
+assertFalse(re.test('\t'));
+assertFalse(re.test('\n'));
+assertTrue(re.test('a'));
+assertTrue(re.test('Z'));
+
+re = /[^\S-:]/;
+assertFalse(re.test('-'));
+assertFalse(re.test(':'));
+assertTrue(re.test(' '));
+assertTrue(re.test('\t'));
+assertTrue(re.test('\n'));
+assertFalse(re.test('a'));
+assertFalse(re.test('Z'));
+
+re = /[\s]/;
+assertFalse(re.test('-'));
+assertFalse(re.test(':'));
+assertTrue(re.test(' '));
+assertTrue(re.test('\t'));
+assertTrue(re.test('\n'));
+assertFalse(re.test('a'));
+assertFalse(re.test('Z'));
+
+re = /[^\s]/;
+assertTrue(re.test('-'));
+assertTrue(re.test(':'));
+assertFalse(re.test(' '));
+assertFalse(re.test('\t'));
+assertFalse(re.test('\n'));
+assertTrue(re.test('a'));
+assertTrue(re.test('Z'));
+
+re = /[\S]/;
+assertTrue(re.test('-'));
+assertTrue(re.test(':'));
+assertFalse(re.test(' '));
+assertFalse(re.test('\t'));
+assertFalse(re.test('\n'));
+assertTrue(re.test('a'));
+assertTrue(re.test('Z'));
+
+re = /[^\S]/;
+assertFalse(re.test('-'));
+assertFalse(re.test(':'));
+assertTrue(re.test(' '));
+assertTrue(re.test('\t'));
+assertTrue(re.test('\n'));
+assertFalse(re.test('a'));
+assertFalse(re.test('Z'));
+
+re = /[\s\S]/;
+assertTrue(re.test('-'));
+assertTrue(re.test(':'));
+assertTrue(re.test(' '));
+assertTrue(re.test('\t'));
+assertTrue(re.test('\n'));
+assertTrue(re.test('a'));
+assertTrue(re.test('Z'));
+
+re = /[^\s\S]/;
+assertFalse(re.test('-'));
+assertFalse(re.test(':'));
+assertFalse(re.test(' '));
+assertFalse(re.test('\t'));
+assertFalse(re.test('\n'));
+assertFalse(re.test('a'));
+assertFalse(re.test('Z'));
+
+// Test beginning and end of line assertions with or without the
+// multiline flag.
+re = /^\d+/;
+assertFalse(re.test("asdf\n123"));
+re = /^\d+/m;
+assertTrue(re.test("asdf\n123"));
+
+re = /\d+$/;
+assertFalse(re.test("123\nasdf"));
+re = /\d+$/m;
+assertTrue(re.test("123\nasdf"));
+
+// Test that empty matches are handled correctly for multiline global
+// regexps.
+re = /^(.*)/mg;
+assertEquals(3, "a\n\rb".match(re).length);
+assertEquals("*a\n*b\r*c\n*\r*d\r*\n*e", "a\nb\rc\n\rd\r\ne".replace(re, "*$1"));
+
+// Test that empty matches advance one character
+re = new RegExp("", "g");
+assertEquals("xAx", "A".replace(re, "x"));
+assertEquals(3, String.fromCharCode(161).replace(re, "x").length);
+
+// Test that we match the KJS behavior with regard to undefined constructor
+// arguments:
+re = new RegExp();
+// KJS actually shows this as '//'.  Here we match the Firefox behavior (ie,
+// giving a syntactically legal regexp literal).
+assertEquals('/(?:)/', re.toString());
+re = new RegExp(void 0);
+assertEquals('/(?:)/', re.toString());
+re.compile();
+assertEquals('/(?:)/', re.toString());
+re.compile(void 0);
+assertEquals('/undefined/', re.toString());
+
+
+// Check for lazy RegExp literal creation
+function lazyLiteral(doit) {
+  if (doit) return "".replace(/foo(/gi, "");
+  return true;
+}
+
+assertTrue(lazyLiteral(false));
+assertThrows("lazyLiteral(true)");
+
+// Check $01 and $10
+re = new RegExp("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)");
+assertEquals("t", "123456789t".replace(re, "$10"), "$10");
+assertEquals("15", "123456789t".replace(re, "$15"), "$10");
+assertEquals("1", "123456789t".replace(re, "$01"), "$01");
+assertEquals("$001", "123456789t".replace(re, "$001"), "$001");
+re = new RegExp("foo(.)");
+assertEquals("bar$0", "foox".replace(re, "bar$0"), "$0");
+assertEquals("bar$00", "foox".replace(re, "bar$00"), "$00");
+assertEquals("bar$000", "foox".replace(re, "bar$000"), "$000");
+assertEquals("barx", "foox".replace(re, "bar$01"), "$01 2");
+assertEquals("barx5", "foox".replace(re, "bar$15"), "$15");
diff --git a/regexp2000/test/mjsunit/regress/regress-1030466.js b/regexp2000/test/mjsunit/regress/regress-1030466.js
new file mode 100644 (file)
index 0000000..8427ba0
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Whenever we enter a with-scope, we copy the context. This in itself is fine
+// (contexts may escape), but when leaving a with-scope, we currently also copy
+// the context instead of reverting to the original. This does not work because
+// inner functions may already have been created using the original context. In
+// the failing test case below, the inner function is run in the original context
+// (where x is undefined), but the assignment to x after the with-statement is
+// run in the copied context:
+
+var result = (function outer() {
+ with ({}) { }
+ var x = 10;
+ function inner() {
+   return x;
+ };
+ return inner();
+})();
+
+assertEquals(10, result);
diff --git a/regexp2000/test/mjsunit/regress/regress-1036894.js b/regexp2000/test/mjsunit/regress/regress-1036894.js
new file mode 100644 (file)
index 0000000..d89ceda
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+xeval = function(s) { eval(s); }
+xeval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
+
+foo = function() { eval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }"); }
+foo();
+
+xeval = function(s) { eval(s); }
+eval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
+
+xeval = function(s) { eval(s); }
+xeval('$=function(){L: {break L;break L;}};');
diff --git a/regexp2000/test/mjsunit/regress/regress-1039610.js b/regexp2000/test/mjsunit/regress/regress-1039610.js
new file mode 100644 (file)
index 0000000..fd5c549
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure that the Debug object does not return to the global object
+assertTrue(typeof(Debug) === 'undefined');
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/regress/regress-1050043.js b/regexp2000/test/mjsunit/regress/regress-1050043.js
new file mode 100644 (file)
index 0000000..e42728f
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function unsignedShiftRight(val, shift) {
+  return val >>> shift;
+}
+
+assertEquals(        15, unsignedShiftRight(15, 0), "15 >>> 0");
+assertEquals(         7, unsignedShiftRight(15, 1), "15 >>> 1");
+assertEquals(         3, unsignedShiftRight(15, 2), "15 >>> 2");
+
+assertEquals(4294967288, unsignedShiftRight(-8, 0), "-8 >>> 0");
+assertEquals(2147483644, unsignedShiftRight(-8, 1), "-8 >>> 1");
+assertEquals(1073741822, unsignedShiftRight(-8, 2), "-8 >>> 2");
+
+assertEquals(         1, unsignedShiftRight(-8, 31), "-8 >>> 31");
+assertEquals(4294967288, unsignedShiftRight(-8, 32), "-8 >>> 32");
+assertEquals(2147483644, unsignedShiftRight(-8, 33), "-8 >>> 33");
+assertEquals(1073741822, unsignedShiftRight(-8, 34), "-8 >>> 34");
+
+assertEquals(2147483648, unsignedShiftRight(0x80000000, 0), "0x80000000 >>> 0");
+assertEquals(1073741824, unsignedShiftRight(0x80000000, 1), "0x80000000 >>> 1");
+assertEquals( 536870912, unsignedShiftRight(0x80000000, 2), "0x80000000 >>> 2");
+
+assertEquals(1073741824, unsignedShiftRight(0x40000000, 0), "0x40000000 >>> 0");
+assertEquals( 536870912, unsignedShiftRight(0x40000000, 1), "0x40000000 >>> 1");
+assertEquals( 268435456, unsignedShiftRight(0x40000000, 2), "0x40000000 >>> 2");
diff --git a/regexp2000/test/mjsunit/regress/regress-1062422.js b/regexp2000/test/mjsunit/regress/regress-1062422.js
new file mode 100644 (file)
index 0000000..1e2c798
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// 1062422 Ensure that accessors can handle unexpected receivers.
+Number.prototype.__proto__ = String.prototype;
+assertEquals((123).length, 0)
diff --git a/regexp2000/test/mjsunit/regress/regress-1066899.js b/regexp2000/test/mjsunit/regress/regress-1066899.js
new file mode 100644 (file)
index 0000000..37fd554
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This test case segfaults in generated code. See
+// issue #1066899.
+function Crash() {
+  for (var key in [0]) {
+    try { } finally { continue; }
+  }
+}
+
+Crash();
+
diff --git a/regexp2000/test/mjsunit/regress/regress-1081309.js b/regexp2000/test/mjsunit/regress/regress-1081309.js
new file mode 100644 (file)
index 0000000..6871039
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Make sure that the backtrace command can be processed when the receiver is
+// undefined.
+listenerCalled = false;
+exception = false;
+
+function safeEval(code) {
+  try {
+    return eval('(' + code + ')');
+  } catch (e) {
+    return undefined;
+  }
+}
+
+function listener(event, exec_state, event_data, data) {
+  try {
+  if (event == Debug.DebugEvent.Exception)
+  {
+    // The expected backtrace is
+    // 1: g
+    // 0: [anonymous]
+    
+    // Get the debug command processor.
+    var dcp = exec_state.debugCommandProcessor();
+
+    // Get the backtrace.
+    var json;
+    json = '{"seq":0,"type":"request","command":"backtrace"}'
+    var backtrace = safeEval(dcp.processDebugJSONRequest(json)).body;
+    assertEquals(2, backtrace.totalFrames);
+    assertEquals(2, backtrace.frames.length);
+
+    assertEquals("g", backtrace.frames[0].func.name);
+    assertEquals("", backtrace.frames[1].func.name);
+
+    listenerCalled = true;
+  }
+  } catch (e) {
+    exception = e
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Call method on undefined.
+function g() {
+  (void 0).f();
+};
+
+// Break on the exception to do a backtrace with undefined as receiver.
+Debug.setBreakOnException(true);
+try {
+  g();
+} catch(e) {
+  // Ignore the exception "Cannot call method 'x' of undefined"
+}
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerCalled, "listener not called");
+assertFalse(exception, "exception in listener", exception)
diff --git a/regexp2000/test/mjsunit/regress/regress-1102760.js b/regexp2000/test/mjsunit/regress/regress-1102760.js
new file mode 100644 (file)
index 0000000..890ecab
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function F() {
+  return arguments.length;
+}
+
+assertEquals(0, F.apply(), "no receiver or args");
+assertEquals(0, F.apply(this), "no args");
+assertEquals(0, F.apply(this, []), "empty args");
+assertEquals(0, F.apply(this, [], 0), "empty args, extra argument");
diff --git a/regexp2000/test/mjsunit/regress/regress-1110164.js b/regexp2000/test/mjsunit/regress/regress-1110164.js
new file mode 100644 (file)
index 0000000..33f96af
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var o = { x: 0, f: function() { return 42; } };
+delete o.x;  // go dictionary
+
+function CallF(o) {
+  return o.f();
+}
+
+// Make sure the call IC in CallF is initialized.
+for (var i = 0; i < 10; i++) assertEquals(42, CallF(o));
+
+var caught = false;
+o.f = 87;
+try {
+  CallF(o);
+} catch (e) {
+  caught = true;
+  assertTrue(e instanceof TypeError);
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/regress/regress-1112051.js b/regexp2000/test/mjsunit/regress/regress-1112051.js
new file mode 100644 (file)
index 0000000..0af6bb4
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Regression test for issue #1112051.
+function f() { }
+assertThrows("f.call.apply()");
+assertThrows("f.call.apply(null)");
+assertThrows("f.call.apply(null, [], 0)");
+assertThrows("f.call.apply(null, [1,2,3,4,5,6,7,8,9], 0)");
diff --git a/regexp2000/test/mjsunit/regress/regress-1114040.js b/regexp2000/test/mjsunit/regress/regress-1114040.js
new file mode 100644 (file)
index 0000000..9d1b320
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function TestBreak() {
+  var sequence = "";
+  for (var a in [0,1]) {
+    L: {
+      for (var b in [2,3,4]) {
+        break L;
+      }
+    }
+    sequence += a;
+  }
+  return sequence;
+}
+
+
+function TestContinue() {
+  var sequence = "";
+  for (var a in [0,1]) {
+    L: do {
+      for (var b in [2,3,4]) {
+        continue L;
+      }
+    } while (false);
+    sequence += a;
+  }
+  return sequence;
+}
+
+
+assertEquals("01", TestBreak());
+assertEquals("01", TestContinue());
+
diff --git a/regexp2000/test/mjsunit/regress/regress-1134697.js b/regexp2000/test/mjsunit/regress/regress-1134697.js
new file mode 100644 (file)
index 0000000..3d851ae
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Regression test case for issue 1134697.
+// Must run using valgrind.
+
+(-90).toPrecision(6);
diff --git a/regexp2000/test/mjsunit/regress/regress-114.js b/regexp2000/test/mjsunit/regress/regress-114.js
new file mode 100644 (file)
index 0000000..6c1a6a3
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// German eszett
+assertEquals("FRIEDRICHSTRASSE 14", "friedrichstra\xDFe 14".toUpperCase());
+assertEquals("XXSSSSSSXX", "xx\xDF\xDF\xDFxx".toUpperCase());
+assertEquals("(SS)", "(\xDF)".toUpperCase());
+assertEquals("SS", "\xDF".toUpperCase());
+
+// Turkish dotted upper-case I lower-case converts to two characters
+assertEquals("i\u0307", "\u0130".toLowerCase());
+assertEquals("(i\u0307)", "(\u0130)".toLowerCase());
+assertEquals("xxi\u0307xx", "XX\u0130XX".toLowerCase());
+
+// Greek small upsilon with dialytika and tonos upper-case converts to three
+// characters
+assertEquals("\u03A5\u0308\u0301", "\u03B0".toUpperCase());
+assertEquals("(\u03A5\u0308\u0301)", "(\u03B0)".toUpperCase());
+assertEquals("XX\u03A5\u0308\u0301XX", "xx\u03B0xx".toUpperCase());
diff --git a/regexp2000/test/mjsunit/regress/regress-116.js b/regexp2000/test/mjsunit/regress/regress-116.js
new file mode 100644 (file)
index 0000000..7b4620c
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var testCache = {};
+var doLookup = function(id) {
+  return testCache[id] = 'foo';
+};
+
+var r2 = doLookup(0);
+var r1 = doLookup([0]);
+
+assertFalse(r1 === testCache);
+assertEquals('foo', r1);
+assertEquals('f', r1[0]);
+assertEquals('foo', r2);
+assertEquals('f', r2[0]);
diff --git a/regexp2000/test/mjsunit/regress/regress-1170187.js b/regexp2000/test/mjsunit/regress/regress-1170187.js
new file mode 100644 (file)
index 0000000..69f1a10
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Make sure that the retreival of local variables are performed correctly even
+// when an adapter frame is present.
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerCalled = false;
+exception = false;
+
+
+function checkName(name) {
+  assertTrue(name == 'a' || name == 'b' || name == 'c');
+}
+
+
+function checkValue(value) {
+  assertEquals(void 0, value);
+}
+
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      var local0Name = exec_state.frame(0).localName(0);
+      var local1Name = exec_state.frame(0).localName(1);
+      var local2Name = exec_state.frame(0).localName(2);
+      checkName(local0Name);
+      checkName(local1Name);
+      checkName(local2Name);
+      var local0Value = exec_state.frame(0).localValue(0).value();
+      var local1Value = exec_state.frame(0).localValue(1).value();
+      var local2Value = exec_state.frame(0).localValue(2).value();
+      checkValue(local0Value);
+      checkValue(local1Value);
+      checkValue(local2Value);
+      listenerCalled = true;
+    }
+  } catch (e) {
+    exception = e;
+  };
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+// Call a function with local variables passing a different number parameters
+// that the number of arguments.
+(function(x,y){var a,b,c; debugger; return 3})()
+
+// Make sure that the debug event listener vas invoked (again).
+assertTrue(listenerCalled);
+assertFalse(exception, "exception in listener")
diff --git a/regexp2000/test/mjsunit/regress/regress-1173979.js b/regexp2000/test/mjsunit/regress/regress-1173979.js
new file mode 100644 (file)
index 0000000..42649d0
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ensure that null only equals null and undefined, also for variables.
+
+var null_var = null;
+var undef_var = [][0];
+var boolean_var = false;
+var number_var = 0;
+var string_var = "";
+var object_var = { foo : 0 };
+
+assertTrue(null_var == null_var);
+assertTrue(null_var == undef_var);
+assertTrue(null_var != boolean_var);
+assertTrue(null_var != number_var);
+assertTrue(null_var != string_var);
+assertTrue(null_var != object_var);
+
+assertTrue(undef_var == null_var);
+assertTrue(boolean_var != null_var);
+assertTrue(number_var != null_var);
+assertTrue(string_var != null_var);
+assertTrue(object_var != null_var);
diff --git a/regexp2000/test/mjsunit/regress/regress-1175390.js b/regexp2000/test/mjsunit/regress/regress-1175390.js
new file mode 100644 (file)
index 0000000..7b1a7e0
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --print-code --debug-code
+// Simply ensure that we can generate comments without crashing.
+a = 0;
diff --git a/regexp2000/test/mjsunit/regress/regress-1177518.js b/regexp2000/test/mjsunit/regress/regress-1177518.js
new file mode 100644 (file)
index 0000000..2ba3c11
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure that natives and delayed natives don't use methods from the global
+// scope that could have been modified by input javascript.
+
+isFinite = 0;
+Math.floor = 0;
+Math.abs = 0;
+
+// uses Math.floor
+assertEquals(4, parseInt(4.5));
+
+// uses Math.abs, Math.floor and isFinite
+assertEquals('string', typeof (new Date(9999)).toString());
diff --git a/regexp2000/test/mjsunit/regress/regress-1177809.js b/regexp2000/test/mjsunit/regress/regress-1177809.js
new file mode 100644 (file)
index 0000000..703e607
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The encoding of large pc jumps caused code to be overwritten with
+// relocation information.  We pass this test if it does not crash.
+
+String.fromCharCode(48,48,48,59,32,102,111,110,116,45,119,101,105,103,104,116,58,98,111,108,100,59,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,32,99,111,108,111,114,61,34,35,70,70,48,48,48,48,34,62,70,79,82,69,88,47,80,65,82,38,35,51,48,52,59,60,119,98,114,32,47,62,84,69,32,38,35,51,48,52,59,38,35,51,53,48,59,76,69,77,76,69,82,38,35,51,48,52,59,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,115,112,97,110,32,105,100,61,34,97,99,95,100,101,115,99,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,49,112,120,59,32,99,111,108,111,114,58,35,48,48,48,48,48,48,59,32,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,62,38,112,111,117,110,100,59,47,36,32,50,32,112,105,112,44,32,89,84,76,32,49,50,32,112,105,112,44,65,108,116,38,35,51,48,53,59,110,32,51,32,99,101,110,116,46,32,83,97,98,105,116,32,83,112,114,101,97,100,45,84,38,117,117,109,108,59,114,60,119,98,114,32,47,62,107,32,66,97,110,107,97,115,38,35,51,48,53,59,32,65,86,65,78,84,65,74,73,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,100,105,118,32,105,100,61,34,97,99,95,117,114,108,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,48,112,120,59,32,99,111,108,111,114,58,35,70,70,54,54,57,57,59,32,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,62,119,119,119,46,104,101,100,101,102,111,60,119,98,114,32,47,62,110,108,105,110,101,46,99,111,109,60,47,102,111,110,116,62,60,47,100,105,118,62,60,47,116,100,62,60,47,116,114,62,60,47,116,97,98,108,101,62,60,47,116,100,62,60,47,116,114,62,60,116,114,62,10,60,116,100,32,99,108,97,115,115,61,34,97,99,95,107,97,114,105,109,34,32,104,101,105,103,104,116,61,34,50,48,37,34,32,98,103,99,111,108,111,114,61,34,35,70,70,70,70,70,70,34,32,105,100,61,34,116,97,119,52,34,32,97,108,105,103,110,61,34,108,101,102,116,34,32,118,97,108,105,103,110,61,34,109,105,100,100,108,101,34,32,111,110,70,111,99,117,115,61,34,115,115,40,39,103,111,32,116,111,32,119,119,119,46,107,97,108,101,100,101,60,119,98,114,32,47,62,46,99,111,109,39,44,39,97,119,52,39,41,34,32,111,110,77,111,117,115,101,79,118,101,114,61,34,115,115,40,39,103,111,32,116,111,32,119,119,119,46,107,97,108,101,100,101,60,119,98,114,32,47,62,46,99,111,109,39,44,39,97,119,52,39,41,34,32,32,111,110,77,111,117,115,101,79,117,116,61,34,99,115,40,41,34,32,111,110,67,108,105,99,107,61,34,103,97,40,39,104,116,116,112,58,47,47,97,100,115,101,114,118,101,114,46,109,121,110,101,116,46,99,111,109,47,65,100,83,101,114,118,101,114,47,99,108,105,99,107,46,106,115,112,63,117,114,108,61,56,56,49,48,48,50,53,49,50,49,55,54,51,57,52,54,50,51,49,56,52,52,48,51,57,54,48,48,54,51,49,51,54,54,52,52,56,50,56,54,50,48,49,49,49,52,55,51,55,54,52,51,50,57,50,52,50,56,51,53,56,51,54,53,48,48,48,48,53,56,49,55,50,56,57,53,48,48,52,49,57,48,54,56,56,55,50,56,49,55,48,55,53,48,57,50,55,53,55,57,57,51,54,53,50,52,54,49,51,56,49,57,53,55,52,53,50,49,52,50,55,54,48,57,53,57,56,52,55,50,55,48,56,52,51,49,54,52,49,54,57,53,48,56,57,50,54,54,54,48,57,49,54,53,55,57,48,57,49,55,57,52,55,52,55,57,50,48,55,50,55,51,51,53,51,50,55,53,50,54,55,50,56,48,51,57,49,56,54,50,56,55,49,51,55,48,52,51,49,51,52,55,56,51,54,51,52,53,50,54,55,53,57,48,57,48,56,54,57,49,52,53,49,49,52,55,53,50,120,49,57,50,88,49,54,56,88,51,56,88,52,49,88,56,48,56,48,88,65,39,41,34,32,115,116,121,108,101,61,34,99,117,114,115,111,114,58,112,111,105,110,116,101,114,34,62,10,60,116,97,98,108,101,32,119,105,100,116,104,61,34,49,53,54,34,32,98,111,114,100,101,114,61,34,48,34,32,99,101,108,108,115,112,97,99,105,110,103,61,34,49,34,32,99,101,108,108,112,97,100,100,105,110,103,61,34,49,34,62,10,60,116,114,62,10,32,32,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,32,62,60,115,112,97,110,32,105,100,61,34,97,99,95,116,105,116,108,101,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,50,112,120,59,32,99,111,108,111,114,58,35,70,70,48,48,48,48,59,32,102,111,110,116,45,119,101,105,103,104,116,58,98,111,108,100,59,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,32,99,111,108,111,114,61,34,35,70,70,48,48,48,48,34,62,66,108,117,101,32,72,111,117,115,101,32,77,105,107,115,101,114,39,100,101,32,38,35,51,53,48,59,111,107,33,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,115,112,97,110,32,105,100,61,34,97,99,95,100,101,115,99,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,49,112,120,59,32,99,111,108,111,114,58,35,48,48,48,48,48,48,59,32,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,62,66,108,117,101,32,72,111,117,115,101,32,77,105,107,115,101,114,39,100,101,32,65,110,110,101,108,101,114,101,32,38,79,117,109,108,59,122,101,108,32,70,105,121,97,116,32,83,65,68,69,67,69,32,50,57,44,57,54,32,89,84,76,33,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,100,105,118,32,105,100,61,34,97,99,95,117,114,108,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,48,112,120,59,32,99,111,108,111,114,58,35,70,70,54,54,57,57,59,32,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,62,119,119,119,46,107,97,108,101,100,101,60,119,98,114,32,47,62,46,99,111,109,60,47,102,111,110,116,62,60,47,100,105,118,62,60,47,116,100,62,60,47,116,114,62,60,47,116,97,98,108,101,62,60,47,116,100,62,60,47,116,114,62,60,116,114,62,10,60,116,100,32,99,108,97,115,115,61,34,97,99,95,107,97,114,105,109,34,32,104,101,105,103,104,116,61,34,50,48,37,34,32,98,103,99,111,108,111,114,61,34,35,70,70,70,70,70,70,34,32,105,100,61,34,116,97,119,53,34,32,97,108,105,103,110,61,34,108,101,102,116,34,32,118,97,108,105,103,110,61,34,109,105,100,100,108,101,34,32,111,110,70,111,99,117,115,61,34,115,115,40,39,103,111,32,116,111,32,119,119,119,46,98,105,116,109,101,100,60,119,98,114,32,47,62,101,110,46,99,111,109,39,44,39,97,119,53,39,41,34,32,111,110,77,111,117,115,101,79,118,101,114,61,34,115,115,40,39,103,111,32,116,111,32,119,119,119,46,98,105,116,109,101,100,60,119,98,114,32,47,62,101,110,46,99,111,109,39,44,39,97,119,53,39,41,34,32,32,111,110,77,111,117,115,101,79,117,116,61,34,99,115,40,41,34,32,111,110,67,108,105,99,107,61,34,103,97,40,39,104,116,116,112,58,47,47,97,100,115,101,114,118,101,114,46,109,121,110,101,116,46,99,111,109,47,65,100,83,101,114,118,101,114,47,99,108,105,99,107,46,106,115,112,63,117,114,108,61,51,51,54,49,55,53,56,50,56,51,56,50,53,52,57,55,54,49,48)
diff --git a/regexp2000/test/mjsunit/regress/regress-1178598.js b/regexp2000/test/mjsunit/regress/regress-1178598.js
new file mode 100644 (file)
index 0000000..9caaec2
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Regression test cases for issue 1178598.
+
+// Make sure const-initialization doesn't conflict
+// with heap-allocated locals for catch variables.
+var value = (function(){
+  try { } catch(e) {
+    // Force the 'e' variable to be heap-allocated
+    // by capturing it in a function closure.
+    (function() { e; });
+  }
+  // Make sure the two definitions of 'e' do
+  // not conflict in any way.
+  eval("const e=1");
+  return e;
+})();
+
+assertEquals(1, value);
+
+
+
+// Make sure that catch variables can be accessed using eval.
+var value = (function() {
+  var result;
+  try {
+    throw 42;
+  } catch (e) {
+    result = eval("e");
+  }
+  return result;
+})();
+
+assertEquals(42, value);
+
+
+
+// Make sure that heap-allocated locals for catch variables aren't
+// visible outside the catch scope and that they are visible from
+// within.
+var value = (function() {
+  var result;
+  try {
+    throw 87;
+  } catch(e) {
+    // Force the 'e' variable to be heap-allocated
+    // by capturing it in a function closure.
+    (function() { e; });
+    result = eval("e");
+  }
+
+  // Expect accessing 'e' to yield an exception because
+  // it is not defined in the current scope.
+  try {
+    eval("e");
+    assertTrue(false);  // should throw exception
+  } catch(exception) {
+    assertTrue(exception instanceof ReferenceError);
+    return result;
+  }
+})();
+
+assertEquals(87, value);
+
+
diff --git a/regexp2000/test/mjsunit/regress/regress-1182832.js b/regexp2000/test/mjsunit/regress/regress-1182832.js
new file mode 100644 (file)
index 0000000..6c4fcb4
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var caught = false;
+try {
+  (function () {
+    var e = 0;
+    eval("const e = 1;");
+  })();
+} catch (e) {
+  caught = true;
+  assertTrue(e instanceof TypeError);
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/regress/regress-1187524.js b/regexp2000/test/mjsunit/regress/regress-1187524.js
new file mode 100644 (file)
index 0000000..2aeb1c5
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure we don't die on conversion to Smi in string indexing
+
+assertEquals(undefined, ""[0x40000000]);
+assertEquals(undefined, ""[0x80000000]);
+assertEquals(undefined, ""[-1]);
+assertEquals(undefined, ""[-0x40000001]);
+assertEquals(undefined, ""[-0x80000000]);
diff --git a/regexp2000/test/mjsunit/regress/regress-1199401.js b/regexp2000/test/mjsunit/regress/regress-1199401.js
new file mode 100644 (file)
index 0000000..792faea
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ensure that we can correctly change the sign of the most negative smi.
+
+assertEquals(1073741824, -1073741824 * -1);
+assertEquals(1073741824, -1073741824 / -1);
+assertEquals(1073741824, -(-1073741824));
+assertEquals(1073741824, 0 - (-1073741824));
+
+var min_smi = -1073741824;
+
+assertEquals(1073741824, min_smi * -1);
+assertEquals(1073741824, min_smi / -1);
+assertEquals(1073741824, -min_smi);
+assertEquals(1073741824, 0 - min_smi);
+
+var zero = 0;
+var minus_one = -1;
+
+assertEquals(1073741824, min_smi * minus_one);
+assertEquals(1073741824, min_smi / minus_one);
+assertEquals(1073741824, -min_smi);
+assertEquals(1073741824, zero - min_smi);
+
+assertEquals(1073741824, -1073741824 * minus_one);
+assertEquals(1073741824, -1073741824 / minus_one);
+assertEquals(1073741824, -(-1073741824));
+assertEquals(1073741824, zero - (-1073741824));
+
+var half_min_smi = -(1<<15);
+var half_max_smi = (1<<15);
+
+assertEquals(1073741824, -half_min_smi * half_max_smi);
+assertEquals(1073741824, half_min_smi * -half_max_smi);
+assertEquals(1073741824, half_max_smi * -half_min_smi);
+assertEquals(1073741824, -half_max_smi * half_min_smi);
diff --git a/regexp2000/test/mjsunit/regress/regress-1199637.js b/regexp2000/test/mjsunit/regress/regress-1199637.js
new file mode 100644 (file)
index 0000000..d9116c1
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Make sure that we can introduce global variables (using
+// both var and const) that shadow even READ_ONLY variables
+// in the prototype chain.
+const NONE = 0;
+const READ_ONLY = 1;
+
+// Use DeclareGlobal...
+%SetProperty(this.__proto__, "a", "1234", NONE);
+assertEquals(1234, a);
+eval("var a = 5678;");
+assertEquals(5678, a);
+
+%SetProperty(this.__proto__, "b", "1234", NONE);
+assertEquals(1234, b);
+eval("const b = 5678;");
+assertEquals(5678, b);
+
+%SetProperty(this.__proto__, "c", "1234", READ_ONLY);
+assertEquals(1234, c);
+eval("var c = 5678;");
+assertEquals(5678, c);
+
+%SetProperty(this.__proto__, "d", "1234", READ_ONLY);
+assertEquals(1234, d);
+eval("const d = 5678;");
+assertEquals(5678, d);
+
+// Use DeclareContextSlot...
+%SetProperty(this.__proto__, "x", "1234", NONE);
+assertEquals(1234, x);
+eval("with({}) { var x = 5678; }");
+assertEquals(5678, x);
+
+%SetProperty(this.__proto__, "y", "1234", NONE);
+assertEquals(1234, y);
+eval("with({}) { const y = 5678; }");
+assertEquals(5678, y);
+
+%SetProperty(this.__proto__, "z", "1234", READ_ONLY);
+assertEquals(1234, z);
+eval("with({}) { var z = 5678; }");
+assertEquals(5678, z);
+
+%SetProperty(this.__proto__, "w", "1234", READ_ONLY);
+assertEquals(1234, w);
+eval("with({}) { const w = 5678; }");
+assertEquals(5678, w);
+
+
diff --git a/regexp2000/test/mjsunit/regress/regress-1200351.js b/regexp2000/test/mjsunit/regress/regress-1200351.js
new file mode 100644 (file)
index 0000000..f752a1e
--- /dev/null
@@ -0,0 +1,2032 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure the 'constructor' property isn't enumerable.
+var enums = "";
+for (var k in this) enums += (k + '|');
+assertEquals(-1, enums.split('|').indexOf("constructor"));
+
+// Make sure this doesn't crash.
+new this.constructor;
+new this.constructor();
+new this.constructor(1,2,3,4,5,6);
+
+var x = 0;
+try {
+  eval("SetValueOf(typeof(break.prototype.name), Math.max(typeof(break)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export Join((void), false.className(), null instanceof continue, return 'a', 0.__defineGetter__(x,function(){native}))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ void&&null.push(goto NaN) : Math.max(undef).toText }) { {-1/null,1.isNull} }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new break>>>=native.charCodeAt(-1.valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Number(this > native)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {native,0.2}?continue+undef:IsSmi(0.2)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = break.toString()&&return continue")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (-1==continue.toJSONProtocol, GetFunctionFor(break.call(NaN)), (!new RegExp).prototype.new Object()<<void) { debugger.__defineSetter__(null,function(){continue})>>>=GetFunctionFor(-1) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (parseFloat(NaN).splice() in null.add(1).className()) { true[0.2]<<x.splice() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (debugger.constructor.valueOf()) { this.sort().true.splice() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("unescape(break.toObject()).prototype.new RegExp.continue.__lookupGetter__(x.slice(1, NaN)) = typeof(null.push(0.2))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(Iterator(continue.pop()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return new RegExp.shift().concat({debugger,continue}) }; X(return goto 0)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(0.add(break)&&x > null)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ eval(Array(x)) : 1.call('a').superConstructor }) { debugger.lastIndex.toLocaleString() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = return true.__defineGetter__(this,function(){0.2})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new typeof(0)&this.lastIndex")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("String(new RegExp.call(1)).prototype.unescape(parseFloat(-1)) = false<<true.x.lastIndexOf(1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ 1+debugger.valueOf() : continue.join().name() }) { parseInt(true)==undef.sort() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new RegExp>>0.2.superConstructor.prototype.eval(void).className() = false.join().prototype.name")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export (new Object()?undef:native)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new null.isNull.slice(x.prototype.value, Iterator(undef))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export function () { 0.2 }.unshift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Math.max(continue.valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = return debugger.toObject()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (-1.length+new Object().prototype.name) { case (debugger.constructor.sort()): IsPrimitive(undef.__defineSetter__(undef,function(){native})); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete (!new Object().toLocaleString())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(0<<'a'>>>=new RegExp['a'])")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native {unescape(true),new RegExp.isNull}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = -1.lastIndexOf(false)?parseFloat(void):Join(null, continue, new Object(), x, break)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label null/void-break.__lookupGetter__(native)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(0.2.join().constructor)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label function () { false }.__lookupGetter__(this==1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(-1.prototype.0.2.unshift())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new return goto -1")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {Number(debugger)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (parseInt(break) instanceof 0.length) { this.(!0.2) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(break.superConstructor[throw new false(true)], this.~x)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(function () { IsSmi(-1) }, unescape(IsPrimitive(void)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (new RegExp.join().className() in new Object().length()>>true.toObject()) { parseFloat(escape(debugger)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new String(debugger).toJSONProtocol")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(1.indexOf('a')<<break.__lookupGetter__('a'), new Object().null.prototype.new RegExp.charCodeAt(-1))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new {parseInt(0)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(void.join().add(escape(undef)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native parseFloat(false.charAt(new RegExp))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(~Iterator(void))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(NaN.shift().toJSONProtocol)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(native-debugger<<continue.slice(x, new RegExp))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = parseFloat(~new Object())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (null.size/true.add(void) in 0+continue&true.null) { continue.toObject()/throw new true(debugger) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (Iterator(native+break) in debugger.superConstructor.constructor) { Math.max(0.add(undef)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {-1.add(native),true.sort()}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {IsSmi(break),throw new 'a'(null)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (parseInt(0).length()) { case ('a'.toObject().__defineSetter__(GetFunctionFor(null),function(){(!x)})): IsSmi(void).constructor; break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new 0.lastIndexOf(NaN).shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ 0>>>=this.lastIndex : new Object().lastIndexOf(true).toObject() }) { x.lastIndex > 1.__defineSetter__(false,function(){this}) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ throw new false(0.2).prototype.name : parseFloat(false)+(!debugger) }) { escape(undef.lastIndex) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Math.pow(0.2).toJSONProtocol.prototype.break.superConstructor.slice(NaN.exec(undef), -1.lastIndexOf(NaN)) = true.splice().length")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native continue.className().constructor")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (0.2.isNull&undef.toString()) { continue/void+parseInt(null) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new Math.pow(break==this)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(continue.__lookupGetter__(null).constructor, debugger.filter(0.2)>>>=this.'a')")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ 0.2.unshift() > true.size : return Math.max(new RegExp) }) { void.splice().toString() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new unescape(false).unshift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return this.true?'a'==this:0.2.__lookupGetter__(void) }; X(Iterator(false).length)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = function () { null }.__defineSetter__(0.charCodeAt(new Object()),function(){null>>>=new Object()})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import goto 'a'.charAt(native.className())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import 0.2.isNull.__lookupGetter__(debugger.size)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (~new Object().push(Array(null)) in new RegExp>>>=void.prototype.name) { goto break.lastIndex }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete String(x).slice(String('a'), parseFloat(false))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new parseInt(continue.__defineGetter__(0.2,function(){1}))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(true.concat(undef)==0.2.new RegExp)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return NaN['a']?-1.exec(0):NaN.prototype.this }; X(native.prototype.name.toLocaleString())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (debugger==continue.toObject(), Array(NaN.className()), Math.max(new RegExp).prototype.value) { GetFunctionFor('a').prototype.value }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new parseInt(break)==Array(x)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (parseInt(0.2.charCodeAt(this)), this.continue.prototype.name, native.superConstructor.superConstructor) { Join(0.__defineGetter__(continue,function(){undef}), {1}, parseFloat(0), undef.__defineSetter__(break,function(){null}), x?-1:-1) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export Join(debugger.splice(), parseInt(NaN), new RegExp.pop(), this.false, x.-1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = Math.max(native).charCodeAt(continue==break)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (void==NaN.sort(), new Object()==new RegExp.toObject(), -1/NaN.unshift()) { GetFunctionFor(true).name() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for ((!'a'.join()), ~NaN.__defineGetter__(undef,function(){this}), Math.pow(NaN).__lookupGetter__(typeof(false))) { throw new debugger.toObject()(Math.max(-1)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (NaN.shift()&&undef&&continue in throw new x(NaN).prototype.-1&x) { return native.toJSONProtocol }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new (0).charAt(this.charCodeAt(new Object()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return x.valueOf().size }; X(0.2.unshift().unshift())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (eval(new Object().valueOf())) { break.prototype.name.__defineGetter__(eval(NaN),function(){Math.max(native)}) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (Math.pow(1).isNull in Iterator(continue.length())) { Join(true, 0.2, null, x, new Object()).length }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(0>>>=void.unshift(), void.exec('a').undef.length())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete throw new this(0.2).pop()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Iterator(unescape(continue))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return unescape(goto debugger) }; X(new RegExp.push(break).name())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = undef/'a'.indexOf(-1.exec(false))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (continue.isNull.filter(this.toText), function () { throw new 'a'(0.2) }, native?break:undef.prototype.return continue) { Array(void.toText) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new this.slice(new Object(), 1).isNull")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (0.2.className().call((!debugger)), native.__defineGetter__(0,function(){x}).name(), null.splice().splice()) { NaN.charCodeAt(new Object()) > true.toString() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native false.length?new RegExp instanceof this:Array(undef)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new ~0.2.call(typeof(false))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Number(0.2.sort())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new x.join().shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (~new Object().toText) { case (new RegExp.unshift().exec(new RegExp<<debugger)): -1.length.exec(this.isNull); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new parseInt(~true)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new unescape(debugger.call(null))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new GetFunctionFor(0.2).toObject()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete IsPrimitive(null.join())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (eval(0.2) instanceof debugger.splice() in null.superConstructor==new Object()&void) { Number(0+x) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let ('a'-continue?null.length():escape(continue)) { return undef.push(false.shift()) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (Array(x.length) in 'a'.length().sort()) { goto (new Object()) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (NaN==true.length) { IsPrimitive(0.2).prototype.value }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(return true&&void, new RegExp.toObject().length())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Math.pow(void).length")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(void.add(continue).charCodeAt(this.toObject()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export Join(break.toObject(), 0.2.isNull, false.call(0), break.filter(break), 1.length())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (1/NaN.__lookupGetter__(undef.prototype.value)) { escape(eval(this)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(Join(unescape(x), new RegExp.__defineGetter__(debugger,function(){NaN}), 'a'.indexOf(0.2), false.prototype.name, (this)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new Math.pow(native).indexOf(1>>>=-1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new RegExp?native:continue.join().prototype.Math.max(x.__defineSetter__(1,function(){continue})) = parseFloat(parseInt(null))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native function () { new RegExp }.new RegExp.pop()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import typeof(new RegExp.valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (0.2.size>>NaN-continue) { case ('a'.push(true).indexOf(NaN.lastIndexOf(-1))): {0.2,x}.toObject(); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (IsSmi(new Object())/false.filter('a')) { function () { Iterator(debugger) } }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = break.lastIndex.size")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(new Object() > 0.length())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native IsPrimitive(continue)==break.charCodeAt(new Object())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new break.true<<'a'-NaN")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Number(-1?'a':-1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (parseFloat('a'.exec(continue)) in (!new RegExp)&&0.2.toObject()) { {true,x}.add(void.prototype.NaN) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (-1.prototype.value.join()) { (!1.prototype.name) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new GetFunctionFor(continue).toJSONProtocol")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (Math.pow(continue.slice(null, native)), goto (!0), native?1:this.charAt(String(debugger))) { parseFloat(~this) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(debugger.pop().length, new RegExp.isNull.toText)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (typeof(new RegExp.slice(new RegExp, 0)) in native.toLocaleString().lastIndexOf(0.2.length())) { native>>>=new RegExp.length() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native x.join().className()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new 0?0:true.toLocaleString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = IsPrimitive(0).concat(new Object().name())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new parseFloat(x)?this.valueOf():IsSmi(x)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new 'a'.slice(null, -1).shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label 'a'+void.concat('a'>>>=-1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(escape(0.length))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = parseInt(0.lastIndexOf(NaN))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(null&debugger.valueOf(), 0[false].push(false.add(debugger)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = parseInt(new RegExp.__lookupGetter__(break))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(~false&&break>>0, new RegExp.lastIndex.add({this}))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = Join(break, continue, 0, debugger, NaN).toLocaleString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import new Object().sort().superConstructor")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new IsSmi(goto -1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return Iterator(null).toObject() }; X(-1==new Object()==0.__lookupGetter__(native))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native void.join().add(parseFloat(continue))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (function () { -1 }.shift()) { escape(1.unshift()) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(new RegExp.indexOf(1).filter(continue instanceof break))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (NaN?continue:NaN.shift()) { native.push(null).add(new Object().superConstructor) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return new Object().length().toText }; X(debugger.indexOf(this).toText)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new Object().call('a').charCodeAt(native.size)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new function () { continue }.add(true.slice(continue, new RegExp))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x[native] instanceof -1.join().prototype.this.null.size = 0.2.prototype.x+0.2.indexOf(false)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (this instanceof new RegExp.splice() in null>>>=new RegExp.valueOf()) { function () { unescape(1) } }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (true.shift()/native.null in undef.call(NaN).isNull) { native+this-x.size }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return false.pop()<<Join(continue, false, break, NaN, -1) }; X(IsSmi(debugger>>x))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if ({parseFloat(null),Math.max(native)}) { 0.2-new Object().__lookupGetter__(eval(new Object())) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(Array(1).toLocaleString(), null.name().exec(undef.filter(false)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(true.filter(this).pop())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (break.lastIndex.superConstructor) { new Object().toString().length() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label (!0.2/debugger)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ NaN.concat(new RegExp)+Join(1, false, new Object(), new Object(), x) : unescape(x).concat(Iterator(-1)) }) { 'a'.isNull.__lookupGetter__(this+native) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export break.name()/IsPrimitive(this)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {null}.prototype.value")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new true+false.__lookupGetter__(null&continue)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (-1.push(new RegExp)[void.valueOf()]) { new RegExp.className().__lookupGetter__(Array(0)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export NaN.__lookupGetter__(undef).__lookupGetter__(void.isNull)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ ~new RegExp.filter(undef&&this) : String(continue)<<NaN.toText }) { this.exec(this).length }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (true&void.exec(void.exec(continue)) in Join('a', undef, new Object(), continue, x) instanceof {undef}) { unescape(-1.prototype.name) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import void.push(true).join()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf({break}&x.name(), 1.charAt(false).slice(continue.superConstructor, this&&break))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (this.call(this) > Iterator(continue)) { new Object().prototype.value.slice(1.slice(native, -1), (!false)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export parseInt(new RegExp>>>=x)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (escape(x==debugger), NaN.shift()&debugger?false:0.2, (!new RegExp)&goto break) { unescape(x.toText) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(throw new NaN.toObject()(this?break:true))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new (typeof(this))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (unescape('a'/0) in ~new Object().lastIndex) { IsSmi(0).push(0.concat(0.2)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("(!new RegExp)[0.2 > new Object()].prototype.Number(debugger.join()) = native&-1.size")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new false.toJSONProtocol&&0.2.constructor")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (~0?0.2:undef in new RegExp.charCodeAt(0).prototype.name) { NaN.toLocaleString().splice() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (~IsPrimitive(new RegExp), true.toString().size, null.charCodeAt('a') > null.concat(0)) { break.toJSONProtocol/IsPrimitive(break) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new parseInt(new Object()).lastIndexOf(NaN > void)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export break.splice()&&-1.prototype.new Object()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("{{true,0}}.prototype.break.length.splice() = 'a'.toText.superConstructor")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (debugger>>>=continue > break.exec(1)) { Math.pow(new RegExp)==NaN>>>=0.2 }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ 0.2==0.2/goto true : IsSmi(native).isNull }) { throw new {x,null}(false.className()) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = {false.concat(null),Math.pow(NaN)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export Array(null).add(NaN.valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (parseFloat(new Object()==true) in GetFunctionFor('a'&false)) { native&undef.toJSONProtocol }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new {eval(null),(debugger)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import {this.0,debugger.filter(NaN)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import break.charAt(-1)<<false.__defineSetter__(0,function(){x})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = goto false > new Object()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("null.superConstructor[debugger.isNull].prototype.Math.max('a').shift() = parseInt(0).size")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native eval(void.add(break))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(x > void.join())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ {this.toObject()} : Number(NaN).toJSONProtocol }) { 0.2.className().prototype.name }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (false.__defineGetter__(undef,function(){undef}).exec(NaN.splice())) { typeof(Join(void, new RegExp, break, -1, -1)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (false.splice().toObject(), continue.name().size, Join(void?debugger:this, new RegExp.__defineSetter__(NaN,function(){NaN}), x.unshift(), this.true, parseInt(break))) { undef<<continue.toText }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (this.0.indexOf(break)) { break.charAt(this).unshift() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import Join(new Object().splice(), this instanceof 1, parseFloat(NaN), undef.concat(x), void.className())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(goto NaN.toString())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label 'a'<<break.shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = Iterator(continue)[new Object()>>NaN]")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = Join(new RegExp, 'a', this, void, true)>>>=continue>>native")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import new Object().toJSONProtocol.splice()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return undef.__defineSetter__(native,function(){void}).toJSONProtocol }; X(eval(x).charCodeAt('a'.concat(true)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(throw new 0.2.__defineGetter__(NaN,function(){-1})(void&&new RegExp))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = 0.unshift() > IsSmi(NaN)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label x.call(null).lastIndex")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(IsSmi(0.2.add(0)), x.add(break).this.__defineGetter__(undef,function(){new RegExp}))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native Number(this).toObject()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new NaN.shift().add(String(new Object()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new null.name().splice()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = 1.undef.push(new Object().call(null))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(parseInt(1).size)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = this.x.sort()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(continue.valueOf().prototype.new RegExp.splice())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(this.charAt(continue)?undef+'a':unescape(1))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf({throw new 'a'(0.2),void.lastIndexOf(NaN)}, Math.pow(new Object().className()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (1.slice(new Object(), this).valueOf()) { parseInt(true).pop() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ 0.2.superConstructor.lastIndex : goto debugger<<Join(undef, 1, true, undef, debugger) }) { function () { NaN }.prototype.name }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("-1.exec(debugger).length.prototype.debugger > null.slice(Iterator(void), continue.concat(0)) = parseInt(throw new 1(1))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(new Object().constructor.call(Number(1)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new null.unshift().call(escape(x))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (Math.pow(native).toLocaleString()) { case (false instanceof native.join()): Math.pow(NaN).size; break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label function () { new Object() }.prototype.true.size")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = Join('a', 0.2, false, new Object(), void).continue.className()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = IsPrimitive(break.__lookupGetter__(-1))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new Object()>>0.2.prototype.name")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new IsPrimitive(new Object()).shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (Array(parseInt(break))) { 'a'.toString().unshift() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = return 0.2>>>=-1?undef:undef")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Object().splice().unshift().prototype.null&&native.__lookupGetter__(undef>>>=NaN) = (1<<break)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete NaN.charAt(1).concat(NaN.0.2)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(new RegExp.sort().toJSONProtocol)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return GetFunctionFor(false).lastIndexOf(1.shift()) }; X(this.0.2.charCodeAt(0.2))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (goto NaN.toObject(), ~true.'a', parseInt(debugger)+eval(false)) { eval(0.2.constructor) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (parseInt(debugger).pop()) { case (this.push(true).valueOf()): Join(continue, debugger, native, native, debugger).filter(Array(continue)); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new debugger.sort() instanceof this>>1")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ parseFloat(false).prototype.(!new Object()) : {unescape(-1)} }) { Math.max(new RegExp.superConstructor) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate({Math.pow(break)})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import typeof(break.valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(Math.pow(-1[new RegExp]))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native IsPrimitive(1).concat({x,null})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("NaN.length.prototype.value.prototype.function () { null==new Object() } = break.name()&IsPrimitive(0)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete NaN.prototype.-1.toString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new continue.unshift()+parseFloat(undef)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new NaN-break.call(false.pop())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native new RegExp.exec(break).pop()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf({'a',null}.prototype.value, 1.shift() instanceof {'a',0})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (debugger.valueOf().size, function () { x.unshift() }, IsSmi(1)&&true==native) { new Object().__defineGetter__(this,function(){'a'})&&eval(native) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export 'a'.pop().charCodeAt(x.className())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export String(IsSmi(debugger))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("typeof(debugger).valueOf().prototype.(1).lastIndexOf(this.break) = x.prototype.name.toLocaleString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native Array(typeof(false))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(1.__defineGetter__(1,function(){1}).null.constructor)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = 1.charAt(0).toObject()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(Math.max('a'.filter(new Object())))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(void.prototype.name.unshift())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (-1.toJSONProtocol.call(-1.size) in ~x.sort()) { eval(0&debugger) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for ('a'==undef.join() in Math.pow(IsSmi(false))) { undef > this>>goto x }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate('a'.constructor.isNull)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (GetFunctionFor(this.slice(0.2, this)), this.prototype.void?null.unshift():native.className(), Number(new Object().call(-1))) { 0.splice() > debugger&&this }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ {goto new RegExp,Join(new Object(), native, continue, -1, x)} : NaN&x/{0,break} }) { this.lastIndexOf(new RegExp).join() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (typeof(break.length())) { native&&false.sort() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new parseFloat(-1 instanceof break)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label throw new continue.unshift()(null.shift())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import Math.max(0.2.toLocaleString())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return false.unshift().className() }; X(escape(NaN&NaN))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(Join(native.toText, goto x, 0.2.splice(), Join('a', 0, void, NaN, 1), eval(native)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (GetFunctionFor(true.prototype.name)) { parseInt(NaN).toLocaleString() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new escape(native).__defineSetter__(return native,function(){undef > native})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new typeof(true > 'a')")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (debugger.prototype.0.2<<new RegExp+false) { case (native.splice().filter({x})): false&true.indexOf(1.__defineGetter__(native,function(){continue})); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label true-NaN.prototype.native.shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new typeof(new RegExp.splice())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (function () { this.NaN }) { case (this.continue.prototype.parseFloat(false)): IsPrimitive(new Object()-'a'); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export break.__lookupGetter__(debugger).indexOf(native.pop())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (GetFunctionFor(NaN.lastIndex)) { case (new RegExp.lastIndex.toLocaleString()): NaN.join().indexOf(eval(-1)); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native {void.charAt(true)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new new Object()==NaN.join()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(typeof(Array(new Object())))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label throw new (false)(eval(x))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new new RegExp.size.charAt(true > -1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = debugger.toObject().charAt(this<<undef)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ 'a'.valueOf()+parseInt(undef) : IsPrimitive(null).lastIndex }) { NaN.toObject().isNull }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new new Object()&&void.lastIndexOf(0.2.splice())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ 1+1.name() : Join(Math.pow(debugger), new RegExp-1, x > 1, x<<-1, new RegExp.size) }) { undef[undef].size }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete native.call(-1).isNull")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (new Object()>>>=break==Math.pow(debugger)) { IsPrimitive(this).lastIndex }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for ((!x&&new RegExp) in undef.toLocaleString().slice(new RegExp.indexOf(NaN), IsPrimitive(-1))) { false.size+debugger[x] }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import 0.length.__defineGetter__(0.2.shift(),function(){'a'.className()})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(goto new Object().push(void))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ Array(this.0) : parseFloat(void).pop() }) { escape(true).slice(continue.lastIndex, false.toObject()) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new native==true.filter({NaN,-1})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for ('a'.__defineSetter__(continue,function(){-1}).unshift(), Array(undef).toLocaleString(), undef.__lookupGetter__(void).toLocaleString()) { parseInt(false/native) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("this.x<<false.prototype.true.toLocaleString()==NaN.pop() = this.superConstructor>>Math.max(true)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return this.prototype.name.splice() }; X(unescape(x).__lookupGetter__(Number(debugger)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new (!NaN).unshift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(escape(Iterator(this)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return Number(new RegExp)<<this?true:-1 }; X(Number(null).lastIndex)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export this.void.splice()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (this.prototype.null.sort() in -1.className()&void.filter(new Object())) { GetFunctionFor(new Object()).pop() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label 0[break].sort()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (null.length().toString(), eval(-1).toObject(), (!continue.concat(continue))) { true.name()/native<<new RegExp }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (unescape(null).sort(), Number(undef).charCodeAt(IsPrimitive(NaN)), null>>true/null.join()) { 0.2.toObject() > IsPrimitive(new RegExp) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date({NaN,native}&&1+undef)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(IsPrimitive(undef>>>=1))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (Join(true, 'a', true, 1, NaN).add({1}), GetFunctionFor(new Object().push(new Object())), goto 1.length) { Math.pow(GetFunctionFor(native)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return break.isNull > parseInt(continue) }; X((new RegExp instanceof 1))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ Number(false).indexOf(x instanceof new Object()) : function () { x.toString() } }) { false.name().indexOf(GetFunctionFor(null)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date('a'.constructor.prototype.name)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("GetFunctionFor(void&new Object()).prototype.debugger.add(null)[void.unshift()] = new RegExp.isNull.Iterator(this)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete false?break:undef.constructor")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ (native.filter(1)) : eval(this&&0.2) }) { undef.length instanceof new Object().toText }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export String(break.lastIndexOf(null))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label (!Iterator(new RegExp))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(String(null==-1), {1&0})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(parseInt('a' > 0))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(debugger.toJSONProtocol.indexOf(escape(0)), this.filter(null).__defineSetter__(continue.break,function(){debugger>>null}))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("this.name().length().prototype.goto false.exec(true.charCodeAt(continue)) = Join(-1-false, undef.superConstructor, 'a'.shift(), (!x), NaN.this)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(typeof(new RegExp).sort())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new 0.2.concat(x).splice()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (goto void.indexOf(throw new x(1)), typeof(return new RegExp), IsPrimitive(-1).add(void.lastIndexOf(debugger))) { null.indexOf(void).toText }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("return new RegExp.pop().prototype.String(x.toObject()) = 1.superConstructor.charCodeAt(new RegExp.charCodeAt(null))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new null&true.prototype.name")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = -1>>>=NaN.indexOf((debugger))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new parseFloat(null).splice()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import -1.lastIndexOf(new RegExp) instanceof throw new void(0.2)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if ((0.shift())) { Join(IsPrimitive(-1), break.__defineSetter__(true,function(){break}), parseInt(null), parseFloat(break), true/null) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new escape(1 > continue)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (parseInt(undef)>>false.filter(continue)) { case (this.undef/new Object()): 'a'.toJSONProtocol.__defineGetter__(new RegExp-undef,function(){parseFloat(new RegExp)}); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("{void}.shift().prototype.this.Array(new Object()) = {0.2,new RegExp}.lastIndexOf(break.splice())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new continue&&new Object().lastIndexOf(new Object() instanceof 1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (throw new 'a'.exec(x)(return false), native/void.constructor, {native}==true.toLocaleString()) { goto 1 instanceof 1.isNull }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (break.concat(break) > native>>>=-1, (debugger.x), Join(x, void, void, new RegExp, null).name()) { void.charCodeAt(true).valueOf() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new 'a'>>0 instanceof new Object().push(new RegExp)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (return ~break) { break.__defineGetter__(break,function(){-1}).shift() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(Join(null, -1, undef, null, 0).toString())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let ({new RegExp,void}.slice(break.isNull, false.shift())) { eval(debugger.slice(this, 1)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return {GetFunctionFor(0)} }; X('a'.prototype.debugger.concat(void.constructor))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (~true instanceof continue) { escape(new RegExp.toObject()) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("escape(0[native]).prototype.debugger.add(1).unshift() = (true.join())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (unescape(void).length, undef.toObject() instanceof x.toObject(), 0.2+true.concat(true.__lookupGetter__(this))) { (x).toJSONProtocol }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(escape(null).__lookupGetter__(undef.size))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label Array(continue[false])")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return Number(this&&false) }; X(NaN.toJSONProtocol.toJSONProtocol)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("null.toString().shift().prototype.Array(x).__lookupGetter__('a'.prototype.x) = {1.length,break.join()}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new 1.charCodeAt(break)+IsSmi(false)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(String(this) > 0.2.toText, new RegExp.length.lastIndexOf(1<<0.2))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (new RegExp.pop().charAt(IsSmi(new RegExp))) { case (native.indexOf(this)/native.lastIndex): this.debugger.indexOf(debugger); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(Number(x)[debugger.prototype.break])")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return new RegExp>>>=x.unshift() }; X(Math.max(continue.name()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(IsSmi(null.size))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = native?0.2:1+GetFunctionFor(void)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (IsPrimitive(-1)>>>=break.valueOf() in String(0 > 0.2)) { Math.max(true.length()) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (escape(unescape(NaN))) { case (Math.pow(eval(undef))): true.charAt(null)&new RegExp.pop(); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete Join(new RegExp, 1, false, new Object(), this).toLocaleString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label return x.filter(x.join())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new new RegExp.pop().shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new (!debugger.size)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label Math.max(debugger.__lookupGetter__(NaN))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(eval(debugger[debugger]))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new 0.2.filter(true)&throw new true(debugger)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(continue.exec(debugger) > Math.pow(0.2))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("void.prototype.value.name().prototype.Number(undef&NaN) = false.__lookupGetter__(-1).name()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(null.__defineGetter__(native,function(){continue}).valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ {new Object()[continue],native.length()} : undef.name().superConstructor }) { Math.pow(break).indexOf(0.toJSONProtocol) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (Iterator(native.call(new RegExp))) { case (String(new RegExp).isNull): goto new RegExp.pop(); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new x.constructor instanceof undef.indexOf(-1)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(this.~null, continue.pop()&0&'a')")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (GetFunctionFor(~0)) { case ('a'.'a'<<undef.__defineGetter__(false,function(){true})): (!1).lastIndex; break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return debugger.unshift().0.toString() }; X(Number(break).0.2>>>=false)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(Iterator(x)/undef.pop())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(undef.join().toLocaleString(), null.add(false).valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("IsSmi(x).toString().prototype.0>>continue.indexOf(NaN.__lookupGetter__(new Object())) = ~-1&typeof(0)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (continue.__lookupGetter__(new RegExp).toObject(), false-0.toString(), return native.sort()) { new RegExp.name().className() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (escape(new RegExp).toString()) { case (goto eval(1)): this.filter(new Object()).call(new RegExp.slice(null, this)); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = debugger-false.toText")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = Number(null>>new RegExp)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete this&native.indexOf('a'.splice())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(~Math.max(break), 0.2.valueOf().length)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(Number(native.charCodeAt(x)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new goto continue.add(0)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete typeof(debugger).name()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("'a'<<false.toText.prototype.throw new true(1).lastIndex = 'a'.name().length")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native 'a'.indexOf(debugger).charAt(NaN.add(new Object()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(break>>false.toString(), (false.indexOf(this)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete goto NaN==(!debugger)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(0.2.join().superConstructor)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new this.void.toLocaleString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("SetValueOf(x.exec(debugger)[GetFunctionFor(0)], native.toObject().exec(new RegExp.sort()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(0.2.valueOf().toLocaleString())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(-1.toJSONProtocol.prototype.name)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(Array(-1.shift()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export break.concat(undef).unshift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native parseFloat(-1)?NaN.toText:debugger.toString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (void-continue/continue.prototype.undef in String(break.toText)) { parseInt(false).isNull }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(true.isNull.toObject())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ typeof(debugger).toObject() : x.constructor>>>=null.__defineGetter__(native,function(){debugger}) }) { unescape(undef.lastIndexOf(false)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export unescape(continue)<<native[0]")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (String(0).unescape(debugger)) { {break.pop(),0.2.constructor} }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("String({true}).prototype.break.length.call(false > 0.2) = GetFunctionFor(0.prototype.new RegExp)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ false.push(0.2).indexOf(Math.max(debugger)) : x&x.prototype.name }) { goto 1.lastIndex }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(0.2.lastIndex&0.2?break:NaN)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = -1.prototype.value.toText")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import native.toLocaleString()-1.prototype.0")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export debugger[-1].indexOf(Join(new Object(), 0, x, new Object(), 0.2))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return (!true).lastIndexOf(true.splice()) }; X(NaN.toString().prototype.value)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return continue.slice(-1, 1).prototype.true.name() }; X('a'.push(void).prototype.value)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (goto new RegExp.length(), x.sort().className(), Math.max(new RegExp.toJSONProtocol)) { (IsSmi(-1)) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = 0.splice()&&-1.sort()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (Math.max(-1>>1)) { break.toLocaleString().toJSONProtocol }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {void.prototype.break,new RegExp.toString()}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new IsSmi(debugger).name()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new 'a'.concat(undef).sort()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new {debugger.toObject(),'a' > false}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (goto 1.concat(Join(x, undef, native, x, new Object()))) { new RegExp.prototype.name==new RegExp.superConstructor }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return new Object().__defineGetter__(0.2,function(){0.2}).length() }; X(void.isNull<<parseFloat(NaN))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete continue.toJSONProtocol.toLocaleString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (continue.constructor.toObject() in true&&undef.toJSONProtocol) { String(0+break) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import true.call(continue)>>break.toString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label escape(this) > Math.pow(new RegExp)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {void}/IsSmi(new Object())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (native==null?debugger.prototype.name:null.toLocaleString()) { case (NaN.push(this).join()): (break instanceof continue); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new Math.pow(x.push(0))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new (Array(NaN))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label IsSmi(new RegExp).toLocaleString()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label NaN.push(1).shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("{escape(undef),debugger.filter(0.2)}.prototype.-1 > new RegExp[0.2.valueOf()] = new RegExp.prototype.value.splice()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new Join(0.2, x, continue, debugger, new Object()).size")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("with ({ Number(null).name() : Math.pow(true).__defineGetter__(debugger.toString(),function(){false+0.2}) }) { this.{x,break} }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Math.pow(goto debugger)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = IsPrimitive(void.pop())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new Object().toString().toJSONProtocol")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(this.String(0.2))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let ({-1.call(new RegExp)}) { break.length().splice() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import null.size.__defineGetter__(void.filter(x),function(){null.pop()})")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new IsPrimitive(null.superConstructor)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new eval(-1.prototype.continue)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (typeof(Iterator('a'))) { case (0.constructor>>~1): void.__defineGetter__(void,function(){1})/GetFunctionFor(0); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for (false instanceof x.add(true.charAt(new RegExp)) in Join(undef.lastIndexOf(break), 0.2.add(new Object()), Iterator(1), {'a',x}, Array(new Object()))) { function () { null }/1&&-1 }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new escape('a'.concat(undef))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(Math.pow(NaN).toText)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new throw new 0(NaN).className()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete String(GetFunctionFor(new Object()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = Iterator(new Object()).charAt((0.2))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Number(undef.charAt(1)).prototype.undef.lastIndexOf(true).slice(1.className(), undef.filter(-1)) = null<<null.push(parseInt('a'))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = {Math.max(1),IsSmi(new Object())}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch (new Object().exec(0).isNull) { case (escape(IsSmi(false))): false.toObject()-null.size; break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new 'a'.__defineSetter__(debugger,function(){false}).name()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = debugger?-1:0+true.prototype.1")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new {false instanceof continue,native.size}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("GetFunctionFor(continue.__lookupGetter__(0.2)).prototype.Math.max(1.splice()) = true.__defineGetter__(undef,function(){NaN}).filter(String(new RegExp))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("null.size-1.toLocaleString().prototype.(this).shift() = GetFunctionFor(native.charAt(break))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate((!null.indexOf(-1)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = {break.sort()}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new throw new debugger.splice()(this.__lookupGetter__(undef))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("unescape(x[native]).prototype.0.splice().-1.prototype.true = x.prototype.value.className()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export x+true.length")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export debugger.indexOf(-1).indexOf(true.constructor)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("for ({break}.exec(new Object().continue) in eval(0.2.charAt(new Object()))) { throw new null.length(null?break:-1) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = NaN.toLocaleString().toObject()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return Math.pow(break+false) }; X(Join(true.add(new Object()), null[-1], new RegExp[true], NaN&&debugger, x.charAt(undef)))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("switch ((break).add(true.sort())) { case (undef.charAt(native).__defineGetter__(IsPrimitive(1),function(){NaN<<new RegExp})): -1.__defineSetter__(null,function(){-1}) > this.charCodeAt(this); break; }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import return 0.2.length")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("continue.join().toText.prototype.Number(debugger).slice(new RegExp.-1, (NaN)) = function () { (!null) }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export Number(break.__lookupGetter__(false))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Date(return null/x)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export Number(undef).shift()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = 1[native]/this&true")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete typeof(debugger.unshift())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import x.charAt(false)&-1>>x")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("if (null.toText.superConstructor) { typeof(-1).toString() }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (parseFloat(continue.superConstructor)) { 0.2.toText.prototype.value }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label parseInt(IsSmi(null))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete new Object().valueOf().indexOf(true-x)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new unescape(1.__defineGetter__(new Object(),function(){x}))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("let (undef.size.splice()) { 1.constructor.charCodeAt(0+'a') }")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("this.new RegExp.pop().prototype.eval(debugger).toJSONProtocol = unescape(continue).valueOf()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("const x = new this.new RegExp.indexOf(unescape(new Object()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = new break instanceof false instanceof native.length()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate(parseFloat(x).valueOf())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label {escape(true),Math.max(null)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("'a'>>>=void.prototype.value.prototype.break.prototype.break.indexOf(0.className()) = (!this&native)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("import Number(NaN).push(IsSmi(break))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("export true.exec(void).toObject()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function({'a',true}/eval(new Object()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("label null.concat(null).toObject()")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("native {0.2.length,new RegExp.lastIndexOf(-1)}")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("function X(x) { return Math.max({0.2}) }; X(true.charCodeAt(null).add(new RegExp.name()))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("delete -1.lastIndex.length")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("new Function(0.2[1].call(true > break))")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("Instantiate('a'.toLocaleString().splice())")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
+
+try {
+  eval("x = typeof(void&&void)")
+} catch (e) { if (e.message.length > 0) { print (e.message); } };
diff --git a/regexp2000/test/mjsunit/regress/regress-1201933.js b/regexp2000/test/mjsunit/regress/regress-1201933.js
new file mode 100644 (file)
index 0000000..d4827e4
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure this doesn't fail with an assertion
+// failure during lazy compilation.
+
+var caught = false;
+try {
+  (function() {
+    const a;
+    var a;
+  })();
+} catch (e) {
+  caught = true;
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/regress/regress-1203459.js b/regexp2000/test/mjsunit/regress/regress-1203459.js
new file mode 100644 (file)
index 0000000..da1e0ed
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ensure that we allow non-index number properties in object literals.
+var obj = { 0.2 : 'a' }
diff --git a/regexp2000/test/mjsunit/regress/regress-1207276.js b/regexp2000/test/mjsunit/regress/regress-1207276.js
new file mode 100644 (file)
index 0000000..ce7efe9
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  const x=n,Glo0al;
+} catch(e){}
+
+delete Date;
+function X(){String(Glo0al)}
+X();
+X();
+X();
diff --git a/regexp2000/test/mjsunit/regress/regress-1213516.js b/regexp2000/test/mjsunit/regress/regress-1213516.js
new file mode 100644 (file)
index 0000000..6703f32
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function run() {
+ var a = 0;
+ L: try {
+   throw "x";
+ } catch(x) {
+   break L;
+ } finally {
+   a = 1;
+ }
+ assertEquals(1, a);
+}
+
+run();
diff --git a/regexp2000/test/mjsunit/regress/regress-1213575.js b/regexp2000/test/mjsunit/regress/regress-1213575.js
new file mode 100644 (file)
index 0000000..0c3dcc2
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure that a const definition always
+// conflicts with a defined setter. This avoid
+// trying to pass 'the hole' to the setter.
+
+this.__defineSetter__('x', function(value) { assertTrue(false); });
+
+var caught = false;
+try {
+  eval('const x'); 
+} catch(e) {
+  assertTrue(e instanceof TypeError);
+  caught = true;
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/regress/regress-1215653.js b/regexp2000/test/mjsunit/regress/regress-1215653.js
new file mode 100644 (file)
index 0000000..881e22c
--- /dev/null
@@ -0,0 +1,365 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure this doesn't crash the VM.
+
+var caught = false;
+try {
+  OverflowParserStack();
+  assertTrue(false);
+} catch (e) {
+  assertTrue(e instanceof RangeError);
+  caught = true;
+}
+assertTrue(caught);
+
+
+function OverflowParserStack() {
+  var s =
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" +
+      "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((";
+  eval(s);
+}
diff --git a/regexp2000/test/mjsunit/regress/regress-124.js b/regexp2000/test/mjsunit/regress/regress-124.js
new file mode 100644 (file)
index 0000000..81526b0
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertEquals("[object global]", this.toString());
+assertEquals("[object global]", toString());
+
+assertEquals("[object global]", eval("this.toString()"));
+assertEquals("[object global]", eval("toString()"));
+
+assertEquals("[object global]", eval("var f; this.toString()"));
+assertEquals("[object global]", eval("var f; toString()"));
+
+
+function F(f) {
+  assertEquals("[object global]", this.toString());
+  assertEquals("[object global]", toString());
+
+  assertEquals("[object global]", eval("this.toString()"));
+  assertEquals("[object global]", eval("toString()"));
+
+  assertEquals("[object global]", eval("var f; this.toString()"));
+  assertEquals("[object global]", eval("var f; toString()"));
+
+  assertEquals("[object global]", eval("f()"));
+
+  // Receiver should be the arguments object here.
+  assertEquals("[object Object]", eval("arguments[0]()"));
+  with (arguments) {
+    assertEquals("[object Object]", toString());
+  }
+}
+
+F(Object.prototype.toString);
diff --git a/regexp2000/test/mjsunit/regress/regress-1254366.js b/regexp2000/test/mjsunit/regress/regress-1254366.js
new file mode 100644 (file)
index 0000000..2f9e011
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function gee() {};
+
+Object.prototype.findOrStore = function() {
+  var z = this.vvv = gee;
+  return z;
+};
+
+var a =  new Object();
+assertEquals(gee, a.findOrStore());
+assertEquals(gee, a.findOrStore());
+
diff --git a/regexp2000/test/mjsunit/regress/regress-1327557.js b/regexp2000/test/mjsunit/regress/regress-1327557.js
new file mode 100644 (file)
index 0000000..bdf4277
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var x = { valueOf: function() { throw "x"; } };
+var y = { valueOf: function() { throw "y"; } };
+
+try {
+  x * -y;
+  assertUnreachable("Didn't throw an exception");
+} catch (e) {
+  assertEquals("y", e);
+}
diff --git a/regexp2000/test/mjsunit/regress/regress-1341167.js b/regexp2000/test/mjsunit/regress/regress-1341167.js
new file mode 100644 (file)
index 0000000..194a7b8
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure that 'this' is bound to the global object when using
+// execScript.
+
+var result;
+execScript("result = this");
+assertTrue(result === this);
diff --git a/regexp2000/test/mjsunit/regress/regress-1346700.js b/regexp2000/test/mjsunit/regress/regress-1346700.js
new file mode 100644 (file)
index 0000000..fe2d6fa
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var o = {"\u59cb\u53d1\u7ad9": 1};
+assertEquals(1, o.\u59cb\u53d1\u7ad9);
diff --git a/regexp2000/test/mjsunit/regress/regress-1439135.js b/regexp2000/test/mjsunit/regress/regress-1439135.js
new file mode 100644 (file)
index 0000000..737a7ba
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+function Test() {
+  var left  = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+  var right = "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY";
+  for (var i = 0; i < 100000; i++) {
+    var cons = left + right;
+    var substring = cons.substring(20, 80);
+    var index = substring.indexOf('Y');
+    assertEquals(34, index);
+  }
+}
+
+Test();
diff --git a/regexp2000/test/mjsunit/regress/regress-20070207.js b/regexp2000/test/mjsunit/regress/regress-20070207.js
new file mode 100644 (file)
index 0000000..e90b2ec
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The following regression test illustrates a problem in using the
+// value of setting a property in the arguments object. 
+
+function f(s) {
+  arguments.length;
+  return (s += 10) < 0;
+}
+
+assertTrue(f(-100));
+assertTrue(f(-20));
+assertFalse(f(-10));
+assertFalse(f(-5));
+assertFalse(f(0));
+assertFalse(f(10));
+
diff --git a/regexp2000/test/mjsunit/regress/regress-35.js b/regexp2000/test/mjsunit/regress/regress-35.js
new file mode 100644 (file)
index 0000000..2fcdbe7
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var result;
+eval("result = 42; while(true)break");
+assertEquals(42, result);
+
+eval("result = 87; while(false)continue");
+assertEquals(87, result);
diff --git a/regexp2000/test/mjsunit/regress/regress-57.js b/regexp2000/test/mjsunit/regress/regress-57.js
new file mode 100644 (file)
index 0000000..1d410b9
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+try {
+  delete (void 0).x;
+} catch (e) {
+  print(e.toString());
+}
diff --git a/regexp2000/test/mjsunit/regress/regress-588599.js b/regexp2000/test/mjsunit/regress/regress-588599.js
new file mode 100644 (file)
index 0000000..a1c16e2
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertFalse(Infinity == -Infinity);
+assertEquals(Infinity, 1 / 1e-9999);
+assertEquals(-Infinity, 1 / -1e-9999);
+
diff --git a/regexp2000/test/mjsunit/regress/regress-662254.js b/regexp2000/test/mjsunit/regress/regress-662254.js
new file mode 100644 (file)
index 0000000..daf5e17
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() {
+  for (var c in []) { }
+}
+
+f();
+
+
+function g() {
+  var c;
+  for (c in []) { }
+}
+
+g();
diff --git a/regexp2000/test/mjsunit/regress/regress-666721.js b/regexp2000/test/mjsunit/regress/regress-666721.js
new file mode 100644 (file)
index 0000000..e2c632f
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function len0(a) { return a.length; }
+function len1(a) { return a.length; }
+function len2(a) { return a.length; }
+function len3(a) { return a.length; }
+
+assertEquals(0, len0([]));
+assertEquals(1, len0({length:1}));
+assertEquals(2, len0([1,2]));
+assertEquals(3, len0('123'));
+
+assertEquals(0, len1(''));
+assertEquals(1, len1({length:1}));
+assertEquals(2, len1('12'));
+assertEquals(3, len1([1,2,3]));
+
+assertEquals(0, len2({length:0}));
+assertEquals(1, len2([1]));
+assertEquals(2, len2({length:2}));
+assertEquals(3, len2([1,2,3]));
+assertEquals(4, len2('1234'));
+
+assertEquals(0, len3({length:0}));
+assertEquals(1, len3('1'));
+assertEquals(2, len3({length:2}));
+assertEquals(3, len3('123'));
+assertEquals(4, len3([1,2,3,4]));
diff --git a/regexp2000/test/mjsunit/regress/regress-667061.js b/regexp2000/test/mjsunit/regress/regress-667061.js
new file mode 100644 (file)
index 0000000..4d29a1a
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test non-ICC case.
+var caught = false;
+try {
+  (('foo'))();
+} catch (o) {
+  assertTrue(o instanceof TypeError);
+  caught = true;
+}
+assertTrue(caught);
+
+
+// Test uninitialized case.
+function h(o) {
+  return o.x();
+}
+
+var caught = false;
+try {
+  h({ x: 1 });
+} catch (o) {
+  assertTrue(o instanceof TypeError);
+  caught = true;
+}
+assertTrue(caught);
+
+
+// Test monomorphic case.
+function g(o) {
+  return o.x();
+}
+
+function O(x) { this.x = x; };
+var o = new O(function() { return 1; });
+assertEquals(1, g(o));  // go monomorphic
+assertEquals(1, g(o));  // stay monomorphic
+
+var caught = false;
+try {
+  g(new O(3));
+} catch (o) {
+  assertTrue(o instanceof TypeError);
+  caught = true;
+}
+assertTrue(caught);
+
+
+// Test megamorphic case.
+function f(o) {
+  return o.x();
+}
+
+assertEquals(1, f({ x: function () { return 1; }}));  // go monomorphic
+assertEquals(2, f({ x: function () { return 2; }}));  // go megamorphic
+assertEquals(3, f({ x: function () { return 3; }}));  // stay megamorphic
+
+var caught = false;
+try {
+  f({ x: 4 });
+} catch (o) {
+  assertTrue(o instanceof TypeError);
+  caught = true;
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/regress/regress-670147.js b/regexp2000/test/mjsunit/regress/regress-670147.js
new file mode 100644 (file)
index 0000000..b5b00d0
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function XXX(x) {
+  var k = delete x;
+  return k;
+}
+
+assertFalse(XXX('Hello'));
+
diff --git a/regexp2000/test/mjsunit/regress/regress-674753.js b/regexp2000/test/mjsunit/regress/regress-674753.js
new file mode 100644 (file)
index 0000000..361b457
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Number
+assertTrue(typeof 0 == 'number');
+assertTrue(typeof 0 === 'number');
+assertTrue(typeof 1.2 == 'number');
+assertTrue(typeof 1.2 === 'number');
+assertFalse(typeof 'x' == 'number');
+assertFalse(typeof 'x' === 'number');
+
+// String
+assertTrue(typeof 'x' == 'string');
+assertTrue(typeof 'x' === 'string');
+assertTrue(typeof ('x' + 'x') == 'string');
+assertTrue(typeof ('x' + 'x') === 'string');
+assertFalse(typeof 1 == 'string');
+assertFalse(typeof 1 === 'string');
+assertFalse(typeof Object() == 'string');
+assertFalse(typeof Object() === 'string');
+
+// Boolean
+assertTrue(typeof true == 'boolean');
+assertTrue(typeof true === 'boolean');
+assertTrue(typeof false == 'boolean');
+assertTrue(typeof false === 'boolean');
+assertFalse(typeof 1 == 'boolean');
+assertFalse(typeof 1 === 'boolean');
+assertFalse(typeof Object() == 'boolean');
+assertFalse(typeof Object() === 'boolean');
+
+// Undefined
+assertTrue(typeof void 0 == 'undefined');
+assertTrue(typeof void 0 === 'undefined');
+assertFalse(typeof 1 == 'undefined');
+assertFalse(typeof 1 === 'undefined');
+assertFalse(typeof Object() == 'undefined');
+assertFalse(typeof Object() === 'undefined');
+
+// Function
+assertTrue(typeof Object == 'function');
+assertTrue(typeof Object === 'function');
+assertFalse(typeof 1 == 'function');
+assertFalse(typeof 1 === 'function');
+assertFalse(typeof Object() == 'function');
+assertFalse(typeof Object() === 'function');
+
+// Object
+assertTrue(typeof Object() == 'object');
+assertTrue(typeof Object() === 'object');
+assertTrue(typeof new String('x') == 'object');
+assertTrue(typeof new String('x') === 'object');
+assertTrue(typeof ['x'] == 'object');
+assertTrue(typeof ['x'] === 'object');
+assertTrue(typeof null == 'object');
+assertTrue(typeof null === 'object');
+assertFalse(typeof 1 == 'object');
+assertFalse(typeof 1 === 'object');
+assertFalse(typeof 'x' == 'object');  // bug #674753
+assertFalse(typeof 'x' === 'object');
+assertFalse(typeof Object == 'object');
+assertFalse(typeof Object === 'object');
+
diff --git a/regexp2000/test/mjsunit/regress/regress-676025.js b/regexp2000/test/mjsunit/regress/regress-676025.js
new file mode 100644 (file)
index 0000000..15157f2
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var result;
+try { eval('a=/(/'); } catch (e) { result = e; }
+assertEquals('object', typeof result);
+assertTrue(result instanceof SyntaxError);
diff --git a/regexp2000/test/mjsunit/regress/regress-678525.js b/regexp2000/test/mjsunit/regress/regress-678525.js
new file mode 100644 (file)
index 0000000..5ff9c3d
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertEquals(0,  '\0'.charCodeAt(0));
+assertEquals(1,  '\1'.charCodeAt(0));
+assertEquals(2,  '\2'.charCodeAt(0));
+assertEquals(3,  '\3'.charCodeAt(0));
+assertEquals(4,  '\4'.charCodeAt(0));
+assertEquals(5,  '\5'.charCodeAt(0));
+assertEquals(6,  '\6'.charCodeAt(0));
+assertEquals(7,  '\7'.charCodeAt(0));
+assertEquals(56, '\8'.charCodeAt(0));
+
+assertEquals('\010', '\10');
+assertEquals('\011', '\11');    
+assertEquals('\012', '\12');
+assertEquals('\013', '\13');
+assertEquals('\014', '\14');
+assertEquals('\015', '\15');
+assertEquals('\016', '\16');
+assertEquals('\017', '\17');
+    
+assertEquals('\020', '\20');
+assertEquals('\021', '\21');    
+assertEquals('\022', '\22');
+assertEquals('\023', '\23');
+assertEquals('\024', '\24');
+assertEquals('\025', '\25');
+assertEquals('\026', '\26');
+assertEquals('\027', '\27');
+
+assertEquals(73,  '\111'.charCodeAt(0));
+assertEquals(105, '\151'.charCodeAt(0));
+
+    
diff --git a/regexp2000/test/mjsunit/regress/regress-682649.js b/regexp2000/test/mjsunit/regress/regress-682649.js
new file mode 100644 (file)
index 0000000..f23aed5
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Should return [object global], v8 returns [object Object]
+
+assertEquals(this.toString(), eval("this.toString()"));
diff --git a/regexp2000/test/mjsunit/regress/regress-69.js b/regexp2000/test/mjsunit/regress/regress-69.js
new file mode 100644 (file)
index 0000000..3fb1f76
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This tests a switch statement with only default clause leaves
+// balanced stack. It should not trigger the break point when --debug_code
+// flag is turned on.
+// See issue: http://code.google.com/p/v8/issues/detail?id=69
+
+// Flags: --debug-code --expose-gc
+function unbalanced_switch(a) {
+  try {
+    switch (a) {
+      default: break;
+    }
+  } catch (e) {}
+  gc();
+}
+
+unbalanced_switch(1);
diff --git a/regexp2000/test/mjsunit/regress/regress-734862.js b/regexp2000/test/mjsunit/regress/regress-734862.js
new file mode 100644 (file)
index 0000000..6239047
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function catcher(o, p) {
+  try { o[p]; } catch (e) { return e; }
+  throw p;
+}
+
+assertTrue(catcher(null, 'foo') instanceof TypeError);
+assertTrue(catcher(void 0, 'foo') instanceof TypeError);
+assertTrue(catcher(null, 123) instanceof TypeError);
+assertTrue(catcher(void 0, 123) instanceof TypeError);
+
diff --git a/regexp2000/test/mjsunit/regress/regress-737588.js b/regexp2000/test/mjsunit/regress/regress-737588.js
new file mode 100644 (file)
index 0000000..0f71dfc
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var goog = goog || {} ;
+goog.global = this;
+goog.globalEval = function(script) {
+  return goog.global.eval(script);
+};
+
+assertEquals(125, goog.globalEval('var foofoofoo = 125; foofoofoo'));
diff --git a/regexp2000/test/mjsunit/regress/regress-780423.js b/regexp2000/test/mjsunit/regress/regress-780423.js
new file mode 100644 (file)
index 0000000..862db32
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var Class = {
+ create: function() {
+   return function kurt() {
+   }
+ }
+};
+
+var o1 = Class.create();
+var o2 = Class.create();
+
+assertTrue(o1 !== o2, "different functions");
+assertTrue(o1.prototype !== o2.prototype, "different protos");
diff --git a/regexp2000/test/mjsunit/regress/regress-799761.js b/regexp2000/test/mjsunit/regress/regress-799761.js
new file mode 100644 (file)
index 0000000..d3be1bd
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// const variables should be read-only
+const c = 42;
+c = 87;
+assertEquals(42, c);
+
+
+// const variables are not behaving like other JS variables when it comes
+// to scoping - in fact they behave more sanely. Inside a 'with' they do
+// not interfere with the 'with' scopes.
+
+(function () {
+  with ({ x: 42 }) {
+    const x = 7;
+  }
+  x = 5;
+  assertEquals(7, x);
+})();
+
+
+// const variables may be declared but never initialized, in which case
+// their value is undefined.
+
+(function (sel) {
+  if (sel == 0)
+    with ({ x: 42 }) {
+    const x;
+    }
+  else
+    x = 3;
+  x = 5;
+  assertTrue(typeof x == 'undefined');
+})(1);
+
+
+// const variables may be initialized to undefined.
+(function () {
+  with ({ x: 42 }) {
+    const x = undefined;
+  }
+  x = 5;
+  assertTrue(typeof x == 'undefined');
+})();
+
+
+// const variables may be accessed in inner scopes like any other variable.
+(function () {
+  function bar() {
+    assertEquals(7, x);
+  }
+  with ({ x: 42 }) {
+    const x = 7;
+  }
+  x = 5
+  bar();
+})();
+
+
+// const variables may be declared via 'eval'
+(function () {
+  with ({ x: 42 }) {
+    eval('const x = 7');
+  }
+  x = 5;
+  assertEquals(7, x);
+})();
diff --git a/regexp2000/test/mjsunit/regress/regress-806473.js b/regexp2000/test/mjsunit/regress/regress-806473.js
new file mode 100644 (file)
index 0000000..6d6485d
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+function catchThese() {
+  L: {
+    try {
+      break L;
+    } catch (e) {}
+  }
+}
+
+function finallyThese() {
+  L: {
+    try {
+      break L;
+    } finally {}
+  }
+}
+
+
+for (var i = 0; i < 10; i++) {
+  catchThese();
+  gc();
+}
+
+for (var j = 0; j < 10; j++) {
+  finallyThese();
+  gc();
+}
+
+assertEquals(10, i);
+assertEquals(10, j);
+
+
diff --git a/regexp2000/test/mjsunit/regress/regress-842017.js b/regexp2000/test/mjsunit/regress/regress-842017.js
new file mode 100644 (file)
index 0000000..3a367bb
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+function break_from_for_in() {
+  L: {
+    try {
+      for (var x in [1,2,3]) {
+        break L;
+      }
+    } finally {}
+  }
+}
+
+function break_from_finally() {
+  L: {
+    try {
+    } finally {
+      break L;
+    }
+  }
+}
+
+for (var i = 0; i < 10; i++) {
+  break_from_for_in();
+  gc();
+}
+
+for (var j = 0; j < 10; j++) {
+  break_from_finally();
+  gc();
+}
+
+assertEquals(10, i);
+assertEquals(10, j);
diff --git a/regexp2000/test/mjsunit/regress/regress-86.js b/regexp2000/test/mjsunit/regress/regress-86.js
new file mode 100644 (file)
index 0000000..a33b60b
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var aList = [1, 2, 3];
+var loopCount = 0;
+var leftThroughFinally = false;
+var enteredFinally = false;
+for (x in aList) {
+  leftThroughFinally = true;
+  try {
+    throw "ex1";
+  } catch(er1) {
+    loopCount += 1;
+  } finally {
+    enteredFinally = true;
+    continue;
+  }
+  leftThroughFinally = false;
+}
+assertEquals(3, loopCount);
+assertTrue(enteredFinally);
+assertTrue(leftThroughFinally);
diff --git a/regexp2000/test/mjsunit/regress/regress-874178.js b/regexp2000/test/mjsunit/regress/regress-874178.js
new file mode 100644 (file)
index 0000000..0ed5434
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function foo(){}
+assertTrue(Function.prototype.isPrototypeOf(foo));
+
+foo.bar = 'hello';
+assertTrue(foo.propertyIsEnumerable('bar'));
diff --git a/regexp2000/test/mjsunit/regress/regress-875031.js b/regexp2000/test/mjsunit/regress/regress-875031.js
new file mode 100644 (file)
index 0000000..f18b084
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Regression test for issue 875031.
+
+var caught = false;
+try {
+  eval("return;");
+  assertTrue(false);  // should not reach here
+} catch (e) {
+  caught = true;
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/regress/regress-877615.js b/regexp2000/test/mjsunit/regress/regress-877615.js
new file mode 100644 (file)
index 0000000..d35aba6
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Number.prototype.toLocaleString = function() { return 'invalid'};
+assertEquals([1].toLocaleString(), 'invalid');  // invalid
+
+Number.prototype.toLocaleString = 'invalid';
+assertEquals([1].toLocaleString(), '1');  // 1
+
+Number.prototype.toString = function() { return 'invalid' };
+assertEquals([1].toLocaleString(), '1');  // 1
+assertEquals([1].toString(), '1');        // 1
+
diff --git a/regexp2000/test/mjsunit/regress/regress-892742.js b/regexp2000/test/mjsunit/regress/regress-892742.js
new file mode 100644 (file)
index 0000000..a60395e
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() {
+  return/* useless*/1;
+};
+
+
+// According to ECMA-262, this comment should actually be parsed as a
+// line terminator making g() return undefined, but this is not the
+// way it's handled by Spidermonkey or KJS.
+function g() {
+  return/* useless
+         */2;
+};
+
+function h() {
+  return// meaningful
+      3;
+};
+
+
+assertEquals(1, f());
+assertEquals(2, g());
+assertTrue(typeof h() == 'undefined', 'h');
+
diff --git a/regexp2000/test/mjsunit/regress/regress-900055.js b/regexp2000/test/mjsunit/regress/regress-900055.js
new file mode 100644 (file)
index 0000000..9a02f22
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var alias = eval;
+function e(s) { return alias(s); }
+
+assertEquals(42, e("42"));
+assertEquals(Object, e("Object"));
+assertEquals(e, e("e"));
+
+var caught = false;
+try {
+  e('s');  // should throw exception since aliased eval is global
+} catch (e) {
+  caught = true;
+  assertTrue(e instanceof ReferenceError);
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/regress/regress-900966.js b/regexp2000/test/mjsunit/regress/regress-900966.js
new file mode 100644 (file)
index 0000000..b95d10e
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertTrue('abc'[10] === undefined);
+String.prototype[10] = 'x';
+assertEquals('abc'[10], 'x');
+
+assertTrue(2[11] === undefined);
+Number.prototype[11] = 'y';
+assertEquals(2[11], 'y');
+
+assertTrue(true[12] === undefined);
+Boolean.prototype[12] = 'z';
+assertEquals(true[12], 'z');
diff --git a/regexp2000/test/mjsunit/regress/regress-925537.js b/regexp2000/test/mjsunit/regress/regress-925537.js
new file mode 100644 (file)
index 0000000..11582ea
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function assertClose(expected, actual) {
+  var delta = 0.00001;
+  if (Math.abs(expected - actual) > delta) {
+    print('Failure: Expected <' + actual + '> to be close to <' + 
+          expected + '>');    
+  }
+}
+
+assertEquals(1, Math.pow(NaN, 0));
+var pinf = Number.POSITIVE_INFINITY, ninf = Number.NEGATIVE_INFINITY;
+assertClose( Math.PI / 4, Math.atan2(pinf, pinf));
+assertClose(-Math.PI / 4, Math.atan2(ninf, pinf));
+assertClose( 3 * Math.PI / 4, Math.atan2(pinf, ninf));
+assertClose(-3 * Math.PI / 4, Math.atan2(ninf, ninf));
+
diff --git a/regexp2000/test/mjsunit/regress/regress-937896.js b/regexp2000/test/mjsunit/regress/regress-937896.js
new file mode 100644 (file)
index 0000000..e8e5ef2
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This used to crash because the label collector in the parser didn't
+// discard duplicates which caused the outer-most continue statement
+// to try to unlink the inner try-handler that wasn't on the stack.
+
+function f() {
+  try {
+    for (var i = 0; i < 2; i++) {
+      continue;
+      try {
+        continue;
+        continue;
+      } catch (ex) {
+        // Empty.
+      }
+    }
+  } catch (e) {
+    // Empty. 
+  }
+  return 42;
+}
+
+
+assertEquals(42, f());
diff --git a/regexp2000/test/mjsunit/regress/regress-990205.js b/regexp2000/test/mjsunit/regress/regress-990205.js
new file mode 100644 (file)
index 0000000..1ab5bf8
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() {
+  // Force eager compilation of x through the use of eval. The break
+  // in function x should not try to break out of the enclosing while.
+  return eval("while(0) function x() { break; }; 42");
+};
+
+assertEquals(42, f());
+
diff --git a/regexp2000/test/mjsunit/regress/regress-992733.js b/regexp2000/test/mjsunit/regress/regress-992733.js
new file mode 100644 (file)
index 0000000..d0f7511
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertEquals("object", typeof this);
+var threw = false;
+try {
+  this();
+} catch (e) {
+  threw = true;
+}
+assertTrue(threw);
diff --git a/regexp2000/test/mjsunit/regress/regress-996542.js b/regexp2000/test/mjsunit/regress/regress-996542.js
new file mode 100644 (file)
index 0000000..8fc704e
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var zero = 0;
+var one = 1;
+var minus_one = -1;
+
+assertEquals(-Infinity, 1 / (0 / -1));
+assertEquals(-Infinity, one / (zero / minus_one));
+assertEquals(Infinity, 1 / (0 / 1));
+assertEquals(Infinity, one / (zero / one));
+
+assertEquals(-Infinity, 1 / (-1 % 1));
+assertEquals(-Infinity, one / (minus_one % one))
+assertEquals(Infinity, 1 / (1 % 1));
+assertEquals(Infinity, one / (one % one));
diff --git a/regexp2000/test/mjsunit/regress/regress-998565.js b/regexp2000/test/mjsunit/regress/regress-998565.js
new file mode 100644 (file)
index 0000000..ff66154
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerCalled = false;
+
+function listener(event, exec_state, event_data, data) {
+ listenerCalled = true;
+ throw 1;
+};
+
+// Add the debug event listener.
+Debug.addListener(listener);
+
+function f() {
+ a=1
+};
+
+// Set a break point and call to invoke the debug event listener.
+Debug.setBreakPoint(f, 0, 0);
+f();
+
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerCalled);
\ No newline at end of file
diff --git a/regexp2000/test/mjsunit/scanner.js b/regexp2000/test/mjsunit/scanner.js
new file mode 100644 (file)
index 0000000..516a4e8
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests that we check if escaped characters are valid indentifier
+// start characters.
+assertThrows('var \\u0030')
diff --git a/regexp2000/test/mjsunit/smi-negative-zero.js b/regexp2000/test/mjsunit/smi-negative-zero.js
new file mode 100644 (file)
index 0000000..99ddc97
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ensure that operations on small integers handle -0.
+
+var zero = 0;
+var one = 1;
+var minus_one = -1;
+var two = 2;
+var four = 4;
+var minus_two = -2;
+var minus_four = -4;
+
+// variable op variable
+
+assertEquals(one / (-zero), -Infinity);
+
+assertEquals(one / (zero * minus_one), -Infinity);
+assertEquals(one / (minus_one * zero), -Infinity);
+assertEquals(one / (zero * zero), Infinity);
+assertEquals(one / (minus_one * minus_one), 1);
+
+assertEquals(one / (zero / minus_one), -Infinity);
+assertEquals(one / (zero / one), Infinity);
+
+assertEquals(one / (minus_four % two), -Infinity);
+assertEquals(one / (minus_four % minus_two), -Infinity);
+assertEquals(one / (four % two), Infinity);
+assertEquals(one / (four % minus_two), Infinity);
+
+// literal op variable
+
+assertEquals(one / (0 * minus_one), -Infinity);
+assertEquals(one / (-1 * zero), -Infinity);
+assertEquals(one / (0 * zero), Infinity);
+assertEquals(one / (-1 * minus_one), 1);
+
+assertEquals(one / (0 / minus_one), -Infinity);
+assertEquals(one / (0 / one), Infinity);
+
+assertEquals(one / (-4 % two), -Infinity);
+assertEquals(one / (-4 % minus_two), -Infinity);
+assertEquals(one / (4 % two), Infinity);
+assertEquals(one / (4 % minus_two), Infinity);
+
+// variable op literal
+
+assertEquals(one / (zero * -1), -Infinity);
+assertEquals(one / (minus_one * 0), -Infinity);
+assertEquals(one / (zero * 0), Infinity);
+assertEquals(one / (minus_one * -1), 1);
+
+assertEquals(one / (zero / -1), -Infinity);
+assertEquals(one / (zero / 1), Infinity);
+
+assertEquals(one / (minus_four % 2), -Infinity);
+assertEquals(one / (minus_four % -2), -Infinity);
+assertEquals(one / (four % 2), Infinity);
+assertEquals(one / (four % -2), Infinity);
+
+// literal op literal
+
+assertEquals(one / (-0), -Infinity);
+
+assertEquals(one / (0 * -1), -Infinity);
+assertEquals(one / (-1 * 0), -Infinity);
+assertEquals(one / (0 * 0), Infinity);
+assertEquals(one / (-1 * -1), 1);
+
+assertEquals(one / (0 / -1), -Infinity);
+assertEquals(one / (0 / 1), Infinity);
+
+assertEquals(one / (-4 % 2), -Infinity);
+assertEquals(one / (-4 % -2), -Infinity);
+assertEquals(one / (4 % 2), Infinity);
+assertEquals(one / (4 % -2), Infinity);
diff --git a/regexp2000/test/mjsunit/smi-ops.js b/regexp2000/test/mjsunit/smi-ops.js
new file mode 100644 (file)
index 0000000..bdd7509
--- /dev/null
@@ -0,0 +1,102 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+const SMI_MAX = (1 << 30) - 1;
+const SMI_MIN = -(1 << 30);
+const ONE = 1;
+const ONE_HUNDRED = 100;
+
+const OBJ_42 = new (function() {
+  this.valueOf = function() { return 42; };
+})();
+
+assertEquals(42, OBJ_42.valueOf()); 
+
+
+function Add1(x) {
+  return x + 1;
+}
+
+function Add100(x) {
+  return x + 100;
+}
+
+function Add1Reversed(x) {
+  return 1 + x;
+}
+
+function Add100Reversed(x) {
+  return 100 + x;
+}
+
+
+assertEquals(1, Add1(0));  // fast case
+assertEquals(1, Add1Reversed(0));  // fast case
+assertEquals(SMI_MAX + ONE, Add1(SMI_MAX));  // overflow
+assertEquals(SMI_MAX + ONE, Add1Reversed(SMI_MAX));  // overflow
+assertEquals(42 + ONE, Add1(OBJ_42));  // non-smi
+assertEquals(42 + ONE, Add1Reversed(OBJ_42));  // non-smi
+
+assertEquals(100, Add100(0));  // fast case
+assertEquals(100, Add100Reversed(0));  // fast case
+assertEquals(SMI_MAX + ONE_HUNDRED, Add100(SMI_MAX));  // overflow
+assertEquals(SMI_MAX + ONE_HUNDRED, Add100Reversed(SMI_MAX));  // overflow
+assertEquals(42 + ONE_HUNDRED, Add100(OBJ_42));  // non-smi
+assertEquals(42 + ONE_HUNDRED, Add100Reversed(OBJ_42));  // non-smi
+
+
+
+function Sub1(x) {
+  return x - 1;
+}
+
+function Sub100(x) {
+  return x - 100;
+}
+
+function Sub1Reversed(x) {
+  return 1 - x;
+}
+
+function Sub100Reversed(x) {
+  return 100 - x;
+}
+
+
+assertEquals(0, Sub1(1));  // fast case
+assertEquals(-1, Sub1Reversed(2));  // fast case
+assertEquals(SMI_MIN - ONE, Sub1(SMI_MIN));  // overflow
+assertEquals(ONE - SMI_MIN, Sub1Reversed(SMI_MIN));  // overflow
+assertEquals(42 - ONE, Sub1(OBJ_42));  // non-smi
+assertEquals(ONE - 42, Sub1Reversed(OBJ_42));  // non-smi
+
+assertEquals(0, Sub100(100));  // fast case
+assertEquals(1, Sub100Reversed(99));  // fast case
+assertEquals(SMI_MIN - ONE_HUNDRED, Sub100(SMI_MIN));  // overflow
+assertEquals(ONE_HUNDRED - SMI_MIN, Sub100Reversed(SMI_MIN));  // overflow
+assertEquals(42 - ONE_HUNDRED, Sub100(OBJ_42));  // non-smi
+assertEquals(ONE_HUNDRED - 42, Sub100Reversed(OBJ_42));  // non-smi
diff --git a/regexp2000/test/mjsunit/sparse-array-reverse.js b/regexp2000/test/mjsunit/sparse-array-reverse.js
new file mode 100644 (file)
index 0000000..9b9f323
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Test reverse on small * and large arrays.
+ */
+
+var VERYLARGE = 4000000000;
+
+// Nicer for firefox 1.5.  Unless you uncomment the following line,
+// smjs will appear to hang on this file.
+//var VERYLARGE = 40000;
+
+
+// Simple test of reverse on sparse array.
+var a = [];
+a.length = 2000;
+a[15] = 'a';
+a[30] = 'b';
+Array.prototype[30] = 'B';  // Should be hidden by a[30].
+a[40] = 'c';
+a[50] = 'deleted';
+delete a[50]; // Should leave no trace once deleted.
+a[1959] = 'd'; // Swapped with a[40] when reversing.
+a[1999] = 'e';
+assertEquals("abcde", a.join(''));
+a.reverse();
+delete Array.prototype[30];
+assertEquals("edcba", a.join(''));
+
+
+
+var seed = 43;
+
+// CONG pseudo random number generator.  Used for fuzzing the sparse array
+// reverse code.
+function DoOrDont() {
+  seed = (69069 * seed + 1234567) % 0x100000000;
+  return (seed & 0x100000) != 0;
+}
+
+var sizes = [140, 40000, VERYLARGE];
+var poses = [0, 10, 50, 69];
+
+
+// Fuzzing test of reverse on sparse array.
+for (var iterations = 0; iterations < 20; iterations++) {
+  for (var size_pos = 0; size_pos < sizes.length; size_pos++) {
+    var size = sizes[size_pos];
+
+    var to_delete = [];
+
+    var a = new Array(size);
+
+    var expected = '';
+    var expected_reversed = '';
+
+    for (var pos_pos = 0; pos_pos < poses.length; pos_pos++) {
+      var pos = poses[pos_pos];
+      var letter = String.fromCharCode(97 + pos_pos);
+      if (DoOrDont()) {
+        a[pos] = letter;
+        expected += letter;
+        expected_reversed = letter + expected_reversed;
+      } else if (DoOrDont()) {
+        Array.prototype[pos] = letter;
+        expected += letter;
+        expected_reversed = letter + expected_reversed;
+        to_delete.push(pos);
+      }
+    }
+    var expected2 = '';
+    var expected_reversed2 = '';
+    for (var pos_pos = poses.length - 1; pos_pos >= 0; pos_pos--) {
+      var letter = String.fromCharCode(110 + pos_pos);
+      var pos = size - poses[pos_pos] - 1;
+      if (DoOrDont()) {
+        a[pos] = letter;
+        expected2 += letter;
+        expected_reversed2 = letter + expected_reversed2;
+      } else if (DoOrDont()) {
+        Array.prototype[pos] = letter;
+        expected2 += letter;
+        expected_reversed2 = letter + expected_reversed2;
+        to_delete.push(pos);
+      }
+    }
+
+    assertEquals(expected + expected2, a.join(''), 'join' + size);
+    a.reverse();
+
+    while (to_delete.length != 0) {
+      var pos = to_delete.pop();
+      delete(Array.prototype[pos]);
+    }
+
+    assertEquals(expected_reversed2 + expected_reversed, a.join(''), 'reverse then join' + size);
+  }
+}
diff --git a/regexp2000/test/mjsunit/sparse-array.js b/regexp2000/test/mjsunit/sparse-array.js
new file mode 100644 (file)
index 0000000..0952f2c
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Because of a bug in the heuristics used to figure out when to
+// convert a slow-case elements backing storage to fast case, the
+// following took a very long time.
+//
+// This test passes if it finishes almost immediately.
+for (var repetitions = 0; repetitions < 20; repetitions++) {
+  var stride = 500;
+  var array = [];
+  for (var i = 0; i < 1000; i++) {
+    array[i * stride] = i;
+  }
+}
+
+
diff --git a/regexp2000/test/mjsunit/str-to-num.js b/regexp2000/test/mjsunit/str-to-num.js
new file mode 100644 (file)
index 0000000..12a3716
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function toNumber(val) {
+  return Number(val);
+}
+
+// assertEquals(, toNumber());
+
+
+assertEquals(123, toNumber(" 123"));
+assertEquals(123, toNumber("\n123"));
+assertEquals(123, toNumber("\r123"));
+assertEquals(123, toNumber("\t123"));
+assertEquals(123, toNumber("\f123"));
+
+assertEquals(123, toNumber("123 "));
+assertEquals(123, toNumber("123\n"));
+assertEquals(123, toNumber("123\r"));
+assertEquals(123, toNumber("123\t"));
+assertEquals(123, toNumber("123\f"));
+
+assertEquals(123, toNumber(" 123 "));
+assertEquals(123, toNumber("\n123\n"));
+assertEquals(123, toNumber("\r123\r"));
+assertEquals(123, toNumber("\t123\t"));
+assertEquals(123, toNumber("\f123\f"));
+
+assertTrue(isNaN(toNumber(" NaN ")));
+assertEquals(Infinity,  toNumber(" Infinity ") ," Infinity");
+assertEquals(-Infinity, toNumber(" -Infinity "));
+assertEquals(Infinity,  toNumber(" +Infinity "), " +Infinity");
+assertEquals(Infinity,  toNumber("Infinity ") ,"Infinity");
+assertEquals(-Infinity, toNumber("-Infinity "));
+assertEquals(Infinity,  toNumber("+Infinity "), "+Infinity");
+
+assertEquals(0,  toNumber("0"));
+assertEquals(0,  toNumber("+0"));
+assertEquals(-0, toNumber("-0"));
+
+assertEquals(1,  toNumber("1"));
+assertEquals(1,  toNumber("+1"));
+assertEquals(-1, toNumber("-1"));
+
+assertEquals(2,  toNumber("2"));
+assertEquals(2,  toNumber("+2"));
+assertEquals(-2, toNumber("-2"));
+
+assertEquals(3.1415926,  toNumber("3.1415926"));
+assertEquals(3.1415926,  toNumber("+3.1415926"));
+assertEquals(-3.1415926, toNumber("-3.1415926"));
+
+assertEquals(5,  toNumber("5."));
+assertEquals(5,  toNumber("+5."));
+assertEquals(-5, toNumber("-5."));
+
+assertEquals(500,   toNumber("5e2"));
+assertEquals(500,   toNumber("+5e2"));
+assertEquals(-500,  toNumber("-5e2"));
+assertEquals(500,   toNumber("5e+2"));
+assertEquals(500,   toNumber("+5e+2"));
+assertEquals(-500,  toNumber("-5e+2"));
+assertEquals(0.05,  toNumber("5e-2"));
+assertEquals(0.05,  toNumber("+5e-2"));
+assertEquals(-0.05, toNumber("-5e-2"));
+
+assertEquals(0.00001,   toNumber(".00001"));
+assertEquals(0.00001,   toNumber("+.00001"));
+assertEquals(-0.00001,  toNumber("-.00001"));
+assertEquals(1,         toNumber(".00001e5"));
+assertEquals(1,         toNumber("+.00001e5"));
+assertEquals(-1,        toNumber("-.00001e5"));
+assertEquals(1,         toNumber(".00001e+5"));
+assertEquals(1,         toNumber("+.00001e+5"));
+assertEquals(-1,        toNumber("-.00001e+5"));
+assertEquals(0.00001,   toNumber(".001e-2"));
+assertEquals(0.00001,   toNumber("+.001e-2"));
+assertEquals(-0.00001,  toNumber("-.001e-2"));
+
+assertEquals(12340000,   toNumber("1234e4"));
+assertEquals(12340000,   toNumber("+1234e4"));
+assertEquals(-12340000,  toNumber("-1234e4"));
+assertEquals(12340000,   toNumber("1234e+4"));
+assertEquals(12340000,   toNumber("+1234e+4"));
+assertEquals(-12340000,  toNumber("-1234e+4"));
+assertEquals(0.1234,     toNumber("1234e-4"));
+assertEquals(0.1234,     toNumber("+1234e-4"));
+assertEquals(-0.1234,    toNumber("-1234e-4"));
+
+assertEquals(0,  toNumber("0x0"));
+assertEquals(1,  toNumber("0x1"));
+assertEquals(2,  toNumber("0x2"));
+assertEquals(9,  toNumber("0x9"));
+assertEquals(10, toNumber("0xa"));
+assertEquals(11, toNumber("0xb"));
+assertEquals(15, toNumber("0xf"));
+assertEquals(10, toNumber("0xA"));
+assertEquals(11, toNumber("0xB"));
+assertEquals(15, toNumber("0xF"));
+
+assertEquals(0,  toNumber("0X0"));
+assertEquals(9,  toNumber("0X9"));
+assertEquals(10, toNumber("0Xa"));
+assertEquals(10, toNumber("0XA"));
+assertEquals(15, toNumber("0Xf"));
+assertEquals(15, toNumber("0XF"));
+
+assertEquals(0,  toNumber("0x000"));
+assertEquals(9,  toNumber("0x009"));
+assertEquals(10, toNumber("0x00a"));
+assertEquals(10, toNumber("0x00A"));
+assertEquals(15, toNumber("0x00f"));
+assertEquals(15, toNumber("0x00F"));
+
+assertEquals(0, toNumber("00"));
+assertEquals(1, toNumber("01"));
+assertEquals(2, toNumber("02"));
+assertEquals(10, toNumber("010"));
+assertEquals(100, toNumber("0100"));
+assertEquals(100, toNumber("000100"));
+
+assertEquals(Infinity,  toNumber("1e999"), "1e999");
+assertEquals(-Infinity, toNumber("-1e999"));
+assertEquals(0,         toNumber("1e-999"));
+assertEquals(0,         toNumber("-1e-999"));
+assertEquals(Infinity,  1 / toNumber("1e-999"), "1e-999");
+assertEquals(-Infinity, 1 / toNumber("-1e-999"));
+
+assertTrue(isNaN(toNumber("junk")), "junk");
+assertTrue(isNaN(toNumber("100 junk")), "100 junk");
+assertTrue(isNaN(toNumber("0x100 junk")), "0x100 junk");
+assertTrue(isNaN(toNumber("100.0 junk")), "100.0 junk");
+assertTrue(isNaN(toNumber(".1e4 junk")), ".1e4 junk");
+assertTrue(isNaN(toNumber("Infinity junk")), "Infinity junk");
diff --git a/regexp2000/test/mjsunit/stress-array-push.js b/regexp2000/test/mjsunit/stress-array-push.js
new file mode 100644 (file)
index 0000000..1db2e2a
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Rewrite of mozilla_js_tests/js1_5/GC/regress-278725
+// to stress test pushing elements to an array.
+var results = [];
+for (var k = 0; k < 60000; k++) {
+  if ((k%10000) == 0) results.length = 0;
+  results.push({});
+}
diff --git a/regexp2000/test/mjsunit/strict-equals.js b/regexp2000/test/mjsunit/strict-equals.js
new file mode 100644 (file)
index 0000000..d080ce8
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var n = null;
+var u = void 0;
+assertTrue(null === null);
+assertTrue(null === n);
+assertTrue(n === null);
+assertTrue(n === n);
+assertFalse(null === void 0);
+assertFalse(void 0 === null);
+assertFalse(u === null);
+assertFalse(null === u);
+assertFalse(n === u);
+assertFalse(u === n);
+assertTrue(void 0 === void 0);
+assertTrue(u === u);
+assertTrue(u === void 0);
+assertTrue(void 0 === u);
+
+assertTrue('foo' === 'foo');
+assertFalse('bar' === 'foo');
+assertFalse('foo' === new String('foo'));
+assertFalse(new String('foo') === new String('foo'));
+var s = new String('foo');
+assertTrue(s === s);
+assertFalse(s === null);
+assertFalse(s === void 0);
+assertFalse('foo' === null);
+assertFalse('foo' === 7);
+assertFalse('foo' === true);
+assertFalse('foo' === void 0);
+assertFalse('foo' === {});
+
+assertFalse({} === {});
+var x = {};
+assertTrue(x === x);
+assertFalse(x === null);
+assertFalse(x === 7);
+assertFalse(x === true);
+assertFalse(x === void 0);
+assertFalse(x === {});
+
+assertTrue(true === true);
+assertTrue(false === false);
+assertFalse(false === true);
+assertFalse(true === false);
+assertFalse(true === new Boolean(true));
+assertFalse(true === new Boolean(false));
+assertFalse(false === new Boolean(true));
+assertFalse(false === new Boolean(false));
+assertFalse(true === 0);
+assertFalse(true === 1);
+
+assertTrue(0 === 0);
+assertTrue(-0 === -0);
+assertTrue(-0 === 0);
+assertTrue(0 === -0);
+assertFalse(0 === new Number(0));
+assertFalse(1 === new Number(1));
+assertTrue(4.2 === 4.2);
+assertTrue(4.2 === Number(4.2));
+
+
+
+
diff --git a/regexp2000/test/mjsunit/string-case.js b/regexp2000/test/mjsunit/string-case.js
new file mode 100644 (file)
index 0000000..13dcd3e
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertEquals("ΚΟΣΜΟΣ ΚΟΣΜΟΣ".toLowerCase(), "κοσμος κοσμος");
diff --git a/regexp2000/test/mjsunit/string-charat.js b/regexp2000/test/mjsunit/string-charat.js
new file mode 100644 (file)
index 0000000..8ec8f1e
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var s = "test";
+
+assertEquals("t", s.charAt());
+assertEquals("t", s.charAt("string"));
+assertEquals("t", s.charAt(null));
+assertEquals("t", s.charAt(void 0));
+assertEquals("t", s.charAt(false));
+assertEquals("e", s.charAt(true));
+assertEquals("", s.charAt(-1));
+assertEquals("", s.charAt(4));
+assertEquals("t", s.charAt(0));
+assertEquals("t", s.charAt(3));
+assertEquals("t", s.charAt(NaN));
+
+assertEquals(116, s.charCodeAt());
+assertEquals(116, s.charCodeAt("string"));
+assertEquals(116, s.charCodeAt(null));
+assertEquals(116, s.charCodeAt(void 0));
+assertEquals(116, s.charCodeAt(false));
+assertEquals(101, s.charCodeAt(true));
+assertEquals(116, s.charCodeAt(0));
+assertEquals(116, s.charCodeAt(3));
+assertEquals(116, s.charCodeAt(NaN));
+assertTrue(isNaN(s.charCodeAt(-1)));
+assertTrue(isNaN(s.charCodeAt(4)));
+
diff --git a/regexp2000/test/mjsunit/string-charcodeat.js b/regexp2000/test/mjsunit/string-charcodeat.js
new file mode 100644 (file)
index 0000000..f66dd3e
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Check all sorts of borderline cases for charCodeAt.
+ */
+
+function Cons() {
+  return "Te" + "st";
+}
+
+
+function Deep() {
+  var a = "T";
+  a += "e";
+  a += "s";
+  a += "t";
+  return a;
+}
+
+
+function Slice() {
+  return "testing Testing".substring(8, 12);
+}
+
+
+function Flat() {
+  return "Test";
+}
+
+function Cons16() {
+  return "Te" + "\u1234t";
+}
+
+
+function Deep16() {
+  var a = "T";
+  a += "e";
+  a += "\u1234";
+  a += "t";
+  return a;
+}
+
+
+function Slice16Beginning() {
+  return "Te\u1234t test".substring(0, 4);
+}
+
+
+function Slice16Middle() {
+  return "test Te\u1234t test".substring(5, 9);
+}
+
+
+function Slice16End() {
+  return "test Te\u1234t".substring(5, 9);
+}
+
+
+function Flat16() {
+  return "Te\u1234t";
+}
+
+
+function Thing() {
+}
+
+
+function NotAString() {
+  var n = new Thing();
+  n.toString = function() { return "Test"; };
+  n.charCodeAt = String.prototype.charCodeAt;
+  return n;
+}
+
+
+function NotAString16() {
+  var n = new Thing();
+  n.toString = function() { return "Te\u1234t"; };
+  n.charCodeAt = String.prototype.charCodeAt;
+  return n;
+}
+
+
+function TestStringType(generator, sixteen) {
+  var g = generator;
+  assertTrue(isNaN(g().charCodeAt(-1e19)));
+  assertTrue(isNaN(g().charCodeAt(-0x80000001)));
+  assertTrue(isNaN(g().charCodeAt(-0x80000000)));
+  assertTrue(isNaN(g().charCodeAt(-0x40000000)));
+  assertTrue(isNaN(g().charCodeAt(-1)));
+  assertTrue(isNaN(g().charCodeAt(4)));
+  assertTrue(isNaN(g().charCodeAt(5)));
+  assertTrue(isNaN(g().charCodeAt(0x3fffffff)));
+  assertTrue(isNaN(g().charCodeAt(0x7fffffff)));
+  assertTrue(isNaN(g().charCodeAt(0x80000000)));
+  assertTrue(isNaN(g().charCodeAt(1e9)));
+  assertEquals(84, g().charCodeAt(0));
+  assertEquals(84, g().charCodeAt("test"));
+  assertEquals(84, g().charCodeAt(""));
+  assertEquals(84, g().charCodeAt(null));
+  assertEquals(84, g().charCodeAt(undefined));
+  assertEquals(84, g().charCodeAt());
+  assertEquals(84, g().charCodeAt(void 0));
+  assertEquals(84, g().charCodeAt(false));
+  assertEquals(101, g().charCodeAt(true));
+  assertEquals(101, g().charCodeAt(1));
+  assertEquals(sixteen ? 0x1234 : 115, g().charCodeAt(2));
+  assertEquals(116, g().charCodeAt(3));
+  assertEquals(101, g().charCodeAt(1.1));
+  assertEquals(sixteen ? 0x1234 : 115, g().charCodeAt(2.1718));
+  assertEquals(116, g().charCodeAt(3.14159));
+}
+
+
+TestStringType(Cons, false);
+TestStringType(Deep, false);
+TestStringType(Slice, false);
+TestStringType(Flat, false);
+TestStringType(NotAString, false);
+TestStringType(Cons16, true);
+TestStringType(Deep16, true);
+TestStringType(Slice16Beginning, true);
+TestStringType(Slice16Middle, true);
+TestStringType(Slice16End, true);
+TestStringType(Flat16, true);
+TestStringType(NotAString16, true);
+
+
+function StupidThing() {
+  // Doesn't return a string from toString!
+  this.toString = function() { return 42; }
+  this.charCodeAt = String.prototype.charCodeAt;
+}
+
+assertEquals(52, new StupidThing().charCodeAt(0));
+assertEquals(50, new StupidThing().charCodeAt(1));
+assertTrue(isNaN(new StupidThing().charCodeAt(2)));
+assertTrue(isNaN(new StupidThing().charCodeAt(-1)));
+
+
+// Medium (>255) and long (>65535) strings.
+
+var medium = "12345678";
+medium += medium; // 16.
+medium += medium; // 32.
+medium += medium; // 64.
+medium += medium; // 128.
+medium += medium; // 256.
+
+var long = medium;
+long += long + long + long;     // 1024.
+long += long + long + long;     // 4096.
+long += long + long + long;     // 16384.
+long += long + long + long;     // 65536.
+
+assertTrue(isNaN(medium.charCodeAt(-1)));
+assertEquals(49, medium.charCodeAt(0));
+assertEquals(56, medium.charCodeAt(255));
+assertTrue(isNaN(medium.charCodeAt(256)));
+
+assertTrue(isNaN(long.charCodeAt(-1)));
+assertEquals(49, long.charCodeAt(0));
+assertEquals(56, long.charCodeAt(65535));
+assertTrue(isNaN(long.charCodeAt(65536)));
diff --git a/regexp2000/test/mjsunit/string-flatten.js b/regexp2000/test/mjsunit/string-flatten.js
new file mode 100644 (file)
index 0000000..91877b2
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Check for regression of bug 1011505 (out of memory when flattening strings).
+var i;
+var s = "";
+
+for (i = 0; i < 1024; i++) {
+  s = s + (i + (i+1));
+  s = s.substring(1);
+}
+// Flatten the string.
+assertEquals(57, s.charCodeAt(0));
diff --git a/regexp2000/test/mjsunit/string-index.js b/regexp2000/test/mjsunit/string-index.js
new file mode 100644 (file)
index 0000000..2256286
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/**
+ * @fileoverview Test indexing on strings with [].
+ */
+
+var foo = "Foo";
+assertEquals("Foo", foo);
+assertEquals("F", foo[0]);
+assertEquals("o", foo[1]);
+assertEquals("o", foo[2]);
+
+assertEquals("F", foo["0" + ""], "string index");
+assertEquals("o", foo["1"], "string index");
+assertEquals("o", foo["2"], "string index");
+
+assertEquals("undefined", typeof(foo[3]), "out of range");
+// SpiderMonkey 1.5 fails this next one.  So does FF 2.0.6.
+assertEquals("undefined", typeof(foo[-1]), "known failure in SpiderMonkey 1.5");
+assertEquals("undefined", typeof(foo[-2]), "negative index");
+
+foo[0] = "f";
+assertEquals("Foo", foo);
+
+foo[3] = "t";
+assertEquals("Foo", foo);
+assertEquals("undefined", typeof(foo[3]), "out of range");
+assertEquals("undefined", typeof(foo[-2]), "negative index");
+
+var S = new String("foo");
+assertEquals("foo", S);
+assertEquals("f", S[0], "string object");
+assertEquals("f", S["0"], "string object");
+S[0] = 'bente';
+assertEquals("f", S[0], "string object");
+assertEquals("f", S["0"], "string object");
+S[-2] = 'spider';
+assertEquals('spider', S[-2]);
+S[3] = 'monkey';
+assertEquals('monkey', S[3]);
+S['foo'] = 'Fu';
+assertEquals("Fu", S.foo);
+
+// In FF this is ignored I think.  In V8 it puts a property on the String object
+// but you won't ever see it because it is hidden by the 0th character in the
+// string.  The net effect is pretty much the same.
+S["0"] = 'bente';
+assertEquals("f", S[0], "string object");
+assertEquals("f", S["0"], "string object");
+
+assertEquals(true, 0 in S, "0 in");
+assertEquals(false, -1 in S, "-1 in");
+assertEquals(true, 2 in S, "2 in");
+assertEquals(true, 3 in S, "3 in");
+assertEquals(false, 4 in S, "3 in");
+
+assertEquals(true, "0" in S, '"0" in');
+assertEquals(false, "-1" in S, '"-1" in');
+assertEquals(true, "2" in S, '"2" in');
+assertEquals(true, "3" in S, '"3" in');
+assertEquals(false, "4" in S, '"3" in');
+
+assertEquals(true, S.hasOwnProperty(0), "0 hasOwnProperty");
+assertEquals(false, S.hasOwnProperty(-1), "-1 hasOwnProperty");
+assertEquals(true, S.hasOwnProperty(2), "2 hasOwnProperty");
+assertEquals(true, S.hasOwnProperty(3), "3 hasOwnProperty");
+assertEquals(false, S.hasOwnProperty(4), "3 hasOwnProperty");
+
+assertEquals(true, S.hasOwnProperty("0"), '"0" hasOwnProperty');
+assertEquals(false, S.hasOwnProperty("-1"), '"-1" hasOwnProperty');
+assertEquals(true, S.hasOwnProperty("2"), '"2" hasOwnProperty');
+assertEquals(true, S.hasOwnProperty("3"), '"3" hasOwnProperty');
+assertEquals(false, S.hasOwnProperty("4"), '"3" hasOwnProperty');
+
+assertEquals(true, "foo".hasOwnProperty(0), "foo 0 hasOwnProperty");
+assertEquals(false, "foo".hasOwnProperty(-1), "foo -1 hasOwnProperty");
+assertEquals(true, "foo".hasOwnProperty(2), "foo 2 hasOwnProperty");
+assertEquals(false, "foo".hasOwnProperty(4), "foo 3 hasOwnProperty");
+
+assertEquals(true, "foo".hasOwnProperty("0"), 'foo "0" hasOwnProperty');
+assertEquals(false, "foo".hasOwnProperty("-1"), 'foo "-1" hasOwnProperty');
+assertEquals(true, "foo".hasOwnProperty("2"), 'foo "2" hasOwnProperty');
+assertEquals(false, "foo".hasOwnProperty("4"), 'foo "3" hasOwnProperty');
+
+//assertEquals(true, 0 in "foo", "0 in");
+//assertEquals(false, -1 in "foo", "-1 in");
+//assertEquals(true, 2 in "foo", "2 in");
+//assertEquals(false, 3 in "foo", "3 in");
+//
+//assertEquals(true, "0" in "foo", '"0" in');
+//assertEquals(false, "-1" in "foo", '"-1" in');
+//assertEquals(true, "2" in "foo", '"2" in');
+//assertEquals(false, "3" in "foo", '"3" in');
+
+delete S[3];
+assertEquals("undefined", typeof(S[3]));
+assertEquals(false, 3 in S);
+assertEquals(false, "3" in S);
+
+var N = new Number(43);
+assertEquals(43, N);
+N[-2] = "Alpha";
+assertEquals("Alpha", N[-2]);
+N[0] = "Zappa";
+assertEquals("Zappa", N[0]);
+assertEquals("Zappa", N["0"]);
+
+var A = ["V", "e", "t", "t", "e", "r"];
+var A2 = (A[0] = "v");
+assertEquals('v', A[0]);
+assertEquals('v', A2);
+
+var S = new String("Onkel");
+var S2 = (S[0] = 'o');
+assertEquals('O', S[0]);
+assertEquals('o', S2);
+
+var s = "Tante";
+var s2 = (s[0] = 't');
+assertEquals('T', s[0]);
+assertEquals('t', s2);
+
+var S2 = (S[-2] = 'o');
+assertEquals('o', S[-2]);
+assertEquals('o', S2);
+
+var s2 = (s[-2] = 't');
+assertEquals('undefined', typeof(s[-2]));
+assertEquals('t', s2);
diff --git a/regexp2000/test/mjsunit/string-indexof.js b/regexp2000/test/mjsunit/string-indexof.js
new file mode 100644 (file)
index 0000000..2018da7
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var s = "test test test";
+
+assertEquals(0, s.indexOf("t"));
+assertEquals(3, s.indexOf("t", 1));
+assertEquals(5, s.indexOf("t", 4));
+assertEquals(1, s.indexOf("e"));
+assertEquals(2, s.indexOf("s"));
+
+assertEquals(5, s.indexOf("test", 4));
+assertEquals(5, s.indexOf("test", 5));
+assertEquals(10, s.indexOf("test", 6));
+assertEquals(0, s.indexOf("test", 0));
+assertEquals(0, s.indexOf("test", -1));
+assertEquals(0, s.indexOf("test"));
+assertEquals(-1, s.indexOf("notpresent"));
+assertEquals(-1, s.indexOf());
+
+for (var i = 0; i < s.length+10; i++) {
+  var expected = i < s.length ? i : s.length;
+  assertEquals(expected, s.indexOf("", i));
+}
+
+var reString = "asdf[a-z]+(asdf)?";
+
+assertEquals(4, reString.indexOf("[a-z]+"));
+assertEquals(10, reString.indexOf("(asdf)?"));
+
+assertEquals(1, String.prototype.indexOf.length);
+
+// Random greek letters
+var twoByteString = "\u039a\u0391\u03a3\u03a3\u0395";
+
+// Test single char pattern
+assertEquals(0, twoByteString.indexOf("\u039a"), "Lamda");
+assertEquals(1, twoByteString.indexOf("\u0391"), "Alpha");
+assertEquals(2, twoByteString.indexOf("\u03a3"), "First Sigma");
+assertEquals(3, twoByteString.indexOf("\u03a3",3), "Second Sigma");
+assertEquals(4, twoByteString.indexOf("\u0395"), "Epsilon");
+assertEquals(-1, twoByteString.indexOf("\u0392"), "Not beta");  
+
+// Test multi-char pattern
+assertEquals(0, twoByteString.indexOf("\u039a\u0391"), "lambda Alpha");
+assertEquals(1, twoByteString.indexOf("\u0391\u03a3"), "Alpha Sigma");
+assertEquals(2, twoByteString.indexOf("\u03a3\u03a3"), "Sigma Sigma");
+assertEquals(3, twoByteString.indexOf("\u03a3\u0395"), "Sigma Epsilon");
+
+assertEquals(-1, twoByteString.indexOf("\u0391\u03a3\u0395"), 
+    "Not Alpha Sigma Epsilon");
+
+//single char pattern
+assertEquals(4, twoByteString.indexOf("\u0395"));
+
+// Test complex string indexOf algorithms. Only trigger for long strings.
+
+// Long string that isn't a simple repeat of a shorter string.
+var long = "A";
+for(var i = 66; i < 76; i++) {  // from 'B' to 'K'
+  long =  long + String.fromCharCode(i) + long;
+}
+
+// pattern of 15 chars, repeated every 16 chars in long
+var pattern = "ABACABADABACABA";
+for(var i = 0; i < long.length - pattern.length; i+= 7) {
+  var index = long.indexOf(pattern, i);
+  assertEquals((i + 15) & ~0xf, index, "Long ABACABA...-string at index " + i);
+}
+assertEquals(510, long.indexOf("AJABACA"), "Long AJABACA, First J");
+assertEquals(1534, long.indexOf("AJABACA", 511), "Long AJABACA, Second J");
+
+pattern = "JABACABADABACABA";
+assertEquals(511, long.indexOf(pattern), "Long JABACABA..., First J");
+assertEquals(1535, long.indexOf(pattern, 512), "Long JABACABA..., Second J");
+
+
+var lipsum = "lorem ipsum per se esse fugiendum. itaque aiunt hanc quasi "
+    + "naturalem atque insitam in animis nostris inesse notionem, ut "
+    + "alterum esse appetendum, alterum aspernandum sentiamus. Alii autem,"
+    + " quibus ego assentior, cum a philosophis compluribus permulta "
+    + "dicantur, cur nec voluptas in bonis sit numeranda nec in malis "
+    + "dolor, non existimant oportere nimium nos causae confidere, sed et"
+    + " argumentandum et accurate disserendum et rationibus conquisitis de"
+    + " voluptate et dolore disputandum putant.\n"
+    + "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem "
+    + "accusantium doloremque laudantium, totam rem aperiam eaque ipsa,"
+    + "quae ab illo inventore veritatis et quasi architecto beatae vitae "
+    + "dicta sunt, explicabo. nemo enim ipsam voluptatem, quia voluptas"
+    + "sit, aspernatur aut odit aut fugit, sed quia consequuntur magni"
+    + " dolores eos, qui ratione voluptatem sequi nesciunt, neque porro"
+    + " quisquam est, qui dolorem ipsum, quia dolor sit, amet, "
+    + "consectetur, adipisci velit, sed quia non numquam eius modi"
+    + " tempora incidunt, ut labore et dolore magnam aliquam quaerat "
+    + "voluptatem. ut enim ad minima veniam, quis nostrum exercitationem "
+    + "ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi "
+    + "consequatur? quis autem vel eum iure reprehenderit, qui in ea "
+    + "voluptate velit esse, quam nihil molestiae consequatur, vel illum, "
+    + "qui dolorem eum fugiat, quo voluptas nulla pariatur?\n";
+
+assertEquals(893, lipsum.indexOf("lorem ipsum, quia dolor sit, amet"),
+        "Lipsum");
+// test a lot of substrings of differing length and start-position.
+for(var i = 0; i < lipsum.length; i += 3) {
+  for(var len = 1; i + len < lipsum.length; len += 7) {
+    var substring = lipsum.substring(i, i + len);
+    var index = -1;
+    do {
+      index = lipsum.indexOf(substring, index + 1);
+      assertTrue(index != -1, 
+                 "Lipsum substring " + i + ".." + (i + len-1) + " not found");
+      assertEquals(lipsum.substring(index, index + len), substring, 
+          "Wrong lipsum substring found: " + i + ".." + (i + len - 1) + "/" + 
+              index + ".." + (index + len - 1));
+    } while (index >= 0 && index < i);
+    assertEquals(i, index, "Lipsum match at " + i + ".." + (i + len - 1));
+  }
+}
diff --git a/regexp2000/test/mjsunit/string-lastindexof.js b/regexp2000/test/mjsunit/string-lastindexof.js
new file mode 100644 (file)
index 0000000..bf46666
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var s = "test test test";
+
+assertEquals(5, s.lastIndexOf("test", 5));
+assertEquals(5, s.lastIndexOf("test", 6));
+assertEquals(0, s.lastIndexOf("test", 4));
+assertEquals(0, s.lastIndexOf("test", 0));
+assertEquals(-1, s.lastIndexOf("test", -1));
+assertEquals(10, s.lastIndexOf("test"));
+assertEquals(-1, s.lastIndexOf("notpresent"));
+assertEquals(-1, s.lastIndexOf());
+assertEquals(10, s.lastIndexOf("test", "not a number"));
+
+for (var i = s.length + 10; i >= 0; i--) {
+  var expected = i < s.length ? i : s.length;
+  assertEquals(expected, s.lastIndexOf("", i));
+}
+
+
+var reString = "asdf[a-z]+(asdf)?";
+
+assertEquals(4, reString.lastIndexOf("[a-z]+"));
+assertEquals(10, reString.lastIndexOf("(asdf)?"));
+
+assertEquals(1, String.prototype.lastIndexOf.length);
diff --git a/regexp2000/test/mjsunit/string-localecompare.js b/regexp2000/test/mjsunit/string-localecompare.js
new file mode 100644 (file)
index 0000000..90a1813
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// String.prototype.localeCompare.
+//
+// Implementation dependent function.  For now, we do not do anything
+// locale specific.
+
+// Equal prefix.
+assertTrue("asdf".localeCompare("asdf") == 0);
+assertTrue("asd".localeCompare("asdf") < 0);
+assertTrue("asdff".localeCompare("asdf") > 0);
+
+// Chars differ.
+assertTrue("asdf".localeCompare("asdq") < 0);
+assertTrue("asdq".localeCompare("asdf") > 0);
diff --git a/regexp2000/test/mjsunit/string-search.js b/regexp2000/test/mjsunit/string-search.js
new file mode 100644 (file)
index 0000000..36891c2
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var str="ABC abc";
+var r = str.search('a');
+assertEquals(r, 4);
diff --git a/regexp2000/test/mjsunit/string-split.js b/regexp2000/test/mjsunit/string-split.js
new file mode 100644 (file)
index 0000000..59d3ad3
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+expected = ["A", undefined, "B", "bold", "/", "B", "and", undefined, "CODE", "coded", "/", "CODE", ""];
+result = "A<B>bold</B>and<CODE>coded</CODE>".split(/<(\/)?([^<>]+)>/);
+assertArrayEquals(expected, result, 1);
+
+expected = ["a", "b"];
+result = "ab".split(/a*?/);
+assertArrayEquals(expected, result, 2);
+
+expected = ["", "b"];
+result = "ab".split(/a*/);
+assertArrayEquals(expected, result, 3);
+
+expected = ["a"];
+result = "ab".split(/a*?/, 1);
+assertArrayEquals(expected, result, 4);
+
+expected = [""];
+result = "ab".split(/a*/, 1);
+assertArrayEquals(expected, result, 5);
+
+expected = ["as","fas","fas","f"];
+result = "asdfasdfasdf".split("d");
+assertArrayEquals(expected, result, 6);
+
+expected = ["as","fas","fas","f"];
+result = "asdfasdfasdf".split("d", -1);
+assertArrayEquals(expected, result, 7);
+
+expected = ["as", "fas"];
+result = "asdfasdfasdf".split("d", 2);
+assertArrayEquals(expected, result, 8);
+
+expected = [];
+result = "asdfasdfasdf".split("d", 0);
+assertArrayEquals(expected, result, 9);
+
+expected = ["as","fas","fas",""];
+result = "asdfasdfasd".split("d");
+assertArrayEquals(expected, result, 10);
+
+expected = [];
+result = "".split("");
+assertArrayEquals(expected, result, 11);
+
+expected = [""]
+result = "".split("a");
+assertArrayEquals(expected, result, 12);
+
+expected = ["a","b"]
+result = "axxb".split(/x*/);
+assertArrayEquals(expected, result, 13);
+
+expected = ["a","b"]
+result = "axxb".split(/x+/);
+assertArrayEquals(expected, result, 14);
+
+expected = ["a","","b"]
+result = "axxb".split(/x/);
+assertArrayEquals(expected, result, 15);
+
+// This was http://b/issue?id=1151354
+expected = ["div", "#id", ".class"]
+result = "div#id.class".split(/(?=[#.])/);
+assertArrayEquals(expected, result, 16);
+
+expected = ["div", "#i", "d", ".class"]
+result = "div#id.class".split(/(?=[d#.])/);
+assertArrayEquals(expected, result, 17);
+
+expected = ["a", "b", "c"]
+result = "abc".split(/(?=.)/);
+assertArrayEquals(expected, result, 18);
+
+/* "ab".split(/((?=.))/)
+ * 
+ * KJS:   ,a,,b
+ * SM:    a,,b,
+ * IE:    a,b
+ * Opera: a,,b
+ * V8:    a,,b
+ * 
+ * Opera seems to have this right.  The others make no sense.
+ */
+expected = ["a", "", "b"]
+result = "ab".split(/((?=.))/);
+assertArrayEquals(expected, result, 19);
+
+/* "ab".split(/(?=)/)
+ *
+ * KJS:   a,b
+ * SM:    ab
+ * IE:    a,b
+ * Opera: a,b
+ * V8:    a,b
+ */
+expected = ["a", "b"]
+result = "ab".split(/(?=)/);
+assertArrayEquals(expected, result, 20);
+
diff --git a/regexp2000/test/mjsunit/substr.js b/regexp2000/test/mjsunit/substr.js
new file mode 100644 (file)
index 0000000..8c276f9
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var s = 'abcdefghijklmn';
+assertEquals(s, s.substr());
+assertEquals(s, s.substr(0));
+assertEquals(s, s.substr('0'));
+assertEquals(s, s.substr(void 0));
+assertEquals(s, s.substr(null));
+assertEquals(s, s.substr(false));
+assertEquals(s, s.substr(0.9));
+assertEquals(s, s.substr({ valueOf: function() { return 0; } }));
+assertEquals(s, s.substr({ toString: function() { return '0'; } }));
+
+var s1 = s.substring(1);
+assertEquals(s1, s.substr(1));
+assertEquals(s1, s.substr('1'));
+assertEquals(s1, s.substr(true));
+assertEquals(s1, s.substr(1.1));
+assertEquals(s1, s.substr({ valueOf: function() { return 1; } }));
+assertEquals(s1, s.substr({ toString: function() { return '1'; } }));
+
+for (var i = 0; i < s.length; i++)
+  for (var j = i; j < s.length + 5; j++)
+    assertEquals(s.substring(i, j), s.substr(i, j - i));
+
+assertEquals(s.substring(s.length - 1), s.substr(-1));
+assertEquals(s.substring(s.length - 1), s.substr(-1.2));
+assertEquals(s.substring(s.length - 1), s.substr(-1.7));
+assertEquals(s.substring(s.length - 2), s.substr(-2));
+assertEquals(s.substring(s.length - 2), s.substr(-2.3));
+assertEquals(s.substring(s.length - 2, s.length - 1), s.substr(-2, 1));
+assertEquals(s, s.substr(-100));
+assertEquals('abc', s.substr(-100, 3));
+assertEquals(s1, s.substr(-s.length + 1));
+
+// assertEquals('', s.substr(0, void 0)); // smjs and rhino 
+assertEquals('abcdefghijklmn', s.substr(0, void 0));  // kjs and v8
+assertEquals('', s.substr(0, null));
+assertEquals(s, s.substr(0, String(s.length)));
+assertEquals('a', s.substr(0, true));
diff --git a/regexp2000/test/mjsunit/switch.js b/regexp2000/test/mjsunit/switch.js
new file mode 100644 (file)
index 0000000..ae5ce2b
--- /dev/null
@@ -0,0 +1,227 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f0() {
+  switch (0) {
+    // switch deliberately left empty
+  }
+}
+
+f0();  // no errors
+
+function f1(x) {
+  switch (x) {
+    default:      return "f1";
+  }
+  return "foo";
+}
+
+assertEquals("f1", f1(0), "default-switch.0");
+assertEquals("f1", f1(1), "default-switch.1");
+
+function f2(x) {
+  var r;
+  switch (x) {
+    case 0:
+      r = "zero";
+      break;
+    case 1:
+      r = "one";
+      break;
+    case 2:
+      r = "two";
+      break;
+    case 3:
+      r = "three";
+      break;
+    default:
+      r = "default";
+  }
+  return r;
+}
+
+assertEquals("zero", f2(0), "0-1-switch.0");
+assertEquals("one", f2(1), "0-1-switch.1");
+assertEquals("default", f2(7), "0-1-switch.2");
+assertEquals("default", f2(-1), "0-1-switch.-1");
+assertEquals("default", f2(NaN), "0-1-switch.NaN");
+assertEquals("default", f2(Math.pow(2,34)), "0-1-switch.largeNum");
+assertEquals("default", f2("0"), "0-1-switch.string");
+assertEquals("default", f2(false), "0-1-switch.bool");
+assertEquals("default", f2(null), "0-1-switch.null");
+assertEquals("default", f2(undefined), "0-1-switch.undef");
+assertEquals("default", f2(new Number(2)), "0-1-switch.undef");
+assertEquals("default", f2({valueOf: function(){return 2; }}), "0-1-switch.obj");
+
+
+function f3(x, c) {
+  var r = 0;
+  switch (x) {
+    default:
+      r = "default";
+      break;
+    case  c:
+      r = "value is c = " + c;
+      break;
+    case  2:
+      r = "two";
+      break;
+    case -5:
+      r = "minus 5";
+      break;
+    case  9:
+      r = "nine";
+      break;
+  }
+  return r;
+}
+
+assertEquals("two", f3(2,0), "value-switch.2-0");
+assertEquals("minus 5", f3(-5,0), "value-switch.-5-0");
+assertEquals("nine", f3(9,0), "value-switch.9-0");
+assertEquals("value is c = 0", f3(0,0), "value-switch.0-0");
+assertEquals("value is c = 2", f3(2,2), "value-switch.2-2");
+assertEquals("default", f3(7,0), "value-switch.7-0");
+
+
+function f4(x) {
+  switch(x) {
+    case 0:
+      x++;
+    default:
+      x++;
+    case 2:
+      x++;
+  }
+  return x;
+}
+
+
+assertEquals(3, f4(0), "fallthrough-switch.0");
+assertEquals(3, f4(1), "fallthrough-switch.1");
+assertEquals(3, f4(2), "fallthrough-switch.2");
+assertEquals(5, f4(3), "fallthrough-switch.3");
+
+
+function f5(x) {
+  switch(x) {
+     case -2: return true;
+     case -1: return false;
+     case 0: return true;
+     case 2: return false;
+     default: return 42;
+  }
+}
+
+assertTrue(f5(-2), "negcase.-2");
+assertFalse(f5(-1), "negcase.-1");
+assertTrue(f5(0), "negcase.-0");
+assertEquals(42, f5(1), "negcase.1");
+assertFalse(f5(2), "negcase.2");
+
+function f6(N) {
+  // long enough case that code buffer grows during code-generation
+  var res = 0;
+  for(var i = 0; i < N; i++) {
+    switch(i & 0x3f) {
+    case 0: res += 0; break;
+    case 1: res += 1; break;
+    case 2: res += 2; break;
+    case 3: res += 3; break;
+    case 4: res += 4; break;
+    case 5: res += 5; break;
+    case 6: res += 6; break;
+    case 7: res += 7; break;
+    case 8: res += 8; break;
+    case 9: res += 9; break;
+    case 10: res += 10; break;
+    case 11: res += 11; break;
+    case 12: res += 12; break;
+    case 13: res += 13; break;
+    case 14: res += 14; break;
+    case 15: res += 15; break;
+    case 16: res += 16; break;
+    case 17: res += 17; break;
+    case 18: res += 18; break;
+    case 19: res += 19; break;
+    case 20: res += 20; break;
+    case 21: res += 21; break;
+    case 22: res += 22; break;
+    case 23: res += 23; break;
+    case 24: res += 24; break;
+    case 25: res += 25; break;
+    case 26: res += 26; break;
+    case 27: res += 27; break;
+    case 28: res += 28; break;
+    case 29: res += 29; break;
+    case 30: res += 30; break;
+    case 31: res += 31; break;
+    case 32: res += 32; break;
+    case 33: res += 33; break;
+    case 34: res += 34; break;
+    case 35: res += 35; break;
+    case 36: res += 36; break;
+    case 37: res += 37; break;
+    case 38: res += 38; break;
+    case 39: res += 39; break;
+    case 40: res += 40; break;
+    case 41: res += 41; break;
+    case 42: res += 42; break;
+    case 43: res += 43; break;
+    case 44: res += 44; break;
+    case 45: res += 45; break;
+    case 46: res += 46; break;
+    case 47: res += 47; break;
+    case 48: res += 48; break;
+    case 49: res += 49; break;
+    case 50: res += 50; break;
+    case 51: res += 51; break;
+    case 52: res += 52; break;
+    case 53: res += 53; break;
+    case 54: res += 54; break;
+    case 55: res += 55; break;
+    case 56: res += 56; break;
+    case 57: res += 57; break;
+    case 58: res += 58; break;
+    case 59: res += 59; break;
+    case 60: res += 60; break;
+    case 61: res += 61; break;
+    case 62: res += 62; break;
+    case 63: res += 63; break;
+    case 64: break;
+    default: break;
+    }
+  }
+  return res;
+}
+
+assertEquals(190, f6(20), "largeSwitch.20");
+assertEquals(2016, f6(64), "largeSwitch.64");
+assertEquals(4032, f6(128), "largeSwitch.128");
+assertEquals(4222, f6(148), "largeSwitch.148"); 
diff --git a/regexp2000/test/mjsunit/testcfg.py b/regexp2000/test/mjsunit/testcfg.py
new file mode 100644 (file)
index 0000000..f65365d
--- /dev/null
@@ -0,0 +1,98 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import test
+import os
+from os.path import join, dirname, exists
+import re
+
+
+FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
+
+
+class MjsunitTestCase(test.TestCase):
+
+  def __init__(self, path, file, mode, context, config):
+    super(MjsunitTestCase, self).__init__(context, path)
+    self.file = file
+    self.config = config
+    self.mode = mode
+
+  def GetLabel(self):
+    return "%s %s" % (self.mode, self.GetName())
+
+  def GetName(self):
+    return self.path[-1]
+
+  def GetCommand(self):
+    result = [self.config.context.GetVm(self.mode)]
+    source = open(self.file).read()
+    flags_match = FLAGS_PATTERN.search(source)
+    if flags_match:
+      result += flags_match.group(1).strip().split()
+    framework = join(dirname(self.config.root), 'mjsunit', 'mjsunit.js')
+    result += [framework, self.file]
+    return result
+
+  def GetSource(self):
+    return open(self.file).read()
+
+
+class MjsunitTestConfiguration(test.TestConfiguration):
+
+  def __init__(self, context, root):
+    super(MjsunitTestConfiguration, self).__init__(context, root)
+
+  def Ls(self, path):
+    def SelectTest(name):
+      return name.endswith('.js') and name != 'mjsunit.js'
+    return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
+
+  def ListTests(self, current_path, path, mode):
+    mjsunit = [current_path + [t] for t in self.Ls(self.root)]
+    regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
+    bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
+    all_tests = mjsunit + regress + bugs
+    result = []
+    for test in all_tests:
+      if self.Contains(path, test):
+        file_path = join(self.root, reduce(join, test[1:], "") + ".js")
+        result.append(MjsunitTestCase(test, file_path, mode, self.context, self))
+    return result
+
+  def GetBuildRequirements(self):
+    return ['sample', 'sample=shell']
+
+  def GetTestStatus(self, sections, defs):
+    status_file = join(self.root, 'mjsunit.status')
+    if exists(status_file):
+      test.ReadConfigurationInto(status_file, sections, defs)
+
+
+
+def GetConfiguration(context, root):
+  return MjsunitTestConfiguration(context, root)
diff --git a/regexp2000/test/mjsunit/this-in-callbacks.js b/regexp2000/test/mjsunit/this-in-callbacks.js
new file mode 100644 (file)
index 0000000..d50be6c
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test 'this' is the right global object of callback functions passed to
+// builtin functions.
+// See bug 1231592
+
+var my_identity = 'id';
+// test Array.sort
+function cp(x, y) {
+  assertEquals('id', this.my_identity);
+  return 0;
+}
+
+[1, 2].sort(cp);
+
+// test String.replace
+function r(x) {
+  return this.my_identity;
+}
+
+assertEquals('id', 'hello'.replace('hello', r));
+assertEquals('id', 'hello'.replace(/hello/, r));
diff --git a/regexp2000/test/mjsunit/this.js b/regexp2000/test/mjsunit/this.js
new file mode 100644 (file)
index 0000000..0019eb2
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() { return this; }
+
+assertFalse(this == null);  // the global object shouldn't be null or undefined
+assertEquals('[object global]', String(this));
+
+assertTrue(this === this);
+assertTrue(this === (function() { return this; })());
+assertTrue(this === f());
+
+var x = {}, y = {};
+x.f = y.f = f; 
+assertFalse(x === f());
+assertFalse(y === f());
+assertTrue(x === x.f());
+assertTrue(x === x[new String('f')]());
+assertTrue(y === y.f(), "y.f()");
+assertTrue(y === y[new String('f')]());
+assertFalse(x === y.f());
+assertFalse(y === x.f());
diff --git a/regexp2000/test/mjsunit/throw-exception-for-null-access.js b/regexp2000/test/mjsunit/throw-exception-for-null-access.js
new file mode 100644 (file)
index 0000000..018cfef
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Must throw TypeError when accessing properties of null.
+var caught = false
+try {
+  null[0];
+  assertTrue(false);
+} catch (e) {
+  caught = true;
+  assertTrue(e instanceof TypeError);
+}
+assertTrue(caught);
diff --git a/regexp2000/test/mjsunit/to-precision.js b/regexp2000/test/mjsunit/to-precision.js
new file mode 100644 (file)
index 0000000..04c7d76
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test the exponential notation output.
+assertEquals("1e+27", (1.2345e+27).toPrecision(1));
+assertEquals("1.2e+27", (1.2345e+27).toPrecision(2));
+assertEquals("1.23e+27", (1.2345e+27).toPrecision(3));
+assertEquals("1.234e+27", (1.2345e+27).toPrecision(4));
+assertEquals("1.2345e+27", (1.2345e+27).toPrecision(5));
+assertEquals("1.23450e+27", (1.2345e+27).toPrecision(6));
+assertEquals("1.234500e+27", (1.2345e+27).toPrecision(7));
+
+assertEquals("-1e+27", (-1.2345e+27).toPrecision(1));
+assertEquals("-1.2e+27", (-1.2345e+27).toPrecision(2));
+assertEquals("-1.23e+27", (-1.2345e+27).toPrecision(3));
+assertEquals("-1.234e+27", (-1.2345e+27).toPrecision(4));
+assertEquals("-1.2345e+27", (-1.2345e+27).toPrecision(5));
+assertEquals("-1.23450e+27", (-1.2345e+27).toPrecision(6));
+assertEquals("-1.234500e+27", (-1.2345e+27).toPrecision(7));
+
+
+// Test the fixed notation output.
+assertEquals("7", (7).toPrecision(1));
+assertEquals("7.0", (7).toPrecision(2));
+assertEquals("7.00", (7).toPrecision(3));
+
+assertEquals("-7", (-7).toPrecision(1));
+assertEquals("-7.0", (-7).toPrecision(2));
+assertEquals("-7.00", (-7).toPrecision(3));
+
+assertEquals("9e+1", (91).toPrecision(1));
+assertEquals("91", (91).toPrecision(2));
+assertEquals("91.0", (91).toPrecision(3));
+assertEquals("91.00", (91).toPrecision(4));
+
+assertEquals("-9e+1", (-91).toPrecision(1));
+assertEquals("-91", (-91).toPrecision(2));
+assertEquals("-91.0", (-91).toPrecision(3));
+assertEquals("-91.00", (-91).toPrecision(4));
+
+assertEquals("9e+1", (91.1234).toPrecision(1));
+assertEquals("91", (91.1234).toPrecision(2));
+assertEquals("91.1", (91.1234).toPrecision(3));
+assertEquals("91.12", (91.1234).toPrecision(4));
+assertEquals("91.123", (91.1234).toPrecision(5));
+assertEquals("91.1234", (91.1234).toPrecision(6));
+assertEquals("91.12340", (91.1234).toPrecision(7));
+assertEquals("91.123400", (91.1234).toPrecision(8));
+
+assertEquals("-9e+1", (-91.1234).toPrecision(1));
+assertEquals("-91", (-91.1234).toPrecision(2));
+assertEquals("-91.1", (-91.1234).toPrecision(3));
+assertEquals("-91.12", (-91.1234).toPrecision(4));
+assertEquals("-91.123", (-91.1234).toPrecision(5));
+assertEquals("-91.1234", (-91.1234).toPrecision(6));
+assertEquals("-91.12340", (-91.1234).toPrecision(7));
+assertEquals("-91.123400", (-91.1234).toPrecision(8));
+
diff --git a/regexp2000/test/mjsunit/tobool.js b/regexp2000/test/mjsunit/tobool.js
new file mode 100644 (file)
index 0000000..65bffb6
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// All objects, including wrappers, must convert to true.
+assertTrue(!!new Boolean(true), "new Boolean(true)");
+assertTrue(!!new Boolean(false), "new Boolean(false)");
+
+assertTrue(!!new Number(-1), "new Number(-1)");
+assertTrue(!!new Number(0), "new Number(0)");
+assertTrue(!!new Number(1), "new Number(1)");
+
+
diff --git a/regexp2000/test/mjsunit/toint32.js b/regexp2000/test/mjsunit/toint32.js
new file mode 100644 (file)
index 0000000..e1a64a6
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function toInt32(x) {
+  return x | 0;
+}
+
+assertEquals(0, toInt32(Infinity));
+assertEquals(0, toInt32(-Infinity));
+assertEquals(0, toInt32(NaN));
+assertEquals(0, toInt32(0.0));
+assertEquals(0, toInt32(-0.0));
+
+assertEquals(0, toInt32(Number.MIN_VALUE));
+assertEquals(0, toInt32(-Number.MIN_VALUE));
+assertEquals(0, toInt32(0.1));
+assertEquals(0, toInt32(-0.1));
+assertEquals(1, toInt32(1));
+assertEquals(1, toInt32(1.1));
+assertEquals(-1, toInt32(-1));
+
+assertEquals(2147483647, toInt32(2147483647));
+assertEquals(-2147483648, toInt32(2147483648));
+assertEquals(-2147483647, toInt32(2147483649));
+
+assertEquals(-1, toInt32(4294967295));
+assertEquals(0, toInt32(4294967296));
+assertEquals(1, toInt32(4294967297));
+
+assertEquals(-2147483647, toInt32(-2147483647));
+assertEquals(-2147483648, toInt32(-2147483648));
+assertEquals(2147483647, toInt32(-2147483649));
+
+assertEquals(1, toInt32(-4294967295));
+assertEquals(0, toInt32(-4294967296));
+assertEquals(-1, toInt32(-4294967297));
+
+assertEquals(-2147483648, toInt32(2147483648.25));
+assertEquals(-2147483648, toInt32(2147483648.5));
+assertEquals(-2147483648, toInt32(2147483648.75));
+assertEquals(-1, toInt32(4294967295.25));
+assertEquals(-1, toInt32(4294967295.5));
+assertEquals(-1, toInt32(4294967295.75));
+assertEquals(-1294967296, toInt32(3000000000.25));
+assertEquals(-1294967296, toInt32(3000000000.5));
+assertEquals(-1294967296, toInt32(3000000000.75));
+
+assertEquals(-2147483648, toInt32(-2147483648.25));
+assertEquals(-2147483648, toInt32(-2147483648.5));
+assertEquals(-2147483648, toInt32(-2147483648.75));
+assertEquals(1, toInt32(-4294967295.25));
+assertEquals(1, toInt32(-4294967295.5));
+assertEquals(1, toInt32(-4294967295.75));
+assertEquals(1294967296, toInt32(-3000000000.25));
+assertEquals(1294967296, toInt32(-3000000000.5));
+assertEquals(1294967296, toInt32(-3000000000.75));
diff --git a/regexp2000/test/mjsunit/touint32.js b/regexp2000/test/mjsunit/touint32.js
new file mode 100644 (file)
index 0000000..f06bddf
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function ToUInt32(x) {
+  return x >>> 0;
+}
+
+assertEquals(0, ToUInt32(0),         "0");
+assertEquals(0, ToUInt32(-0),        "-0");
+assertEquals(0, ToUInt32(Infinity),  "Infinity");
+assertEquals(0, ToUInt32(-Infinity), "-Infinity");
+assertEquals(0, ToUInt32(NaN),       "NaN");
+
+assertEquals(0, ToUInt32(Number.MIN_VALUE),  "MIN");
+assertEquals(0, ToUInt32(-Number.MIN_VALUE), "-MIN");
+assertEquals(0, ToUInt32(0.1),               "0.1");
+assertEquals(0, ToUInt32(-0.1),              "-0.1");
+assertEquals(1, ToUInt32(1),                 "1");
+assertEquals(1, ToUInt32(1.1),               "1.1");
+
+assertEquals(4294967295, ToUInt32(-1),   "-1");
+assertEquals(4294967295, ToUInt32(-1.1), "-1.1");
+
+assertEquals(2147483647, ToUInt32(2147483647), "2147483647");
+assertEquals(2147483648, ToUInt32(2147483648), "2147483648");
+assertEquals(2147483649, ToUInt32(2147483649), "2147483649");
+
+assertEquals(4294967295, ToUInt32(4294967295), "4294967295");
+assertEquals(0,          ToUInt32(4294967296), "4294967296");
+assertEquals(1,          ToUInt32(4294967297), "4294967297");
+
+assertEquals(2147483649, ToUInt32(-2147483647), "-2147483647");
+assertEquals(2147483648, ToUInt32(-2147483648), "-2147483648");
+assertEquals(2147483647, ToUInt32(-2147483649), "-2147483649");
+
+assertEquals(1,          ToUInt32(-4294967295), "-4294967295");
+assertEquals(0,          ToUInt32(-4294967296), "-4294967296");
+assertEquals(4294967295, ToUInt32(-4294967297), "-4294967297");
+
+assertEquals(2147483647, ToUInt32('2147483647'), "'2147483647'");
+assertEquals(2147483648, ToUInt32('2147483648'), "'2147483648'");
+assertEquals(2147483649, ToUInt32('2147483649'), "'2147483649'");
+
+assertEquals(4294967295, ToUInt32('4294967295'), "'4294967295'");
+assertEquals(0,          ToUInt32('4294967296'), "'4294967296'");
+assertEquals(1,          ToUInt32('4294967297'), "'4294967297'");
+
+
diff --git a/regexp2000/test/mjsunit/try-finally-nested.js b/regexp2000/test/mjsunit/try-finally-nested.js
new file mode 100644 (file)
index 0000000..c05f96a
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function f() {
+  try {
+    return 42;
+  } finally {
+    var executed = false;
+    while (!executed) {
+      try {
+        break;
+      } finally {
+        executed = true;
+      }
+      assertTrue(false, "should not reach here");
+    }
+    assertTrue(executed, "finally block executed");
+  }
+  return 87;
+};
+
+assertEquals(42, f());
diff --git a/regexp2000/test/mjsunit/try.js b/regexp2000/test/mjsunit/try.js
new file mode 100644 (file)
index 0000000..a3f4433
--- /dev/null
@@ -0,0 +1,349 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+function Catch(f, g) {
+  var r;
+  try { r = f(); } catch (o) { return g(o); }
+  return r;
+}
+
+function CatchReturn(f, g) {
+  try { return f(); } catch (o) { return g(o); }
+}
+
+
+var a = [Catch, CatchReturn]
+for (var n in a) {
+  var c = a[n];
+  assertEquals(1, c(function() { return 1; }));
+  assertEquals('bar', c(function() { return 'bar'; }));
+  assertEquals(1, c(function () { throw 1; }, function (x) { return x; }));
+  assertEquals('bar', c(function () { throw 'bar'; }, function (x) { return x; }));
+}
+
+
+assertEquals(1, (function() { try { return 1; } finally { } })());
+assertEquals(1, (function() { try { return 1; } finally { var x = 12; } })());
+assertEquals(2, (function() { try { } finally { return 2; } })());
+assertEquals(4, (function() { try { return 3; } finally { return 4; } })());
+
+function f(x, n, v) { try { return x; } finally { x[n] = v; } }
+assertEquals(2, f({}, 'foo', 2).foo);
+assertEquals(5, f({}, 'bar', 5).bar);
+
+function guard(f) { try { f(); } catch (o) { return o; } }
+assertEquals('baz', guard(function() { throw 'baz'; }));
+assertEquals(2, (function() { try { throw {}; } catch(e) {} finally { return 2; } })());
+assertEquals(1, guard(function() { try { throw 1; } finally { } }));
+assertEquals(2, guard(function() { try { throw 2; } finally { var x = 12; } }));
+assertEquals(4, guard(function() { try { throw 3; } finally { throw 4; } }));
+
+(function () {
+  var iter = 10000000;
+  for (var i = 1; i <= iter; i++) {
+    try {
+      if (i == iter) gc();
+    } finally {
+      if (i == iter) gc();
+    }
+  }
+})();
+
+function trycatch(a) {
+  var o;
+  try {
+    throw 1;
+  } catch (o) {
+    a.push(o);
+    try {
+      throw 2;
+    } catch (o) {
+      a.push(o);
+    }
+    a.push(o);
+  }
+  a.push(o);
+}
+var a = [];
+trycatch(a);
+assertEquals(4, a.length);
+assertEquals(1, a[0], "a[0]");
+assertEquals(2, a[1], "a[1]");
+
+assertEquals(1, a[2], "a[2]");
+assertTrue(typeof a[3] === 'undefined', "a[3]");
+
+assertTrue(typeof o === 'undefined', "global.o");
+
+
+function return_from_nested_catch(x) {
+  try {
+    try {
+      return x;
+    } catch (o) {
+      return -1;
+    }
+  } catch (o) {
+    return -2;
+  }
+}
+
+assertEquals(0, return_from_nested_catch(0));
+assertEquals(1, return_from_nested_catch(1));
+
+
+function return_from_nested_finally(x) {
+  var a = [x-2];
+  try {
+    try {
+      return a;
+    } finally {
+      a[0]++;
+    }
+  } finally {
+    a[0]++;
+  }
+}
+
+assertEquals(0, return_from_nested_finally(0)[0]);
+assertEquals(1, return_from_nested_finally(1)[0]);
+
+
+function break_from_catch(x) {
+  x--;
+ L:
+  {
+    try {
+      x++;
+      if (false) return -1;
+      break L;
+    } catch (o) {
+      x--;
+    }
+  }
+  return x;
+}
+
+assertEquals(0, break_from_catch(0));
+assertEquals(1, break_from_catch(1));
+
+
+function break_from_finally(x) {
+ L:
+  {
+    try {
+      x++;
+      if (false) return -1;
+      break L;
+    } finally {
+      x--;
+    }
+    x--;
+  }
+  return x;
+}
+
+assertEquals(0, break_from_finally(0), "break from finally");
+assertEquals(1, break_from_finally(1), "break from finally");
+
+
+function continue_from_catch(x) {
+  x--;
+  var cont = true;
+  while (cont) {
+    try {
+      x++;
+      if (false) return -1;
+      cont = false;
+      continue;
+    } catch (o) {
+      x--;
+    }
+  }
+  return x;
+}
+
+assertEquals(0, continue_from_catch(0));
+assertEquals(1, continue_from_catch(1));
+
+
+function continue_from_finally(x) {
+  var cont = true;
+  while (cont) {
+    try {
+      x++;
+      if (false) return -1;
+      cont = false;
+      continue;
+    } finally {
+      x--;
+    }
+    x--;
+  }
+  return x;
+}
+
+assertEquals(0, continue_from_finally(0));
+assertEquals(1, continue_from_finally(1));
+
+
+function continue_alot_from_finally(x) {
+  var j = 0;
+  for (var i = 0; i < x;) {
+    try {
+      j++;
+      continue;
+      j++;  // should not happen
+    } finally {
+      i++; // must happen
+    }
+    j++; // should not happen
+  }
+  return j;
+}
+
+
+assertEquals(100, continue_alot_from_finally(100));
+assertEquals(200, continue_alot_from_finally(200));
+
+
+
+function break_from_nested_catch(x) {
+  x -= 2;
+ L:
+  {
+    try {
+      x++;
+      try {
+        x++;
+        if (false) return -1;
+        break L;
+      } catch (o) {
+        x--;
+      }
+    } catch (o) {
+      x--;
+    }
+  } 
+  return x;
+}
+
+assertEquals(0, break_from_nested_catch(0));
+assertEquals(1, break_from_nested_catch(1));
+
+
+function break_from_nested_finally(x) {
+ L:
+  {
+    try {
+      x++;
+      try {
+        x++;
+        if (false) return -1;
+        break L;
+      } finally {
+        x--;
+      }
+    } finally {
+      x--;
+    }
+    x--; // should not happen
+  } 
+  return x;
+}
+
+assertEquals(0, break_from_nested_finally(0));
+assertEquals(1, break_from_nested_finally(1));
+
+
+function continue_from_nested_catch(x) {
+  x -= 2;
+  var cont = true;
+  while (cont) {
+    try {
+      x++;
+      try {
+        x++;
+        if (false) return -1;
+        cont = false;
+        continue;
+      } catch (o) {
+        x--;
+      }
+    } catch (o) {
+      x--;
+    }
+  }
+  return x;
+}
+
+assertEquals(0, continue_from_nested_catch(0));
+assertEquals(1, continue_from_nested_catch(1));
+
+
+function continue_from_nested_finally(x) {
+  var cont = true;
+  while (cont) {
+    try {
+      x++;
+      try {
+        x++;
+        if (false) return -1;
+        cont = false;
+        continue;
+      } finally {
+        x--;
+      }
+    } finally {
+      x--;
+    }
+    x--;  // should not happen
+  }
+  return x;
+}
+
+assertEquals(0, continue_from_nested_finally(0));
+assertEquals(1, continue_from_nested_finally(1));
+
+
+var caught = false;
+var finalized = false;
+var broke = true;
+L: try {
+  break L;
+  broke = false;
+} catch (o) {
+  caught = true;
+} finally {
+  finalized = true;
+}
+assertTrue(broke);
+assertFalse(caught);
+assertTrue(finalized);
+
diff --git a/regexp2000/test/mjsunit/try_catch_scopes.js b/regexp2000/test/mjsunit/try_catch_scopes.js
new file mode 100644 (file)
index 0000000..c5bada2
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Exception variables used in try-catch should be scoped, e.g. only
+// visible inside the catch block. They should *not* just be treated
+// as local variables and they should be allowed to nest.
+var e = 0;
+try {
+  throw e + 1;
+} catch(e) {
+  try {
+    throw e + 1;
+  } catch (e) {
+    assertEquals(2, e);
+  }
+  assertEquals(1, e);
+}
+assertEquals(0, e);
diff --git a/regexp2000/test/mjsunit/unicode-string-to-number.js b/regexp2000/test/mjsunit/unicode-string-to-number.js
new file mode 100644 (file)
index 0000000..13a7acf
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Make sure not to treat 16-bit unicode characters as ASCII
+// characters when converting to numbers.
+assertEquals(272, Number('2\u00372'));
+assertTrue(isNaN(Number('2\u11372')), "short-string");
+
+// Check that long string can convert to proper numbers.
+var s = '\u0031';
+for (var i = 0; i < 7; i++) {
+  s += s;
+}
+assertTrue(isFinite(Number(s)));
+
+// Check that long strings with non-ASCII characters cannot convert.
+var s = '\u1131';
+for (var i = 0; i < 7; i++) {
+  s += s;
+}
+assertTrue(isNaN(Number(s)), "long-string");
+
diff --git a/regexp2000/test/mjsunit/unicode-test.js b/regexp2000/test/mjsunit/unicode-test.js
new file mode 100644 (file)
index 0000000..581b3b7
--- /dev/null
@@ -0,0 +1,9143 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Texts are from the Unibrow test suite.
+
+// Note that this file is in UTF-8.  smjs and testkjs do not read their
+// source files as UTF-8, so they will fail on this test.  If you want
+// to run the test on them you can do so after filtering it with the
+// following piece of perl-based line noise:
+
+// perl -CIO -ne '$_ =~ s/([^\n -~])/"\\u" . sprintf("%04x", ord($1))/ge; print $_;' < unicode-test.js > unicode-test-ascii.js
+
+// The result is predictably illegible even for those fluent in Hindi.
+
+var chinese =
+"中国历史\n" +
+"[编辑首段]维基百科,自由的百科全书\n" +
+"跳转到: 导航, 搜索\n" +
+"中國歷史\n" +
+"中国历史系列条目\n" +
+"史前时期\n" +
+"传说时期\n" +
+"(另见三皇五帝)\n" +
+"夏\n" +
+"商\n" +
+"西周        周\n" +
+"春秋        东周\n" +
+"战国\n" +
+"秦\n" +
+"西汉        汉\n" +
+"新朝\n" +
+"东汉\n" +
+"魏   蜀     吴     三\n" +
+"国\n" +
+"西晋        晋\n" +
+"东晋        十六国\n" +
+"宋   南\n" +
+"朝   北魏  北\n" +
+"朝   南\n" +
+"北\n" +
+"朝\n" +
+"齐\n" +
+"梁   东\n" +
+"魏   西\n" +
+"魏\n" +
+"陈   北\n" +
+"齐   北\n" +
+"周\n" +
+"隋\n" +
+"唐\n" +
+"(另见武周)\n" +
+"五代十国\n" +
+"辽\n" +
+"(西辽)      西\n" +
+"夏   北宋  宋\n" +
+"金   南宋\n" +
+"元\n" +
+"明\n" +
+"清\n" +
+"中华民国\n" +
+"中华人民\n" +
+"共和国     中华\n" +
+"民国\n" +
+"(见台湾问题)\n" +
+"\n" +
+"    * 中国历史年表\n" +
+"    * 中国军事史\n" +
+"    * 中国美术史\n" +
+"    * 中国科学技术史\n" +
+"    * 中国教育史\n" +
+"\n" +
+"中国\n" +
+"天坛\n" +
+"文化\n" +
+"中文 - 文学 - 哲学 - 教育\n" +
+"艺术 - 国画 - 戏曲 - 音乐\n" +
+"神话 - 宗教 - 术数 - 建筑\n" +
+"文物 - 电影 - 服饰 - 饮食\n" +
+"武术 - 书法 - 节日 - 姓名\n" +
+"地理\n" +
+"疆域 - 行政区划 - 城市\n" +
+"地图 - 旅游 - 环境 - 生物\n" +
+"人口 - 民族 - 交通 - 时区\n" +
+"历史\n" +
+"年表 - 传说时代 - 朝代\n" +
+"民国史 - 共和国史\n" +
+"文化史 - 科技史 - 教育史\n" +
+"人口史 - 经济史 - 政治史\n" +
+"政治\n" +
+"中华人民共和国政治 - 中华民国政治\n" +
+"宪法 - 外交 - 军事 - 国旗\n" +
+"两岸问题 - 两岸关系\n" +
+"一个中国 - 中国统一\n" +
+"经济\n" +
+"金融 - 农业 - 工业 - 商业\n" +
+"中国各省经济 - 五年计划\n" +
+"其他\n" +
+"列表 - 体育 - 人权 - 媒体\n" +
+"\n" +
+"中国历史自商朝起算约有3600年,自黄帝时代起算约有4000多年。有历史学者认为,在人类文明史中,“历史时代”的定义是指从有文字发明时起算,那之前则称为“史前”;中国历史中传说伏羲做八卦,黄帝时代仓颉造文字;近代考古发现了3600多年前(公元前1600年)商朝的甲骨文、约4000年前至7000年前的陶文、约7000年前至10000年前具有文字性貭的龟骨契刻符号。另外,目前在中国发现最早的史前人类遗址距今约200万年。\n" +
+"\n" +
+"从政治形态区分中国历史,可见夏朝以前长达3000年以上的三皇五帝是母系氏族社会到父系氏族社会的过渡时代,而夏朝开始君王世袭,周朝建立完备的封建制度至东周逐渐解构,秦朝首度一统各国政治和许多民间分歧的文字和丈量制度,并建立中央集权政治,汉朝起则以文官主治国家直至清朝,清末以降,民主政治、马克思主义等各种政治思潮流传,先促成中华民国的建立,并于其后四、五十年再出现中华人民共和国,而由于内战失败,中华民国政府退守台湾。\n" +
+"\n" +
+"由经济形态观察,中国古代人口主要由自由民构成,私有制、商业活动发达。周朝时商业主要由封建领主阶层控制的官商贸易和庶民的自由贸易构成。秦汉以后实行中央集权,人口由士、农、工、商等构成,其中以从事农业的自由民为主体,是一个君权官僚制下的以土地为主要生产资本的较为自由的商业经济社会,一些重要的行业由官商垄断。除了农业,手工业以及商业贸易也有很大的发展。早在汉朝丝路的开通,促进了东亚与中亚至欧洲的陆上交通时,国际贸易早已起步;隋唐时大运河的开通促进了南北贸易;唐朝的盛世及外交的开放、交通的建设,更使各国文化、物资得以交流;宋代时出现了纸币;元代时与中亚的商业交流十分繁荣;明清两代受到西方国家海上发展的影响,海上国际贸易发展迅猛。自中华民国成立起试图建立民主国家,实行自由经济,直到1990年代台湾落实民主制度,1950年代以后30多年迅速实现了向工业化社会的转型;而中国大陆则在1949年后采用一党制统治,起先为公有制的计划经济社会,改革开放后逐步向私有制的市场经济社会転型,同时,1980年代以来工业化发展迅猛,数亿人口在短短20多年内从农民转为产业工人(目前仅仅被称为“农民工”的产业工人就达到约2亿)。伴随经济的迅速国际化,中国经济成为全球经济中越来越重要的组成部分。\n" +
+"目录\n" +
+"[隐藏]\n" +
+"\n" +
+"    * 1 史前时代\n" +
+"    * 2 传说时代\n" +
+"    * 3 先秦时期\n" +
+"          o 3.1 三代\n" +
+"          o 3.2 春秋战国\n" +
+"    * 4 秦汉时期\n" +
+"    * 5 魏晋南北朝时期\n" +
+"    * 6 隋唐五代时期\n" +
+"    * 7 宋元时期\n" +
+"    * 8 明清时期\n" +
+"          o 8.1 清末的内忧外患\n" +
+"    * 9 20世纪至今\n" +
+"    * 10 参见\n" +
+"    * 11 其他特定主题中国史\n" +
+"    * 12 注解\n" +
+"    * 13 参考文献\n" +
+"    * 14 相关著作\n" +
+"    * 15 外部链接\n" +
+"\n" +
+"[编辑] 史前时代\n" +
+"大汶口文化的陶鬹,山東莒县大朱村出土\n" +
+"大汶口文化的陶鬹,山东莒县大朱村出土\n" +
+"\n" +
+"迄今为止发现的最早的高等灵长类中华曙猿在4500万年前生活在中国江南一带。考古证据显示224万年至25万年前,中国就有直立人居住,目前考古发现的有巫山人、元谋人、蓝田人、南京直立人、北京直立人等。这些都是目前所知较早的原始人类踪迹。\n" +
+"\n" +
+"中国史前时代的各种文化是经过了以下几个阶段:以直立猿\n" +
+"人为主的旧石器时代早中期(距今约50至40多万年前),接着进入了旧石器时代中晚期,以山顶洞人为代表,距今约在20至10余万年前。新石器时代早期的代表性文化是裴李岗文化,紧接着是以仰韶文化为代表的新石器时代中期。而以龙山文化为代表的新石器时代晚期,大约出现在公元前2500年到公元前1300年间。\n" +
+"\n" +
+"根据现在的考古学研究,中国的新石器时代呈现多元并立的情形:约西元前5000年到3000年前在河南省、河北省南部、甘肃省南部和山西省南部出现的仰韶文化便具备使用红陶、彩陶以及食用粟和畜养家畜的特质。而大约在同一时间,尚有在浙江省北边出现的河姆渡文化、山东省的大汶口文化。而之后发现的如二里头遗址和三星堆遗址则为青铜器时代的代表。\n" +
+"\n" +
+"[编辑] 传说时代\n" +
+"\n" +
+"    主条目:三皇五帝\n" +
+"\n" +
+"後人所繪的黄帝像\n" +
+"后人所绘的黄帝像\n" +
+"\n" +
+"华夏文明形成于黄河流域中原地区。早期的历史,口口相传。神话中有盘古开天地、女娲造人的说法。传说中的三皇五帝,是夏朝以前数千年杰出首领的代表,具体而言有不同的说法。一般认为,三皇是燧人、伏羲、神农以及女娲、祝融中的三人,五帝一般指黄帝、颛顼、帝喾、尧、舜。自三皇至五帝,历年无确数,最少当不下数千年。\n" +
+"\n" +
+"据现今整理出来的传说,黄帝原系炎帝部落的一个分支的首领,强大之后在阪泉之战中击败炎帝,成为新部落联盟首领,之后又与东南方的蚩尤部落发生冲突,在涿鹿之战中彻底击败对手,树立了自己的霸主地位。\n" +
+"\n" +
+"后来黄帝的孙子颛顼和玄孙帝喾继续担任部落联盟的首领。帝喾的儿子尧继位,他是一名贤君,创立了禅让制,传位给了舜。在舜时期,洪水泛滥,鲧采用堵塞的方法,结果洪水更厉害了,鲧被处决,他的儿子禹采用疏导的方法,成功治理了洪水,因此被推举为首领。然而他的儿子启破坏了禅让制方式,自立为王(但据《史记》及香港中学课本所述,启是被推举为领袖),建立了第一个世袭王朝——夏朝,夏朝持续了400多年,在最后一个夏朝君主——桀末期,东方诸侯国商首领成汤夺取了政权,建立了商朝。\n" +
+"\n" +
+"[编辑] 先秦时期\n" +
+"\n" +
+"[编辑] 三代\n" +
+"\n" +
+"    主条目:夏朝、商朝、周朝和西周\n" +
+"\n" +
+"甲骨文\n" +
+"甲骨文\n" +
+"\n" +
+"最早的世袭朝代夏朝约在前21世纪到前16世纪,由于这段历史目前没有发现文字性文物做印证,所以只能靠后世的记录和出土文物互相对照考证,中国学者一般认为河南洛阳二里头遗址是夏朝首都遗址,有学者对此持有疑问。根据文字记载,夏朝有了中国最早的历法--夏小正。不过之后的商朝是目前所发现的最早有文字文物的历史时期,存在于前16世纪到约前1046年。据说夏朝最后一个君主——桀,由于荒淫无道而被汤推翻。而商代时文明已经十分发达,有历法、青铜器以及成熟的文字——甲骨文等。商王朝时已经有一个完整的国家组织,并且具有了封建王朝的规模。当时的主要生产部门是农业,不过手工业,特别是青铜器的冶铸水平也已经十分高超。并且已经出现了原始的瓷器。商朝自盘庚之后,定都于殷(今河南安阳),因此也称为殷朝。商朝的王位继承制度是传子或传弟,多按年龄的长幼继承。\n" +
+"\n" +
+"与此同时,黄河上游的另一个部落周正在逐步兴起,到了大约前1046年,周武王伐纣,在牧野之战中取得决定性胜利,商朝灭亡。周朝正式建立,建都渭河流域的镐京(今陕西西安附近)。之后周朝的势力又慢慢渗透到黄河下游和淮河一带。周王朝依然是封建贵族统治,有许多贵族的封国(诸侯)。到鼎盛时,周朝的影响力已经在南方跨过长江,东北到今天的辽宁,西至甘肃,东到山东。周朝时的宗法制度已经建立,政权机构也较完善。自唐尧、虞舜至周朝皆封建时代,帝王与诸侯分而治之[1]。中国最早有确切时间的历史事件是发生于公元前841年西周的国人暴动。\n" +
+"\n" +
+"[编辑] 春秋战国\n" +
+"\n" +
+"    主条目:周朝、东周、春秋时期和战国 (中国)\n" +
+"\n" +
+"先師孔子行教像,為唐朝画家吳道子所画\n" +
+"先师孔子行教像,为唐朝画家吴道子所画\n" +
+"\n" +
+"前770年,由于遭到北方游牧部落犬戎的侵袭,周平王东迁黄河中游的洛邑(今河南洛阳),东周开始。此后,周王朝的影响力逐渐减弱,取而代之的是大大小小一百多个小国(诸侯国和附属国),史称春秋时期。春秋时期的大国共有十几个,其中包括了晋、秦、郑、齐及楚等。这一时期社会动荡,战争不断,先后有五个国家称霸,即齐、宋、晋、楚、秦(又有一说是齐、晋、楚、吴、越),合称春秋五霸。到了前546年左右,黄河流域的争霸基本结束,晋、楚两国平分了霸权。前403年,晋国被分成韩、赵、魏三个诸侯国,史称“三家分晋”。再加上被田氏夺去了政权的齐国,和秦、楚及燕,并称战国七雄,战国时期正式开始。大部分马克思主义史学家将战国开始划为封建社会,然而大部分西方及台湾学者却又将之划为封建社会的崩溃。前356年秦国商鞅变法开始后,秦国国力大大增强,最后终于在前221年消灭六国最后的齐国,完成统一,中国历史也进入了新时代。\n" +
+"\n" +
+"春秋战国时期学术思想比较自由,史称百家争鸣。出现了多位对之后中国有深远影响的思想家(诸子百家),例如老子、孔子、墨子、庄子、孟子、荀子、韩非等人。出现了很多学术流派,较出名的有十大家,即道家(自然)、儒家(伦理)、阴阳家(星象占卜)、法家(法治)、名家(修辞辩论)、墨家(科技)、众、杂、农家(农业)、小说家(小说)等。文化上则出现了第一个以个人名字出现在中国文学史上的诗人屈原,他著有楚辞、离骚等文学作品。孔子编成了诗经。战争史上出现了杰出的兵法家孙武、孙膑、吴起等等。科技史上出现了墨子,建筑史上有鲁班,首次发明了瓦当,奠定了中国建筑技术的基础。能制造精良的战车与骑兵,同时此时中国的冶金也十分发达,能制造精良的铁器,在农业上出现了各种灌溉机械,大大提高了生产率,从而为以后人口大大膨胀奠定了基础。历史上出现了春秋(左传),国语,战国策。中华文化的源头基本上都可以在这一时期找到。\n" +
+"\n" +
+"这一时期科技方面也取得了很大进步。夏朝发明了干支纪年,出现了十进位制。西周人用圭表测日影来确定季节;春秋时期确定了二十八宿;后期则产生了古四分历。\n" +
+"\n" +
+"[编辑] 秦汉时期\n" +
+"\n" +
+"    主条目:秦朝、汉朝、西汉、新朝和东汉\n" +
+"\n" +
+"北京八達嶺長城\n" +
+"北京八达岭长城\n" +
+"\n" +
+"前221年,秦并其他六国后统一了中国主体部分,成为了中国历史上第一个统一的中央集权君主统治国家,定都咸阳(今西安附近)。由于秦王嬴政自认“功盖三皇,德过五帝”,于是改用皇帝称号,自封始皇帝,人称秦始皇,传位后的皇帝称二世,直至千世万世。他对国家进行了许多项改革,包括了中央集权的确立,取代了周朝的诸侯分封制;统一了文字,方便官方行文;统一度量衡,便于工程上的计算。秦始皇还大力修筑驰道,并连接了战国时赵国、燕国和秦国的北面围城,筑成了西起临洮、东至辽东的万里长城以抵御北方来自匈奴,东胡等游牧民族的侵袭。秦始皇推崇法治,重用法家的李斯作为丞相,并听其意见,下令焚书坑儒,收缴天下兵器,役使七十万人修筑阿房宫以及自己的陵墓——包括兵马俑等。部分史学家对以上事件存有怀疑,认为由于秦始皇的一系列激进改革得罪了贵族,平民无法适应,才在史书上留此一笔。[来源请求]\n" +
+"\n" +
+"前210年,秦始皇病死于出巡途中,胡亥(即秦二世)杀害太子扶苏即位。但十个月后,陈胜、吴广在大泽乡揭竿而起,包括六国遗臣等野心家乘势作乱,前206年刘邦围攻咸阳,秦王子婴自缚出城投降,秦亡。此后,汉王刘邦与西楚霸王项羽展开了争夺天下的楚汉战争。 前202年十二月,项羽被汉军围困于垓下(今安徽灵壁),四面楚歌。项羽在乌江自刎而死。楚汉之争至此结束。汉高祖刘邦登基,定都长安(今陕西西安),西汉开始。到了汉武帝时,西汉到达鼎盛。并与罗马,安息(帕提亚),贵霜并称为四大帝国。武帝实行推恩令,彻底削弱了封国势力,强化监察制度,实现中央集权;他派遣卫青、霍去病、李广等大将北伐,成功地击溃了匈奴,控制了西域,还派遣张骞出使西域,开拓了著名的丝绸之路,发展了对外贸易,使中国真正了解了外面的世界,促进中西文化交流。儒家学说也被确立为官方的主流意识形态,成为了占统治地位的思想。其他艺术与文化也蒸蒸日上。同时期还出现了第一部通史性质的巨著——《史记》,同时这时的中国出现造纸术,大大推动了文化发展。\n" +
+"\n" +
+"西汉发展到了一世纪左右开始逐渐衰败。公元9年,外戚王莽夺权,宣布进行一系列的改革,改国号为新。然而这些改革却往往不切实际,最终导致农民纷纷起义。公元25年刘秀复辟了汉朝,定都洛阳,史称东汉,而他就是汉光武帝。东汉的发展延续了西汉的传统,此时出现了天文学家张衡。汉的文化吸取了秦的教训,显得相当开明,当时佛教通过西域到达中国,在河南洛阳修建了中国的第一座佛教寺庙——白马寺,佛教正式传入中国。\n" +
+"\n" +
+"[编辑] 魏晋南北朝时期\n" +
+"\n" +
+"    主条目:魏晋南北朝、三国、晋朝、十六国和南北朝\n" +
+"\n" +
+"赤壁\n" +
+"赤壁\n" +
+"\n" +
+"东汉中后期,宦官和外戚长期争权,在黄巾起义的打击下,到了公元二世纪左右时再度衰败,196年曹操控制了东汉朝廷,把汉献帝迎至许都,“挟天子以令诸侯”,220年,曹操死后,长子曹丕废汉献帝自立,建立魏国,同时尚有刘氏的汉和孙氏的吴,历史进入了三国时期。\n" +
+"\n" +
+"265年,魏权臣司马炎称帝,建立晋朝。280年三国归晋,再度统一。晋朝的文化也有一定发展,当时由于战乱纷纷,很多学士选择归隐,不问世事,典型的代表人物是陶渊明(陶潜),当时的书法艺术也十分兴盛。290年晋武帝死后不到一年,十六年的朝廷权利斗争开始,史称“八王之乱”。与此同时,中原周边的五个游牧民族(匈奴、鲜卑、羌、氐、羯)与各地流民起来反晋,史称五胡乱华。这些游牧民族纷纷建立自己的国家,从304年到409年,北部中国陆陆续续有多个国家建立,包括了汉、前赵、后赵、前燕、前凉、前秦、后秦、后燕、西秦、后凉、北凉、南凉、南燕、西凉、夏和北燕, 史称十六国。\n" +
+"\n" +
+"自东汉后期开始,为躲避战乱,北方的汉族人民大量迁居南方,造成经济重心南移;晋朝南迁,建都建康(今江苏南京),历史上称此前为西晋,南迁后为东晋。最后,拓跋鲜卑统一北方,建立北朝的第一个王朝——北魏,形成了南北朝的对立。南朝经历了宋、齐、梁、陈的更替,而北朝则有北魏、东魏、西魏、北齐和北周。南北朝时期是佛教十分盛行的时期,西方的佛教大师络绎不绝地来到中国,许多佛经被翻译成汉文。\n" +
+"\n" +
+"[编辑] 隋唐五代时期\n" +
+"\n" +
+"    主条目:隋朝、唐朝和五代十国\n" +
+"\n" +
+"唐代画家张萱作《捣练图》。\n" +
+"唐代画家张萱作《捣练图》。\n" +
+"\n" +
+"581年,杨坚取代北周建立了隋朝,并于589年灭掉南朝最后一个政权——陈,中国历经了三百多年的分裂之后再度实现了统一。不过隋朝也是一个短命的王朝,在修筑了巨大工程——京杭大运河后就灭亡了,只经历了两代37年。\n" +
+"\n" +
+"618年,唐高祖李渊推翻隋朝建立了唐朝,它是中国历史上延续时间最长的朝代之一。626年,唐太宗李世民即位,唐朝开始进入鼎盛时期,史称贞观之治。长安(今陕西西安)是当时世界上最大的城市,唐王朝也是当时最发达的文明。高宗李治之妻武则天迁都洛阳,并称帝,成为中国史上唯一的女皇帝,改国号周,并定佛教为国教,广修佛寺,大兴土木。隋唐时期开创的科举制是当时比较科学与公平的人材选拔制度。唐王朝与许多邻国发展了良好的关系,文成公主嫁到吐蕃,带去了大批丝织品和手工艺品。日本则不断派遣使节、学问僧和留学生到中国。唐朝的文化也处于鼎盛,特别是诗文得到较大的发展,还编撰了许多纪传体史书。唐代涌现出许多伟大的文学家,例如诗人李白、杜甫、白居易、杜牧,以及散文家韩愈、柳宗元。唐代的佛教是最兴盛的宗教,玄奘曾赴天竺取经,回国后译成1335卷的经文,并于西安修建了大雁塔以存放佛经。唐朝前期对宗教采取宽容政策,佛教外,道教、摩尼教(Manicheism)、景教和伊斯兰教等也得到了广泛传播。这一切都在李世民的曾孙唐玄宗李隆基统治时期达到顶峰,史称开元盛世。然而在755年,爆发了安史之乱,唐朝由此开始走向衰落。\n" +
+"\n" +
+"875年,黄巢起义爆发,唐朝再度分裂,并于907年灭亡,形成了五代十国的混乱局面。\n" +
+"\n" +
+"[编辑] 宋元时期\n" +
+"\n" +
+"    主条目:辽朝、金朝、西夏、宋朝和元朝\n" +
+"\n" +
+"清明上河圖局部,描繪了清明時節,北宋京城汴梁及汴河兩岸的繁華和熱鬧的景象和優美的自然風光。\n" +
+"清明上河图局部,描绘了清明时节,北宋京城汴梁及汴河两岸的繁华和热闹的景象和优美的自然风光。\n" +
+"\n" +
+"经过了五十多年的纷争后,960年北宋控制了中国大部分地区,但是燕云十六州在北方契丹族建立的辽朝手中(五代中的后晋太祖“儿皇帝”石敬瑭所献),河西走廊被党项族建立的西夏趁中原内乱占据,北宋初期虽然曾出兵讨还(宋太宗)但是以失败告终,木以成舟,无可奈何,不得不向日益坐大的辽和西夏交纳岁币。北宋晚期发生了分别以王安石、司马光为首的党派斗争,增加了社会的不安。到了1125年松花江流域女真族,也就是后来的满族,建立的金国势力逐渐强大,1125年,金国灭辽。金国随即开始进攻积弱的北宋,1127年(靖康元年)金国攻破北宋首都汴京(今河南开封),俘虏三千多皇族,其中包括了当时的皇帝宋钦宗和太上皇宋徽宗,因为钦宗其时的年号为靖康,史称靖康之难,北宋灭亡。同年宋钦宗的弟弟赵构在南京应天府(今河南商丘)即皇位,定都临安(今浙江杭州),史称南宋,偏安江南。\n" +
+"\n" +
+"此后金与南宋多次交战,英雄人物层出不穷(如名将岳飞)。直到1234年,蒙古南宋联合灭金。随即蒙古与南宋对抗,经历了空前绝后的大规模血腥战争(如襄樊之战, 钓鱼城之战)。1271年忽必烈建立元朝,定都大都(今北京)。元军于1279年与南宋进行了崖山海战,8岁的小皇帝赵昺被民族英雄陆秀夫背着以身殉国惨烈地跳海而死。崖山海战以元朝的胜利告终,南宋随之灭亡。另有一说, 原华夏文明至此夭折.[来源请求]\n" +
+"\n" +
+"北宋时期中国出现印刷术和火药。当时中国经济发达,中国海上贸易十分兴盛,福建泉州一带成为繁华的港口,中国当时的经济总量占世界的一半,财政收入超过一亿两白银,首都开封和杭州人口达到400到500万人口,相对当时佛罗伦萨和巴黎十几万人口来讲确实是十分繁华,各国商人云集,文化也极盛,出现了程颐、朱熹等理学家,提倡三从四德。与唐诗并驾齐驱的宋词,有苏轼等词文优秀的词人,出现了中国历史上最著名的女词人李清照,社会文化发达,出现了白蛇传,梁祝等浪漫爱情传说,以至于宋朝被西方学者称为中国的“文艺复兴”。\n" +
+"\n" +
+"元朝建立后,一方面吸收了许多中原、汉族文化,以中原的统治机构和方式来统治人民,并大力宣扬朱熹一派的理论(即程朱理学),使得程朱理学成为元朝(以及其后朝代)的官方思想,另一方面却实行了民族等级制度,第一等是蒙古人;第二等是“色目人”,包括原西夏统治区以及来自西域、中亚等地的人口;第三等是“汉人”,包括原金统治区的汉族和契丹、女真等族人;第四等是“南人”,包括原南宋统治区的汉族和其他族人。这种民族制度导致汉族的不满,许多汉族人将元朝视为外来政权,并发动多次反抗。元朝政府除了传统的农业外,也比较重视商业。元朝首都大都十分繁华,来自世界各国的商人云集。在文化上,则出现了与唐诗、宋词并称的元曲,涌现出诸如关汉卿、马致远、王实甫等著名作曲家。\n" +
+"\n" +
+"[编辑] 明清时期\n" +
+"紫禁城太和殿\n" +
+"紫禁城太和殿\n" +
+"\n" +
+"    主条目:明朝、南明、清朝和中国近代史\n" +
+"\n" +
+"1368年,农民起义军领袖朱元璋推翻元朝并建立了明朝。明朝前期建都南京,1405年曾帮助明成祖篡位的太监郑和奉命七次下西洋,曾经到达印度洋、东南亚及非洲等地,但后来明朝逐渐走向闭关锁国。1421年,明朝迁都北京。明朝文化上则出现了王阳明、李贽等思想家,以及《三国演义》、《水浒传》、《西游记》和《金瓶梅》等长篇小说。由于明朝末年行政混乱及严重自然灾害,1627年,明末农民大起义爆发,1644年,起义首领李自成攻克北京,明思宗自缢。南方大臣先后拥护福王朱由崧(弘光)、唐王朱聿键(隆武)、桂王朱由榔(永历)为帝,史称南明,最终因实力不足及政治内斗,仍为当时强盛的清朝所灭。\n" +
+"\n" +
+"明朝晚期,居住在东北地区的满族开始兴盛起来,终于在1644年李自成攻克北京后不久,驱逐李自成,进入北京,建立了清朝,当时明朝旧臣郑成功南撤到台湾岛,并驱逐了那里的荷兰殖民者,后来被清朝军队攻下。清朝在之后的半个世纪还成功地征服了许多地区,例如新疆、西藏、蒙古以及台湾。康熙年间,清廷还与沙俄在黑龙江地区发生战争,最终于1689年签订停战条约——《中俄尼布楚条约》。清朝由于取消了丁税(人头税),导致人口增加,到19世纪已达当时世界总人口的三分之一,人口的增多促进当时农业的兴盛,为当时世界上第一强国,到1820年时中国的经济总量占世界的三分之一。\n" +
+"\n" +
+"然而到了19世纪初,清朝已经走向衰落,在嘉庆年间先后爆发白莲教、天理教的大规模起义。与此同时海上强国英国、荷兰与葡萄牙等纷纷开始强制与中国进行贸易。1787年,英国商人开始向华输入鸦片,导致中国的国际贸易由顺差变为巨额逆差。清廷于1815年颁布搜查洋船鸦片章程,然而英商无视禁令依然走私大量鸦片,道光皇帝不得不于1838年派林则徐赴广州禁烟。1839年6月,将237万多斤鸦片在虎门销毁,史称虎门销烟。英国政府因此于1840年6月发动鸦片战争。一般中国大陆史学界认为这是中国近代史的开始。\n" +
+"\n" +
+"[编辑] 清末的内忧外患\n" +
+"一幅描繪列強瓜分中國情形的漫畫\n" +
+"一幅描绘列强瓜分中国情形的漫画\n" +
+"\n" +
+"鸦片战争持续了一年多,1841年8月英军到达南京,清廷恐惧英军会进逼北京,于是求和,1842年8月29日,《南京条约》签署。香港岛被割让;上海、广州、厦门、福州和宁波开放作为通商口岸,还赔偿款银(西班牙银圆)2100万元。1844年,美国与法国也与清廷分别签订了《望厦条约》和《黄埔条约》,中国的主权受到破坏。\n" +
+"\n" +
+"与此同时中国国内反抗清朝的斗争再度兴起。1851年至1864年间,受到基督教影响的秀才洪秀全建立拜上帝会,发动金田起义并创建了太平天国。太平天国曾经一度占领南方部分省份,并定都南京(改名“天京”),建立政教合一的中央政权。同一时期其它的运动还有天地会、捻军、上海小刀会起义、甘肃回民起义等。这些反抗清朝的斗争直到1860年代才基本平息下来。\n" +
+"\n" +
+"19世纪后期,英、美、法、俄、日等国多次侵入中国,强迫中国与之签定不平等条约。1858年中俄签定《瑷珲条约》,俄国割去黑龙江以北、外兴安岭以南60多万平方公里的中国领土。1860年,英法联军发动第二次鸦片战争,侵入北京,掠夺并烧毁皇家园林圆明园,并于1860年与清廷签定《北京条约》,各赔英法800万两白银,开放更多通商口岸。同年中俄《北京条约》将乌苏里江以东,包括库页岛(萨哈林岛)、海参崴(符拉迪沃斯托克)约40万平方公里的中国领土,划归俄国。1864年,《中俄勘分西北界约记》将巴尔喀什湖以东、以南和斋桑卓尔南北44万平方公里的中国领土,割给俄国。\n" +
+"\n" +
+"为了增强国力并巩固国防,清朝自1860年代开始推行洋务运动,国力有所恢复,并一度出现了同治中兴的局面。1877年清军收复新疆,1881年通过《伊犁条约》清军收复被沙俄占据多年的伊犁。中法战争后清朝还建立了当时号称亚洲第一、世界第六的近代海军舰队—北洋水师。然而在1894年爆发的中日甲午战争中,中国战败,次年被迫与日本签定《马关条约》,赔偿日本2亿两白银,并割让台湾、澎湖列岛给日本。甲午战争的失败,对当时的中国产生了很大的影响。1898年,光绪帝在亲政后同意康有为、梁启超等人提出的变法主张,从6月11日到9月21日的被称为百日维新的103天中进行了多项改革,但最终在慈禧太后发动政变后失败落幕,康有为、梁启超逃亡国外,谭嗣同、刘光第等六人被杀,史称“戊戌六君子”。\n" +
+"\n" +
+"1899年,义和团运动爆发,以“扶清灭洋”为宗旨并在慈禧太后默许下开始围攻外国驻北京使馆。于是,各国以解救驻京使馆人员的名义侵入中国,史称八国联军。1901年,清政府被迫与各国签定辛丑条约,赔款4.5亿两白银,分39年还清(本息合计9.8亿两),同时从北京到山海关铁路沿线由各国派兵驻扎,开北京东交民巷为使馆区,国人不得入内等。\n" +
+"\n" +
+"[编辑] 20世纪至今\n" +
+"\n" +
+"    主条目:中华民国历史和中华人民共和国史\n" +
+"\n" +
+"1901年,革命党开始兴起,孙中山等人在海外积极筹款,指挥国内的多次起义运动。经过十次失败的起义后,与革命党互不沟通的湖北新军在武昌起义获得成功。1912年元月,中华民国宣告成立。孙中山就任临时大总统。以清帝退位为条件,孙中山辞去总统位置,由袁世凯接任。但袁世凯妄图恢复帝制。此后,孙中山发起护法运动与护国运动讨伐袁世凯。1916年,袁世凯在称帝83天之后死去,中华民国进入北洋军阀控制中央政府统治时期,地方政府分别由各个军阀派系占据。\n" +
+"\n" +
+"孙中山之后多次试图联合南方地方军阀北伐北京中央政府未果。1921年,在共产国际的指导下中国共产党成立,并成为共产国际中国支部。1924年,孙中山提出新三民主义并确定联俄联共扶助农工的政策,国民党在共产国际帮助下改组,共产党员以个人身份加入国民党,国共两党进行第一次合作。孙中山自建立广州军政府(1923年改称大元帅府)以后,曾经三次进行北伐,均因条件不具备而未果。1925年春,孙中山病逝于北京。同年,广州国民政府为统一与巩固广东革命根据地,先后举行第一次东征第二次东征与南征,肃清广东境内的军阀势力和反革命武装,并将广东境内倾向革命的军队统一改编为国民革命军,下辖第1至第6军。不久又将广西部队改编为第7军。为北伐战争作了重要准备。1926年6月5日,国民党中央执行委员会正式通过国民革命军出师北伐案,并任命蒋介石为国民革命军总司令正式开始北伐。然而随着北伐和国民革命的深入,国民党不能容忍共产党激进的工人运动,国共两党分裂,大量共产党员及其支持者被清出国民党,有的被拘捕和杀害。1927年8月1日,以周恩来、贺龙、叶挺为首的共产党员在江西南昌发动南昌叛乱,共产党从此有自己独立的军队(中华人民共和国成立后,8月1日被定为建军节)。并于江西瑞金建立了第一个红色苏维埃地方割据政权。此后南京国民政府先后对中央苏区进行五次围剿,红军逃过了前四次围剿,在第五次战争失败,不得不离开红区。1934年开始,红军进行战略转移,在贵州遵义确立了毛泽东对红军的领导和指挥权,四渡赤水河,终于摆脱了追击,途经江西,贵州,四川,甘肃,陕西,经过二万五千里长征,最后在陕西北部与陕北红军刘志丹部会师,建立陕甘宁共产党临时政府。\n" +
+"毛泽東在天安门城楼上宣布中华人民共和國的成立\n" +
+"毛泽东在天安门城楼上宣布中华人民共和国的成立\n" +
+"\n" +
+"1931年9月18日,日本开始侵华,占领了东北全境。1936年12月12日,西安事变后国共第二次合作抗日。1937年7月7日,抗日战争全面爆发,蒋中正在庐山发表著名的“最后关头”的演说,号召全国人民一致抗日。在日军进行南京大屠杀前夕,中华民国首都从南京迁至武汉,后来迁至重庆,在八年间蒋中正为统帅的抗日力量共进行了22次大会战,和成千上万次大小战斗。1945年,二战结束后,当时的中国国民政府从日本手里获得了台湾及澎湖列岛以及其他一些领土,但也在1946年与苏联签订的条约中承认了外蒙古的独立(1951年,迁往台湾的国民党国民政府以苏联未履约为由,不承认该条约及依据该条约而独立的外蒙古的独立地位;但是,蒙古独立已为既成事实)。1946年6月,国共两党又进行了内战。中国共产党最终于1949年获得决定性胜利,中华民国中央政府迁往战后的台湾。中华人民共和国在北平成立,并将北平改名为北京,毛泽东宣布中华人民共和国政府为包括台湾在内的全中国的唯一合法政府。与此同时,蒋介石宣布台北为中华民国临时首都,宣誓三年内反攻大陆。(请参看台湾问题)\n" +
+"\n" +
+"中共执政之初,采取“土地革命”“公私合营”等手段,国内纷乱的局势暂时得到了稳定。按照中共的史观,自1956年“三大改造”完成后,中国正式进入社会主义阶段。并制订第一个五年计划,大力发展重工业,国家经济一度好转。但是1958年,毛泽东发动“大跃进”运动与人民公社话运动,各地浮夸风“放卫星”等谎报数据的情况盛行。自1959年到1961年,国家经济又陷入濒临崩溃的境地,中共称其为“三年自然灾害”。毛泽东因此退居幕后,以刘少奇为首的一批官僚着手恢复经济,国家形式得到了回稳。1966年,文化大革命爆发,刘少奇、贺龙等人被打倒,毛泽东再度成为政治领导,林彪一度成为内定接班人。在林彪阴谋败露后,四人帮成为新的重要政治势力。1976年,周恩来朱德先后去世;9月9日,毛泽东去世。华国锋接替了毛的领导地位,四人帮被打倒。但是华提出了“两个凡是”的路线,国家实质上仍然没有完全脱离文化大革命阶段。 1978年,邓小平复出,中共十一届三中全会召开,改革开放时代正式到来。中国的经济开始步入正轨。但是,由于通货膨胀与政治腐败,民间不满情绪开始酝酿。胡耀邦的去世成为愤怒爆发的导火索,终致爆发了六四事件。从此以后,改革的步伐一度停滞,直到1992年邓小平南巡后才得以改变。1997年,中国收复香港的主权,江泽民也接替邓成为了新的中国领导人。2002 年后,胡锦涛成为新的国家领导人,上海帮淡出政治中心。中共政府近几年渐渐放弃“韬光养晦”的外交方针,在外交舞台上动作频繁,并加强对台湾的攻势。经济改革依然得到了持续,但政治改革的话题仍然是禁忌。而由于贫富差距的拉大与政治腐败不见好转,民间对中共的评价与看法也日益两极。\n" +
+"\n" +
+"至于中华民国,在国府迁台后,国民党始终保持对政治与言论自由的强力控制。1986年,中华民国第一个反对党民主进步党成立,威权时代的戒严体制开始松动。1987年,中华民国政府正式宣告台湾省解严,进入了一个新的时代。之后,1996年实现了第一次民选总统;2000年更实现第一次政党和平轮替。2005年,末代国民大会召开,中华民国宪法出现了重大修改。今后,民主化的中华民国仍然充满变量。\n" +
+"\n" +
+"[编辑] 参见\n" +
+"\n" +
+"    * 中国\n" +
+"    * 中国历史年表\n" +
+"    * 中国历史事件列表\n" +
+"    * 诸侯会盟\n" +
+"    * 中国历史地图\n" +
+"\n" +
+"      \n" +
+"\n" +
+"    * 中华人民共和国历史年表\n" +
+"    * 中华人民共和国史\n" +
+"    * 汉学\n" +
+"    * 中华文明\n" +
+"    * 中国历史大事年表\n" +
+"\n" +
+"      \n" +
+"\n" +
+"    * 中国文化\n" +
+"    * 中国行政区划\n" +
+"    * 中国朝代\n" +
+"    * 夏商周断代工程\n" +
+"    * 中国古都\n" +
+"\n" +
+"      \n" +
+"\n" +
+"    * 中国战争列表\n" +
+"    * 中国国旗\n" +
+"    * 中国皇帝\n" +
+"    * 中国历代王朝君主世系表\n" +
+"    * 中国君王诸子女列表\n" +
+"    * 中华民国历史\n" +
+"\n" +
+"[编辑] 其他特定主题中国史\n" +
+"\n" +
+"    * 中国军事史\n" +
+"    * 中国科学技术史\n" +
+"    * 中国文化史\n" +
+"    * 中国文学史\n" +
+"    * 中国艺术史\n" +
+"    * 中国经济史\n" +
+"    * 中国体育史\n" +
+"    * 中国人口史\n" +
+"    * 中国疆域史\n" +
+"    * 中国盗墓史\n" +
+"    * 中国酷刑史\n" +
+"    * 中国食人史\n" +
+"    * 中国盐业史\n" +
+"\n" +
+"[编辑] 注解\n" +
+"\n" +
+"   1. ↑ 柳翼谋:《中国文化史》\n" +
+"\n" +
+"[编辑] 参考文献\n" +
+"\n" +
+"   1. 白寿彝主编:中国通史纲要,1993年上海:人民出版社,ISBN 7208001367\n" +
+"   2. 周谷城著:中国通史,1995年上海:人民出版社,ISBN 7208003300\n" +
+"   3. 李敖著:独白下的传统,2000年香港:三联书店(香港)有限公司,ISBN 9620418913\n" +
+"   4. 范文澜著:中国近代史,1962年北京:人民出版社,统一书号 11001241\n" +
+"   5. 徐中约著:中国近代史(上册),香港2001 中文大学出版社,ISBN 9622019870\n" +
+"   6. Korotayev A., Malkov A., Khaltourina D. Introduction to Social Macrodynamics: Secular Cycles and Millennial Trends. Moscow: URSS, 2006. ISBN 5-484-00559-0 [1] (Chapter 2: Historical Population Dynamics in China).\n" +
+"\n" +
+"[编辑] 相关著作\n" +
+"\n" +
+"    * 《二十四史》 (正史)\n" +
+"    * 《国史要义》 柳诒徵\n" +
+"    * 《国史大纲》 钱穆\n" +
+"    * 《中华五千年史》 张其昀\n" +
+"\n" +
+"[编辑] 外部链接\n" +
+"维基共享资源中相关的多媒体资源:\n" +
+"中国历史\n" +
+"\n" +
+"    * 中华万年网\n" +
+"    * 一个全面专门研究中华历史的论坛:中华历史网论坛\n" +
+"    * (正体中文 - 台湾)《中国大百科全书》:中国历史概述\n";
+
+var cyrillic =
+"История Китая\n" +
+"[править]\n" +
+"Материал из Википедии — свободной энциклопедии\n" +
+"Перейти к: навигация, поиск\n" +
+"История Китая\n" +
+"История Китая\n" +
+"Три властителя и пять императоров\n" +
+"Династия Ся\n" +
+"Династия Шан\n" +
+"Династия Чжоу     \n" +
+"Западное Чжоу\n" +
+"Восточное Чжоу   Чуньцю\n" +
+"Чжаньго\n" +
+"Династия Цинь\n" +
+"(Династия Чу) - смутное время\n" +
+"Династия Хань     Западная Хань\n" +
+"Синь, Ван Ман\n" +
+"Восточная Хань\n" +
+"Эпоха Троецарствия   Вэй  Шу    У\n" +
+"Цзинь\n" +
+"      Западная Цзинь\n" +
+"Шестнадцать варварских государств      Восточная Цзинь\n" +
+"Северные и Южные Династии\n" +
+"Династия Суй\n" +
+"Династия Тан\n" +
+"Ляо\n" +
+"      \n" +
+"5 династий и 10 царств\n" +
+"Северная Сун\n" +
+"      \n" +
+"Сун\n" +
+"Цзинь\n" +
+"      \n" +
+"Западная Ся\n" +
+"      \n" +
+"Южная Сун\n" +
+"Династия Юань\n" +
+"Династия Мин\n" +
+"Династия Цин\n" +
+"Китайская республика\n" +
+"Китайская Народная Республика\n" +
+"      Китайская республика (Тайвань)\n" +
+"\n" +
+"Китайская цивилизация — одна из старейших в мире. По утверждениям китайских учёных, её возраст может составлять пять тысяч лет, при этом имеющиеся письменные источники покрывают период не менее 3500 лет. Наличие систем административного управления, которые совершенствовались сменявшими друг друга династиями, ранняя освоенность крупнейших аграрных очагов в бассейнах рек Хуанхэ и Янцзы создавало преимущества для китайского государства, экономика которого основывалась на развитом земледелии, по сравнению с соседями-кочевниками и горцами. Ещё более укрепило китайскую цивилизацию введение конфуцианства в качестве государственной идеологии (I век до н. э.) и единой системы письма (II век до н. э.).\n" +
+"Содержание\n" +
+"[убрать]\n" +
+"\n" +
+"    * 1 Древний Китай\n" +
+"    * 2 Государство Шан-Инь\n" +
+"    * 3 Государство Чжоу (XI—III вв. до н. э.)\n" +
+"    * 4 Империя Цинь\n" +
+"    * 5 Империя Хань\n" +
+"    * 6 Государство Цзинь и период Нань-бэй чао (IV—VI вв.)\n" +
+"    * 7 Государство Суй (581—618)\n" +
+"    * 8 Государство Тан\n" +
+"    * 9 Государство Сун\n" +
+"    * 10 Монголы и государство Юань (1280—1368)\n" +
+"    * 11 Государство Мин (1368—1644)\n" +
+"    * 12 Государство Цин\n" +
+"          o 12.1 Внешняя экспансия Цин\n" +
+"          o 12.2 Цинский Китай и Россия\n" +
+"          o 12.3 Опиумные войны\n" +
+"          o 12.4 Японо-китайская война 1894—1895 годов\n" +
+"          o 12.5 Тройственная интервенция\n" +
+"          o 12.6 Успехи русской политики в Китае\n" +
+"          o 12.7 Захват Цзяочжоу Германией\n" +
+"          o 12.8 Сто дней реформ\n" +
+"    * 13 XX век\n" +
+"          o 13.1 Боксерское восстание\n" +
+"          o 13.2 Русско-японская война\n" +
+"          o 13.3 Смерть Цыси\n" +
+"          o 13.4 Аннексия Кореи\n" +
+"          o 13.5 Революция 1911 года и создание Китайской Республики\n" +
+"          o 13.6 Первая мировая война\n" +
+"          o 13.7 Эра милитаристов\n" +
+"          o 13.8 Победа Гоминьдана\n" +
+"          o 13.9 Японская оккупация и Вторая мировая война\n" +
+"          o 13.10 Создание Китайской Народной Республики\n" +
+"          o 13.11 Культурная революция\n" +
+"          o 13.12 Экономическая либерализация\n" +
+"    * 14 См. также\n" +
+"    * 15 Литература\n" +
+"\n" +
+"[править] Древний Китай\n" +
+"\n" +
+"Китайская цивилизация (предков государствообразующего этноса хань) — группа культур (Баньпо 1, Шицзя, Баньпо 2, Мяодигоу, Чжуншаньчжай 2, Хоуган 1 и др.) среднего неолита (ок. 4500-2500 до н.э.) в бассейне реки Хуанхэ, которые традиционно объединяются общим названием Яншао. Представители этих культур выращивали зерновые (чумиза и др.) и занимались разведением скота (свиньи). Позднее в этом районе появились ближневосточные виды злаков (пшеница и ячмень) и породы домашнего скота (коровы, овцы, козы).\n" +
+"\n" +
+"[править] Государство Шан-Инь\n" +
+"\n" +
+"Первым известным государством бронзового века на территории Китая было государство Шан-Инь, сформировавшееся в XIV веке до н. э. в среднем течении реки Хуанхэ, в районе Аньяна.\n" +
+"\n" +
+"В результате войн с соседними племенами его территория расширилась и к XI веку до н. э. охватывала территории современных провинций Хэнань и Шаньси, а также часть территории провинций Шэньси и Хэбэй. Уже тогда появились зачатки лунного календаря и возникла письменность — прообраз современного иероглифического китайского письма. Иньцы значительно превосходили окружающие их племена и с военной точки зрения — у них было профессиональное войско, использовавшее бронзовое оружие, луки, копья и боевые колесницы. Иньцы практиковали человеческие жертвоприношения — чаще всего в жертву приносились пленные.\n" +
+"\n" +
+"В XI веке до н. э. государство Инь было завоёвано немногочисленным западным племенем Чжоу, которое до этого находилось в вассальных отношениях с иньцами, но постепенно укрепилось и создало коалицию племён.\n" +
+"\n" +
+"[править] Государство Чжоу (XI—III вв. до н. э.)\n" +
+"Китайская медная монета в виде мотыги. Провинция Лоян, V-III в. до н.э.\n" +
+"Китайская медная монета в виде мотыги. Провинция Лоян, V-III в. до н.э.\n" +
+"\n" +
+"Обширная территория государства Чжоу, охватывавшая практически весь бассейн Хуанхэ, со временем распалась на множество соперничающих между собой самостоятельных государственных образований — изначально, наследственных уделов на территориях, заселённых различными племенами и расположенных на удалении от столиц — Цзунчжоу (западной - около г. Сиань) и Чэнчжоу (восточной - Лои, Лоян). Эти уделы предоставлялись во владение родственникам и приближённым верховного правителя — обычно чжоусцам. В междоусобной борьбе число первоначальных уделов постепенно сокращалось, а сами уделы укреплялись и становились более самостоятельными.\n" +
+"\n" +
+"Население Чжоу было разнородным, причём наиболее крупную и развитую его часть составляли иньцы. В государстве Чжоу значительная часть иньцев была расселена на новых землях на востоке, где была построена новая столица — Чэнчжоу (современная провинция Хэнань).\n" +
+"\n" +
+"Для периода Чжоу в целом характерно активное освоение новых земель, расселение и этническое смешивание выходцев из различных районов, уделов (впоследствии — царств), что способствовало созданию фундамента будущей китайской общности.\n" +
+"\n" +
+"Период Чжоу (XI—III вв. до н. э.) делится на так называемые Западное и Восточное Чжоу, что связано с переездом правителя Чжоу в 770 до н. э. под угрозой нашествия варварских племён из Цзунчжоу — первоначальной столицы государства — в Чэнчжоу. Земли в районе старой столицы были отданы одному из союзников правителя государства, который создал здесь новый удел Цинь. Впоследствии именно этот удел станет центром единой китайской империи.\n" +
+"\n" +
+"Период Восточное Чжоу, в свою очередь, разделяется на два периода:\n" +
+"\n" +
+"    * Чуньцю ( «Период Весны и Осени» VIII—V вв. до н. э.);\n" +
+"    * Чжаньго («Период Сражающихся царств», V—III вв. до н. э.).\n" +
+"\n" +
+"В период Восточного Чжоу власть центрального правителя — вана, сына Неба (тянь-цзы), правящего Поднебесной по Мандату Неба (тянь-мин), — постепенно ослабла, а ведущую политическую роль стали играть сильные уделы, превращавшиеся в крупные царства. Большинство из них (за исключением окраинных) именовали себя «срединными государствами» (чжун-го), ведущими своё происхождение от раннечжоуских уделов.\n" +
+"\n" +
+"В период Восточного Чжоу формируются основные философские школы древнего Китая — конфуцианство (VI—V вв. до н. э.), моизм (V в. до н. э.), даосизм (IV в. до н. э.), легизм.\n" +
+"\n" +
+"В V—III вв. до н.э. (период Чжаньго) Китай вступает в железный век. Расширяются сельскохозяйственные площади, увеличиваются ирригационные системы, развиваются ремёсла, революционные изменения происходят в военном деле.\n" +
+"\n" +
+"В период Чжаньго на территории Китая сосуществовало семь крупнейших царств — Вэй, Чжао и Хань (ранее все три входили в царство Цзинь), Цинь, Ци, Янь и Чу. Постепенно в результате ожесточённого соперничества верх стало одерживать самое западное — Цинь. Присоединив одно за другим соседние царства, в 221 до н. э. правитель Цинь — будущий император Цинь Ши Хуан — объединил весь Китай под своей властью.\n" +
+"\n" +
+"Так в середине III века до н. э. завершился период Восточного Чжоу.\n" +
+"\n" +
+"[править] Империя Цинь\n" +
+"\n" +
+"Объединив древнекитайские царства, император Цинь Ши Хуан конфисковал всё оружие у населения, переселил десятки тысяч семей наследственной знати из различных царств в новую столицу — Сяньян и разделил огромную страну на 36 новых областей, которые возглавили назначаемые губернаторы.\n" +
+"\n" +
+"При Цинь Шихуанди были соединены оборонительные стены (валы) северных чжоуских царств и создана Великая китайская стена. Было сооружено несколько стратегических дорог из столицы на окраины империи. В результате успешных войн на севере гунны (сюнну) были оттеснены за Великую стену. На юге к империи были присоединены значительные территории племён юэ, в том числе северная часть современного Вьетнама.\n" +
+"Строительство Великой китайской стены, протянувшейся на более чем 6700 км, было начато в III веке до н. э. для защиты северных районов Китая от набегов кочевников.\n" +
+"Строительство Великой китайской стены, протянувшейся на более чем 6700 км, было начато в III веке до н. э. для защиты северных районов Китая от набегов кочевников.\n" +
+"\n" +
+"Цинь Шихуанди, строивший все свои реформы на основах легизма с казарменной дисциплиной и жестокими наказаниями провинившихся, преследовал конфуцианцев, предавая их казни (погребение заживо) и сжигая их сочинения — за то, что они смели выступать против установившегося в стране жесточайшего гнёта.\n" +
+"\n" +
+"Империя Цинь прекратила существование вскоре после смерти Цинь Шихуанди.\n" +
+"\n" +
+"[править] Империя Хань\n" +
+"\n" +
+"Вторую в истории Китая империю, получившую название Хань (206 до н. э.—220 н. э.) основал выходец из среднего чиновничества Лю Бан (Гао-цзу), один из военачальников возрожденного царства Чу, воевавших против Цинь после смерти императора Цинь Шихуана в 210 г. до н.э.\n" +
+"\n" +
+"Китай в это время переживал экономический и социальный кризис, вызванный потерей управляемости и войнами военачальников циньских армий с элитами уничтоженных раннее царств, пытавшихся восстановить свою государственность. Из-за переселений и войн значительно сократилась численность сельского населения в основных аграрных районах.\n" +
+"\n" +
+"Важная особенность смены династий в Китае состояла в том, что каждая новая династия приходила на смену предыдущей в обстановке социально-экономического кризиса, ослабления центральной власти и войн между военачальниками. Основателем нового государства становился тот из них, кто мог захватить столицу и насильственно отстранить правившего императора от власти.\n" +
+"\n" +
+"С правления Гао-цзу (206–195 до н.э.) начинается новый период китайской истории, который получил название Западная Хань.\n" +
+"\n" +
+"При императоре У-ди (140—87 до н. э.) была взята на вооружение иная философия — восстановленное и реформированное конфуцианство, которое стало господствующей официальной идеологией вместо дискредитировавшего себя легизма с его жёсткими нормами и бесчеловечной практикой. Именно с этого времени берёт своё начало китайская конфуцианская империя.\n" +
+"\n" +
+"При нем территория ханьской империи значительно расширяется. Были уничтожены вьетское государство Намвьет (территория современной провинции Гуандун, Гуанси-Чжуанского автономного района и север Индокитайского полуострова), вьетские государства в южных частях современных провинций Чжэцзян и Фуцзянь, корейское государство Чосон, присоеденены земли на юго-западе, сюнну оттеснены далее на севере.\n" +
+"\n" +
+"Китайский путешественник Чжан Цянь проникает далеко на запад и описывает многие страны Средней Азии (Фергана, Бактрия, Парфия и др.). Вдоль пройденного им маршрута прокладывается торговый путь через Джунгарию и Восточный Туркестан в страны Средней Азии и Ближнего Востока — так называемый «Великий шёлковый путь». Империя на некоторое время подчиняет себе оазисы-протогосударства вдоль Шёлкового пути и распространяет своё влияние до Памира.\n" +
+"\n" +
+"В I в. н. э. в Китай из Индии начинает проникать буддизм.\n" +
+"\n" +
+"В период с 8 по 23 гг. н. э. власть захватывает Ван Ман, провозглашающий себя императором и основателем государства Синь. Начинается ряд преобразований, который прерывается экологической катастрофой - река Хуанхэ изменила русло. Из-за трехлетнего голода центральная власть ослабла. В этих условиях началось движение представителей рода Лю за возвращение престола. Ван Ман был убит, столица взята, власть возвратилась династии Лю.\n" +
+"\n" +
+"Новый период получил название Восточная Хань, он продлился до 220 г. н. э.\n" +
+"\n" +
+"[править] Государство Цзинь и период Нань-бэй чао (IV—VI вв.)\n" +
+"\n" +
+"Восточную Хань сменил период Троецарствия (Вэй, Шу и У). В ходе борьбы за власть между военачальниками было основано новое государство Цзинь (265—420).\n" +
+"\n" +
+"В начале IV века Китай подвергается нашествию кочевников — сюнну (гуннов), сяньбийцев, цянов, цзе и др. Весь Северный Китай был захвачен кочевниками, которые создали здесь свои царства, так называемые 16 варварских государств Китая. Значительная часть китайской знати бежала на юг и юго-восток, основанное там государство получило название Восточная Цзинь.\n" +
+"\n" +
+"Кочевники приходят волнами, одна за другой, и после каждой из этих волн в Северном Китае возникают новые царства и правящие династии, которые, однако, принимают классические китайские названия (Чжао, Янь, Лян, Цинь, Вэй и др.).\n" +
+"\n" +
+"В это время, с одной стороны, происходит варваризация образа жизни оседлых китайцев — разгул жестокости, произвола, массовых убийств, нестабильности, казней и бесконечных переворотов. А с другой стороны, пришельцы-кочевники активно стремятся использовыть китайский опыт управления и китайскую культуру для стабилизации и упрочения своей власти — мощь китайской конфуцианской цивилизации в конечном счёте гасит волны нашествий варварских племён, которые подвергаются китаизации. К концу VI века потомки кочевников практически полностью ассимилируются с китайцами.\n" +
+"\n" +
+"На севере Китая верх в столетней борьбе между некитайскими царствами берёт сяньбийское государство Тоба Вэй (Северная Вэй), объединившее под своей властью весь Северный Китай (бассейн Хуанхэ) и к концу V века в борьбе против южнокитайского государства Сун распространившее своё влияние до берегов Янцзы. При этом уже в VI веке, как было сказано, захватчики-сяньбийцы ассимилировались с подавляющим большинством местного населения.\n" +
+"\n" +
+"С началом варварских вторжений на север Китая, сопровождавшихся массовым уничтожением и порабощением местного населения, до миллиона местных жителей — в первую очередь знатных, богатых и образованных, включая императорский двор, — перебрались на юг, в районы, сравнительно недавно присоединённые к империи. Пришельцы с севера, заселив речные долины, активно занялись выращиванием риса и постепенно превратили Южный Китай в основной земледельческий район империи. Уже в V веке здесь стали собирать по два урожая риса в год. Резко ускорилась китаизация и ассимиляция местного населения, колонизация новых земель, строительство новых городов и развитие старых. На юге сосредоточился центр китайской культуры.\n" +
+"\n" +
+"Одновременно здесь укрепляет свои позиции буддизм — на севере и юге построено уже несколько десятков тысяч монастырей с более чем 2 млн. монахов. В немалой степени распространению буддизма способствует ослабление официальной религии — конфуцианства — в связи с варварскими вторжениями и междоусобицами. Первыми китайскими буддистами, способствовавшими популяризации новой религии, были приверженцы даосизма — именно с их помощью переводились с санскрита на китайский древние буддийские тексты. Буддизм постепенно стал процветающей религией.\n" +
+"\n" +
+"[править] Государство Суй (581—618)\n" +
+"\n" +
+"Процесс китаизации варваризованного севера и колонизованного юга создаёт предпосылки для нового объединения страны. В 581 севернокитайский полководец Чжоу Ян Цзянь объединяет под своей властью весь Северный Китай и провозглашает новую династию Суй (581—618), а после уничтожения южнокитайского государства Чэнь возглавляет объединённый Китай. В начале VII века его сын Ян Ди ведёт войны против корейского государства Когурё (611 - 614) и вьетнамского государства Вансуан, строит Великий канал между Хуанхэ и Янцзы для транспортировки риса с юга в столицу, создаёт роскошные дворцы в столице Лоян, восстанавливает и строит новые участки Великой китайской стены, пришедшей в упадок за тысячу лет.\n" +
+"\n" +
+"Подданные не выдерживают тягот и лишений и восстают. Ян Ди убивают, а династию Суй сменяет династия Тан (618—907), основатель — шансийский феодал Ли Юань.\n" +
+"\n" +
+"[править] Государство Тан\n" +
+"\n" +
+"Правители из династии Лю покончили с выступлениями знати и провели ряд успешных преобразований. Происходит разделение страны на 10 провинций, была восстановлена \"надельная система\", усовершенствовано административное законодательство, укреплена вертикаль власти, оживились торговля и городская жизнь. Значительно увеличились размеры многих городов и численность городского населения.\n" +
+"\n" +
+"К концу VII века усилившееся военное могущество Танской империи приводит к расширению территории Китая за счёт Восточно-Тюркского и Западно-Тюркского каганатов. Государства, расположенные в Джунгарии и Восточном Туркестане, на некоторое время становятся данниками Китая. Корейское государство Когурё покорено и становится Аньдунским наместничеством Китая. Вновь открыт Великий шёлковый путь.\n" +
+"\n" +
+"В VIII—X вв. в Китае получают распространение новые сельскохозяйственные культуры — в частности, чай, хлопок.\n" +
+"\n" +
+"Развивается морская торговля, главным образом через Гуанчжоу (Кантон), с Индией и Ираном, Арабским Халифатом, корейским государством Силла и Японией.\n" +
+"\n" +
+"В VIII веке империю Тан ослабляют конфликты между центральной властью и военными наместниками на периферии. Окончательно господство династии Лю подрывает война Хуан Чао за престол 874—901.\n" +
+"\n" +
+"В течение долгого времени (907—960) в стране не удаётся восстановить единую государственную власть, что связано с междоусобными войнами, особенно на севере страны.\n" +
+"\n" +
+"[править] Государство Сун\n" +
+"\n" +
+"В 960 военачальник Чжао Куан-инь основывает династию Сун (960—1279). Все три столетия Сун прошли под знаком успешного давления на Китай со стороны северных степных народов.\n" +
+"\n" +
+"Ещё в начале X века усилилось развитие и консолидация протомонгольской этнической общности киданей, соседствовавшей с Китаем на северо-востоке. Государство киданей, основанное в 916 и существовавшее по 1125, получило название Ляо. Активно укрепляясь на северных рубежах, кидани отторгли часть китайских территорий (часть современных провинций Хэбэй и Шаньси). Основы управления в государстве Ляо были созданы китайцами и корейцами, на основе китайских иероглифов и из китайских элементов письма была создана письменность, развивались города, ремёсла, торговля. Не сумев справиться с соседями и вернуть утраченные территории, Сунская империя была вынуждена пойти на подписание в 1004 мирного договора и согласиться на выплату дани. В 1042 дань была увеличена, а в 1075 Китай отдал киданям ещё часть своей территории.\n" +
+"\n" +
+"В то же время на северо-западных окраинах Сунской империи, к западу от киданей, на рубеже X—XI вв. складывается сильное государство тангутов — Западное Ся. Тангуты отторгли от Китая часть современной провинции Шэньси, целиком территорию современной провинции Ганьсу и Нинся-Хуэйского автономного района. С 1047 Сунской империи пришлось и тангутам платить дань серебром и шёлком.\n" +
+"\n" +
+"Несмотря на вынужденные территориальные уступки соседям период Сун считается эпохой экономического и культурного расцвета Китая. Растёт число городов, продолжается рост численности городского населения, китайские ремесленники достигают высот в изготовлении изделий из фарфора, шёлка, лака, дерева, слоновой кости и др. Изобретены порох и компас, распространяется книгопечатание, выводятся новые высокоурожайные сорта зерновых, увеличиваются посевы хлопка. Одной из наиболее впечатляющих и эффективных из данных инноваций было вполне сознательное, систематическое и хорошо организованное внедрение и распространение новых сортов скороспелого риса из Южного Вьетнама (Чампы).\n" +
+"Чжан Цзэдуань. «По реке в День поминовения усопших» (XII век).\n" +
+"Чжан Цзэдуань. «По реке в День поминовения усопших» (XII век).\n" +
+"\n" +
+"В XII веке Китаю приходится отдать ещё большую территорию новым захватчикам — южноманьчжурским чжурчжэням, создавшим (на базе уничтоженной ими в 1125 империи киданей Ляо) государство (впоследствии — империю) Цзинь (1115—1234), границы которой проходили по р. Хуайхэ. При этом часть разбитых киданей ушла на запад, где в районе рек Талас и Чу сложилось небольшое государство кара-китаев — Западное Ляо (1124—1211).\n" +
+"\n" +
+"В 1127 чжурчжэни захватывают столицу империи Сун — Кайфын и берут в плен императорскую семью. Один из сыновей императора бежит на юг, в Ханчжоу, который впоследствии становится столицей новой — южносунской империи (1127—1280). Продвижение армии чжурчжэней на юг сдерживает лишь река Янцзы. Граница между Цзинь и южносунской империей устанавливается по междуречью Хуанхэ и Янцзы. Северный Китай вновь на длительное время оказывается под господством иноземных завоевателей.\n" +
+"\n" +
+"В 1141 подписан мирный договор, согласно которому Сунская империя признаёт себя вассалом империи Цзинь и обязуется платить ей дань.\n" +
+"\n" +
+"[править] Монголы и государство Юань (1280—1368)\n" +
+"\n" +
+"В начале XIII века в Китай вторгаются монголы. До XIII века монголы являлись частью большой степной общности, которую китайцы называли \"татарами\". Их предшественники — протомонгольские и раннемонгольские группы и народы, одним из которых были кидани, представляли собой степных кочевников, разводивших лошадей и рогатый скот, кочевавших от пастбища к пастбищу и организованных в небольшие родоплеменные коллективы, связанные общностью происхождения, языка, культуры и т. п.\n" +
+"\n" +
+"Соседство развитой китайской цивилизации способствовало ускорению процесса создания племён, а затем и мощных племенных союзов во главе с влиятельными вождями. В 1206 на всемонгольском курултае вождём всех монголов был провозглашён победивший в жестокой междоусобной борьбе Темучин, принявший имя и титул Чингисхана.\n" +
+"\n" +
+"Чингисхан создал организованную и боеспособную армию, которая и стала решающим фактором в последующих успехах сравнительно немногочисленного монгольского этноса.\n" +
+"\n" +
+"Покорив соседние народы Южной Сибири, Чингисхан в 1210 пошёл войной на чжурчжэней и в 1215 взял Пекин.\n" +
+"\n" +
+"В 1219—1221 была разорена Средняя Азия и разбито государство Хорезмшахов. В 1223 — разбиты русские князья, в 1226—1227 — уничтожено государство тангутов. В 1231 основные силы монголов вернулись в Северный Китай и к 1234 завершили разгром чжурчжэньского государства Цзинь.\n" +
+"\n" +
+"Завоевания в Южном Китае были продолжены уже в 1250-х, после походов в Европу и на Ближний и Средний Восток. Вначале монголы захватили страны, окружавшие Южно-Сунскую империю — государство Дали (1252—1253), Тибет (1253). В 1258 монгольские войска под предводительством хана Хубилая с разных сторон вторглись в Южный Китай, но осуществлению их планов помешала неожиданная смерть Великого хана Мункэ (1259). Хан Хубилай, захватив ханский престол, в 1260 перенёс столицу из Каракорума на территорию Китая (сначала в Кайпин, а в 1264 в Чжунду — современный Пекин). Столицу южносунского государства Ханчжоу монголам удалось взять лишь в 1276. К 1280 весь Китай был завоёван, а Сунская империя — уничтожена.\n" +
+"\n" +
+"После покорения Китая хан Хубилай основывает новую династию Юань (1271—1368), на службу новой власти привлекаются кидани, чжурчжэни, тюрки и даже европейцы — в частности, в это время Китай посещает венецианский купец Марко Поло.\n" +
+"\n" +
+"Тяжёлый экономический, политический и национальный гнёт, установленный монгольскими феодалами, сдерживает развитие страны. Множество китайцев было обращено в рабство. Земледелие и торговля были подорваны. Не выполнялись необходимые работы по поддержанию ирригационных сооружений (дамб и каналов), что привело в 1334 к чудовищному наводнению и гибели нескольких сот тысяч человек. Великтий Китайский канал был построен во время монгольского господства.\n" +
+"\n" +
+"Народное недовольство новыми правителями вылилось в мощное патриотическое движение и восстания, которые возглавили руководители тайного общества «Белый лотос» (Байляньцзяо).\n" +
+"\n" +
+"[править] Государство Мин (1368—1644)\n" +
+"\n" +
+"В результате длительной борьбы в середине XIV века монголы были изгнаны. К власти пришёл один из руководителей восстания — сын крестьянина Чжу Юаньчжан, основавший государствоМин (1368—1644).\n" +
+"\n" +
+"Монголы, оттеснённые на север, приступают к активному освоению степей современной Монголии. Империя Мин подчиняет себе часть чжурчжэньских племён, государство Наньчжао (современные провинции Юньнань и Гуйчжоу), часть современных провинций Цинхай и Сычуань.\n" +
+"\n" +
+"Китайский флот под командой Чжэн Хэ, состоящий из нескольких десятков многопалубных фрегатов, за период с 1405 по 1433 совершает несколько морских экспедиций в Юго-Восточную Азию, Индию и к восточному побережью Африки. Не принеся Китаю никакой экономической выгоды, экспедиции были прекращены, а корабли — разобраны.\n" +
+"\n" +
+"В XVI веке происходит первая попытка усилившейся Японии вторгнуться в Китай и Корею. В это же время в Китай проникают европейцы — португальцы, испанцы, голландцы. В 1557 Португалия овладела на правах «аренды» китайской территорией Аомынь (Макао). В Китае появляются и христианские миссионеры — иезуиты. Они привезли в Китай новые инструменты и механизмы — часы, астрономические приборы, наладили здесь производство огнестрельного оружия. В то же время они занимаются доскональным изучением Китая.\n" +
+"\n" +
+"[править] Государство Цин\n" +
+"\n" +
+"К концу XVI века северные соседи империи Мин — потомки чжурчжэньских племён, разбитых в своё время Чингисханом, — объединяются вокруг владения Маньчжоу под предводительством вождя Нурхаци (1559—1626). В 1609 Нурхаци прекращает платить дань Китаю, а затем провозглашает собственную династию Цзинь. С 1618 маньчжуры усиливают вооружённое давление на Китай. За восемь лет они выходят практически к Великой китайской стене (на крайнем востоке).\n" +
+"\n" +
+"Преемник Нурхаци Абахай провозглашает себя императором и меняет название династии на Цин. В начале XVII века маньчжуры завоевали Южную (Внутреннюю) Монголию. На всей территории Южной Маньчжурии и захваченных ханств Южной Монголии устанавливается централизованная администрация.\n" +
+"\n" +
+"Маньчжурская конница, поддержанная внутренними монголами, начинает совершать регулярные набеги на Китай, грабя и обращая в рабство сотни тысяч китайцев. Императору Мин приходится направить на северные рубежи свою лучшую армию под командованием У Саньгуя. Тем временем в Китае разгорается очередное крестьянское восстание. В 1644 крестьянские отряды под предводительством Ли Цзычэна, разгромив все остальные армии, занимают Пекин, а сам Ли Цзычэн провозглашает себя императором. У Саньгуй пропускает маньчжурскую конницу на Пекин. 6 июня 1644 маньчжуры захватывают столицу. Ли Цзычэн вскоре гибнет, а маньчжуры объявляют своего малолетнего императора Шуньчжи правителем всего Китая. У Саньгуй вместе со всей армией переходит на службу к завоевателям.\n" +
+"\n" +
+"Борьба против маньчжурских захватчиков продолжается ещё долго, но ослабленный Китай не в силах противостоять хорошо вооружённому и организованному войску. Последний оплот сопротивления — Тайвань захвачен маньчжурами в 1683.\n" +
+"\n" +
+"Маньчжурская династия в государстве Цин правила с 1644 по 1911 год. В руках маньчжурской знати находились высшие органы власти и руководство армией. Смешанные браки были запрещены, и тем не менее маньчжуры быстро китаизировались, тем более что, в отличие от монголов, они не противопоставляли себя китайской культуре.\n" +
+"\n" +
+"Начиная с Канси (годы правления 1662—1723), маньчжурские императоры были ревностными конфуцианцами, управляя страной по древним законам. Китай под властью династии Цин в XVII—XVIII вв. развивался достаточно интенсивно. К началу XIX века в Китае насчитывалось уже около 300 млн. человек — примерно в пять раз больше, чем в среднем на протяжении предыдущих двух тысяч лет. Демографическое давление привело к необходимости интенсификации сельского хозяйственного производства при активном участии государства. Маньчжуры обеспечили покорность китайского населения, но при этом заботились о процветании экономики страны и благосостоянии народа.\n" +
+"\n" +
+"[править] Внешняя экспансия Цин\n" +
+"\n" +
+"Правители государства Цин проводили политику изоляции Китая от внешнего мира. Европейская колонизация почти не затронула Китай. Католические миссионеры играли заметную роль при императорском дворе до конца XVII века, после чего христианские церкви были постепенно закрыты, а миссионеры — высланы из страны. В середине XVIII века была ликвидирована торговля с европейцами, за исключением одного порта в Кантоне (Гуанчжоу). Опорным пунктом иностранной торговли оставался остров Макао, находившийся под контролем португальцев.\n" +
+"\n" +
+"В первые два столетия цинской династии Китай, закрытый от повседневных контактов с внешним миром, проявлял себя как сильное независимое государство, осуществляющее экспансию во всех направлениях.\n" +
+"\n" +
+"Вассалом Китая была Корея. В середине XVIII века в империю вошла Северная (Внешняя) Монголия. В 1757 было уничтожено Джунгарское ханство, и территория его вместе с покорённым к 1760 Восточным Туркестаном была включена в состав Цинской империи под названием Синьцзян («Новая граница»). После ряда походов маньчжуро-китайской армии против Тибета этот район был в конце XVIII века присоединён к Цинской империи. Войны Цинской империи против Бирмы (1765—1769) и Вьетнама (1788—1789) оказались неудачными и закончились поражением цинских войск.\n" +
+"\n" +
+"Одновременно осуществлялась экспансия на север и северо-восток, что неминуемо привело к конфликту с Россией в Приамурье. В течение двух веков территория Китая увеличилась практически вдвое. Цинская империя обзавелась своего рода буферными зонами — Маньчжурией, Монголией, Тибетом, Синьцзяном — которые охраняли китайские земли.\n" +
+"\n" +
+"В цинском Китае любые официальные представители иностранных государств рассматривались исключительно как представители вассальных государств — реальных или потенциальных.\n" +
+"\n" +
+"[править] Цинский Китай и Россия\n" +
+"\n" +
+"    Основная статья: Российско-китайские отношения\n" +
+"\n" +
+"Первые шаги по установлению русско-китайских отношений были предприняты Россией в конце периода Мин (миссия И. Петлина в 1618—1619), но основные миссии (Фёдора Байкова в 1654—1657, Николая Спафария в 1675—1678 и др.) последовали уже в цинский период. Параллельно с миссиями шло продвижение на восток русских казаков — походы первопроходцев Василия Пояркова (1643—1646) и Ерофея Хабарова (1649—1653) положили начало освоению русскими людьми Приамурья и привели к присоединению его к России, в то время как маньчжуры считали эти районы своей вотчиной.\n" +
+"\n" +
+"В середине XVII века на обоих берегах Амура уже существовали русские крепости-остроги (Албазинский, Кумарский и др.), крестьянские слободы и пашни. В 1656 было образовано Даурское (позднее — Албазинское) воеводство, в которое входила долина Верхнего и Среднего Амура по обоим берегам.\n" +
+"\n" +
+"Хотя граница империи Цин тогда проходила чуть севернее Ляодунского полуострова («Ивовый палисад»), в 1650-е годы и позднее Цинская империя попыталась военной силой захватить русские владения в бассейне Амура и предотвратить принятие местными племенами российского подданства. Маньчжурское войско на какое-то время вытеснило казаков из крепости Албазин. Вслед за миссиями Фёдора Байкова и Николая Спафария Россия направила в 1686 к пограничным властям на Амуре полномочное посольство Фёдора Головина для мирного урегулирования конфликта.\n" +
+"\n" +
+"Переговоры велись в окружении многотысячной маньчжурской армии. С китайской стороны в переговорах участвовали миссионеры-иезуиты, противившиеся соглашению Китая с Россией, что ещё более осложняло обстановку. Китай отказался определить русско-китайскую границу по Амуру, потребовав себе всё Албазинское воеводство, всё Забайкалье, а впоследствии — вообще все земли к востоку от Лены.\n" +
+"\n" +
+"Угрожая захватить Нерчинск штурмом, цинские представители вынудили Головина согласиться на уход русских с Верхнего и Среднего Амура. По Нерчинскому договору Россия была вынуждена уступить Цинской империи свои владения по правому берегу р. Аргунь и на части левого и правого берегов Амура. Казаки были обязаны разрушить и оставить Албазин. Вследствие разночтений в текстах договора, составленных каждой из сторон, однако, большая территория оказалась неразграниченной и фактически превратилась в буферную зону между двумя государствами. Разграничение между Россией и Китаем в пределах этой зоны завершилось в XIX веке. Окончательно граница России с Китаем на Дальнем Востоке была определена Айгуньским (1858) и Пекинским (1860) договорами; она прошла по рекам Амур и Уссури через озеро Ханка и горные хребты до р. Туманьцзян; русско-китайское территориальное разграничение в Центральной Азии было завершено к середине 1890-х.\n" +
+"\n" +
+"[править] Опиумные войны\n" +
+"Территория собственно Китая в 1875\n" +
+"Территория собственно Китая в 1875\n" +
+"\n" +
+"К концу XVIII века торговля Китая с внешним миром вновь начала расширяться. Китайский шёлк, фарфор, чай и другие товары пользовались большим спросом в Европе, но китайцы отказывались что-либо покупать у европейцев, так что тем приходилось платить серебром за китайские товары. Тогда англичане начали ввозить в Китай опиум — в основном контрабандой из Индии — и вскоре приобщили к курению опиума местное население, особенно в приморских районах. Ввоз опиума постоянно возрастал и стал подлинным бедствием для страны, что привело к серии Опиумных войн в середине XIX века. Поражение в этих войнах привело к постепенному превращению Китая в фактическую полуколонию европейских держав.\n" +
+"\n" +
+"[править] Японо-китайская война 1894—1895 годов\n" +
+"\n" +
+"В 1874 году Япония захватила Формозу, однако вынуждена была покинуть её по требованию Англии. Тогда Япония обратила свои усилия на Корею, находившуюся в вассальной зависимости от Китая и Манчжурию. В июне 1894 по просьбе корейского правительства Китай направил войска в Корею для подавления крестьянского восстания. Воспользовавшись этим предлогом, Япония также направила сюда свои войска, после чего потребовала от корейского короля проведения «реформ», означавших фактически установление в Корее японского контроля.\n" +
+"\n" +
+"В ночь на 23 июля при поддержке японских войск в Сеуле был организован правительственный переворот. Новое правительство 27 июля обратилось к Японии с «просьбой» об изгнании китайских войск из Кореи. Однако ещё 25 июля японский флот уже без объявления войны начал военные действия против Китая; официальное объявление войны последовало только 1 августа 1894. Началась Японо-китайская война\n" +
+"\n" +
+"В ходе войны превосходство японской армии и флота привело к крупным поражениям Китая на суше и на море (под Асаном, июль 1894; под Пхеньяном, сентябрь 1894; при Цзюляне, октябрь 1894).\n" +
+"\n" +
+"С 24 октября 1894 военные действия перешли на территорию Северо-Восточного Китая. К марту 1895 японские войска захватили Ляодунский полуостров, Вэйхайвэй, Инкоу, под угрозой находился Мукден.\n" +
+"\n" +
+"17 апреля 1895 в Симоносеки представители Японии и Китая подписали унизительный для Китая Симоносекский договор.\n" +
+"\n" +
+"[править] Тройственная интервенция\n" +
+"\n" +
+"Условия, навязанные Японией Китаю, привели к так называемой \"тройственной интервенции\" России, Германии и Франции - держав, которые к этому времени уже поддерживали обширные контакты с Китаем и поэтому восприняли подписанный договор как наносящий ущерб их интересам. 23 апреля 1895 Россия, Германия и Франция одновременно, но по отдельности обратились к японскому правительству с требованием отказа от аннексии Ляодунского полуострова, которая могла бы привести к установлению японского контроля над Порт-Артуром, в то время как Николай II, поддерживаемый западными союзниками, имел собственные виды на Порт-Артур как незамерзающий порт для России. Германская нота была наиболее жесткой, даже оскорбительной для Японии.\n" +
+"\n" +
+"Японии пришлось уступить. 10 мая 1895 года японское правительство заявило о возвращении Китаю Ляодунского полуострова, правда, добившись увеличения суммы китайской контрибуции на 30 миллионов таэлей.\n" +
+"\n" +
+"[править] Успехи русской политики в Китае\n" +
+"\n" +
+"В 1895 году Россия предоставила Китаю заём в 150 миллионов рублей под 4% годовых. Договор содержал обязательство Китая не соглашаться на иностранный контроль над своими финансами, если в нём не будет участвовать Россия. В конце 1895 года по инициативе Витте был основан Русско-Китайский банк. 3 июня 1896 года в Москве был подписан русско-китайский договор об оборонительном союзе против Японии. 8 сентября 1896 года между китайским правительством и Русско-Китайским банком был подписан концессионный договор о сроительстве Китайской Восточной железной дороги. Общество КВЖД получало полосу земли вдоль дороги, которая переходила под его юрисдикцию. В марте 1898 года был подписан русско-китайский договор об аренде Россией Порт-Артура и Ляодунского полуострова.\n" +
+"\n" +
+"[править] Захват Цзяочжоу Германией\n" +
+"\n" +
+"В августе 1897 года Вильгельм II посетил Николая II в Петергофе и добился согласия на устройство немецкой военно-морской базы в Цзяочжоу (в тогдашнем варианте транскрипции - \"Киао-Чао\"), на южном побережье Шаньдуна. В начале ноября в Шаньдуне китайцами были убиты германские миссионеры. 14 ноября 1897 года немцы высадили десант на побережье Цзяочжоу и захватили его. 6 марта 1898 года было подписано германо-китайское соглашение, по которому Китай арендовал Германии Цзяочжоу сроком на 99 лет. Одновременно китайское правительство предоставило Германии концессию на постройку двух железных дорог в Шаньдуне и ряд горных концессий в этой провинции.\n" +
+"\n" +
+"[править] Сто дней реформ\n" +
+"\n" +
+"Непродолжительный период реформ начался 11 июня 1898 с издания маньчжурским императором Цзай Тянем (название годов правления — Гуансюй) указа «Об установлении основной линии государственной политики». Цзай Тянь привлек группу молодых реформаторов — учеников и единомышленников Кан Ювэя для разработки серии указов о реформах. В общей сложности было издано свыше 60 указов, которые касались системы образования, строительства железных дорог, заводов и фабрик, модернизации сельского хозяйства, развития внутренней и внешней торговли, реорганизации вооружённых сил, чистки государственного аппарата и т.д. Период радикальных реформ окончился 21 сентября того же года, когда вдовствующая Императрица Цыси произвела дворцовый переворот и отменила реформы.\n" +
+"\n" +
+"[править] XX век\n" +
+"\n" +
+"[править] Боксерское восстание\n" +
+"\n" +
+"В мае 1900 года в Китае началось большое восстание, получившее название боксерского или Ихэтуаньского восстания. 20 июня в Пекине был убит германский посланник Кеттелер. Вслед за этим восставшими были осаждены дипломатические миссии, находившиеся в особом квартале Пекина. Было осаждено также здание католического кафедрального собора Петанг (Бейтанг). Начались массовые убийства \"ихэтуанями\" китайцев-христиан, в том числе было убито 222 православных китайца. 21 июня 1900 года Императрица Цыси объявила войну Великобритании, Германии, Австро-Венгрии, Франции, Италии, Японии, США и России. Великие державы согласились о совместных действиях против восставших. Главнокомандующим экспедиционными силами был назначен германский генерал Вальдерзее. Однако, когда он прибыл в Китай, Пекин был уже освобожден небольшим передовым отрядом под командованием русского генерала Линевича. Русская армия заняла Манчжурию.\n" +
+"\n" +
+"[править] Русско-японская война\n" +
+"\n" +
+"8 февраля 1904 года началась Русско-японская война за контроль над Манчжурией и Кореей. Война, шедшая на территории Китая была для России неудачной, по её результатам, Россия была вынуждена уступить Японии Порт-Артур и Ляодунский полуостров с частью построенной к тому времени КВЖД.\n" +
+"\n" +
+"[править] Смерть Цыси\n" +
+"\n" +
+"14 декабря 1908 года в один день умерли Императрица Цыси и Император Гуансюй, которого Цыси ранее отстранила от власти. Возможно, Гуансюй был отравлен, так как Цыси не хотела, чтобы он её пережил. На престол взошёл Император Пу И, которому было два года. Регентом назначен его отец князь Чунь, однако вскоре власть перешла к его брату.\n" +
+"\n" +
+"[править] Аннексия Кореи\n" +
+"\n" +
+"В 1910 году Япония аннексировала Корею, хотя японские войска там находились с начала Русско-японской войны.\n" +
+"\n" +
+"[править] Революция 1911 года и создание Китайской Республики\n" +
+"\n" +
+"В 1911 году в Китае началось Учанское восстание. Оно стало началом Синьхайской революции (1911—1913) в Китае, в результате которой было свергнута маньчжурская династия Цин и провозглашено создание Китайской республики.\n" +
+"\n" +
+"После падения монархии правитель Монголии отказался повиноваться республике и отделился от Китая. 3 ноября им было заключено соглашение с Россией. Англия воспользовалась внутренней борьбой в Китае для превращения Тибета в свою зону влияния. Тибет поднялся на борьбу и заставил китайский гарнизон покинуть страну. Все последующие попытки китайцев восстановить там свою власть пресекались Британией. Россия согласилась считать Тибет английской сферой влияния, а Англия признала русские интересы в независимой (внешней) Монголии.\n" +
+"\n" +
+"12 февраля 1912 года Император Пу И отрекся от престола. К власти пришел генерал Юань Шикай премьер-министр и главнокомандующий армией. Вскоре он был провозглашен президентом Китая.\n" +
+"\n" +
+"В 1913 году произошла \"Вторая революция\". Юань Шикай подавил разрозненные выступления в центральных и южных провинциях. В стране устанавливается военная диктатура Юань Шикая, основателя группировки бэйянских (северных) милитаристов. Сунь Ятсен вынужден эмигрировать за границу.\n" +
+"\n" +
+"[править] Первая мировая война\n" +
+"\n" +
+"После начала первой мировой войны китайское правительство объявляет о своем нейтралитете и просит воюющие державы не переносить военные действия на территорию Китая, в том числе и на \"арендованные\" державами китайские земли. Однако 22 августа 1914 года Япония объявила о своем состоянии войны с Германией и высадила 30-тысячную армию севернее Циндао - центра немецкой колонии в провинции Шаньдун. После двухмесячной военной кампании Япония захватила германские владения в Шаньдуне, а также распространила свой контроль на всю территорию провинции.\n" +
+"\n" +
+"В 1915 году китайские принцы голосуют за установленче в Китае монархии с Юанем Шикаем на императорском троне. Распускается парламент. Объявляется монархия. Это вызывает ряд восстаний в провинциях Китая. Независимость от Пекина объявляют провинции Юньнань, Гуйчжоу и Гуанси. Потом отделяются Гуандун, Чжэцзян, Сычуань и Хунань.\n" +
+"\n" +
+"22 марта 1916 года умирает Юань Шикай.\n" +
+"\n" +
+"[править] Эра милитаристов\n" +
+"\n" +
+"После смерти Юань Шикая в Китае начали оформляться многочисленные военно-феодальные вотчины различных милитаристских группировок. Наиболее крупной была бэйянская (северная), делившаяся на фэнтяньскую (маньчжурскую) во главе с бывшим главарем шайки хунхузов Чжан Цзолинем, чжилийскую во главе с генералом Фэн Гочжаном, и аньхойскую во главе с генералом Дуань Цижуем. В провинции Шаньси господствовал милитарист Янь Сишань, заигрывавший с бэйянской группировкой, а в провинции Шэньси - генерал Чэнь Шуфань. Лагерь юго-западных милитаристов состоял из двух крупных группировок: юньнаньской во главе с генералом Тан Цзияо, и гуансийской во главе с генералом Лу Жунтином.\n" +
+"\n" +
+"Под контролем фэнтяньской группировки находились провинции Хэйлунцзян, Гирин и Фэнтянь, под контролем чжилийской - Шаньдун, Цзянсу, Чжэцзян, Фуцзянь, Цзянси, Хунань, Хубэй и часть Чжили. Фэнтяньская и аньхойская клики финансировались Японией, чжилийская - Англией и США. Ли Юаньхун был ставленником юго-западных милитаристов. Вице-президент генерал Фэн Гочжан ориентировался на Англию и США, а премьер-министр генерал Дуань Цижуй держался прояпонского направления. В 1917 году Япония начала предоставлять Дуань Цижую крупные займы, получая за них все новые и новые уступки, в том числе концессии в Маньчжурии.\n" +
+"\n" +
+"[править] Победа Гоминьдана\n" +
+"\n" +
+"Партия Гоминьдан была создана в 1912 году в провинции Гуанчжоу. Примерно в тоже время, в 1921 г., была создана и Китайская коммунистическая партия, малочисленная и не пользовавшаяся в тот период особой популярностью. 8 сентября 1923 в Китай по просьбе Сунь Ятсена, который просил прислать ему человека с которым он мог бы говорить по-английски без переводчика, прибыл агент коминтерна М.М.Бородин, ставший политическим советником ЦИК Гоминьдана и советником Сунь Ятсена. Он организовал сотрудничество между Гоминьданом и КПК. 20 января 1924 г. проходит I Всекитайский съезд Гоминьдана в Гуанчжоу. На съезде был принят курс на союз с китайскими коммунистами и СССР. 16 июня учреждена Военная академия Вампу под руководством Чан Кайши. В первый набор было зачислено 400, во второй - 500, в третий - 800 и четвертый - около 2600 слушателей; при школе было создано два учебных полка. В академию Вампу прибыла большая группа советских военных советников. В октябре 1924 г. в Гуанчжоу на должность главного военного советника прибыл Василий Константинович Блюхер.\n" +
+"В марте 1926 Чан Кайши осуществил в Кантоне военный переворот, изгнал из города коммунистов, а спустя три месяца был избран председателем Гоминьдана и главнокомандующим вооруженными войсками. Добившись высокой власти, Чан Кайши пригласил немецких советников во главе бывшим генералом рейхсвера фон Сектом.\n" +
+"В качестве советников у Чан Кайши действовали офицеры Германии:\n" +
+"\n" +
+"    * полковник В.Бауэр (друг Гитлера и ученик Людендорфа)\n" +
+"    * нацист подполковник Крибель\n" +
+"    * генерал-лейтенант Ветцель\n" +
+"    * генерал Фалькенхаузен\n" +
+"\n" +
+"Гоминьдановцы старательно перенимали опыт нацистов по наведению порядка в стране. Китайские офицеры в организованном порядке направлялись на обучение в Германию.\n" +
+"В 1926 Национально-революционная армия Китая Чан Кайши предприняла так называемый Великий Северный поход. В течение шести месяцев непрерывных боев от власти местных военных правителей были освобождены центральные районы Китая.\n" +
+"В начале 1927 Чан Кайши пошел на открытый развал единого фронта ГМД и КПК: его войска начали разоружение шанхайских рабочих отрядов и дружин, начались массовые аресты и казни профсоюзных деятелей и коммунистов. В ответ на это коммунисты организовали 1 августа в городе Наньчан восстание части гоминьдановских войск, вошедшее в историю Китая как \"Наньчанское восстание\".\n" +
+"В декабре 1927 было поднято коммунистическое восстание в Кантоне, которое гоминьдановцы жесточайшим образом подавили после четырех дней кровопролитных боев.\n" +
+"После нескольких военных операций к 1927 году войска Гоминьдана контролировали большую часть территории Китая.\n" +
+"\n" +
+"[править] Японская оккупация и Вторая мировая война\n" +
+"\n" +
+"Осенью 1931 Япония напала на Китай. 18 сентября после серии провокаций японцы перешли в наступление, за короткое оккупировав всю Манчжурию. В марте 1932 здесь было провозглашено прояпонское марионеточное государство Маньчжоу-Го, которое возглавил Пу И – последний отпрыск маньчжурской династии Цин, свергнутой в годы Синьхайской революции.\n" +
+"\n" +
+"В этих сложных условиях Чан Кайши был вынужден бороться одновременно с тремя врагами: внешней японской агрессией, спорадическими бунтами отдельных милитаристов на местах, и вооружёнными силами КПК, претендовавшими на захват власти в стране. Он выбрал политику компромисса с японцами, с милитаристами вёл дела в зависимости от конкретных обстоятельств, с коммунистами же никакой компромисс был невозможен. В 1934 году основные силы КПК были блокированы в провинции Цзянси. В этих сложных условиях руководство КПК сумело организовать прорыв, и после многомесячного марша привело войска на Северо-Запад страны в т.н. \"особый район\" с центром в городе Яньань; эти события вошли в историю КПК как \"Великий поход\". Чан Кайши планировал продолжать борьбу с коммунистами и там, но тут взбунтовался ряд его генералов, считавших более приоритетной задачей примирение с коммунистами и совместную борьбу с японской агрессией. В результате \"Сианьского инцидента\" было подписано соглашение о создании единого фронта между КПК и Гоминьданом.\n" +
+"\n" +
+"7 июля 1937 конфликтом у моста Лугоуцяо недалеко от Пекина началась «большая» война. С этого момента, по мнению китайских историков, начинается Вторая мировая война.\n" +
+"\n" +
+"\n" +
+"   Этот раздел не завершён. Вы можете помочь проекту, исправив и дополнив его.\n" +
+"Японская оккупация (1940)\n" +
+"Японская оккупация (1940)\n" +
+"\n" +
+"[править] Создание Китайской Народной Республики\n" +
+"\n" +
+"Разгром милитаристской Японии в августе-сентябре 1945 завершил Вторую мировую войну, освободив от порабощения страны Азиатско-Тихоокеанского региона. В Китае шла ожесточенная гражданская война.\n" +
+"Советская Красная Армия полностью оккупировала Манчжурию, приняв капитуляцию фактически у всей японской Квантунской армии. К тому времени на территории Манчжурии действовали лишь разрозненные партизанские отряды и разведгруппы китайских партизан.\n" +
+"В сентябре 1945 начала осуществляться массовая переброска вооруженных сил КПК из северного и Восточного Китая на северо-восток страны. К ноябрю туда перешли около 100 тысяч бойцов 8-ой и 4-ой армий. Из этих частей, партизанских формирований и местных жителей была сформирована Объединенная демократическая армия (ОДА) Северо-Востока, которая стала костяком Народно-освободительной армии Китая.\n" +
+"Советская армия находилась в Манчжурии вплоть до мая 1946. За это время советская сторона помогла китайским коммунистам организовать, обучить и вооружить новые китайские войска. В результате, когда гоминьдановские войска начали в апреле 1946 входить в Манчжурию, они, к своему удивлению, обнаружили там не разрозненные партизанские отряды, а современную дисциплинированную армию коммунистов, вовсе не намеревавшуюся самораспускаться.\n" +
+"Ситуация в Манчжурии стала шоком и для Белого дома. Первый отряд вооруженных сил США в составе двух дивизий морской пехоты высадился в Китае в районе Тяньцзиня еще 30 сентября 1945. К осени в Китае находилось уже свыше 100 тысяч американских военнослужащих.\n" +
+"Американские экспедиционные войска, главным образом части морской пехоты, старались не вмешиваться в отношения между КПК и ГМД. Однако они активно взаимодействовали с вооруженными силами легитимного китайского правительства - войсками Гоминьдана, прежде всего в приеме капитуляции японских войск в Северном и Центральном Китае, а также в поддержании порядка и охране различных важных объектов в китайских городах.\n" +
+"С самого начала командование войск ГМД допустило стратегическую ошибку: несмотря на успехи первых столкновений с ОДА в Манчжурии, военные действия в Северо-Восточном Китае не были доведены до конца, ГМД направил свои усилия не на борьбу с регулярными войсками КПК, а на уничтожение партизанского движения и партизанских баз в Центральном, Восточном и Северном Китае.\n" +
+"Укрепившись с помощью советской стороны, при поддержке местного населения, войска Мао Цзэдуна к осени 1948 достигли численности в 600 тысяч человек. С 1 ноября ОДА стала именоваться 4-й Полевой армией. возглавили ее Линь Бяо.\n" +
+"В ноябре 1948 4-я полевая армия перешла к решительным боевым действиям против гоминьдановцев. За короткие сроки было разбито 52 дивизии Чан Кайши, еще 26 дивизий, обученных военными инструкторами США, перешли на сторону КПК. В начале 1949 армия вошла в Северный Китай, где объединилась с войсками 8-й армии КПК. 15 января был взят Тяньцзинь, 22 января - Пекин.\n" +
+"К весне 1949 вооруженные силы КПК освободили от гоминьдановцев весь Китай севернее реки Янцзы и восточнее провинции Ганьсу. К концу гражданской войны Народно-освободительная армия представляла собой мощную 4-миллионую армию, крупнейшую в Азии.\n" +
+"24 апреля 1949 войска КПК под командованием маршала Лю Бочэна вступили в столицу гоминьдановского Китая - город Нанкин. Само гоминьдановское правительство еще в феврале переехало на юг страны, в Кантон, а затем вместе с остатками верных ему войск - бежало на остров Тайвань.\n" +
+"В конце года Народно-освободительная армия Китая уничтожила все основные группировки Гоминьдана на континенте, победоносно завершив тем самым третью гражданскую войну в Китае.\n" +
+"1 октября 1949 г. в Пекине была провозглашена Китайская Народная Республика.\n" +
+"На следующий же день Советский Союз первым признал КНР и заключил с ней Договор о дружбе, союзе и взаимной помощи. Таким образом, в конце 1949 года родился советско-китайский «монолит» - тот самый, который на многие годы стал кошмаром для Запада.\n" +
+"\n" +
+"[править] Культурная революция\n" +
+"\n" +
+"В 1966 году председателем КПК Мао Цзэдуном была начата культурная революция для утверждения маоизма в качестве единственной государственной идеологии и уничтожения политической оппозиции. Было организовано массовое ополчение молодёжи, называвшееся «красногвардейцы». Красногвардейцы занялись преследованием «контререволюционеров» из числа аппарата КПК, интеллигенции и вообще всех, кто мог им не понравиться.\n" +
+"\n" +
+"[править] Экономическая либерализация\n" +
+"\n" +
+"После падения \"банды четырех\" власть в стране взяли реформаторы Дэн Сяопин и Ху Яобан, которые в конце 1978 года провозгласили на 3-м пленуме ЦК КПК 11-го созыва политику \"реформ и открытости\". Реальный старт \"Экономической реформе\" был дан на XII съезде КПК (1982 г.). На XIII съезде КПК (1987 г.) было дано подробное толкование теории начального этапа социализма, согласно которой социалистический строй и социалистическая экономическая система - разные вещи, т.е. социалистический политический режим не подразумевает безусловной плановой централизации всей экономики, а позволяет использовать и рыночные механизмы, особенно в паре \"государство-предприятие\". На XIV съезде КПК (1992 г.) был провозглашен курс на построение социалистической рыночной экономической системы с китайской спецификой. Данное изменение идеологии хорошо иллюстрирует высказываение Д.Сяопина: \"Неважно какого цвета кошка - главное, чтобы ловила мышей\".\n" +
+"\n" +
+"Фактически введение \"Экономической реформы\" означало настоящую \"революцию сверху\", заключавшуюся в постепенном и частичном сворачивании тоталитарной сталинско-маоистской модели жестко централизованной экономики и переводе части отраслей народного хозяйства на рыночные рельсы, но при полностью неизменной политической надстройке в лице монопольно управляющей страной КПК. К концу 70-х исторически слабая экономика Китая \"лежала\" из-за негативных последствий авантюристических кампаний Мао Цзедуна - \"большого скачка\" и \"культурной революции\". От систематического голода в Китае ежегодно страдали практически все 800 млн. крестьян (из миллиардного населения), страна занимала последние места в мире по уровню производства товаров и продовольствия на душу населения. Для решения проблемы голода необходимо было обеспечить стабильный валовый сбор зерна в объеме не менее 400 млн. т в год. Аграрные преобразования были связаны с отменой народной коммуны и заменой ее семейным подрядом и единой коллективной собственностью. Практически все 800 млн. крестьян получили право на свободное сельскохозяйственное производство. В основном была отменена система госзаготовок, освобождены цены на большинство видов сельскохозяйственной продукции. Результатом этих мер стал выход аграрного сектора из застоя, вступление крестьянских хозяйств на путь специализации и повышения товарности. Организованные в деревне по инициативе крестьян волостно-поселковые предприятия позволили обеспечить рост занятости (120 млн. чел.) и повысить жизненный уровень крестьян.Задача обеспечения страны зерном была в основном решена в 80-х. Постепенно в деревне сформировалась двухслойная хозяйственная система на основе сочетания коллективной собственности и семейного подряда.\n" +
+"\n" +
+"В области промышленной политики правительство Китая, начиная с 1984 года сделало упор концепцию плановой товарной экономики. На практике это означало перевод части отдельных городских предприятий на самоокупаемость. Позже правительство разрешило и подразделениям армии Китая (НОАК) перейти на самообеспечение и заниматься свободным предпринимательством. В соответствии с принципом \"Чжуа Да Фан Сяо\" (\"держать в руках большие предприятия, отпустить маленькие\") многие мелкие госпредприятия получили право изменить не только механизм хозяйствования, но и форму собственности. Это позволило государству сосредоточить силы на улучшении положения крупных предприятий. Четыре города - Шэньчжэнь, Чжухай, Сямынь, Шаньтоу - были объявлены специальными экономическими зонами. Вслед за ними 14 приморских городов, четыре региона в устьях рек Янцзы и Чжуцзян, юго-восточная часть провинции Фуцзянь и регион в районе Бахайского залива стали открытыми экономическими зонами. На острове Хайнань была создана одноименная новая провинция, а сам он стал специальной экономической зоной. Все эти города и районы получили различные инвестиционные и налоговые льготы для привлечения иностранного капитала и технологий, заимствования у иностранных партнеров эффективных методов управления. Быстрое развитие их экономики способствовало эффективному росту в масштабе страны. Характерно, что значительную долю ввозимого капитала на начальном этапе обеспечила китайская диаспора (хуацяо), проживающая преимущественно в странах тихоокеанского бассейна (основные зоны компактного проживания: Гонконг, Макао, Сингапур, Малайзия, США). Успешное проведение политики либерализации в сочетании с жестко проводимой политикой ограничения рождаемости (снижение рождаемости за 20 лет составило не менее 200 млн. человек) позволило создать многоукладную экономику, в которой госпредприятия дают 48% промышленной продукции, коллективные - 38%, частные, в том числе с иностранным участием, - 13,5%. На долю государственной торговли приходится свыше 41% общего розничного оборота, коллективной - почти 28% и частной - 31%. Доля рыночных цен по потребительским товарам достигла 90%, средствам производства - 80%, по сельскохозяйственным продуктам - 85%. Доля видов промышленной продукции, производство которых регулируется государственными директивными планами, снизилась с 95% в 1978 г. до 5% в настоящее время. Удельный вес товаров, ценами которых непосредственно управляет государство, в розничном товарообороте упал с 95 до 6%. Помимо рынка товаров начали создаваться рынки капиталов, машин и оборудования, рабочей силы, других необходимых для производства элементов. ВВП Китая рос в течение 20 лет, начиная с 1985 года в среднем на 9,5% ежегодно. Страна вышла на 1-е место в мире по производству цемента, цветных металлов, хлопчатобумажных тканей, велосипедов (свыше 80 млн.), мотоциклов (21,3 млн.), телевизоров (35 млн.), угля, зерна, хлопка, рапсовых семян, мяса, яиц, на 2-е - химических удобрений, 3-е - сахара, автомобилей (7,3 млн., вкл. 4,6 млн. легковых), 4-е - электроэнергии, 5-е - сырой нефти. По объему ВВП Китай находится на 4-м месте в мире (при расчете по паритетному покупательскому курсу - на 2-м). На его долю приходится 5,4% мирового валового продукта (2006 г.). Золотовалютные резервы страны превысили в 2006 г. триллион долларов США. Положительное сальдо торгового баланса составляет 180 млрд. долларов. Правда, несмотря на такой рекордно длительный и масштабный экономический рост, среднедушевые показатели ВВП Китая остаются еще на относительно низком уровне, ВВП на душу населения в 2005 году составил 7600 долларов (109-110 место в мире рядом с Украиной). В тоже время средний доход горожанина в открытых городах на конец 2006 г. превысил 10000 юаней в месяц. В китайской деревне от 100 до 150 млн. человек не могут найти работу, еще несколько сотен миллионов заняты частично. Официальный уровень безработицы в городах 4,2% (2005 г.).\n" +
+"\n" +
+"В начале 21-го века Китай превратился в \"мировую фабрику\" куда переводится ряд производств из развитых стран Европы, Северной Америки и Японии. Бурный экономический рост во многом связан с дешевизной рабочей силы, слабым уровнем техники безопасности и низким контролем за экологией. В результате Китай уже стал вторым загрязнителем мировой атмосферы и гидросферы, после гораздо более мощной экономики США, а также вышел в \"лидеры\" по эррозии почвы (особенно в северных областях). Возросший из-за роста авто- и мотопарка уровень импорта Китаем нефти (3,2 млн. баррелей/сут. в 2005-м, 2-е место в мире) приводит в последние годы к росту ее среднемировой цены.\n" +
+"\n" +
+"В тоже время экономическое и политическое влияние страны в мире в последние годы постоянно возрастает. Так Китаю в 1997-м и 1999-и годах были возращены \"арендованные\" еще у Поднебесной империи территории Гонконг (Сянган) и Макао (Аомынь). Постоянно возрастает уровень обороноспособности страны и техническое оснащение НОАК, чему в немалой степени способствует и РФ, поставляющая в Китай самые современные виды вооружения.\n" +
+"\n" +
+"Либерализация экономики КНР пока не сопровождается смягчением политического режима. В стране продолжаются политические репрессии против оппозиции, особенно масштабно реализованные во время \"событий на площади Тяньаньмэнь\" в мае 1989-го, жестко контролируются СМИ, включая Интернет. В тоже время в последние годы предпринят ряд важных изменений устава КПК, например, в партию разрешено вступать представителям предпринимательских кругов, введена ротация высших кадров руководства Партии. Во внутренней политике сняты все ограничения на рост личных состояний и разрешено владение личными автомобилями. В тоже время страна лидирует в мире по количеству смертных казней (более 7000 в год). Несмотря на такую суровую практику, уровень преступности и коррупции постоянно возрастает.\n" +
+"\n" +
+"Политика либерализации дала сенсационно высокие результаты, перевела экономику Китая на иной качественный уровень. При этом развитие экономики идет неравномерно по регионам, накапливаются социальные диспропорции, а экологическим аспектам уделяется недостаточное внимание, что уже затрагивает не только территорию Китая, но и интересы сопредельных с ним стран.\n" +
+"\n" +
+"[править] См. также\n" +
+"\n" +
+"    * Китай (цивилизация)\n" +
+"    * События на площади Тяньаньмэнь 1989 года\n" +
+"\n" +
+"[править] Литература\n" +
+"\n" +
+"    * Васильев Л.С. Древний Китай: в 3 т. Т. 3. Период Чжаньго (V–III вв. до н.э.). М.: Восточная литература, 2006. ISBN 502018103X\n" +
+"    * Непомнин О.Е. История Китая: Эпоха Цин. XVII – начало XX века. М.: Восточная литература, 2005. ISBN 5020184004\n";
+
+var devanagari = 
+"भारत\n" +
+"विकिपीडिया, एक मुक्त ज्ञानकोष से\n" +
+"Jump to: navigation, search\n" +
+"      यह लेख एक निर्वाचित लेख उम्मीदवार है। अधिक जानकारी के लिए और इस लेख को निर्वाचित लेख बनने के लिए क्या आवश्यकताएँ हैं यह जानने के लिए कृपया यहाँ देखें।\n" +
+"भारत गणराज्य\n" +
+"Flag of भारत  Coat of arms of भारत\n" +
+"ध्वज  कुलचिह्न\n" +
+"राष्ट्रवाक्य: \"सत्यमेव जयते\" (संस्कृत)\n" +
+"\n" +
+"सत्य ही विजयी होता है\n" +
+"राष्ट्रगान: जन गण मन\n" +
+"भारत की स्थिति\n" +
+"राजधानी         नई दिल्ली\n" +
+"८७, ५९०) 28°34′ N 77°12′ E\n" +
+"सबसे बड़ा शहर   मुम्बई\n" +
+"राजभाषा(एँ)         हिन्दी, अंग्रेज़ी तथा अन्य भारतीय भाषाएं\n" +
+"सरकार\n" +
+"राष्ट्रपति\n" +
+"प्रधानमंत्री\n" +
+"      गणराज्य\n" +
+"प्रतिभा पाटिल\n" +
+"डॉ मनमोहन सिंह\n" +
+"ब्रिटिश राज से स्वतंत्रता\n" +
+"      १५ अगस्त, १९४७\n" +
+"क्षेत्रफल\n" +
+" - कुल\n" +
+" \n" +
+" - जलीय (%)    \n" +
+"३२, ८७, ५९० km² (सातवां)\n" +
+"१२,२२,५५९ sq mi \n" +
+"९.५६\n" +
+"जनसंख्या\n" +
+" - २००५ अनुमान\n" +
+" - २००१ जनगणना\n" +
+" - जनसंख्या का घनत्व     \n" +
+"१,१०,३३,७१,००० (द्वितीय)\n" +
+"१,०२,७०,१५,२४८\n" +
+"३२९/km² (३१ वीं)\n" +
+"८५२/sq mi \n" +
+"सकल घरेलू उत्पाद (जीडीपी) (पीपीपी)\n" +
+" - कुल\n" +
+" - प्रतिव्यत्ति       २००५ estimate\n" +
+"$३.६३३ महासंख (चौथी GDP_PPP_per_capita = $३,३२०)\n" +
+"{{{GDP_PPP_per_capita}}} (१२२ वीं)\n" +
+"मानव विकास संकेतांक (एइचडीआइ)         ०.६११ (१२६ वीं) – medium\n" +
+"मुद्रा    भारतीय रुपया (आइएनआर)\n" +
+"समय मण्डल\n" +
+" - ग्रीष्म ऋतु (डेलाइट सेविंग टाइम)       आइएसटी (UTC+५:३०)\n" +
+"अब्सर्व्ड नहीं है (UTC+५:३०)\n" +
+"इंटरनेट टॉप लेवेल डोमेन       .आइएन\n" +
+"दूरभाष कोड  +९१\n" +
+"\n" +
+"भारत गणराज्य, पौराणिक जम्बुद्वीप, दक्षिण एशिया में स्थित एक देश है। यह भारतीय उपमहाद्वीप का सबसे बड़ा देश है। भारत का भौगोलिक फैलाव 8० 4' से 37० 6' उत्तरी अक्षांश तक तथा 68० 7' से 97० 25'पूर्वी देशान्तर तक है । भारत का क्षेत्रफल ३२,८७,२६३ वर्ग कि. मी. हैं | भारत का विस्तार उत्तर से दक्षिण तक ३,२१४ कि. मी. और पूर्व से पश्चिम तक २,९३३ कि. मी. हैं । भारत की समुद्र तट रेखा ७५१६.६ किलोमीटर लम्बी है। भारत, भौगोलिक दृष्टि से विश्व का सातवाँ सबसे बड़ा और जनसँख्या के दृष्टिकोण से दूसरा बड़ा देश है | भारत के पश्चिम में पाकिस्तान , उत्तर-पूर्व मे चीन, नेपाल, और भूटान और पूर्व में बांग्लादेश और म्यांमार देश स्थित हैं। हिन्द महासागर में इसके दक्षिण पश्चिम में मालदीव, दक्षिण में श्रीलंका और दक्षिण-पूर्व में इंडोनेशिया है। भारत उत्तर-पश्चिम में अफ़्ग़ानिस्तान के साथ सीमा का दावा करता है। इसके उत्तर में हिमालय पर्वत है। दक्षिण में हिन्द महासागर है। पूर्व में बंगाल की खाड़ी है। पश्चिम में अरब सागर है। भारत में कई बड़ी नदियाँ है। गंगा नदी भारतीय सभ्यता मै बहुत पवित्र मानी जाती है। अन्य बड़ी नदियाँ ब्रह्मपुत्र, यमुना, गोदावरी, कावेरी, कृष्णा, चम्बल, सतलज, बियास हैं ।\n" +
+"\n" +
+"भारत की १०० करोड़ (१ अरब) से अधिक जनसंख्या, चीन के बाद विश्व में सबसे अधिक है। यह विश्व का सबसे बड़ा लोकतंत्र है। यहाँ ३०० से अधिक भाषाएँ बोली जाती है (साइटेसन चाहिए)। यह एक बहुत प्राचीन सभ्यता की भूमि है।\n" +
+"\n" +
+"भारत विश्व की दसवीं सबसे बड़ी अर्थव्यवस्था है, किन्तु हाल में भारत ने काफी प्रगति की है, और ताज़ा स्थिति में भारत विश्व में तीसरे, चौथे स्थान पर होने का दावा करता है (साइटेसन चाहिए)। भारत भौगोलिक क्षेत्रफल के आधार पर विश्व का सातवाँ सबसे बड़ा राष्ट्र है। यह विश्व की कुछ प्राचीनतम सभ्यताओं का पालना रहा है जैसे - सिन्धु घाटी सभ्यता , और महत्वपूर्ण ऐतिहासिक व्यापार पथों का अभिन्न अंग है। विश्व के चार प्रमुख धर्म : हिन्दू , बौध , जैन तथा सिख भारत में प्रतिपादित हुए | १९४७ में स्वतंत्रता प्राप्ति से पूर्व ब्रिटिश भारत के रूप में ब्रिटिश साम्राज्य के प्रमुख अंग भारत ने विगत २० वर्ष में सार्थक प्रगति की है, विशेष रूप से आर्थिक और सैन्य | भारतीय सेना एक क्षेत्रिय शक्ति और विश्वव्यापक शक्ति है।\n" +
+"\n" +
+"भारत की राजधानी नई दिल्ली है। भारत के अन्य बड़े महानगर मुम्बई (बम्बई), कोलकाता (कलकत्ता) और चेन्नई (मद्रास) हैं।\n" +
+"\n" +
+"\n" +
+"अनुक्रम\n" +
+"[छुपाएं]\n" +
+"\n" +
+"    * १ नाम\n" +
+"    * २ इतिहास\n" +
+"    * ३ सरकार\n" +
+"    * ४ राजनीति\n" +
+"    * ५ राज्य और केन्द्रशासित प्रदेश\n" +
+"    * ६ भूगोल और मौसम\n" +
+"    * ७ अर्थव्यवस्था\n" +
+"    * ८ जनवृत्त\n" +
+"    * ९ संस्कृति\n" +
+"    * १० यह भी देखें\n" +
+"    * ११ बाहरी कड़ियाँ\n" +
+"\n" +
+"[संपादित करें] नाम\n" +
+"मुख्य लेख: भारत नाम की उत्पत्ति\n" +
+"\n" +
+"भारत के दो आधिकारिक नाम है हिन्दी में भारत और अंग्रेज़ी में इन्डिया (India)। इन्डिया नाम की उत्पत्ति सिन्धु नदी के फारसी नाम से हुई। भारत नाम एक प्राचीन हिन्दू राजा भरत, जिनकी कथा महाभारत में है, के नाम से लिया गया है। एक तीसरा नाम हिन्दुस्तान (उत्पत्ति फारसी) या हिन्दुओं की भूमि मुगल काल से प्रयोग होता है यद्यपि इसका समकालीन उपयोग कम है।\n" +
+"\n" +
+"[संपादित करें] इतिहास\n" +
+"मुख्य लेख: भारतीय इतिहास\n" +
+"\n" +
+"पाषाण युग भीमबेटका मध्य प्रदेश की गुफाएं भारत में मानव जीवन का प्राचीनतम प्रमाण है। प्रथम स्थाई बस्तियों ने ९००० वर्ष पूर्व स्वरुप लिया। यही आगे चल कर सिन्धु घाटी सभ्यता में विकसित हुई , जो २६०० ईसवी और १९०० ईसवी के मध्य अपने चरम पर थी। लगभग १६०० ईसापूर्व आर्य भारत आए और उत्तर भारतीय क्षेत्रों में वैदिक सभ्यता का सूत्रपात किया । इस सभ्यता के स्रोत वेद और पुराण हैं। यह परम्परा कई सहस्र वर्ष पुरानी है। इसी समय दक्षिण बारत में द्रविड़ सभ्यता का विकास होता रहा। दोनो जातियों ने एक दूसरे की खूबियों को अपनाते हुए भारत में एक मिश्रित संस्कृति का निर्माण किया।\n" +
+"\n" +
+"५०० ईसवी पूर्व कॆ बाद, कई स्वतंत्र राज्य बन गए। उत्तर में मौर्य राजवंश, जिसमें बौद्ध महाराजा अशोक सम्मिलित थे, ने भारत के सांस्कृतिक पटल पर उल्लेखनीय छाप छोड़ी। १८० ईसवी के आरम्भ से, मध्य एशिया से कई आक्रमण हुए, जिनके परिणामस्वरूप उत्तरी भारतीय उपमहाद्वीप में यूनानी, शक, पार्थी और अंततः कुषाण राजवंश स्थापित हुए | तीसरी शताब्दी के आगे का समय जब भारत पर गुप्त वंश का शासन था, भारत का \"स्वर्णिम काल\" कहलाया।\n" +
+"तीसरी शताब्दी में सम्राट अशोक द्वारा बनाया गया मध्य प्रदेश में साँची का स्तूप\n" +
+"तीसरी शताब्दी में सम्राट अशोक द्वारा बनाया गया मध्य प्रदेश में साँची का स्तूप\n" +
+"\n" +
+"दक्षिण भारत में भिन्न-भिन्न समयकाल में कई राजवंश चालुक्य, चेर, चोल, पल्लव तथा पांड्य चले | विज्ञान, कला, साहित्य, गणित, खगोल शास्त्र, प्राचीन प्रौद्योगिकी, धर्म, तथा दर्शन इन्हीं राजाओं के शासनकाल में फ़ले-फ़ूले |\n" +
+"\n" +
+"१२वीं शताब्दी के प्रारंभ में, भारत पर इस्लामी आक्रमणों के पश्चात, उत्तरी व केन्द्रीय भारत का अधिकांश भाग दिल्ली सल्तनत के शासनाधीन हो गया; और बाद में, अधिकांश उपमहाद्वीप मुगल वंश के अधीन । दक्षिण भारत में विजयनगर साम्राज्य शक्तिशाली निकला। हालांकि, विशेषतः तुलनात्मक रूप से, संरक्षित दक्षिण में अनेक राज्य शेष रहे अथवा अस्तित्व में आये।\n" +
+"\n" +
+"१७वीं शताब्दी के मध्यकाल में पुर्तगाल, डच, फ्रांस, ब्रिटेन सहित अनेकों यूरोपीय देशों, जो भारत से व्यापार करने के इच्छुक थे, उन्होनें देश की शासकीय अराजकता का लाभ प्राप्त किया। अंग्रेज दूसरे देशों से व्यापार के इच्छुक लोगों को रोकने में सफल रहे और १८४० तक लगभग संपूर्ण देश पर शासन करने में सफल हुए। १८५७ में ब्रिटिश इस्ट इंडिया कम्पनी के विरुद्ध असफल विद्रोह, जो कि भारतीय स्वतन्त्रता के प्रथम संग्राम से जाना जाता है, के बाद भारत का अधिकांश भाग सीधे अंग्रेजी शासन के प्रशासनिक नियंत्रण में आ गया।\n" +
+"कोणार्क चक्र - १३वीं शताब्दी में बने उड़ीसा के सूर्य मन्दिर में स्थित, यह दुनिया के सब से प्रसिद्घ ऐतिहासिक स्थानों में से एक है।\n" +
+"कोणार्क चक्र - १३वीं शताब्दी में बने उड़ीसा के सूर्य मन्दिर में स्थित, यह दुनिया के सब से प्रसिद्घ ऐतिहासिक स्थानों में से एक है।\n" +
+"\n" +
+"बीसवीं शताब्दी के प्रारंभ में एक लम्बे समय तक स्वतंत्रता प्राप्ति के लिये विशाल अहिंसावादी संघर्ष चला, जिसका नेतृत्‍व महात्मा गांधी, जो कि आधिकारिक रुप से आधुनिक भारत के राष्ट्रपिता से संबोधित किये जाते हैं, ने किया। ईसके साथ - साथ चंद्रशेखर आजाद, सरदार भगत सिंह, सुख देव, राजगुरू, नेताजी सुभाष चन्द्र बोस आदि के नेतृत्‍व मे चले क्रांतिकारी संघर्ष के फलस्वरुप 15 अगस्त, 1947 भारत ने अंग्रेजी शासन से पूर्णतः स्वतंत्रता प्राप्त की। तदुपरान्त 26 जनवरी, 1950 को भारत एक गणराज्य बना।\n" +
+"\n" +
+"एक बहुजातीय तथा बहुधर्मिक राष्ट्र होने के कारण भारत को समय-समय पर साम्प्रदायिक तथा जातीय विद्वेष का शिकार होना पङा है। क्षेत्रीय असंतोष तथा विद्रोह भी हालाँकि देश के अलग-अलग हिस्सों में होते रहे हैं, पर इसकी धर्मनिरपेक्षता तथा जनतांत्रिकता, केवल १९७५-७७ को छोड़, जब तत्कालीन प्रधानमंत्री इंदिरा गांधी ने आपातकाल की घोषणा कर दी थी, अक्षुण्य रही है।\n" +
+"\n" +
+"भारत के पड़ोसी राष्ट्रों के साथ अनसुलझे सीमा विवाद हैं। इसके कारण इसे छोटे पैमानों पर युद्ध का भी सामना करना पड़ा है। १९६२ में चीन के साथ, तथा १९४७, १९६५, १९७१ एवम् १९९९ में पाकिस्तान के साथ लड़ाइयाँ हो चुकी हैं।\n" +
+"\n" +
+"भारत गुटनिरपेक्ष आन्दोलन तथा संयुक्त राष्ट्र संघ के संस्थापक सदस्य देशों में से एक है।\n" +
+"\n" +
+"१९७४ में भारत ने अपना पहला परमाणु परीक्षण किया था जिसके बाद १९९८ में 5 और परीक्षण किये गये। १९९० के दशक में किये गये आर्थिक सुधारीकरण की बदौलत आज देश सबसे तेजी से विकासशील राष्ट्रों की सूची में आ गया है।\n" +
+"\n" +
+"[संपादित करें] सरकार\n" +
+"मुख्य लेख: भारत सरकार\n" +
+"\n" +
+"भारत का संविधान भारत को एक सार्वभौमिक, समाजवादी, धर्मनिरपेक्ष, लोकतान्त्रिक गणराज्य की उपाधि देता है। भारत एक लोकतांत्रिक गणराज्य है, जिसका द्विसदनात्मक संसद वेस्टमिन्स्टर शैली के संसदीय प्रणाली द्वारा संचालित है। इसके शासन में तीन मुख्य अंग हैं: न्यायपालिका, कार्यपालिका और व्यवस्थापिका।\n" +
+"\n" +
+"राष्ट्रपति,जो कि राष्ट्र का प्रमुख है, has a largely ceremonial role. उसके कार्यों में संविधान का अभिव्यक्तिकरण, प्रस्तावित कानूनों (विधेयक) पर अपनी सहमति देना, और अध्यादेश जारी करना। वह भारतीय सेनाओं का मुख्य सेनापति भी है। राष्ट्रपति और उपराष्ट्रपति को एक अप्रत्यक्ष मतदान विधि द्वारा ५ वर्षों के लिये चुना जाता है। प्रधानमन्त्री सरकार का प्रमुख है और कार्यपालिका की सारी शक्तियाँ उसी के पास होती हैं। इसका चुनाव राजनैतिक पार्टियों या गठबन्धन के द्वारा प्रत्यक्ष विधि से संसद में बहुमत प्राप्त करने पर होता है। बहुमत बने रहने की स्थिति में इसका कार्यकाल ५ वर्षों का होता है। संविधान में किसी उप-प्रधानमंत्री का प्रावधान नहीं है पर समय-समय पर इसमें फेरबदल होता रहा है।\n" +
+"\n" +
+"व्यवस्थापिका संसद को कहते हैं जिसके दो सदन हैं - उच्चसदन राज्यसभा, or Council of States,और निम्नसदन लोकसभा. राज्यसभा में २४५ सदस्य होते हैं जबकि लोकसभा में ५५२। राज्यसभा के सदस्यों का चुनाव, अप्रत्यक्ष विधि से ६ वर्षों के लिये होता है, जबकि लोकसभा के सदस्यों का चुनाव प्रत्यक्ष विधि से, ५ वर्षों की अवधि के लिये। १८ वर्ष से अधिक उम्र के सभी भारतीय नागरिक मतदान कर सकते हैं।\n" +
+"\n" +
+"कार्यपालिका के तीन अंग हैं - राष्ट्रपति, उपराष्ट्रपति और मंत्रीमंडल। मंत्रीमंडल का प्रमुख प्रधानमंत्री होता है। मंत्रीमंडल के प्रत्येक मंत्री को संसद का सदस्य होना अनिवार्य है। कार्यपालिका, व्यवस्थापिका से नीचे होता है।\n" +
+"\n" +
+"भारत की स्वतंत्र न्यायपालिका का शीर्ष सर्वोच्च न्यायालय है, जिसका प्रधान प्रधान न्यायाधीश होता है। सर्वोच्च न्यायालय को अपने नये मामलों तथा उच्च न्यायालयों के विवादों, दोनो को देखने का अधिकार है। भारत में 21 उच्च न्यायालय हैं, जिनके अधिकार और उत्तरदायित्व सर्वोच्च न्यायालय की अपेक्षा सीमित हैं। न्यायपालिका और व्यवस्थापिका के परस्पर मतभेद या विवाद का सुलह राष्ट्रपति करता है।\n" +
+"\n" +
+"[संपादित करें] राजनीति\n" +
+"मुख्य लेख: भारत की राजनीति\n" +
+"भारत का मानचित्र\n" +
+"भारत का मानचित्र\n" +
+"\n" +
+"स्वतंत्र भारत के इतिहास में उसकी सरकार मुख्य रूप से भारतीय राष्ट्रीय कान्ग्रेस पार्टी के हाथ में रही है। स्वतन्त्रतापूर्व भारत में सबसे बडे़ राजनीतिक संगठन होने के कारण काँग्रेस की, जिसका नेता मूल रूप से नेहरू - गाँधी परिवार का कोई न कोई सदस्य होता है, चालीस वर्षों तक राष्ट्रीय राजनीति में प्रमुख भूमिका रही। १९७७ में, पूर्व काँग्रेस शासन की इंदिरा गाँधी के आपातकाल लगाने के बाद एक संगठित विपक्ष जनता पार्टी ने चुनाव जीता और उसने अत्यधिक छोटी अवधि के लिये एक गैर-काँग्रेसी सरकार बनाई।\n" +
+"\n" +
+"१९९६ में, भारतीय जनता पार्टी (भाजपा), सबसे बड़े राजनीतिक संगठन के रूप में उभरी और उसने काँग्रेस के आगे इतिहास में पहली बार एक ठोस विपक्ष प्रस्तुत किया। परन्तु आगे चलकर सत्ता वास्तविक रूप से दो गठबन्धन सरकारों के हाथ में रही जिन्हें काँग्रेस का सम्पूर्ण समर्थन था। १९९९ में, भाजपा ने छोटे दलों को साथ लेकर राष्ट्रीय जनतान्त्रिक गठबन्धन (राजग) बनाया और ५ वर्षों तक कार्यकाल पूरा करने वाली वह पहली गैर-काँग्रेसी सरकार बनी। १९९९ से पूर्व का दशक अल्पावधि सरकारों का था, इन वर्षों में सात भिन्न सरकारें बनी। परन्तु १९९१ मे बनी काँग्रेस सरकार ने अपना ५ वर्ष का कार्यकाल पूरा किया और कई आर्थिक सुधार लाई।\n" +
+"\n" +
+"भारतीय आम चुनाव २००४ के फ़लस्वरूप काँग्रेस दल ने सर्वाधिक सीटें जीतीं और वह बड़े ही कम बहुमत से सत्ता में वापिस आई। काँग्रेस ने गठजोड़ द्वारा भारतीय कम्युनिस्ट पार्टी (मार्क्सवादी) और बहुत सी राज्य स्तरीय पार्टियों को साथ लेकर यूनाईटेड प्रोग्रेसिव अलायन्स (यूपीए) नामक सरकार बनाई। आज बीजेपी और उसके सहयोगी विपक्ष में मुख्य भूमिका निभाते हैं। राष्ट्रीय स्तर पर किसी विशेष पार्टी का दबदबा न होने और राज्य स्तर की कई पार्टियों के राष्ट्रीय स्तर पर उभरने के कारण १९९६ से बनी सभी सरकारों को राजनीतिक गठबन्धनों की आवश्यक्ता पड़ी है।\n" +
+"\n" +
+"[संपादित करें] राज्य और केन्द्रशासित प्रदेश\n" +
+"मुख्य लेख: भारत के राज्य\n" +
+"\n" +
+"वर्तमान में भारत २८ राज्यों, ६ केन्द्रशासित प्रदेशों और राजधानी दिल्ली मे बँटा हुआ है। राज्यों की चुनी हुई स्वतंत्र सरकारें हैं जबकि केन्द्रशासित प्रदेशों पर केन्द्र द्वारा नियुक्त प्रबंधन शासन करता है, हालाँकि कुछ की लोकतांत्रिक सरकार भी है।\n" +
+"\n" +
+"अन्टार्कटिका और दक्षिण गंगोत्री और मैत्री पर भी भारत के वैज्ञानिक स्थल हैं यद्यपि अभी तक कोई वास्तविक आधिपत्य स्थापित नहीं किया गया है।\n" +
+"\n" +
+"[संपादित करें] भूगोल और मौसम\n" +
+"मुख्य लेख: भारत का भूगोल\n" +
+"हिमालय उत्तर में जम्मू और काश्मीर से लेकर पूर्व में अरुणाचल प्रदेश तक भारत की अधिकतर पूर्वी सीमा बनाता है\n" +
+"हिमालय उत्तर में जम्मू और काश्मीर से लेकर पूर्व में अरुणाचल प्रदेश तक भारत की अधिकतर पूर्वी सीमा बनाता है\n" +
+"\n" +
+"भारत के अधिकतर उत्तरी और उत्तरपश्चिमीय प्रांत हिमालय की पहाङियों में स्थित हैं। शेष का उत्तरी, मध्य और पूर्वी भारत गंगा के उपजाऊ मैदानों से बना है। उत्तरी-पूर्वी पाकिस्तान से सटा हुआ, भारत के पश्चिम में थार का मरुस्थल है। दक्षिण भारत लगभग संपूर्ण ही दक्खन के पठार से निर्मित है। यह पठार पूर्वी और पश्चिमी घाटों के बीच स्थित है।\n" +
+"\n" +
+"कई महत्वपूर्ण और बड़ी नदियाँ जैसे गंगा, ब्रह्मपुत्र, यमुना, गोदावरी और कृष्णा भारत से होकर बहती हैं। इन नदियों के कारण उत्तर भारत की भूमि कृषि के लिए उपजाऊ है।\n" +
+"\n" +
+"भारत के विस्तार के साथ ही इसके मौसम में भी बहुत भिन्नता है। दक्षिण में जहाँ तटीय और गर्म वातावरण रहता है वहीं उत्तर में कड़ी सर्दी, पूर्व में जहाँ अधिक बरसात है वहीं पश्चिम में रेगिस्तान की शुष्कता। भारत में वर्षा मुख्यतया मानसून हवाओं से होती है।\n" +
+"\n" +
+"भारत के मुख्य शहर है - दिल्ली, मुम्बई, कोलकाता, चेन्नई, बंगलोर ( बेंगलुरु ) | ये भी देंखे - भारत के शहर\n" +
+"\n" +
+"[संपादित करें] अर्थव्यवस्था\n" +
+"मुख्य लेख: भारत की अर्थव्यवस्था\n" +
+"सूचना प्रोद्योगिकी (आईटी) भारत के सबसे अधिक विकासशील उद्योगों में से एक है, वार्षिक आय $२८५० करोड़ डालर, इन्फ़ोसिस, भारत की सबसे बडी आईटी कम्पनियों में से एक\n" +
+"सूचना प्रोद्योगिकी (आईटी) भारत के सबसे अधिक विकासशील उद्योगों में से एक है, वार्षिक आय $२८५० करोड़ डालर, इन्फ़ोसिस, भारत की सबसे बडी आईटी कम्पनियों में से एक\n" +
+"\n" +
+"मुद्रा स्थानांतरण की दर से भारत की अर्थव्यवस्था विश्व में दसवें और क्रयशक्ति के अनुसार चौथे स्थान पर है। वर्ष २००३ में भारत में लगभग ८% की दर से आर्थिक वृद्धि हुई है जो कि विश्व की सबसे तीव्र बढती हुई अर्थव्यवस्थओं में से एक है। परंतु भारत की अत्यधिक जनसंख्या के कारण प्रतिव्यक्ति आय क्रयशक्ति की दर से मात्र ३२६२ अमेरिकन डॉलर है जो कि विश्व बैंक के अनुसार १२५वें स्थान पर है। भारत का विदेशी मुद्रा भंडार १४३ अरब अमेरिकन डॉलर है। मुम्बई भारत की आर्थिक राजधानी है और भारतीय रिजर्व बैंक और बॉम्बे स्टॉक एक्सचेंज का मुख्यालय भी। यद्यपि एक चौथाई भारतीय अभी भी निर्धनता रेखा से नीचे हैं, तीव्रता से बढ़ती हुई सूचना प्रोद्योगिकी कंपनियों के कारण मध्यमवर्गीय लोगों में वृद्धि हुई है। १९९१ के बाद भारत मे आर्थिक सुधार की नीति ने भारत के सर्वंगीण विकास मे बडी भूमिका निभाआयी।\n" +
+"\n" +
+"१९९१ के बाद भारत मे हुए [आर्थिक सुधार। आर्थिक सुधारोँ]] ने भारत के सर्वांगीण विकास मे बड़ी भूमिका निभाई। भारतीय अर्थव्यवस्था ने कृषि पर अपनी ऐतिहासिक निर्भरता कम की है और कृषि अब भारतीय सकल घरेलू उत्पाद (जीडीपी) का केवल २५% है। दूसरे प्रमुख उद्योग हैं उत्खनन, पेट्रोलियम, बहुमूल्य रत्न, चलचित्र, टेक्स्टाईल, सूचना प्रोद्योगिकी सेवाएं, तथा सजावटी वस्तुऐं। भारत के अधिकतर औद्योगिक क्षेत्र उसके प्रमुख महानगरों के आसपास स्थित हैं। हाल ही के वर्षों में $१७२० करोड़ अमरीकी डालर वार्षिक आय २००४-२००५ के साथ भारत सॉफ़्टवेयर और बीपीओ सेवाओं का सबसे बडा केन्द्र बनकर उभरा है। इसके साथ ही कई लघु स्तर के उद्योग भी हैं जोकि छोटे भारतीय गाँव और भारतीय नगरों के कई नागरिकों को जीविका प्रदान करते हैं। पिछले वषों मंे भारत में वित्तीय संस्थानो ने विकास में बड़ी भूमिका निभाई है।\n" +
+"\n" +
+"केवल तीस लाख विदेशी पर्यटकों के प्रतिवर्ष आने के बाद भी भार्तीय पर्यटन राष्ट्रीय आय का एक अति आवश्यक परन्तु कम विकसित स्त्रोत है। पर्यटन उद्योग भारत के जीडीपी का कुल ५.३% है। पर्यटन १०% भारतीय कामगारों को आजीविका देता है। वास्तविक संख्या ४.२ करोड है। आर्थिक रूप से देखा जाए तो पर्यटन भारतीय अर्थव्यवस्था को लगभग $४०० करोड डालर प्रदान करता है। भारत के प्रमुख व्यापार सहयोगी हैं अमरीका, जापान, चीन और संयुक्त अरब अमीरात।\n" +
+"\n" +
+"भारत के निर्यातों में कृषि उत्पाद, चाय, कपड़ा, बहुमूल्य रत्न व ज्वैलरी, साफ़्टवेयर सेवायें, इंजीनियरिंग सामान, रसायन तथा चमड़ा उत्पाद प्रमुख हैं जबकि उसके आयातों में कच्चा तेल, मशीनरी, बहुमूल्य रत्न, फ़र्टिलाइज़र तथा रसायन प्रमुख हैं। वर्ष २००४ के लिये भारत के कुल निर्यात $६९१८ करोड़ डालर के थे जबकि उसके आयात $८९३३ करोड डालर के थे।\n" +
+"\n" +
+"[संपादित करें] जनवृत्त\n" +
+"मुख्य लेख: भारत के लोग\n" +
+"\n" +
+"भारत चीन के बाद विश्व का दूसरा सबसे बड़ी जनसंख्या वाला देश है। भारत की विभिन्नताओं से भरी जनता में भाषा, जाति और धर्म, सामाजिक और राजनीतिक संगठन के मुख्य शत्रु हैं।\n" +
+"हिन्दुत्व भारत का सबसे बङा धर्म है - इस चित्र मे गोआ का एक मंदिर दर्शाया गया है\n" +
+"हिन्दुत्व भारत का सबसे बङा धर्म है - इस चित्र मे गोआ का एक मंदिर दर्शाया गया है\n" +
+"\n" +
+"भारत में ६४.८ प्रतिशत साक्षरता है जिसमे से ७५.३ % पुरुष और ५३.७% स्त्रियाँ साक्षर है। लिंग अनुपात की दृष्टि से भारत में प्रत्येक १००० पुरुषों के पीछे मात्र ९३३ महिलायें हैं। कार्य भागीदारी दर (कुल जनसंख्या मे कार्य करने वालों का भाग) ३९.१% है। पुरुषों के लिये यह दर ५१.७% और स्त्रियों के लिये २५.६% है। भारत की १००० जनसंख्या में २२.३२ जन्मों के साथ बढती जनसंख्या के आधे लोग २२.६६ वर्ष से कम आयु के हैं।\n" +
+"\n" +
+"यद्यपि भारत की ८०.५ प्रतिशत जनसंख्या हिन्दू है, १३.४ प्रतिशत जनसंख्या के साथ भारत विश्व में मुसलमानों की संख्या में भी इंडोनेशिया के बाद दूसरे स्थान पर है। अन्य धर्मावलम्बियों में ईसाई (२.३३ %), सिख (१.८४ %), बौद्ध (०.७६ %), जैन (०.४० %), अय्यावलि (०.१२ %), यहूदी, पारसी, अहमदी और बहाई आदि सम्मिलित हैं।\n" +
+"\n" +
+"भारत दो मुख्य भाषा सूत्रों, आर्यन् और द्रविङियन्, का भी स्त्रोत है (साइटेसन चाहिए)। भारत का संविधान कुल २३ भाषाओं को मान्यता देता है। हिन्दी और अंग्रेजी केन्द्रीय सरकार द्वारा सरकारी कामकाज के लिये उपयोग की जाती है। संस्कृत और तमिल जैसी अति प्राचीन भाषाएं भारत में ही जन्मी हैं। कुल मिलाकर भारत में १६५२ से भी अधिक भाषाएं एवं बोलियाँ बोली जातीं हैं।\n" +
+"\n" +
+"[संपादित करें] संस्कृति\n" +
+"मुख्य लेख: भारतीय संस्कृति\n" +
+"ताजमहल विश्व के सबसे प्रसिद्ध पर्यटक स्थलों में गिना जाता है।\n" +
+"ताजमहल विश्व के सबसे प्रसिद्ध पर्यटक स्थलों में गिना जाता है।\n" +
+"\n" +
+"भारत की सांस्कृतिक धरोहर बहुत संपन्न है। यहां की संस्कृति अनोखी है, और वर्षों से इसके कई अवयव अबतक अक्षुण्य हैं। आक्रमणकारियों तथा प्रवासियों से विभिन्न चीजों को समेटकर यह एक मिश्रित संस्कृति बन गई है। आधुनिक भारत का समाज, भाषाएं, रीति-रिवाज इत्यादि इसका प्रमाण हैं। ताजमहल और अन्य उदाहरण, इस्लाम प्रभावित स्थापत्य कला के अतिसुन्दर नमूने हैं।\n" +
+"गुम्पा नृत्य एक तिब्बती बौद्ध समाज का सिक्किम में छिपा नृत्य है। यह बौद्ध नव बर्ष में है।\n" +
+"गुम्पा नृत्य एक तिब्बती बौद्ध समाज का सिक्किम में छिपा नृत्य है। यह बौद्ध नव बर्ष में है।\n" +
+"\n" +
+"भारतीय समाज बहुधर्मिक, बहुभाषी तथा मिश्र-सांस्कृतिक है। पारंपरिक भारतीय पारिवारिक मूल्यों को काफी आदर की दृष्टि से देखा जाता है।\n" +
+"\n" +
+"विभिन्न धर्मों के इस भूभाग पर कई मनभावन पर्व त्यौहार मनाए जाते हैं - दिवाली, होली, दशहरा. पोंगल तथा ओणम . ईद-उल-फितर, मुहर्रम, क्रिसमस, ईस्टर आदि भी काफ़ी लोकप्रिय हैं।\n" +
+"\n" +
+"हालाँकि हॉकी देश का राष्ट्रीय खेल है, क्रिकेट सबसे अधिक लोकप्रिय है। वर्तमान में फुटबॉल, हॉकी तथा टेनिस में भी बहुत भारतीयों की अभिरुचि है। देश की राष्ट्रीय क्रिकेट टीम में 1983 में एक बार विश्व कप भी जीता है। इसके अतिरिक्त वर्ष 2003 में वह विश्व कप के फाइनल तक पहुँचा था। 1930 तथा 40 के दशक में हाकी में भारत अपने चरम पर था। मेजर ध्यानचंद ने हॉकी में भारत को बहुत प्रसिद्धि दिलाई और एक समय भारत ने अमरीका को 24-0 से हराया था जो अब तर विश्व कीर्तिमान है। शतरंज के जनक देश भारत के खिलाड़ी शतरंज में भी अच्छा प्रदर्शन करते आए हैं।\n" +
+"\n" +
+"भारतीय खानपान बहुत ही समृद्ध है। शाकाहारी तथा मांसाहारी दोनो तरह का खाना पसन्द किया जाता है। भारतीय व्यंजन विदेशों में भी बहुत पसन्द किए जाते है।\n" +
+"\n" +
+"भारत में संगीत तथा नृत्य की अपनी शैलियां भी विकसित हुईं जो बहुत ही लोकप्रिय हैं। भरतनाट्यम, ओडिसी, कत्थक प्रसिद्ध भारतीय नृत्य शैली है। हिन्दुस्तानी संगीत तथा कर्नाटक संगीत भारतीय परंपरागत संगीत की दो मुख्य धाराएं हैं।\n" +
+"\n" +
+"वैश्वीकरण के इस युग में शेष विश्व की तरह भारतीय समाज पर भी अंग्रेजी तथा यूरोपीय प्रभाव पड़ रहा है। बाहरी लोगों की खूबियों को अपनाने की भारतीय परंपरा का नया दौर कई भारतीयों की दृष्टि में अनुचित है। एक खुले समाज के जीवन का यत्न कर रहे लोगों को मध्यमवर्गीय तथा वरिष्ठ नागरिकों की उपेक्षा का शिकार होना पड़ता है। कुछ लोग इसे भारतीय पारंपरिक मूल्यों का हनन मानते हैं। विज्ञान तथा साहित्य में अधिक प्रगति ना कर पाने की वजह से भारतीय समाज यूरोपीय लोगों पर निर्भर होता जा रहा है। ऐसे समय में लोग विदेशी अविष्कारों का भारत में प्रयोग अनुचित भी समझते हैं। हालाँकि ऐसे कई लोग है जो ऐसा विचार नहीं रखते।\n" +
+"\n" +
+"[संपादित करें] यह भी देखें\n" +
+"\n" +
+"    * दक्षिण भारत\n" +
+"    * उत्तर पूर्वी भारत\n" +
+"    * भारत की भाषाएँ\n" +
+"\n" +
+"\n" +
+"[संपादित करें] बाहरी कड़ियाँ\n" +
+"\n" +
+"सरकार (हिन्दी)\n" +
+"\n" +
+"    * भारत का राष्ट्रीय पोर्टल\n" +
+"\n" +
+"सरकार (अंग्रेज़ी)\n" +
+"\n" +
+"    * भारतीय सरकार का सरकारी वैबसाइट\n" +
+"    * भारतीय सरकार का वेबसाइट का सरकारी निर्देशिका\n" +
+"\n" +
+"सेनापति निर्देश (अंग्रेज़ी)\n" +
+"\n" +
+"    * सीआईए में भारत निबन्ध\n" +
+"    * एन्साक्लोपीडिया ब्रिटैनिका का भारत निबन्ध\n" +
+"    * बीबीसी का भारत निबन्ध\n" +
+"\n" +
+"भारत का देश नक्शा\n" +
+"\n" +
+"सैटेलाइट चित्र (अंग्रेज़ी)\n" +
+"\n" +
+"    * गूगल मानचित्र से भारत का सैटेलाइट चित्र\n" +
+"\n" +
+"अन्य (अंग्रेज़ी)\n" +
+"\n" +
+"    * विकिभ्रमण का भारत निबन्ध\n" +
+"    * भारत ओपेन डायरैक्टरी प्रॉजेक्ट में\n" +
+"    * भारत यात्रा - सामूहिक यात्रा ब्लॉग\n";
+
+var english =
+"English language\n" +
+"From Wikipedia, the free encyclopedia\n" +
+"• Learn more about citing Wikipedia •\n" +
+"Jump to: navigation, search\n" +
+"      Editing of this article by unregistered or newly registered users is currently disabled.\n" +
+"If you cannot edit this article and you wish to make a change, you can discuss changes on the talk page, request unprotection, log in, or create an account.\n" +
+"English  \n" +
+"Pronunciation:        /ˈɪŋɡlɪʃ/[37]\n" +
+"Spoken in:    Listed in the article\n" +
+"Total speakers:       First language: 309[38] – 380 million[3]\n" +
+"Second language: 199[39] – 600 million[40]\n" +
+"Overall: 1.8 billion[41] \n" +
+"Ranking:      3 (native speakers)[9][10]\n" +
+"Total: 1 or 2 [11]\n" +
+"Language family:      Indo-European\n" +
+" Germanic\n" +
+"  West Germanic\n" +
+"   Anglo–Frisian\n" +
+"    Anglic\n" +
+"     English \n" +
+"Writing system:       Latin (English variant) \n" +
+"Official status\n" +
+"Official language of:         53 countries\n" +
+"Flag of the United Nations United Nations\n" +
+"Regulated by:         no official regulation\n" +
+"Language codes\n" +
+"ISO 639-1:    en\n" +
+"ISO 639-2:    eng\n" +
+"ISO 639-3:    eng \n" +
+"World countries, states, and provinces where English is a primary language are dark blue; countries, states and provinces where it is an official but not a primary language are light blue. English is also one of the official languages of the European Union.\n" +
+"Note: This page may contain IPA phonetic symbols in Unicode. See IPA chart for English for an English-​based pronunciation key.\n" +
+"\n" +
+"English is a West Germanic language originating in England, and the first language for most people in Australia, Canada, the Commonwealth Caribbean, Ireland, New Zealand, the United Kingdom and the United States of America (also commonly known as the Anglosphere). It is used extensively as a second language and as an official language throughout the world, especially in Commonwealth countries such as India, Sri Lanka, Pakistan and South Africa, and in many international organisations.\n" +
+"\n" +
+"Modern English is sometimes described as the global lingua franca.[1][2] English is the dominant international language in communications, science, business, aviation, entertainment, radio and diplomacy.[3] The influence of the British Empire is the primary reason for the initial spread of the language far beyond the British Isles.[4] Following World War II, the growing economic and cultural influence of the United States has significantly accelerated the spread of the language.\n" +
+"\n" +
+"A working knowledge of English is required in certain fields, professions, and occupations. As a result over a billion people speak English at least at a basic level (see English language learning and teaching). English is one of six official languages of the United Nations.\n" +
+"Contents\n" +
+"[hide]\n" +
+"\n" +
+"    * 1 History\n" +
+"    * 2 Classification and related languages\n" +
+"    * 3 Geographical distribution\n" +
+"          o 3.1 English as a global language\n" +
+"          o 3.2 Dialects and regional varieties\n" +
+"          o 3.3 Constructed varieties of English\n" +
+"    * 4 Phonology\n" +
+"          o 4.1 Vowels\n" +
+"                + 4.1.1 See also\n" +
+"          o 4.2 Consonants\n" +
+"                + 4.2.1 Voicing and aspiration\n" +
+"          o 4.3 Supra-segmental features\n" +
+"                + 4.3.1 Tone groups\n" +
+"                + 4.3.2 Characteristics of intonation\n" +
+"    * 5 Grammar\n" +
+"    * 6 Vocabulary\n" +
+"          o 6.1 Number of words in English\n" +
+"          o 6.2 Word origins\n" +
+"                + 6.2.1 Dutch origins\n" +
+"                + 6.2.2 French origins\n" +
+"    * 7 Writing system\n" +
+"          o 7.1 Basic sound-letter correspondence\n" +
+"          o 7.2 Written accents\n" +
+"    * 8 Formal written English\n" +
+"    * 9 Basic and simplified versions\n" +
+"    * 10 Notes\n" +
+"    * 11 References\n" +
+"    * 12 See also\n" +
+"    * 13 External links\n" +
+"          o 13.1 Dictionaries\n" +
+"\n" +
+"History\n" +
+"\n" +
+"    Main article: History of the English language\n" +
+"\n" +
+"English is an Anglo-Frisian language. Germanic-speaking peoples from northwest Germany (Saxons and Angles) and Jutland (Jutes) invaded what is now known as Eastern England around the fifth century AD. It is a matter of debate whether the Old English language spread by displacement of the original population, or the native Celts gradually adopted the language and culture of a new ruling class, or a combination of both of these processes (see Sub-Roman Britain).\n" +
+"\n" +
+"Whatever their origin, these Germanic dialects eventually coalesced to a degree (there remained geographical variation) and formed what is today called Old English. Old English loosely resembles some coastal dialects in what are now northwest Germany and the Netherlands (i.e., Frisia). Throughout the history of written Old English, it retained a synthetic structure closer to that of Proto-Indo-European, largely adopting West Saxon scribal conventions, while spoken Old English became increasingly analytic in nature, losing the more complex noun case system, relying more heavily on prepositions and fixed word order to convey meaning. This is evident in the Middle English period, when literature was to an increasing extent recorded with spoken dialectal variation intact, after written Old English lost its status as the literary language of the nobility. It is postulated that the early development of the language was influenced by a Celtic substratum.[5][6] Later, it was influenced by the related North Germanic language Old Norse, spoken by the Vikings who settled mainly in the north and the east coast down to London, the area known as the Danelaw.\n" +
+"\n" +
+"The Norman Conquest of England in 1066 profoundly influenced the evolution of the language. For about 300 years after this, the Normans used Anglo-Norman, which was close to Old French, as the language of the court, law and administration. By the fourteenth century, Anglo-Norman borrowings had contributed roughly 10,000 words to English, of which 75% remain in use. These include many words pertaining to the legal and administrative fields, but also include common words for food, such as mutton[7] and beef[8]. The Norman influence gave rise to what is now referred to as Middle English. Later, during the English Renaissance, many words were borrowed directly from Latin (giving rise to a number of doublets) and Greek, leaving a parallel vocabulary that persists into modern times. By the seventeenth century there was a reaction in some circles against so-called inkhorn terms.\n" +
+"\n" +
+"During the fifteenth century, Middle English was transformed by the Great Vowel Shift, the spread of a prestigious South Eastern-based dialect in the court, administration and academic life, and the standardising effect of printing. Early Modern English can be traced back to around the Elizabethan period.\n" +
+"\n" +
+"Classification and related languages\n" +
+"\n" +
+"The English language belongs to the western sub-branch of the Germanic branch of the Indo-European family of languages.\n" +
+"\n" +
+"The question as to which is the nearest living relative of English is a matter of discussion. Apart from such English-lexified creole languages such as Tok Pisin, Scots (spoken primarily in Scotland and parts of Northern Ireland) is not a Gaelic language, but is part of the English family of languages: both Scots and modern English are descended from Old English, also known as Anglo-Saxon. The closest relative to English after Scots is Frisian, which is spoken in the Northern Netherlands and Northwest Germany. Other less closely related living West Germanic languages include German, Low Saxon, Dutch, and Afrikaans. The North Germanic languages of Scandinavia are less closely related to English than the West Germanic languages.\n" +
+"\n" +
+"Many French words are also intelligible to an English speaker (though pronunciations are often quite different) because English absorbed a large vocabulary from Norman and French, via Anglo-Norman after the Norman Conquest and directly from French in subsequent centuries. As a result, a large portion of English vocabulary is derived from French, with some minor spelling differences (word endings, use of old French spellings, etc.), as well as occasional divergences in meaning, in so-called \"faux amis\", or false friends.\n" +
+"\n" +
+"Geographical distribution\n" +
+"\n" +
+"    See also: List of countries by English-speaking population\n" +
+"\n" +
+"Over 380 million people speak English as their first language. English today is probably the third largest language by number of native speakers, after Mandarin Chinese and Spanish.[9][10] However, when combining native and non-native speakers it is probably the most commonly spoken language in the world, though possibly second to a combination of the Chinese Languages, depending on whether or not distinctions in the latter are classified as \"languages\" or \"dialects.\"[11][12] Estimates that include second language speakers vary greatly from 470 million to over a billion depending on how literacy or mastery is defined.[13][14] There are some who claim that non-native speakers now outnumber native speakers by a ratio of 3 to 1.[15]\n" +
+"\n" +
+"The countries with the highest populations of native English speakers are, in descending order: United States (215 million),[16] United Kingdom (58 million),[17] Canada (17.7 million),[18] Australia (15 million),[19] Ireland (3.8 million),[17] South Africa (3.7 million),[20] and New Zealand (3.0-3.7 million).[21] Countries such as Jamaica and Nigeria also have millions of native speakers of dialect continuums ranging from an English-based creole to a more standard version of English. Of those nations where English is spoken as a second language, India has the most such speakers ('Indian English') and linguistics professor David Crystal claims that, combining native and non-native speakers, India now has more people who speak or understand English than any other country in the world.[22] Following India is the People's Republic of China.[23]\n" +
+"Distribution of native English speakers by country (Crystal 1997)\n" +
+"Distribution of native English speakers by country (Crystal 1997)\n" +
+"      Country         Native speakers\n" +
+"1     USA     214,809,000[16]\n" +
+"2     UK      58,200,000[17]\n" +
+"3     Canada  17,694,830[18]\n" +
+"4     Australia       15,013,965[19]\n" +
+"5     Ireland         4,200,000+ (Approx)[17]\n" +
+"6     South Africa    3,673,203[20]\n" +
+"7     New Zealand     3,500,000+ (Approx)[21]\n" +
+"8     Singapore       665,087[24]\n" +
+"\n" +
+"English is the primary language in Anguilla, Antigua and Barbuda, Australia (Australian English), the Bahamas, Barbados, Bermuda, Belize, the British Indian Ocean Territory, the British Virgin Islands, Canada (Canadian English), the Cayman Islands, Dominica, the Falkland Islands, Gibraltar, Grenada, Guernsey (Guernsey English), Guyana, Ireland (Hiberno-English), Isle of Man (Manx English), Jamaica (Jamaican English), Jersey, Montserrat, Nauru, New Zealand (New Zealand English), Pitcairn Islands, Saint Helena, Saint Lucia, Saint Kitts and Nevis, Saint Vincent and the Grenadines, Singapore, South Georgia and the South Sandwich Islands, Trinidad and Tobago, the Turks and Caicos Islands, the United Kingdom, the U.S. Virgin Islands, and the United States (various forms of American English).\n" +
+"\n" +
+"In many other countries, where English is not the most spoken language, it is an official language; these countries include Botswana, Cameroon, Fiji, the Federated States of Micronesia, Ghana, Gambia, Hong Kong, India, Kiribati, Lesotho, Liberia, Kenya, Madagascar, Malta, the Marshall Islands, Namibia, Nigeria, Pakistan, Papua New Guinea, the Philippines, Puerto Rico, Rwanda, the Solomon Islands, Samoa, Sierra Leone, Singapore, Sri Lanka, Swaziland, Tanzania, Uganda, Zambia, and Zimbabwe. It is also one of the 11 official languages that are given equal status in South Africa (\"South African English\"). English is also an important language in several former colonies or current dependent territories of the United Kingdom and the United States, such as in Hong Kong and Mauritius.\n" +
+"\n" +
+"English is not an official language in either the United States or the United Kingdom.[25][26] Although the United States federal government has no official languages, English has been given official status by 30 of the 50 state governments.[27]\n" +
+"\n" +
+"English as a global language\n" +
+"\n" +
+"    See also: English on the Internet and global language\n" +
+"\n" +
+"Because English is so widely spoken, it has often been referred to as a \"global language\", the lingua franca of the modern era.[2] While English is not an official language in many countries, it is currently the language most often taught as a second language around the world. Some linguists believe that it is no longer the exclusive cultural sign of \"native English speakers\", but is rather a language that is absorbing aspects of cultures worldwide as it continues to grow. It is, by international treaty, the official language for aerial and maritime communications, as well as one of the official languages of the European Union, the United Nations, and most international athletic organisations, including the International Olympic Committee.\n" +
+"\n" +
+"English is the language most often studied as a foreign language in the European Union (by 89% of schoolchildren), followed by French (32%), German (18%), and Spanish (8%).[28] In the EU, a large fraction of the population reports being able to converse to some extent in English. Among non-English speaking countries, a large percentage of the population claimed to be able to converse in English in the Netherlands (87%), Sweden (85%), Denmark (83%), Luxembourg (66%), Finland (60%), Slovenia (56%), Austria (53%), Belgium (52%), and Germany (51%). [29] Norway and Iceland also have a large majority of competent English-speakers.\n" +
+"\n" +
+"Books, magazines, and newspapers written in English are available in many countries around the world. English is also the most commonly used language in the sciences.[2] In 1997, the Science Citation Index reported that 95% of its articles were written in English, even though only half of them came from authors in English-speaking countries.\n" +
+"\n" +
+"Dialects and regional varieties\n" +
+"\n" +
+"    Main article: List of dialects of the English language\n" +
+"\n" +
+"The expansion of the British Empire and—since WWII—the primacy of the United States have spread English throughout the globe.[2] Because of that global spread, English has developed a host of English dialects and English-based creole languages and pidgins.\n" +
+"\n" +
+"The major varieties of English include, in most cases, several subvarieties, such as Cockney slang within British English; Newfoundland English within Canadian English; and African American Vernacular English (\"Ebonics\") and Southern American English within American English. English is a pluricentric language, without a central language authority like France's Académie française; and, although no variety is clearly considered the only standard, there are a number of accents considered to be more prestigious, such as Received Pronunciation in Britain.\n" +
+"\n" +
+"Scots developed — largely independently — from the same origins, but following the Acts of Union 1707 a process of language attrition began, whereby successive generations adopted more and more features from English causing dialectalisation. Whether it is now a separate language or a dialect of English better described as Scottish English is in dispute. The pronunciation, grammar and lexis of the traditional forms differ, sometimes substantially, from other varieties of English.\n" +
+"\n" +
+"Because of the wide use of English as a second language, English speakers have many different accents, which often signal the speaker's native dialect or language. For the more distinctive characteristics of regional accents, see Regional accents of English speakers, and for the more distinctive characteristics of regional dialects, see List of dialects of the English language.\n" +
+"\n" +
+"Just as English itself has borrowed words from many different languages over its history, English loanwords now appear in a great many languages around the world, indicative of the technological and cultural influence of its speakers. Several pidgins and creole languages have formed using an English base, such as Jamaican Creole, Nigerian Pidgin, and Tok Pisin. There are many words in English coined to describe forms of particular non-English languages that contain a very high proportion of English words. Franglais, for example, is used to describe French with a very high English word content; it is found on the Channel Islands. Another variant, spoken in the border bilingual regions of Québec in Canada, is called FrEnglish.\n" +
+"\n" +
+"Constructed varieties of English\n" +
+"\n" +
+"    * Basic English is simplified for easy international use. It is used by manufacturers and other international businesses to write manuals and communicate. Some English schools in Asia teach it as a practical subset of English for use by beginners.\n" +
+"    * Special English is a simplified version of English used by the Voice of America. It uses a vocabulary of only 1500 words.\n" +
+"    * English reform is an attempt to improve collectively upon the English language.\n" +
+"    * Seaspeak and the related Airspeak and Policespeak, all based on restricted vocabularies, were designed by Edward Johnson in the 1980s to aid international cooperation and communication in specific areas. There is also a tunnelspeak for use in the Channel Tunnel.\n" +
+"    * English as a lingua franca for Europe and Euro-English are concepts of standardising English for use as a second language in continental Europe.\n" +
+"    * Manually Coded English — a variety of systems have been developed to represent the English language with hand signals, designed primarily for use in deaf education. These should not be confused with true sign languages such as British Sign Language and American Sign Language used in Anglophone countries, which are independent and not based on English.\n" +
+"    * E-Prime excludes forms of the verb to be.\n" +
+"\n" +
+"Euro-English (also EuroEnglish or Euro-English) terms are English translations of European concepts that are not native to English-speaking countries. Due to the United Kingdom's (and even the Republic of Ireland's) involvement in the European Union, the usage focuses on non-British concepts. This kind of Euro-English was parodied when English was \"made\" one of the constituent languages of Europanto.\n" +
+"\n" +
+"Phonology\n" +
+"\n" +
+"    Main article: English phonology\n" +
+"\n" +
+"Vowels\n" +
+"IPA   Description     word\n" +
+"monophthongs\n" +
+"i/iː         Close front unrounded vowel     bead\n" +
+"ɪ    Near-close near-front unrounded vowel   bid\n" +
+"ɛ    Open-mid front unrounded vowel  bed\n" +
+"æ    Near-open front unrounded vowel         bad\n" +
+"ɒ    Open back rounded vowel         bod 1\n" +
+"ɔ    Open-mid back rounded vowel     pawed 2\n" +
+"ɑ/ɑː       Open back unrounded vowel       bra\n" +
+"ʊ    Near-close near-back rounded vowel      good\n" +
+"u/uː         Close back rounded vowel        booed\n" +
+"ʌ/ɐ         Open-mid back unrounded vowel, Near-open central vowel  bud\n" +
+"ɝ/ɜː       Open-mid central unrounded vowel        bird 3\n" +
+"ə    Schwa   Rosa's 4\n" +
+"ɨ    Close central unrounded vowel   roses 5\n" +
+"diphthongs\n" +
+"e(ɪ)/eɪ     Close-mid front unrounded vowel\n" +
+"Close front unrounded vowel   bayed 6\n" +
+"o(ʊ)/əʊ    Close-mid back rounded vowel\n" +
+"Near-close near-back rounded vowel    bode 6\n" +
+"aɪ   Open front unrounded vowel\n" +
+"Near-close near-front unrounded vowel         cry\n" +
+"aʊ   Open front unrounded vowel\n" +
+"Near-close near-back rounded vowel    bough\n" +
+"ɔɪ  Open-mid back rounded vowel\n" +
+"Close front unrounded vowel   boy\n" +
+"ʊɝ/ʊə     Near-close near-back rounded vowel\n" +
+"Schwa         boor 9\n" +
+"ɛɝ/ɛə     Open-mid front unrounded vowel\n" +
+"Schwa         fair 10\n" +
+"\n" +
+"Notes:\n" +
+"\n" +
+"It is the vowels that differ most from region to region.\n" +
+"\n" +
+"Where symbols appear in pairs, the first corresponds to American English, General American accent; the second corresponds to British English, Received Pronunciation.\n" +
+"\n" +
+"   1. American English lacks this sound; words with this sound are pronounced with /ɑ/ or /ɔ/.\n" +
+"   2. Many dialects of North American English do not have this vowel. See Cot-caught merger.\n" +
+"   3. The North American variation of this sound is a rhotic vowel.\n" +
+"   4. Many speakers of North American English do not distinguish between these two unstressed vowels. For them, roses and Rosa's are pronounced the same, and the symbol usually used is schwa /ə/.\n" +
+"   5. This sound is often transcribed with /i/ or with /ɪ/.\n" +
+"   6. The diphthongs /eɪ/ and /oʊ/ are monophthongal for many General American speakers, as /eː/ and /oː/.\n" +
+"   7. The letter <U> can represent either /u/ or the iotated vowel /ju/. In BRP, if this iotated vowel /ju/ occurs after /t/, /d/, /s/ or /z/, it often triggers palatalization of the preceding consonant, turning it to /ʨ/, /ʥ/, /ɕ/ and /ʑ/ respectively, as in tune, during, sugar, and azure. In American English, palatalization does not generally happen unless the /ju/ is followed by r, with the result that /(t, d,s, z)jur/ turn to /tʃɚ/, /dʒɚ/, /ʃɚ/ and /ʒɚ/ respectively, as in nature, verdure, sure, and treasure.\n" +
+"   8. Vowel length plays a phonetic role in the majority of English dialects, and is said to be phonemic in a few dialects, such as Australian English and New Zealand English. In certain dialects of the modern English language, for instance General American, there is allophonic vowel length: vowel phonemes are realized as long vowel allophones before voiced consonant phonemes in the coda of a syllable. Before the Great Vowel Shift, vowel length was phonemically contrastive.\n" +
+"   9. This sound only occurs in non-rhotic accents. In some accents, this sound may be, instead of /ʊə/, /ɔ:/. See pour-poor merger.\n" +
+"  10. This sound only occurs in non-rhotic accents. In some accents, the schwa offglide of /ɛə/ may be dropped, monophthising and lengthening the sound to /ɛ:/.\n" +
+"\n" +
+"See also\n" +
+"\n" +
+"    * International Phonetic Alphabet for English for more vowel charts.\n" +
+"\n" +
+"Consonants\n" +
+"\n" +
+"This is the English Consonantal System using symbols from the International Phonetic Alphabet (IPA).\n" +
+"      bilabial        labio-\n" +
+"dental        dental  alveolar        post-\n" +
+"alveolar      palatal         velar   glottal\n" +
+"plosive       p  b                    t  d                    k  ɡ    \n" +
+"nasal         m                       n                       ŋ 1     \n" +
+"flap                          ɾ 2                             \n" +
+"fricative             f  v    θ  ð 3        s  z    ʃ  ʒ 4        ç 5    x 6     h\n" +
+"affricate                                     tʃ  dʒ 4                       \n" +
+"approximant                           ɹ 4            j                \n" +
+"lateral approximant                           l                                \n" +
+"      labial-velar\n" +
+"approximant   ʍ  w 7\n" +
+"\n" +
+"   1. The velar nasal [ŋ] is a non-phonemic allophone of /n/ in some northerly British accents, appearing only before /k/ and /g/. In all other dialects it is a separate phoneme, although it only occurs in syllable codas.\n" +
+"   2. The alveolar flap [ɾ] is an allophone of /t/ and /d/ in unstressed syllables in North American English and Australian English.[30] This is the sound of tt or dd in the words latter and ladder, which are homophones for many speakers of North American English. In some accents such as Scottish English and Indian English it replaces /ɹ/. This is the same sound represented by single r in most varieties of Spanish.\n" +
+"   3. In some dialects, such as Cockney, the interdentals /θ/ and /ð/ are usually merged with /f/ and /v/, and in others, like African American Vernacular English, /ð/ is merged with dental /d/. In some Irish varieties, /θ/ and /ð/ become the corresponding dental plosives, which then contrast with the usual alveolar plosives.\n" +
+"   4. The sounds /ʃ/, /ʒ/, and /ɹ/ are labialised in some dialects. Labialisation is never contrastive in initial position and therefore is sometimes not transcribed. Most speakers of General American realize <r> (always rhoticized) as the retroflex approximant /ɻ/, whereas the same is realized in Scottish English, etc. as the alveolar trill.\n" +
+"   5. The voiceless palatal fricative /ç/ is in most accents just an allophone of /h/ before /j/; for instance human /çjuːmən/. However, in some accents (see this), the /j/ is dropped, but the initial consonant is the same.\n" +
+"   6. The voiceless velar fricative /x/ is used only by Scottish or Welsh speakers of English for Scots/Gaelic words such as loch /lɒx/ or by some speakers for loanwords from German and Hebrew like Bach /bax/ or Chanukah /xanuka/. In some dialects such as Scouse (Liverpool) either [x] or the affricate [kx] may be used as an allophone of /k/ in words such as docker [dɒkxə]. Most native speakers have a great deal of trouble pronouncing it correctly when learning a foreign language. Most speakers use the sounds [k] and [h] instead.\n" +
+"   7. Voiceless w [ʍ] is found in Scottish and Irish English, as well as in some varieties of American, New Zealand, and English English. In most other dialects it is merged with /w/, in some dialects of Scots it is merged with /f/.\n" +
+"\n" +
+"Voicing and aspiration\n" +
+"\n" +
+"Voicing and aspiration of stop consonants in English depend on dialect and context, but a few general rules can be given:\n" +
+"\n" +
+"    * Voiceless plosives and affricates (/ p/, / t/, / k/, and / tʃ/) are aspirated when they are word-initial or begin a stressed syllable — compare pin [pʰɪn] and spin [spɪn], crap [kʰɹ̥æp] and scrap [skɹæp].\n" +
+"          o In some dialects, aspiration extends to unstressed syllables as well.\n" +
+"          o In other dialects, such as Indo-Pakistani English, all voiceless stops remain unaspirated.\n" +
+"    * Word-initial voiced plosives may be devoiced in some dialects.\n" +
+"    * Word-terminal voiceless plosives may be unreleased or accompanied by a glottal stop in some dialects (e.g. many varieties of American English) — examples: tap [tʰæp̚], sack [sæk̚].\n" +
+"    * Word-terminal voiced plosives may be devoiced in some dialects (e.g. some varieties of American English) — examples: sad [sæd̥], bag [bæɡ̊]. In other dialects they are fully voiced in final position, but only partially voiced in initial position.\n" +
+"\n" +
+"Supra-segmental features\n" +
+"\n" +
+"Tone groups\n" +
+"\n" +
+"English is an intonation language. This means that the pitch of the voice is used syntactically, for example, to convey surprise and irony, or to change a statement into a question.\n" +
+"\n" +
+"In English, intonation patterns are on groups of words, which are called tone groups, tone units, intonation groups or sense groups. Tone groups are said on a single breath and, as a consequence, are of limited length, more often being on average five words long or lasting roughly two seconds. For example:\n" +
+"\n" +
+"    - /duː juː niːd ˈɛnɪˌθɪŋ/ Do you need anything?\n" +
+"    - /aɪ dəʊnt | nəʊ/ I don't, no\n" +
+"    - /aɪ dəʊnt nəʊ/ I don't know (contracted to, for example, - /aɪ dəʊnəʊ/ or /aɪ dənəʊ/ I dunno in fast or colloquial speech that de-emphasises the pause between don't and know even further)\n" +
+"\n" +
+"Characteristics of intonation\n" +
+"\n" +
+"English is a strongly stressed language, in that certain syllables, both within words and within phrases, get a relative prominence/loudness during pronunciation while the others do not. The former kind of syllables are said to be accentuated/stressed and the latter are unaccentuated/unstressed. All good dictionaries of English mark the accentuated syllable(s) by either placing an apostrophe-like ( ˈ ) sign either before (as in IPA, Oxford English Dictionary, or Merriam-Webster dictionaries) or after (as in many other dictionaries) the syllable where the stress accent falls. In general, for a two-syllable word in English, it can be broadly said that if it is a noun or an adjective, the first syllable is accentuated; but if it is a verb, the second syllable is accentuated.\n" +
+"\n" +
+"Hence in a sentence, each tone group can be subdivided into syllables, which can either be stressed (strong) or unstressed (weak). The stressed syllable is called the nuclear syllable. For example:\n" +
+"\n" +
+"    That | was | the | best | thing | you | could | have | done!\n" +
+"\n" +
+"Here, all syllables are unstressed, except the syllables/words best and done, which are stressed. Best is stressed harder and, therefore, is the nuclear syllable.\n" +
+"\n" +
+"The nuclear syllable carries the main point the speaker wishes to make. For example:\n" +
+"\n" +
+"    John hadn't stolen that money. (... Someone else had.)\n" +
+"    John hadn't stolen that money. (... You said he had. or ... Not at that time, but later he did.)\n" +
+"    John hadn't stolen that money. (... He acquired the money by some other means.)\n" +
+"    John hadn't stolen that money. (... He had stolen some other money.)\n" +
+"    John hadn't stolen that money. (... He stole something else.)\n" +
+"\n" +
+"Also\n" +
+"\n" +
+"    I didn't tell her that. (... Someone else told her.)\n" +
+"    I didn't tell her that. (... You said I did. or ... But now I will!)\n" +
+"    I didn't tell her that. (... I didn't say it; she could have inferred it, etc.)\n" +
+"    I didn't tell her that. (... I told someone else.)\n" +
+"    I didn't tell her that. (... I told her something else.)\n" +
+"\n" +
+"This can also be used to express emotion:\n" +
+"\n" +
+"    Oh really? (...I didn't know that)\n" +
+"    Oh really? (...I disbelieve you)\n" +
+"\n" +
+"The nuclear syllable is spoken more loudly than the others and has a characteristic change of pitch. The changes of pitch most commonly encountered in English are the rising pitch and the falling pitch, although the fall-rising pitch and/or the rise-falling pitch are sometimes used. In this opposition between falling and rising pitch, which plays a larger role in English than in most other languages, falling pitch conveys certainty and rising pitch uncertainty. This can have a crucial impact on meaning, specifically in relation to polarity, the positive–negative opposition; thus, falling pitch means \"polarity known\", while rising pitch means \"polarity unknown\". This underlies the rising pitch of yes/no questions. For example:\n" +
+"\n" +
+"    When do you want to be paid?\n" +
+"    Now? (Rising pitch. In this case, it denotes a question: \"Can I be paid now?\" or \"Do you desire to be paid now?\")\n" +
+"    Now. (Falling pitch. In this case, it denotes a statement: \"I choose to be paid now.\")\n" +
+"\n" +
+"Grammar\n" +
+"\n" +
+"    Main article: English grammar\n" +
+"\n" +
+"English grammar has minimal inflection compared with most other Indo-European languages. For example, Modern English, unlike Modern German or Dutch and the Romance languages, lacks grammatical gender and adjectival agreement. Case marking has almost disappeared from the language and mainly survives in pronouns. The patterning of strong (e.g. speak/spoke/spoken) versus weak verbs inherited from its Germanic origins has declined in importance in modern English, and the remnants of inflection (such as plural marking) have become more regular.\n" +
+"\n" +
+"At the same time, the language has become more analytic, and has developed features such as modal verbs and word order as rich resources for conveying meaning. Auxiliary verbs mark constructions such as questions, negative polarity, the passive voice and progressive tenses.\n" +
+"\n" +
+"Vocabulary\n" +
+"\n" +
+"The English vocabulary has changed considerably over the centuries.[31]\n" +
+"\n" +
+"Germanic words (generally words of Old English or to a lesser extent Norse origin) which include all the basics such as pronouns (I, my, you, it) and conjunctions (and, or, but) tend to be shorter than the Latinate words of English, and more common in ordinary speech. The longer Latinate words are often regarded as more elegant or educated. However, the excessive or superfluous use of Latinate words is considered at times to be either pretentious (as in the stereotypical policeman's talk of \"apprehending the suspect\") or an attempt to obfuscate an issue. George Orwell's essay \"Politics and the English Language\" is critical of this, as well as other perceived abuses of the language.\n" +
+"\n" +
+"An English speaker is in many cases able to choose between Germanic and Latinate synonyms: come or arrive; sight or vision; freedom or liberty. In some cases there is a choice between a Germanic derived word (oversee), a Latin derived word (supervise), and a French word derived from the same Latin word (survey). The richness of the language arises from the variety of different meanings and nuances such synonyms harbour, enabling the speaker to express fine variations or shades of thought. Familiarity with the etymology of groups of synonyms can give English speakers greater control over their linguistic register. See: List of Germanic and Latinate equivalents.\n" +
+"\n" +
+"An exception to this and a peculiarity perhaps unique to English is that the nouns for meats are commonly different from, and unrelated to, those for the animals from which they are produced, the animal commonly having a Germanic name and the meat having a French-derived one. Examples include: deer and venison; cow and beef; swine/pig and pork, or sheep and mutton. This is assumed to be a result of the aftermath of the Norman invasion, where a French-speaking elite were the consumers of the meat, produced by English-speaking lower classes.\n" +
+"\n" +
+"In everyday speech, the majority of words will normally be Germanic. If a speaker wishes to make a forceful point in an argument in a very blunt way, Germanic words will usually be chosen. A majority of Latinate words (or at least a majority of content words) will normally be used in more formal speech and writing, such as a courtroom or an encyclopedia article. However, there are other Latinate words that are used normally in everyday speech and do not sound formal; these are mainly words for concepts that no longer have Germanic words, and are generally assimilated better and in many cases do not appear Latinate. For instance, the words mountain, valley, river, aunt, uncle, move, use, push and stay are all Latinate.\n" +
+"\n" +
+"English is noted for the vast size of its active vocabulary and its fluidity.[citation needed][weasel words] English easily accepts technical terms into common usage and imports new words and phrases that often come into common usage. Examples of this phenomenon include: cookie, Internet and URL (technical terms), as well as genre, über, lingua franca and amigo (imported words/phrases from French, German, modern Latin, and Spanish, respectively). In addition, slang often provides new meanings for old words and phrases. In fact, this fluidity is so pronounced that a distinction often needs to be made between formal forms of English and contemporary usage. See also: sociolinguistics.\n" +
+"\n" +
+"Number of words in English\n" +
+"\n" +
+"English has an extraordinarily rich vocabulary and willingness to absorb new words. As the General Explanations at the beginning of the Oxford English Dictionary states:\n" +
+"\n" +
+"    The Vocabulary of a widely diffused and highly cultivated living language is not a fixed quantity circumscribed by definite limits... there is absolutely no defining line in any direction: the circle of the English language has a well-defined centre but no discernible circumference.\n" +
+"\n" +
+"The vocabulary of English is undoubtedly vast, but assigning a specific number to its size is more a matter of definition than of calculation. Unlike other languages, there is no Academy to define officially accepted words. Neologisms are coined regularly in medicine, science and technology and other fields, and new slang is constantly developed. Some of these new words enter wide usage; others remain restricted to small circles. Foreign words used in immigrant communities often make their way into wider English usage. Archaic, dialectal, and regional words might or might not be widely considered as \"English\".\n" +
+"\n" +
+"The Oxford English Dictionary, 2nd edition (OED2) includes over 600,000 definitions, following a rather inclusive policy:\n" +
+"\n" +
+"    It embraces not only the standard language of literature and conversation, whether current at the moment, or obsolete, or archaic, but also the main technical vocabulary, and a large measure of dialectal usage and slang (Supplement to the OED, 1933).[32]\n" +
+"\n" +
+"The editors of Webster's Third New International Dictionary, Unabridged (475,000 main headwords) in their preface, estimate the number to be much higher. It is estimated that about 25,000 words are added to the language each year.[33]\n" +
+"\n" +
+"Word origins\n" +
+"Influences in English vocabulary\n" +
+"Influences in English vocabulary\n" +
+"\n" +
+"    Main article: Lists of English words of international origin\n" +
+"\n" +
+"One of the consequences of the French influence is that the vocabulary of English is, to a certain extent, divided between those words which are Germanic (mostly Old English) and those which are \"Latinate\" (Latin-derived, either directly from Norman French or other Romance languages).\n" +
+"\n" +
+"Numerous sets of statistics have been proposed to demonstrate the various origins of English vocabulary. None, as yet, are considered definitive by a majority of linguists.\n" +
+"\n" +
+"A computerised survey of about 80,000 words in the old Shorter Oxford Dictionary (3rd ed.) was published in Ordered Profusion by Thomas Finkenstaedt and Dieter Wolff (1973)[34] that estimated the origin of English words as follows:\n" +
+"\n" +
+"    * Langue d'oïl, including French and Old Norman: 28.3%\n" +
+"    * Latin, including modern scientific and technical Latin: 28.24%\n" +
+"    * Other Germanic languages (including words directly inherited from Old English): 25%\n" +
+"    * Greek: 5.32%\n" +
+"    * No etymology given: 4.03%\n" +
+"    * Derived from proper names: 3.28%\n" +
+"    * All other languages contributed less than 1% (e.g. Arabic-English loanwords)\n" +
+"\n" +
+"A survey by Joseph M. Williams in Origins of the English Language of 10,000 words taken from several thousand business letters[35] gave this set of statistics:\n" +
+"\n" +
+"    * French (langue d'oïl), 41%\n" +
+"    * \"Native\" English, 33%\n" +
+"    * Latin, 15%\n" +
+"    * Danish, 2%\n" +
+"    * Dutch, 1%\n" +
+"    * Other, 10%\n" +
+"\n" +
+"However, 83% of the 1,000 most-common English words are Anglo-Saxon in origin. [36]\n" +
+"\n" +
+"Dutch origins\n" +
+"\n" +
+"    Main article: List of English words of Dutch origin\n" +
+"\n" +
+"Words describing the navy, types of ships, and other objects or activities on the water are often from Dutch origin. Yacht (Jacht) and cruiser (kruiser) are examples.\n" +
+"\n" +
+"French origins\n" +
+"\n" +
+"    Main article: List of French phrases used by English speakers\n" +
+"\n" +
+"There are many words of French origin in English, such as competition, art, table, publicity, police, role, routine, machine, force, and many others that have been and are being anglicised; they are now pronounced according to English rules of phonology, rather than French. A large portion of English vocabulary is of French or Oïl language origin, most derived from, or transmitted via, the Anglo-Norman spoken by the upper classes in England for several hundred years after the Norman Conquest.\n";
+
+
+var greek = 
+"Ελλάδα\n" +
+"Από τη Βικιπαίδεια, την ελεύθερη εγκυκλοπαίδεια\n" +
+"Ελληνική Δημοκρατία\n" +
+"      \n" +
+"Σημαία  Εθνόσημο\n" +
+"Εθνικό σύνθημα: Ελευθερία ή Θάνατος\n" +
+"Εθνικός ύμνος: Ὕμνος εἰς τὴν Ἐλευθερίαν\n" +
+"\n" +
+"Πρωτεύουσα  Αθήνα \n" +
+"38.01.36N 23.44.00E\n" +
+"\n" +
+"Μεγαλύτερη πόλη Αθήνα\n" +
+"Επίσημες γλώσσες       Ελληνική\n" +
+"Πολίτευμα\n" +
+"\n" +
+"Πρόεδρος της Δημοκρατίας\n" +
+"Πρωθυπουργός      Προεδρευόμενη\n" +
+"Κοινοβουλευτική Δημοκρατία\n" +
+"Κάρολος Παπούλιας\n" +
+"Κωνσταντίνος Καραμανλής\n" +
+"Ανεξαρτησία\n" +
+"- Κηρύχθηκε\n" +
+"- Αναγνωρίστηκε\n" +
+"\n" +
+"25 Μαρτίου, 1821\n" +
+"1828\n" +
+"Έκταση\n" +
+" - Σύνολο\n" +
+" - Νερό (%)        \n" +
+"131.940 km² (94ηη)\n" +
+"%0.86\n" +
+"Πληθυσμός\n" +
+" - Εκτίμηση 2006\n" +
+" - Απογραφή 2001\n" +
+" - Πυκνότητα  \n" +
+"11.120.000 [1] (72ηη)\n" +
+"10.964.020\n" +
+"83.1 κάτ./km² (87ηη)\n" +
+"Α.Ε.Π.\n" +
+" - Ολικό\n" +
+" - Κατά κεφαλή      Εκτίμηση 2007\n" +
+"$305,595 δισ. (37η)\n" +
+"$27,360 (27η)\n" +
+"Νόμισμα        Ευρώ\n" +
+"(€)\n" +
+"Ζώνη ώρας\n" +
+" - Θερινή ώρα        (UTC+2)\n" +
+"(UTC+3)\n" +
+"Internet TLD  .gr\n" +
+"Κωδικός κλήσης   +30\n" +
+"Η Ελλάδα (αρχαΐζουσα: Ἑλλάς, επίσημα: Ελληνική Δημοκρατία), είναι χώρα στην νοτιοανατολική Ευρώπη, στο νοτιότερο άκρο της Βαλκανικής χερσονήσου, στην Ανατολική Μεσόγειο. Συνορεύει στην ξηρά, βόρεια με την Πρώην Γιουγκοσλαβική Δημοκρατία της Μακεδονίας και την Βουλγαρία, στα βορειοδυτικά με την Αλβανία και στα βορειοανατολικά με την Τουρκία. Βρέχεται ανατολικά από το Αιγαίο Πέλαγος, στα δυτικά και νότια από το Ιόνιο και από την Μεσόγειο Θάλασσα. Είναι το λίκνο του Δυτικού πολιτισμού. Η Ελλάδα έχει μια μακρά και πλούσια ιστορία κατά την οποία άσκησε μεγάλη πολιτισμική επίδραση σε τρεις ηπείρους.\n" +
+"Πίνακας περιεχομένων [Απόκρυψη]\n" +
+"1 Ιστορία\n" +
+"2 Πολιτικά\n" +
+"2.1 Κόμματα\n" +
+"2.2 Κυβέρνηση\n" +
+"3 Περιφέρειες\n" +
+"3.1 Βουνά της Ελλάδας\n" +
+"3.2 Λίμνες της Ελλάδας\n" +
+"3.3 Ποτάμια της Ελλάδας\n" +
+"3.4 Κλίμα\n" +
+"4 Οικονομία\n" +
+"5 Δημογραφία\n" +
+"6 Ένοπλες δυνάμεις και Σώματα ασφαλείας\n" +
+"6.1 Υποχρεωτική στράτευση\n" +
+"7 Πολιτισμός\n" +
+"7.1 Αργίες\n" +
+"8 Σημειώσεις\n" +
+"9 Δείτε επίσης\n" +
+"10 Εξωτερικές συνδέσεις\n" +
+"[Επεξεργασία]\n" +
+"Ιστορία\n" +
+"\n" +
+"Κύριο άρθρο: Ελληνική ιστορία\n" +
+"Στις ακτές του Αιγαίου Πελάγους εμφανίστηκαν οι πρώτοι πολιτισμοί της Ευρώπης, ο Μινωικός και ο Μυκηναϊκός. Την εποχή των πολιτισμών αυτών, ακολούθησε μία σκοτεινή περίοδος περίπου μέχρι το 800 π.Χ., οπότε εμφανίζεται ένας καινούριος Ελληνικός πολιτισμός, βασισμένος στο μοντέλο της πόλης-κράτους. Είναι ο πολιτισμός που θα διαδοθεί με τον αποικισμό των ακτών της Μεσογείου, θα αντισταθεί στην Περσική εισβολή με τους δύο επιφανέστερους εκπροσώπους του, την κοσμοπολίτικη και δημοκρατική Αθήνα και την μιλιταριστική και ολιγαρχική Σπάρτη, θα αποτελέσει τη βάση του Ελληνιστικού πολιτισμού που δημιούργησαν οι κατακτήσεις του Μεγάλου Αλεξάνδρου, θα επηρεάσει ως ένα βαθμό την πολιτισμική φυσιογνωμία της Βυζαντινής Αυτοκρατορίας και αργότερα θα πυροδοτήσει την Αναγέννηση στην Ευρώπη.\n" +
+"Στρατιωτικά έχανε δύναμη σε σύγκριση με τη Ρωμαϊκή αυτοκρατορία μέχρι που κατακτήθηκε τελικά από τους Ρωμαίους το 146 π.Χ., αν και ο Ελληνικός πολιτισμός τελικά κατέκτησε το Ρωμαϊκό τρόπο ζωής. Οι Ρωμαίοι αναγνώρισαν και θαύμασαν τον πλούτο του Ελληνικού πολιτισμού, τον μελέτησαν βαθιά και έγιναv συνειδητά συνεχιστές του. Διέσωσαν επίσης και μεγάλο μέρος της αρχαιοελληνικής γραμματείας. Αν και ήταν μόνο ένα μέρος της Ρωμαϊκής αυτοκρατορίας, ο ελληνικός πολιτισμός θα συνέχιζε να δεσπόζει στην Ανατολική Μεσόγειο, και όταν τελικά η Αυτοκρατορία χωρίστηκε στα δύο, η ανατολική ή Βυζαντινή Αυτοκρατορία με πρωτεύουσα την Κωνσταντινούπολη, θα είχε κυρίως λόγω γλώσσας έντονο τον ελληνικό χαρακτήρα. Από τον 4ο μέχρι τον 15ο αιώνα, η Ανατολική Ρωμαϊκή Αυτοκρατορία επέζησε επιθέσεις 11 αιώνων από δυτικά και ανατολικά, μέχρι που η Κωνσταντινούπολη έπεσε στις 29 Μαΐου του 1453 στα χέρια της Οθωμανικής Αυτοκρατορίας. Σταδιακά το Βυζάντιο κατακτήθηκε ολόκληρο μέσα στον 15ο αιώνα.\n" +
+"Η Οθωμανική κυριαρχία συνεχίστηκε μέχρι το 1821 που οι Έλληνες κήρυξαν την ανεξαρτησία τους. Η Ελληνική Επανάσταση του 1821 έληξε το 1828. Το 1830 αναγνωρίζεται η ανεξαρτησία του νέου ελληνικού κράτους. Εγκαθιδρύθηκε μοναρχία το 1833. Μέσα στον 19ο και τον πρώιμο 20ό αιώνα, η Ελλάδα προσπάθησε να προσαρτήσει στα εδάφη της όλες τις περιοχές που ακόμη ανήκαν στην Οθωμανική Αυτοκρατορία και είχαν Ελληνόφωνο πληθυσμό, πράγμα που κατάφερε εν μέρει, επεκτείνοντας σταδιακά την έκτασή της, μέχρι να φτάσει το σημερινό της μέγεθος το 1947.\n" +
+"Μετά τον Δεύτερο Παγκόσμιο Πόλεμο στην Ελλάδα ξέσπασε εμφύλιος πόλεμος μέχρι το 1949. Αργότερα, το 1952, η Ελλάδα έγινε μέλος του ΝΑΤΟ. Στις 21 Απριλίου του 1967 ο στρατός, υποβοηθούμενος από την κυβέρνηση των ΗΠΑ, πήρε την εξουσία με πραξικόπημα. Οι δικτατορες στη συνεχεια διαχωριστηκαν και απο τον βασιλια, τον εκδίωξαν απο την χώρα και κατήργησαν τη μοναρχία. Η στρατιωτική Χούντα υπήρξε η αιτία δημιουργίας, μετά από λανθασμένους χειρισμούς που εκμεταλλεύτηκε η Τουρκική πλευρά, του Κυπριακού ζητήματος, το οποίο οδήγησε στην κατάρρευσή της το 1974. Έπειτα από δημοψήφισμα για την κατάργηση της μοναρχίας στις 8 Δεκεμβρίου 1974 το πολίτευμα της Ελλάδας μετατράπηκε ξανά σε αβασίλευτη Δημοκρατία και συντάχθηκε νέο σύνταγμα από την πέμπτη Αναθεωρητική Βουλή που τέθηκε σε ισχύ στις 11 Ιουνίου 1975, το οποίο ισχύει σήμερα όπως αναθεωρήθηκε το 1986 και το 2001. Η Ελλάδα έγινε μέλος της Ευρωπαϊκής Ένωσης το 1981 και μέλος της Ευρωπαϊκής Οικονομικής και Νομισματικής Ένωσης (ΟΝΕ) γνωστής και ως ζώνης ευρώ, το 2001.\n" +
+"Ελληνική ιστορία \n" +
+"Κυκλαδικός πολιτισμός     (3η χιλιετία π.Χ.)\n" +
+"Μινωικός πολιτισμός (3000-1450 π.Χ.)\n" +
+"Μυκηναϊκός πολιτισμός     (1600-1100 π.Χ.)\n" +
+"Γεωμετρική εποχή       (1100-800 π.Χ.)\n" +
+"Αρχαϊκή εποχή     (800-500 π.Χ.)\n" +
+"Κλασική εποχή     (500 π.Χ.- 323 π.Χ.)\n" +
+"Ελληνιστική εποχή     (323-146 π.Χ.)\n" +
+"Ρωμαϊκή περίοδος       (146 π.Χ.-330 μ.Χ.)\n" +
+"Βυζαντινή περίοδος   (330-1453)\n" +
+"Οθωμανική περίοδος   (1453-1821)\n" +
+"Νεότερη Ελλάδα   (1821 έως σήμερα)\n" +
+"Σχετικά\n" +
+"Αρχαία ελληνική γραμματεία\n" +
+"Ελληνική γλώσσα\n" +
+"Ονομασίες Ελλήνων\n" +
+"\n" +
+"[Επεξεργασία]\n" +
+"Πολιτικά\n" +
+"\n" +
+"Το Σύνταγμα του 1975 περιέχει εκτενείς εγγυήσεις των ελευθεριών και των δικαιωμάτων του πολίτη, ελευθερίες και δικαιώματα που ενισχύθηκαν περαιτέρω με την αναθεώρηση του 2001. Είναι χαρακτηριστικό ότι κατά την αναθεώρηση αυτή κατοχυρώθηκαν, για πρώτη φορά συνταγματικά, πέντε ανεξάρτητες αρχές, οι τρεις εκ των οποίων (Συνήγορος του Πολίτη, Αρχή Διασφάλισης Ατομικών Δικαιωμάτων και Αρχή Προστασίας Προσωπικών Δεδομένων) είναι ταγμένες στην προστασία και διασφάλιση των ατομικών δικαιωμάτων. Η Ελλάδα είναι επίσης μέλος της Ευρωπαϊκής Σύμβασης για τα Δικαιώματα του Ανθρώπου.\n" +
+"Σε πολιτειακό και οργανωτικό επίπεδο, το Σύνταγμα διακρίνει τρεις εξουσίες: τη νομοθετική, την εκτελεστική και τη δικαστική. Στη νομοθετική μετέχουν ο Πρόεδρος της Δημοκρατίας και η Βουλή· στην εκτελεστική ο Πρόεδρος της Δημοκρατίας και η Κυβέρνηση, ενώ η δικαστική εξουσία ασκείται από τα δικαστήρια στο όνομα του ελληνικού λαού.\n" +
+"Ο Πρόεδρος της Δημοκρατίας, ιεραρχικά, βρίσκεται στην κορυφή της εκτελεστικής εξουσίας, μετέχει στη νομοθετική με τη δημοσίευση των νόμων και τη δυνατότητα αναπομπής ψηφισμένου νομοσχεδίου, ενώ ορίζεται από το Σύνταγμα ως ρυθμιστής του πολιτεύματος [2] . Εκλέγεται έμμεσα από τη Βουλή με διαδοχικές ψηφοφορίες των μελών της, στις οποίες επιδιώκεται η εξασφάλιση πλειοψηφίας 2/3, σε πρώτη φάση, και 3/5, σε δεύτερη, του συνόλου των μελών της. Σε περίπτωση αποτυχίας συγκέντρωσης των ανωτέρω πλειοψηφιών, διαλύεται η Βουλή, προκηρύσσονται εκλογές και η νέα Βουλή εκλέγει τον Πρόεδρο της Δημοκρατίας με την απόλυτη πλειοψηφία των μελών της, ή και με σχετική αν δεν συγκεντρωθεί η απόλυτη πλειοψηφία. Οι εξουσίες του Προέδρου είναι περιορισμένες καθώς ασκεί, κυρίως, τελετουργικά καθήκοντα. Όλες, σχεδόν, οι πράξεις του, χρήζουν προσυπογραφής από τον Πρωθυπουργό ή άλλο μέλος της Κυβέρνησης (υπουργό), όπως, π.χ., τα προεδρικά διατάγματα. Από την υποχρέωση προσυπογραφής εξαιρούνται ρητά ελάχιστες πράξεις του Προέδρου που προβλέπονται από το Σύνταγμα, όπως ο διορισμός των υπαλλήλων της Προεδρίας της Δημοκρατίας. Η θητεία του είναι πενταετής με δικαίωμα επανεκλογής για μία ακόμη φορά.\n" +
+"Η νομοθετική εξουσία ασκείται από τη Βουλή, τα μέλη της οποίας εκλέγονται με καθολική μυστική ψηφοφορία για τετραετή θητεία. Εκλογές μπορεί να κηρυχθούν νωρίτερα για έκτακτους λόγους, όπως αυτοί ορίζονται στο Σύνταγμα. Μετά, πάντως, το 1975 η προκήρυξη πρόωρων εκλογών αποτελεί τον κανόνα, με την επίκληση, συνήθως, από τις απερχόμενες κυβερνήσεις ιδιαζούσης σημασίας εθνικού θέματος. Η Ελληνική Δημοκρατία χρησιμοποιεί για την ανάδειξη των βουλευτών ένα σύνθετο ενδυναμωμένο εκλογικό σύστημα αναλογικής εκπροσώπησης (ενισχυμένη αναλογική), που αποθαρρύνει τη δημιουργία πολυκομματικών Κυβερνήσεων συνεργασίας και επιτρέπει ισχυρή κυβέρνηση πλειοψηφίας, ακόμα και αν το πρώτο κόμμα υστερεί της πλειοψηφίας των ψήφων. Για να μπορεί να καταλάβει μία από τις 300 βουλευτικές έδρες ένα κόμμα, πρέπει να έχει λάβει τουλάχιστον το 3% του συνόλου των ψήφων, ενώ με τον εκλογικό νόμο, που θα εφαρμοστεί, για πρώτη φορά, στις μετά το 2004 βουλευτικές εκλογές, το πρώτο κόμμα εξασφαλίζει απόλυτη πλειοψηφία στη Βουλή με ποσοστό 41%.\n" +
+"Η εκτελεστική εξουσία ασκείται από την Κυβέρνηση, κεφαλή της οποίας είναι ο Πρωθυπουργός, το ισχυρότερο πρόσωπο του ελληνικού πολιτικού συστήματος. Η Κυβέρνηση καθορίζει και κατευθύνει τη γενική πολιτική της Χώρας [3], εφαρμόζει την πολιτική, που εγκρίνει μέσω των νομοθετικών πράξεων η Βουλή, αλλά ταυτόχρονα μετέχει στη νομοπαρασκευαστική διαδικασία, μέσω της σύνταξης και της προώθησης προς ψήφιση των νομοσχεδίων. Η Κυβέρνηση με βάση την αρχή της δεδηλωμένης οφείλει να απολαύει της εμπιστοσύνης της Βουλής, να έχει λάβει δηλαδή ψήφο εμπιστοσύνης από την πλειοψηφία των Βουλευτών. Στα πλαίσια δε της σύγχρονης κομματικής δημοκρατίας, η Κυβέρνηση κυριαρχεί και στη νομοθετική λειτουργία, καθώς προέρχεται από το Κόμμα που ελέγχει την πλειοψηφία του Κοινοβουλίου, καθιστώντας, έτσι, την ψήφιση των νόμων μια τυπική, κατά κανόνα, διαδικασία. Λόγω δε της συχνής έως καταχρηστικής επίκλησης της κομματικής πειθαρχίας, η δυνατότητα διαφωνίας κυβερνητικού βουλευτή με την Κυβέρνηση που στηρίζει θεωρείται σπάνιο φαινόμενο. Σε έκτακτες περιπτώσεις μπορεί η Κυβέρνηση να εκδίδει Πράξεις Νομοθετικού Περιεχομένου. Οι Π.Ν.Π. έχουν ισχύ νόμου και οφείλουν να εγκριθούν εντός 40 ημερών από τη Βουλή.\n" +
+"Ο Πρωθυπουργός αποτελεί την κεφαλή της κυβέρνησης και, με βάση το Σύνταγμα, είναι, συνήθως (αν και όχι απαραίτητα), ο αρχηγός του έχοντος την απόλυτη πλειοψηφία στη Βουλή κυβερνώντος κόμματος. Βάσει του άρθρου 82 του Συντάγματος, \"ο Πρωθυπουργός εξασφαλίζει την ενότητα της Κυβέρνησης και κατευθύνει τις ενέργειές της, καθώς και των δημοσίων γενικά υπηρεσιών για την εφαρμογή της κυβερνητικής πολιτικής μέσα στο πλαίσιο των νόμων\" [3]. Οι βασικότερες εξουσίες του είναι οι εξής:\n" +
+"Προεδρεύει του Υπουργικού Συμβουλίου, στο οποίο μετέχει μαζί με τους Υπουργούς.\n" +
+"Με δέσμια πρόταση του διορίζονται και παύονται από τον Πρόεδρο της Δημοκρατίας οι υπουργοί και οι υφυπουργοί της Κυβέρνησης.\n" +
+"Καθορίζει με τον οικείο Υπουργό τις αρμοδιότητες των υφυπουργών.\n" +
+"Προΐσταται τεσσάρων αυτοτελών υπηρεσιών και γραμματειών: του Πολιτικού Γραφείου του Πρωθυπουργού, της Γραμματείας της Κυβερνήσεως, της Κεντρικής Νομοπαρασκευαστικής Επιτροπής και της Γενικής Γραμματείας Τύπου.\n" +
+"Δίνει άδεια για τη δημοσίευση στην Εφημερίδα της Κυβερνήσεως οποιουδήποτε κειμένου πρέπει, κατά το νόμο, να καταχωρισθεί σε αυτήν.\n" +
+"[Επεξεργασία]\n" +
+"Κόμματα\n" +
+"Περισσότερα: Κατάλογος ελληνικών πολιτικών κομμάτων\n" +
+"Μετά την αποκατάσταση της Δημοκρατίας το 1974 (μεταπολίτευση) το πολιτικό σύστημα κυριαρχείται από το φιλελεύθερο κόμμα της Νέας Δημοκρατίας και το σοσιαλιστικό ΠΑΣΟΚ (Πανελλλήνιο Σοσιαλιστικό Κίνημα). Άλλα κόμματα είναι το Κομμουνιστικό Κόμμα Ελλάδας, ο Συνασπισμός της Αριστεράς και ο ΛΑ.Ο.Σ..\n" +
+"[Επεξεργασία]\n" +
+"Κυβέρνηση\n" +
+"Περισσότερα: Κυβέρνηση της Ελλάδας\n" +
+"Στις εκλογές της 7 Μαρτίου 2004, πρωθυπουργός εκλέχθηκε ο Κωνσταντίνος Α. Καραμανλής, πρόεδρος της Νέας Δημοκρατίας. Ήταν η πρώτη εκλογική νίκη του κόμματος μετά από 11 χρόνια. Ο Καραμανλής αντικατέστησε τον Κωνσταντίνο Σημίτη και σχημάτισε δική του κυβέρνηση. Οι επόμενες βουλευτικές εκλογές προβλέπονταν από το Σύνταγμα για το 2008, όμως διεξήχθησαν πρόωρα στις 16 Σεπτεμβρίου 2007. Τις εκλογές της 16ης κέρδισε ξανά η ΝΔ. Η Νέα βουλή είναι η πρώτη πεντακομματική Βουλή τα τελευταία χρόνια και σε αυτή συμμετέχουν η ΝΔ το ΠΑΣΟΚ, το ΚΚΕ, ο ΣΥ.ΡΙ.ΖΑ και το ΛΑ.Ο.Σ. Συγκεκριμένα η ΝΔ εξασφάλισε το 41.83% και 152 από τις 300 Έδρες. Το ΠΑΣΟΚ εξασφάλισε το 38.10 % και 102 Έδρες. Το Κ.Κ.Ε εξασφάλισε το 8.15% και 22 έδρες. Ο ΣΥ.ΡΙ.ΖΑ εξασφάλισε το 5.04% και 14 έδρες και τέλος το ΛΑ.Ο.Σ εξασφάλισε το 3.80% κερδίζοντας 10 έδρες.\n" +
+"[Επεξεργασία]\n" +
+"Περιφέρειες\n" +
+"\n" +
+"Κύριο άρθρο: Περιφέρειες της Ελλάδας\n" +
+"Η Ελλάδα χωρίζεται σε 13 διοικητικές περιοχές γνωστές σαν Περιφέρειες, που διαχωρίζονται περαιτέρω σε 51 Νομούς:\n" +
+"Αττική\n" +
+"Αττική\n" +
+"Στερεά Ελλάδα\n" +
+"Εύβοια\n" +
+"Ευρυτανία\n" +
+"Φωκίδα\n" +
+"Φθιώτιδα\n" +
+"Βοιωτία\n" +
+"Κεντρική Μακεδονία\n" +
+"Χαλκιδική\n" +
+"Ημαθία\n" +
+"Κιλκίς\n" +
+"Πέλλα\n" +
+"Πιερία\n" +
+"Σέρρες\n" +
+"Θεσσαλονίκη\n" +
+"Κρήτη\n" +
+"Χανιά\n" +
+"Ηράκλειο\n" +
+"Λασίθι\n" +
+"Ρέθυμνο\n" +
+"Ανατολική Μακεδονία και Θράκη\n" +
+"Καβάλα\n" +
+"Δράμα\n" +
+"Ξάνθη\n" +
+"Ροδόπη\n" +
+"Έβρος\n" +
+"Ήπειρος\n" +
+"Άρτα\n" +
+"Ιωάννινα\n" +
+"Πρέβεζα\n" +
+"Θεσπρωτία\n" +
+"Ιόνια νησιά\n" +
+"Κέρκυρα\n" +
+"Κεφαλονιά\n" +
+"Λευκάδα\n" +
+"Ζάκυνθος\n" +
+"Βόρειο Αιγαίο\n" +
+"Χίος\n" +
+"Λέσβος\n" +
+"Σάμος - Ικαρία\n" +
+"Πελοπόννησος\n" +
+"Αρκαδία\n" +
+"Αργολίδα\n" +
+"Κορινθία\n" +
+"Λακωνία\n" +
+"Μεσσηνία\n" +
+"Νότιο Αιγαίο\n" +
+"Κυκλάδες\n" +
+"Δωδεκάνησα\n" +
+"Θεσσαλία\n" +
+"Καρδίτσα\n" +
+"Λάρισα\n" +
+"Μαγνησία\n" +
+"Τρίκαλα\n" +
+"Δυτική Ελλάδα\n" +
+"Αχαΐα\n" +
+"Αιτωλοακαρνανία\n" +
+"Ηλεία\n" +
+"Δυτική Μακεδονία\n" +
+"Φλώρινα\n" +
+"Γρεβενά\n" +
+"Καστοριά\n" +
+"Κοζάνη\n" +
+"Επιπλέον, στη Μακεδονία υπάρχει μία αυτόνομη περιοχή, το Άγιο Όρος, μία μοναστική πολιτεία υπό Ελληνική κυριαρχία. Οι νομοί χωρίζονται σε 147 επαρχίες, που διαιρούνται σε 900 δήμους και 133 κοινότητες. Πριν το 1999, υπήρχαν 5.775 οργανισμοί τοπικής αυτοδιοίκησης: 361 δήμοι και 5.560 κοινότητες, υποδιαιρούμενες σε 12.817 οικισμούς\n" +
+"\n" +
+"\n" +
+"\n" +
+"Αλβανία\n" +
+"\n" +
+"П.Γ.Δ.Μ.\n" +
+"\n" +
+"Βουλγαρία\n" +
+"'\n" +
+"\n" +
+"Τουρκία\n" +
+"\n" +
+"EΛΛAΣ\n" +
+"AΘHNA\n" +
+"Θεσσαλονίκη\n" +
+"Καβάλα\n" +
+"Αλεξανδρούπολη\n" +
+"Κέρκυρα\n" +
+"Ηγουμενίτσα\n" +
+"Λάρισα\n" +
+"Βόλος\n" +
+"Ιωάννινα\n" +
+"Χαλκίδα\n" +
+"Πάτρα\n" +
+"Πειραιάς\n" +
+"Ελευσίνα\n" +
+"Λαύριο\n" +
+"Ηράκλειο\n" +
+"Μ α κ ε δ ο ν ί α\n" +
+"Θράκη\n" +
+"Ήπειρος\n" +
+"Θεσσαλία\n" +
+"Στερεά Ελλάδα\n" +
+"Πελοπόννησος\n" +
+"Όλυμπος (2917m)\n" +
+"Λευκάδα\n" +
+"Κεφαλονιά\n" +
+"Λήμνος\n" +
+"Λέσβος\n" +
+"Χίος\n" +
+"Σάμος\n" +
+"Τήνος\n" +
+"Ικαρία\n" +
+"Νάξος\n" +
+"Σαντορίνη\n" +
+"Κως\n" +
+"Ρόδος\n" +
+"Κάρπαθος\n" +
+"Κύθηρα\n" +
+"Γαύδος\n" +
+"Αιγαίον\n" +
+"Πέλαγος\n" +
+"Μυρτώον\n" +
+"Πέλαγος\n" +
+"Κρητικόν Πέλαγος\n" +
+"Ιόνιον\n" +
+"Πέλαγος\n" +
+"Μεσόγειος\n" +
+"Θάλασσα\n" +
+"Κρήτη\n" +
+"[Επεξεργασία]\n" +
+"Βουνά της Ελλάδας\n" +
+"Κύριο άρθρο: Κατάλογος βουνών της Ελλάδας\n" +
+"Περίπου το 80% του εδάφους της χώρας είναι ορεινό ή λοφώδες. Μεγάλο μέρος του είναι ξηρό και βραχώδες, μόνο 28% του εδάφους είναι καλλιεργήσιμο.\n" +
+"Όλυμπος 2917 μ. Θεσσαλία, Κεντρική Μακεδονία (Λάρισα, Πιερία)\n" +
+"Σμόλικας 2637 μ. Βόρεια Πίνδος (Ιωάννινα)\n" +
+"Βόρας 2524 μ. Κεντρική Μακεδονία (Πέλλα, Φλώρινα, Π.Γ.Δ.Μ.)\n" +
+"Γράμος 2520 μ. Δυτική Μακεδονία (Καστοριά, Ιωάννινα, Αλβανία)\n" +
+"Γκιώνα 2510 μ. Στερεά (Φωκίδα)\n" +
+"Τύμφη 2497 μ. Βόρεια Πίνδος (Ιωάννινα)\n" +
+"Βαρδούσια 2495 μ. Στερεά (Φωκίδα)\n" +
+"Αθαμανικά όρη 2469 μ. Νότια Πίνδος (Άρτα)\n" +
+"Παρνασσός 2457 μ. Στερεά (Φωκίδα, Φθιώτιδα)\n" +
+"Ψηλορείτης 2456 μ. Κρήτη (Ηράκλειο)\n" +
+"\n" +
+"\n" +
+"\n" +
+"\n" +
+"Η χώρα αποτελείται από ένα μεγάλο ηπειρωτικό τμήμα, το νότιο άκρο των Βαλκανίων, ενωμένο με την πρώην ηπειρωτική Πελοπόννησο, από τον Ισθμό της Κορίνθου, και το Ιόνιο και Αιγαίο πέλαγος. Η Πελοπόννησος πλέον μετά την κατασκευή της διώρυγας της Κορίνθου είναι στην πραγματικότητα νησί. Το Αιγαίο περιέχει πολυάριθμα νησιά, ανάμεσά τους τη Ρόδο, την Εύβοια, τη Λέσβο και τα συμπλέγματα των Κυκλάδων και Δωδεκανήσων. 180 χιλιόμετρα νότια των ακτών δεσπόζει η Κρήτη, το πέμπτο μεγαλύτερο νησί της Μεσογείου. Η Ελλάδα έχει μήκος ακτών 15.021 χιλιόμετρα, που θεωρείται εξαιρετικά μεγάλο, και οφείλεται στον πλούσιο οριζόντιο εδαφικό διαμελισμό, καθώς και στο πλήθος των αναρίθμητων νησιών, τα οποία είναι πάνω από 1500. Έχει μήκος συνόρων που πλησιάζει τα 1.181 χιλιόμετρα.\n" +
+"\n" +
+"\n" +
+"Δορυφορική εικόνα της Ελλάδας\n" +
+"Κύριο άρθρο: Γεωγραφία της Ελλάδας\n" +
+"[Επεξεργασία]\n" +
+"Λίμνες της Ελλάδας\n" +
+"Κύριο άρθρο: Κατάλογος λιμνών της Ελλάδας\n" +
+"Η Ελλάδα έχει αρκετές λίμνες, οι περισσότερες των οποίων βρίσκονται στο ηπειρωτικό της τμήμα. Οι μεγαλύτερες λίμνες στην ελληνική επικράτεια είναι:\n" +
+"Τριχωνίδα 96.513 τ.χλμ.\n" +
+"Βόλβη 75.600 τ.χλμ\n" +
+"Λίμνη Βεγορίτιδα 72.488 τ.χλμ\n" +
+"Λίμνη Βιστονίδα 45.625 τ.χλμ\n" +
+"Λίμνη Κορώνεια 42.823 τ.χλμ\n" +
+"Μικρή Πρέσπα (ελληνικό τμήμα) 43.122 τ.χλμ\n" +
+"Μεγάλη Πρέσπα (ελληνικό τμήμα) 38.325 τ.χλμ\n" +
+"Κερκίνη 37.688 τ.χλμ\n" +
+"Υπάρχουν επίσης και αρκετές τεχνητές λίμνες κυρίως για παραγωγή ηλεκτρικού ρεύματος, όπως η Λίμνη Κρεμαστών (68.531 τ.χλμ) και η Λίμνη Πολυφύτου (56.793 τ.χλμ).\n" +
+"\n" +
+"[Επεξεργασία]\n" +
+"Ποτάμια της Ελλάδας\n" +
+"Αρκετά ποτάμια διαρρέουν την Ελλάδα, από τα οποίο κανένα δεν είναι πλεύσιμο. Μερικά από τα μεγαλύτερα, τα Δέλτα που σχηματίζουν στην εκροή τους προς την θάλασσα αποτελούν σημαντικούς υγροβιότοπους, όπως αυτοί του Αλιάκμονα και του Έβρου. Ποταμοί όπως ο Πηνειός στην Θεσσαλία, υδροδοτούν μεγάλες γεωργικές εκτάσεις με την βοήθεια καναλιών, ενώ σε άλλα έχουν δημιουργηθεί τεχνητές λίμνες για την λειτουργία υδροηλεκτρικών εργοστασίων. Ένα αμφιλεγόμενο για οικολογικούς λόγους σχέδιο των τελευταίων δεκαετιών, είναι η εκτροπή του Αχελώου από τη νότια Πίνδο για την αντιμετώπιση του υδατικού προβλήματος της Θεσσαλίας.\n" +
+"Ακολουθεί κατάλογος των μεγαλύτερων σε μήκος ποταμών της Ελλάδας. Το μήκος που αναγράφεται είναι αυτό που διατρέχει την ελληνική επικράτεια.\n" +
+"Αλιάκμονας 297 χλμ.\n" +
+"Αχελώος 220 χλμ.\n" +
+"Πηνειός (Θεσσαλίας) 205 χλμ.\n" +
+"Έβρος [4] 204 χλμ.\n" +
+"Νέστος [4] 130 χλμ.\n" +
+"Στρυμόνας [4] 118 χλμ.\n" +
+"Θύαμις (Καλαμάς) 115 χλμ.\n" +
+"Αλφειός 110 χλμ.\n" +
+"Άραχθος 110 χλμ.\n" +
+"[Επεξεργασία]\n" +
+"Κλίμα\n" +
+"Η Ελλάδα χαρακτηρίζεται από τον μεσογειακό τύπο του εύκρατου κλίματος και έχει ήπιους υγρούς χειμώνες και ζεστά ξηρά καλοκαίρια. Το κλίμα της χώρας μπορεί να διαιρεθεί σε τέσσερις βασικές κατηγορίες:\n" +
+"- υγρό μεσογειακό (δυτική Ελλάδα, δυτική Πελοπόννησος, πεδινά και ημιορεινά της Ηπείρου) - ξηρό μεσογειακό (Κυκλάδες, παραλιακή Κρήτη, Δωδεκάνησα, ανατολική Πελοπόννησος, Αττική, πεδινές περιοχές Ανατολικής Στερεάς) - ηπειρωτικό (δυτική Μακεδονία, εσωτερικά υψίπεδα ηπειρωτικής Ελλάδας, βόρειος Έβρος) - ορεινό (ορεινές περιοχές με υψόμετρο περίπου >1500μ στη βόρεια Ελλάδα, >1800μ στην κεντρική Ελλάδα και >2000μ στην Κρήτη).\n" +
+"Οι θερμοκρασίες είναι σπάνια υπερβολικές στις παραθαλάσσιες περιοχές. Στις κλειστές εσωτερικές πεδιάδες και στα υψίπεδα της χώρας παρατηρούνται τα μεγαλύτερα θερμοκρασιακά εύρη -τόσο ετήσια όσο και ημερήσια. Οι χιονοπτώσεις είναι κοινές στα ορεινά από τα τέλη Σεπτεμβρίου (στη βόρεια Ελλάδα, τέλη Οκτωβρίου κατά μέσο όρο στην υπόλοιπη χώρα), ενώ στις πεδινές περιοχές χιονίζει κυρίως από τον Δεκέμβριο μέχρι τα μέσα Μαρτίου. Έχει χιονίσει, πάντως, ακόμα και κατά μήνα Μάιο στη Φλώρινα. Στις παραθαλάσσιες περιοχές των νησιωτικών περιοχών, οι χιονοπτώσεις συμβαίνουν σπανιότερα και δεν αποτελούν βασικό χαρακτηριστικό του κλίματος. Η πόλη της Ρόδου έχει μέσο όρο 0,0 μέρες χιονόπτωσης το χρόνο. Οι καύσωνες επηρεάζουν κυρίως τις πεδινές περιοχές και είναι κοινότεροι τον Ιούλιο και τον Αύγουστο. Σπάνια, πάντως, διαρκούν περισσότερες από 3 μέρες.\n" +
+"Η Ελλάδα βρίσκεται μεταξύ των παραλλήλων 34ου και 42oυ του βορείου ημισφαιρίου και έχει μεγάλη ηλιοφάνεια όλο σχεδόν το χρόνο. Λεπτομερέστερα στις διάφορες περιοχές της Ελλάδας παρουσιάζεται μια μεγάλη ποικιλία κλιματικών τύπων, πάντα βέβαια μέσα στα πλαίσια του μεσογειακού κλίματος. Αυτό οφείλεται στην τοπογραφική διαμόρφωση της χώρας που έχει μεγάλες διαφορές υψομέτρου (υπάρχουν μεγάλες οροσειρές κατά μήκος της κεντρικής χώρας και άλλοι ορεινοί όγκοι) και εναλλαγή ξηράς και θάλασσας. Έτσι από το ξηρό κλίμα της Αττικής και γενικά της ανατολικής Ελλάδας μεταπίπτουμε στο υγρό της βόρειας και δυτικής Ελλάδας. Τέτοιες κλιματικές διαφορές συναντώνται ακόμη και σε τόπους που βρίσκονται σε μικρή απόσταση μεταξύ τους, πράγμα που παρουσιάζεται σε λίγες μόνο χώρες σε όλο τον κόσμο.\n" +
+"Από κλιματολογικής πλευράς το έτος μπορεί να χωριστεί κυρίως σε δύο εποχές: Την ψυχρή και βροχερή χειμερινή περίοδο που διαρκεί από τα μέσα του Οκτωβρίου και μέχρι το τέλος Μαρτίου και τη θερμή και άνομβρη εποχή που διαρκεί από τον Απρίλιο έως τον Οκτώβριο.\n" +
+"Κατά την πρώτη περίοδο οι ψυχρότεροι μήνες είναι ο Ιανουάριος και ο Φεβρουάριος, όπου κατά μέσον όρο η μέση ελάχιστη θερμοκρασία κυμαίνεται από 5-10 °C στις παραθαλάσσιες περιοχές, από 0-5 °C στις ηπειρωτικές περιοχές και σε χαμηλότερες τιμές κάτω από το μηδέν στις βόρειες περιοχές.\n" +
+"Οι βροχές ακόμη και τη χειμερινή περίοδο δεν διαρκούν για πολλές ημέρες και ο ουρανός της Ελλάδας δεν μένει συννεφιασμένος για αρκετές συνεχόμενες ημέρες, όπως συμβαίνει σε άλλες περιοχές της γης. Οι χειμερινές κακοκαιρίες διακόπτονται συχνά κατά τον Ιανουάριο και το πρώτο δεκαπενθήμερο του Φεβρουαρίου από ηλιόλουστες ημέρες, τις γνωστές από την αρχαιότητα Αλκυονίδες ημέρες.\n" +
+"Η χειμερινή εποχή είναι γλυκύτερη στα νησιά του Αιγαίου και του Ιονίου από ό,τι στη Βόρεια και Ανατολική ηπειρωτική Ελλάδα. Κατά τη θερμή και άνομβρη εποχή ο καιρός είναι σταθερός, ο ουρανός σχεδόν αίθριος, ο ήλιος λαμπερός και δεν βρέχει εκτός από σπάνια διαστήματα με ραγδαίες βροχές ή καταιγίδες μικρής γενικά διάρκειας.\n" +
+"Η θερμότερη περίοδος είναι το τελευταίο δεκαήμερο του Ιουλίου και το πρώτο του Αυγούστου οπότε η μέση μεγίστη θερμοκρασία κυμαίνεται από 29 °C μέχρι 35 °C. Κατά τη θερμή εποχή οι υψηλές θερμοκρασίες μετριάζονται από τη δροσερή θαλάσσια αύρα στις παράκτιες περιοχές της χώρας και από τους βόρειους ανέμους (ετησίες) που φυσούν κυρίως στο Αιγαίο.\n" +
+"Η άνοιξη έχει μικρή διάρκεια, διότι ο μεν χειμώνας είναι όψιμος, το δε καλοκαίρι αρχίζει πρώιμα. Το φθινόπωρο είναι μακρύ και θερμό και πολλές φορές παρατείνεται στη νότια Ελλάδα μέχρι τα μισά του Δεκεμβρίου.\n" +
+"[Επεξεργασία]\n" +
+"Οικονομία\n" +
+"\n" +
+"Κύριο άρθρο: Οικονομία της Ελλάδας\n" +
+"Η Ελλάδα έχει μικτή καπιταλιστική οικονομία, με τον δημόσιο τομέα να συνεισφέρει περίπου στο μισό του Α.Ε.Π.. Ο Τουρισμός αποτελεί μία πολύ σημαντική βιομηχανία, που συνεισφέρει κι αυτή σε μεγάλο ποσοστό του Α.Ε.Π., και επίσης αποτελεί πηγή συναλλάγματος. Το 2004 η μεγαλύτερη βιομηχανία στην Ελλάδα με έσοδα γύρω στα 12 δισ. ευρώ ήταν η συνήθως σχετικά αφανής ναυτιλία.\n" +
+"Η οικονομία βελτιώνεται σταθερά τα τελευταία χρόνια, καθώς η κυβέρνηση εφάρμοσε αποτελεσματική οικονομική πολιτική, στην προσπάθεια της ένταξης της Ελλάδας στην ζώνη του ευρώ, την 1 Ιανουαρίου 2001. Παράγων που σίγουρα βοήθησε σε αυτήν την πορεία είναι ότι η Ελλάδα είναι αποδέκτης οικονομικής βοήθειας από την Ευρωπαϊκή Ένωση, ίσης περίπου με το 3,3% του Α.Ε.Π. Η συνέχιση τόσο γενναιόδωρων ενισχύσεων από την Ε.Ε. όμως είναι υπό αμφισβήτηση. Η διεύρυνση της Ευρωπαϊκής Ένωσης με την είσοδο χωρών πολύ φτωχότερων από την Ελλάδα σε συνδυασμό με την ανοδική πορεία της ελληνικής οικονομίας θα βγάλει πιθανότατα πολλές περιοχές από τον λεγόμενο Στόχο 1 του Κοινοτικού Πλαισίου Στήριξης στον οποίο κατευθύνονται και οι περισσότερες επιδοτήσεις και στον οποίο ανήκουν περιοχές με Α.Ε.Π. κατά κεφαλήν μικρότερο του 75% του ευρωπαϊκού μέσου όρου. Με τα στοιχεία του 2003 από τον Στόχο 1 έχουν βγει οι εξής περιοχές: Αττική, Νότιο Αιγαίο, Στερεά Ελλάδα, Κεντρική Μακεδονία, Βόρειο Αιγαίο και οριακά η Πελοπόννησος.\n" +
+"Μεγάλες προκλήσεις παραμένουν, η μείωση της ανεργίας και η περαιτέρω ανοικοδόμηση της οικονομίας μέσω και της ιδιωτικοποίησης διαφόρων μεγάλων κρατικών εταιρειών, η αναμόρφωση της κοινωνικής ασφάλισης, διόρθωση του φορολογικού συστήματος, και η ελαχιστοποίηση των γραφειοκρατικών αδυναμιών. Η ανάπτυξη υπολογίζεται σε 3,9% για το 2004.\n" +
+"Η εθνική κεντρική τράπεζα του κράτους της Ελλάδας είναι η Τράπεζα της Ελλάδος (ΤτΕ), η οποία όμως έχει παραχωρήσει τις περισσότερες αρμοδιότητές της στην Ευρωπαϊκή Κεντρική Τράπεζα (Ε.Κ.Τ.), μετά την είσοδό της στην ζώνη του ευρώ το 2001.\n" +
+"[Επεξεργασία]\n" +
+"Δημογραφία\n" +
+"\n" +
+"Κύριο άρθρο: Δημογραφία της Ελλάδας\n" +
+"Άρθρο βασικών αποτελεσμάτων απογραφής: Απογραφή 2001\n" +
+"Σύμφωνα με την τελευταία απογραφή (2001)[5] ο μόνιμος πληθυσμός της χώρας είναι 10.934.097 κ. Την ημέρα της απογραφής, στη χώρα βρέθηκαν και απογράφηκαν (πραγματικός πληθυσμός) 10.964.020 κ.\n" +
+"Η Διεθνής Έκθεση για τις Θρησκευτικές Ελευθερίες που συντάσσει κάθε έτος το Υπουργείο Εξωτερικών των Ηνωμένων Πολιτειών, αναφέρει το 2005: «Περίπου 97% των πολιτών αυτοπροσδιορίζονται, τουλάχιστον κατ’ όνομα, ως Ελληνoρθόδοξοι. Υπάρχουν περίπου 500.000-800.000 παλαιοημερολογίτες σε ολόκληρη τη χώρα – υπερ-συντηρητικοί Ορθόδοξοι, οι οποίοι χρησιμοποιούν το Ιουλιανό ημερολόγιο και είναι αφοσιωμένοι στις παραδοσιακές Ελληνορθόδοξες πρακτικές. Η κυβέρνηση δεν τηρεί στατιστικά στοιχεία για τις θρησκευτικές ομάδες. Κατά τη διάρκεια των απογραφών πληθυσμού, οι κάτοικοι δεν ερωτώνται για το θρησκευτικό τους πιστεύω. Οι αρχές υπολογίζουν ότι η Τουρκόφωνη Μουσουλμανική κοινότητα αριθμεί 98.000 άτομα, αλλά, άλλοι υπολογίζουν ότι ο αριθμός αυτός ανέρχεται σε 140.000 άτομα. Τα περισσότερα χριστιανικά μη Ορθόδοξα δόγματα συναπαρτίζονται κατά κύριο λόγο από γηγενείς Έλληνες. Οι Μάρτυρες του Ιεχωβά αναφέρουν ότι έχουν 30.000 περίπου ενεργά μέλη και 50.000 άτομα που έχουν προσχωρήσει στην πίστη. Οι Καθολικοί υπολογίζονται σε 50.000. Οι Προτεστάντες, συμπεριλαμβανόμενων των Ευαγγελιστών, είναι 30.000, και οι οπαδοί της Εκκλησίας του Ιησού Χριστού των Αγίων των Τελευταίων Ημερών (Μορμόνοι) 300. Οι Σαϊεντολόγοι ισχυρίζονται ότι έχουν 500 ενεργά εγγεγραμμένα μέλη. Η από αιώνων υπάρχουσα Εβραϊκή κοινότητα αριθμεί περίπου 5.000 πιστούς, από τους οποίους 2.000 υπολογίζεται ότι διαμένουν στη Θεσσαλονίκη. Περίπου 250 μέλη της κοινότητας των Μπαχάι είναι διασκορπισμένα στην χώρα, τα περισσότερα των οποίων δεν είναι πολίτες ελληνικής καταγωγής. Η αρχαία Ελληνική Θρησκεία του Δωδεκαθέου έχει περίπου 2.000 μέλη. Υπάρχουν ακόμα μικρές ομάδες Αγγλικανών, Βαπτιστών, καθώς και άλλοι Χριστιανοί που δεν ανήκουν σε κάποιο συγκεκριμένο δόγμα. Δεν υπάρχει επίσημη ή ανεπίσημη εκτίμηση ως προς τον αριθμό των αθέων. Η πλειοψηφία των κατοίκων μη ελληνικής υπηκοότητας δεν είναι Ορθόδοξοι. Η μεγαλύτερη από αυτές τις ομάδες είναι Αλβανοί[5], συμπεριλαμβανόμενων των νομίμων και παρανόμων μεταναστών. Αν και οι περισσότεροι Αλβανοί δεν ανήκουν σε κάποια θρησκεία, παραδοσιακά συνδέονται με τη Μουσουλμανική, την Ορθόδοξη, ή τη Ρωμαιοκαθολική πίστη. Εκτός της εντόπιας Μουσουλμανικής μειονότητας στη Θράκη, οι Μουσουλμάνοι μετανάστες που βρίσκονται στην υπόλοιπη χώρα υπολογίζεται ότι ανέρχονται σε 200.000-300.000.» [6]\n" +
+"Τις τελευταίες δεκαετίες η Ελλάδα έχει δεχτεί ένα μεγάλο κύμα μετανάστευσης. Ο συνολικός αριθμός των μεταναστών υπολογίζεται περίπου στο 10% του συνολικού πληθυσμού ή στις 950.000 ανθρώπους. Νόμιμοι κάτοικοι της χώρας είναι περίπου οι μισοί αν και οι αριθμοί έχουν μεγάλη διακύμανση λόγω της έλλειψης επίσημης μεταναστευτικής πολιτικής και της αστάθειας στις γειτονικές χώρες πηγές μεταναστών. Οι μεγαλύτερες πληθυσμιακές ομάδες σύμφωνα με την απογραφή του 2001 φαίνεται να είναι οι προερχόμενοι από Αλβανία, Ρουμανία, Βουλγαρία, Πακιστάν, Ουκρανία, Πολωνία, Αίγυπτο.\n" +
+"Πέρα από τους αλλοδαπούς μετανάστες έχουν έρθει μετά την πτώση του Τείχους και αρκετοί ομογενείς από περιοχές της πρώην Ε.Σ.Σ.Δ. και από τα Βαλκάνια. Οι μεγαλύτερες ομάδες παλιννοστούντων είναι από την Αλβανία, την Ρωσία και την Γεωργία.\n" +
+"[Επεξεργασία]\n" +
+"Ένοπλες δυνάμεις και Σώματα ασφαλείας\n" +
+"\n" +
+"Ελληνικές Ένοπλες Δυνάμεις:\n" +
+"Ελληνικός Στρατός\n" +
+"Ελληνικό Πολεμικό Ναυτικό\n" +
+"Ελληνική Πολεμική Αεροπορία\n" +
+"Σώματα ασφαλείας:\n" +
+"Ελληνική Αστυνομία\n" +
+"Πυροσβεστικό Σώμα\n" +
+"Λιμενικό Σώμα\n" +
+"[Επεξεργασία]\n" +
+"Υποχρεωτική στράτευση\n" +
+"Κύριο άρθρο: Η θητεία στην Ελλάδα\n" +
+"Μέχρι το 2004, η Ελλάδα είχε νομοθετήσει υποχρεωτική θητεία 12 μηνών, για όλους τους άνδρες άνω των 18 ετών. Ωστόσο, κινείται προς την ανάπτυξη ενός πλήρως επαγγελματικού στρατού, με στόχο την πλήρη κατάργηση της θητείας. Το Υπουργείο Εθνικής Άμυνας έχει αναγγείλει τη σταδιακή μείωση στους 6 μήνες το 2008 και πιθανολογείται ότι μπορεί και να καταργηθεί τελείως. Παρότι γίνονται δεκτές αιτήσεις γυναικών που θέλουν να υπηρετήσουν, δεν είναι υποχρεωτικό. Η κίνηση αυτή δημιουργεί αντιρρήσεις από τους κύκλους που αντιτίθενται στην υποχρεωτική στράτευση, γιατί ενώ το Άρθρο 2 του Ελληνικού Συντάγματος θέτει υπόχρεους όλους τους Έλληνες πολίτες να υπερασπιστούν την Ελλάδα, ο φόρτος έγκειται ολοκληρωτικά στον ανδρικό πληθυσμό.\n" +
+"Οι κληρωτοί δεν λαμβάνουν ιατρική ασφάλιση κατά τη διάρκεια της θητείας τους, ούτε ο χρόνος της θητείας συνυπολογίζεται στα χρόνια εργασίας τους που θεμελιώνουν το συνταξιοδοτικό δικαίωμα. Λαμβάνουν, όμως, πλήρη ιατρική και νοσοκομειακή περίθαλψη από τα κατά τόπους στρατιωτικά νοσοκομεία, εφ' όσον αυτά υπάρχουν στον τόπο που υπηρετούν, αλλιώς αναγκάζονται να μεταφερθούν στην Αθήνα. Ο μισθός του κληρωτού είναι συμβολικός (9 ευρώ το μήνα για τους οπλίτες, σμηνίτες, κληρωτούς, 11 ευρώ για τους στρατεύσιμους δεκανείς, υποσμηνίες, υποκελευστές και τους στρατεύσιμους λοχίες, σμηνίες, κελευστές και 600 ευρώ για τους δόκιμους και των τριών σωμάτων). Οι δόκιμοι υπηρετούν 5 μήνες παραπάνω από τους υπόλοιπους συναδέλφους τους. Ο μισθός δεν αρκεί για να καλύψει τα έξοδα των κληρωτών, ιδιαίτερα όταν ένας κληρωτός υπηρετεί μακριά από τον τόπο διαμονής του, με αποτέλεσμα πρακτικά οι κληρωτοί να ζούνε από την οικονομική στήριξη των γονέων τους κατά την διάρκεια της θητείας τους.\n" +
+"[Επεξεργασία]\n" +
+"Πολιτισμός\n" +
+"\n" +
+"Κατάλογος διάσημων Ελλήνων\n" +
+"Ελληνική μυθολογία\n" +
+"Αρχαία ελληνική λογοτεχνία\n" +
+"Ελληνική Αρχιτεκτονική\n" +
+"Ελληνική κουζίνα\n" +
+"Ελληνική Γλώσσα\n" +
+"Ελληνική Μουσική\n" +
+"Ελληνικά Μουσεία\n" +
+"Μέσα Ενημέρωσης\n" +
+"[Επεξεργασία]\n" +
+"Αργίες\n" +
+"Ημερομηνία  Ονομασία        Σχόλια\n" +
+"1 Ιανουαρίου        Πρωτοχρονιά   \n" +
+"6 Ιανουαρίου        Θεοφάνεια       \n" +
+"κινητή  Καθαρά Δευτέρα     έναρξη της Μεγάλης Τεσσαρακοστής\n" +
+"25η Μαρτίου   Ευαγγελισμός της Θεοτόκου και Εθνική Εορτή Εθνική Εορτή για την Επανάσταση του 1821\n" +
+"κινητή  Μεγάλη Παρασκευή  \n" +
+"κινητή  Πάσχα      Ανάσταση του Χριστού\n" +
+"κινητή  Δευτέρα Διακαινησίμου (Δευτέρα του Πάσχα)    Δευτέρα μετά την Ανάσταση\n" +
+"1 Μαΐου  Πρωτομαγιά     \n" +
+"κινητή  Αγίου Πνεύματος    \n" +
+"15 Αυγούστου Κοίμηση της Θεοτόκου   \n" +
+"28η Οκτωβρίου       Επέτειος του Όχι  Εθνική Εορτή (1940)\n" +
+"25 Δεκεμβρίου       Χριστούγεννα         \n" +
+"26 Δεκεμβρίου       Σύναξις Θεοτόκου  \n" +
+"[Επεξεργασία]\n" +
+"Σημειώσεις\n" +
+"\n" +
+"↑ www.destatis.de εκτίμηση πληθυσμού χώρας, 2006\n" +
+"↑ Σύνταγμα της Ελλάδας, άρθρο 30\n" +
+"↑ 3,0 3,1 Σύνταγμα της Ελλάδας, άρθρο 82\n" +
+"↑ 4,0 4,1 4,2 Πηγάζει στη Βουλγαρία\n" +
+"↑ 5,0 5,1 απογραφή 2001\n" +
+"↑ Πηγή: Διεθνής Έκθεση Θρησκευτικής Ελευθερίας του 2005 στην ελληνική και στην αγγλική, Υπουργείο Εξωτερικών των Η.Π.Α.\n" +
+"[Επεξεργασία]\n" +
+"Δείτε επίσης\n" +
+"\n" +
+"Σημαία της Ελλάδας\n" +
+"Κατάλογος γλωσσών της Ελλάδας\n" +
+"Τράπεζα της Ελλάδος\n" +
+"Ονομασίες της Ελλάδας σε διάφορες γλώσσες\n" +
+"Άτλας της Ελλάδας: συλλογή διαφόρων χαρτών της Ελλάδας στα Κοινά (Commons).\n" +
+"Κατάλογος νοσοκομείων της Ελλάδας\n" +
+"[Επεξεργασία]\n" +
+"Εξωτερικές συνδέσεις\n" +
+"\n" +
+"Πρωθυπουργός της Ελλάδας (Γραφείο Πρωθυπουργού)\n" +
+"Βουλή των Ελλήνων\n" +
+"Παράθυρο στην Ελλάδα (χρήσιμες πληροφορίες και σύνδεσμοι για την Ελλάδα)\n" +
+"Παράθυρο στην Ελλάδα (παλαιότερη «έκδοση»)\n" +
+"Ελληνικός Οργανισμός Τουρισμού\n" +
+"Υπουργείο Εξωτερικών\n";
+
+
+var hebrew =
+"היסטוריה של סין\n" +
+"מתוך ויקיפדיה, האנציקלופדיה החופשית\n" +
+"קפיצה אל: ניווט, חפש\n" +
+"\n" +
+"    ערך זה עוסק בההיסטוריה של הישות התרבותית והגאוגרפית במזרח אסיה. אם התכוונתם לההיסטוריה של מדינה המוכרת היום בשם \"סין\", ראו היסטוריה של הרפובליקה העממית של סין.\n" +
+"\n" +
+"בערך זה מופיע גופן מזרח אסייתי\n" +
+"\n" +
+"כדי שתוכלו לראות את הכתוב בערך זה בצורה תקינה, תצטרכו להתקין גופן מזרח אסייתי במחשבכם. אם אינכם יודעים כיצד לעשות זאת, לחצו כאן לקבלת עזרה\n" +
+"\n" +
+"סין הנה התרבות המפותחת והרציפה העתיקה ביותר בעולם, תיעודים כתובים של התרבות נמצאים כבר מלפני 3,500 שנים והסינים עצמם נוקבים במספר 5,000 כמספר שנות קיומה של תרבותם. שושלות השלטון בסין פיתחו לאורך השנים שיטות בירוקרטיה שלטונית שהעניקו לסינים יתרון משמעותי על העמים השבטיים שחיו מסביבם. פיתוח אידאולוגיה למדינה, המבוססת על משנתו הפילוסופית של קונפוציוס (המאה ה-1 לפנה\"ס), יחד עם פיתוח מערכת כתב זמינה לכל (המאה ה-2 לפנה\"ס) חיזקו עוד יותר את התרבות הסינית. מבחינה פוליטית, סין נעה בתנועה מתמדת בין איחוד ופירוד ולעתים גם נכבשה על ידי כוחות זרים אשר מרביתם התמזגו לתוך תרבותה והפכו לחלק בלתי נפרד ממנה. השפעות תרבותיות ופוליטיות אלו שהגיעו מכל קצוות אסיה כמו גם גלי הגירה אל ומחוץ למדינה יצרו יחד את דמותם של התרבות והעם הסיני כפי שהם מוכרים לנו היום.\n" +
+"היסטוריה של סין\n" +
+"\n" +
+"    * התקופה הקדומה\n" +
+"\n" +
+"    שלושת המלכים וחמשת הקיסרים\n" +
+"    שושלת שיה\n" +
+"    שושלת שאנג\n" +
+"    שושלת ג'ואו\n" +
+"    תקופת האביב והסתיו\n" +
+"    תקופת המדינות הלוחמות\n" +
+"\n" +
+"    * סין הקיסרית\n" +
+"\n" +
+"    שושלת צ'ין\n" +
+"    שושלת האן המערבית\n" +
+"    שושלת שין\n" +
+"    שושלת האן המזרחית\n" +
+"    שלושת הממלכות\n" +
+"    שושלת ג'ין\n" +
+"    השושלת הצפונית והדרומית\n" +
+"    שושלת סוי\n" +
+"    שושלת טאנג\n" +
+"    שושלת סונג\n" +
+"    שושלת יו'אן\n" +
+"    שושלת מינג\n" +
+"    שושלת צ'ינג\n" +
+"\n" +
+"    * התפוררות הקיסרות\n" +
+"\n" +
+"    מלחמת האופיום הראשונה\n" +
+"    מרד טאיפינג\n" +
+"    מלחמת האופיום השנייה\n" +
+"    מלחמת סין-צרפת\n" +
+"    מלחמת סין-יפן הראשונה\n" +
+"    רפורמת מאה הימים\n" +
+"    מרד הבוקסרים\n" +
+"\n" +
+"    * סין המודרנית\n" +
+"\n" +
+"    מהפכת שינהאי\n" +
+"    הקמתה של המפלגה הקומניסטית של סין\n" +
+"    המצעד הארוך\n" +
+"    תקרית שיאן\n" +
+"    מלחמת סין-יפן השנייה\n" +
+"    מלחמת האזרחים הסינית\n" +
+"\n" +
+"    * העת החדשה\n" +
+"\n" +
+"    הקמת הרפובליקה העממית של סין\n" +
+"    מערכת מאה הפרחים\n" +
+"    הזינוק הגדול קדימה\n" +
+"    הפיצול הסיני-סובייטי\n" +
+"    מלחמת הודו-סין\n" +
+"    מהפכת התרבות בסין\n" +
+"    תקרית טיאנאנמן\n" +
+"\n" +
+"ראו גם\n" +
+"\n" +
+"    * הרפובליקה הסינית\n" +
+"    * לוח זמנים של ההיסטוריה של סין\n" +
+"\n" +
+"פורטל סין\n" +
+"קטגוריה ראשית\n" +
+"\n" +
+"\n" +
+"תוכן עניינים\n" +
+"[הסתר]\n" +
+"\n" +
+"    * 1 פרה-היסטוריה\n" +
+"          o 1.1 שלושת המלכים וחמשת הקיסרים\n" +
+"    * 2 היסטוריה קדומה\n" +
+"          o 2.1 שושלת שְׂיָה\n" +
+"          o 2.2 שושלת שָׁאנְג\n" +
+"          o 2.3 שושלת ג'וֹאוּ\n" +
+"          o 2.4 תקופת האביב והסתיו\n" +
+"          o 2.5 תקופת המדינות הלוחמות\n" +
+"    * 3 שושלת צ'ין: האימפריה הסינית הראשונה\n" +
+"    * 4 שושלת האן: תקופה של שגשוג\n" +
+"    * 5 ג'ין, שש עשרה הממלכות והשושלות הדרומית והצפונית: התקופה האפלה של סין\n" +
+"    * 6 שושלת טאנג: חזרה לשיגשוג\n" +
+"    * 7 שושלת סונג ושכנותיה הצפוניות, ליאו וג'ין\n" +
+"    * 8 המונגולים\n" +
+"    * 9 תחייתה מחדש של התרבות הסינית\n" +
+"    * 10 תקופת מינג: מהתפתחות לבידוד\n" +
+"    * 11 שושלת צ'ינג\n" +
+"    * 12 הרפובליקה הסינית\n" +
+"    * 13 הרפובליקה העממית של סין\n" +
+"    * 14 ראו גם\n" +
+"    * 15 לקריאה נוספת\n" +
+"    * 16 קישורים חיצוניים\n" +
+"    * 17 הערות שוליים\n" +
+"\n" +
+"[עריכה] פרה-היסטוריה\n" +
+"\n" +
+"העדויות הארכאולוגיות הקדומות ביותר לנוכחות אנושית בסין של ימינו הן של הומו ארקטוס. מחקרים חדשים מגלים כי עמודי האבן שנמצאו באתר שיאוצ'אנגליאנג מתאורכים מבחינה סטרטיגרפית מלפני 1.36 מיליוני שנים. באתר הארכאולוגי שִׂיהוֹאוּדוּ שבמחוז שאנסי נמצאות העדויות הראשונות בעולם לשימוש באש על ידי ההומו ארקטוס, ומתאורכות ללפני 1.27 מיליוני שנים. עם זאת תושביו הנוכחיים של האזור אינם צאצאי אותו הומו ארקטוס, אלא צאצאי הומו סאפיינס שהגיע לאזור מאזור אפריקה רק לפני 65,000 שנים.\n" +
+"\n" +
+"עדויות מוקדמות לחקלאות סינית טיפוסית – גידולי אורז בברכות – מתוארכות לשנת 6,000 לפנה\"ס. בדומה לתרבויות קדומות בכל העולם, הביאה החקלאות לגידול מהיר באוכלוסייה, כיוון שהתבססות על גידולים חקלאיים הבטיחה יכולת שימור המזון ואגירתו לזמן ממושך יותר, וזו הביאה בהדרגה לגידול האוכלוסייה, להתפתחותה התרבותית ולריבוד חברתי.\n" +
+"\n" +
+"בשלהי התקופה הניאוליטית החל עמק הנהר הצהוב בסין לפתח את מעמדו כמרכז תרבותי, כאשר ראשוני הכפרים באזור הופיעו שם. מרבית העדויות למרכז חשוב זה נמצאות באזור העיר שי-אן בסין.\n" +
+"\n" +
+"[עריכה] שלושת המלכים וחמשת הקיסרים\n" +
+"\n" +
+"    ערך מורחב – שלושת המלכים וחמשת הקיסרים\n" +
+"\n" +
+"ספרי ההיסטוריה הקדומים, רשומות ההיסטוריון, שנכתבו על ידי ההיסטורוגרף הסיני סְה-מָה צְ'ייֵן במאה השנייה לפנה\"ס, וספר תולדות החיזרן, שנכתבו במאה הרביעית לפנה\"ס מתארכים את תחילת ההיסטוריה הסינית לתקופת שלושת המלכים וחמשת הקיסרים - 2800 לפנה\"ס. לתקופה זו מאפיינים מיתולוגיים מובהקים. למלכים ולקיסרים תכונות מיסטיות והם מתוארים כשליטים נבונים ובעלי מוסר למופת. אחד מהם, הקיסר הצהוב נחשב לאבי בני ההאן.\n" +
+"\n" +
+"סה-מה צ'יאן כותב כי תחילת ביסוס מערכת ממשלתית נעשה בימי שושלת שיה, וסגנון המערכת הונצח על ידי שושלות שאנג וג'ואו. בתקופת שלושת השושלות האלו, החלה סין לפצוע על שחר ההיסטוריה. מכאן ואילך, עד למאה העשרים, מתוארות תולדות סין לפי השושלות שמשלו בה.\n" +
+"\n" +
+"[עריכה] היסטוריה קדומה\n" +
+"\n" +
+"[עריכה] שושלת שְׂיָה\n" +
+"\n" +
+"    ערך מורחב – שושלת שיה\n" +
+"\n" +
+"שושלת שְׂיָה (סינית: 夏, פיניין: Xià), היא השושלת הראשונה בתולדות סין. שושלת זו התקיימה לפני המצאת הכתב בסין, כך שהעדויות לקיומה מסתמכות על מסמכים מאוחרים יותר ועל ארכאולוגיה. סְה-מָה צְ'ייֵן וספר תולדות החיזרן מתארכים את ימי השושלת לכלפני 4,200 שנה, אולם אין בידינו לאמת את הדברים. 17 מלכים ו-14 דורות מנתה השושלת, שהתחילה בימיו של יוּ'‏ הגדול והסתיימה בימיו של גְ'יֵה איש שְׂיָה, כך על-פי סְה-מָה צְ'ייֵן ומקורות אחרים מתקופת שושלת צ'ין.\n" +
+"\n" +
+"שושלות שאנג וג'ואו התקיימו במקביל לשושלת שיה כבר מתחילתה, אך היו כפופות לה. אורך ימיה של השושלת לא ברור, אך 431 או 471 שנים הן שתי החלופות הסבירות ביותר.\n" +
+"\n" +
+"ארכאולוגים רבים מזהים את שושלת שְׂיָה עם אתר אָרלִיטוֹאוּ שבמרכז מחוז הנאן[1]. באתר זה נתגלה כור היתוך מברונזה משנת 2000 לפנה\"ס לערך. נטען גם כי סימונים על-גבי חרס וקונכיות מתקופה זו הן גילגול קדום של הכתב הסיני[2]. בהיעדר עדויות כתובות בכתב המוכר מעצמות הניחוש של שושלת שאנג ומכלי הברונזה של שושלת ג'ואו, נותר טיבה של שושלת שיה לוט בערפל.\n" +
+"\n" +
+"[עריכה] שושלת שָׁאנְג\n" +
+"\n" +
+"    ערך מורחב – שושלת שאנג\n" +
+"\n" +
+"הרישומים הכתובים העתיקים ביותר בסין נחרטו לצורך הגדת עתידות על עצמות או קונכיות. כתבים אלה, המכונים עצמות ניחוש, מתוארכים למאה ה-13 לפנה\"ס לערך, תקופת שושלת שָׁאנְג (סינית: 商, פיניין: Shāng). ממצאים ארכאולוגיים, המעידים על קיומה של השושלת בשנים 1600-1046 לפנה\"ס בקירוב, מחולקים לשתי קבוצות. הקבוצה המוקדמת, עד ל-1300 בקירוב, מגיעה מאתרים שונים במחוז הנאן. הקבוצה המאוחרת, מתקופת יִין (殷), מורכבת מאסופה רחבה של עצמות ניחוש, גם הן ממחוז הנאן. אָנְיָאנְג שבמחוז הנאן הייתה הבירה התשיעית והאחרונה של שושלת שאנג. לשושלת היו 31 מלכים, והיא הייתה הארוכה שבשושלות סין.\n" +
+"\n" +
+"על פי רשומות ההיסטוריון העבירה שושלת שאנג את בירתה שש פעמים, כשהמעבר השישי והאחרון לעיר יִין ב-1350 לפנה\"ס סימן את תחילת תור הזהב של השושלת. ההיסטוריה התמטית של סין מתארת בדרך-כלל קיום של שושלת אחת אחרי השנייה, אך המצב לאשורו באותה עת היה מורכב יותר. חוקרים טוענים כי ייתכן ושושלות שיה ושאנג התקיימו במקביל, כשם ששושלת ג'ואו (שֶׁירשה את שושלת שאנג), התקיימה אף היא בזמן שושלת שאנג. עדויות כתובות מאתר אניאנג מאששים אמנם את קיומה של שושלת שאנג, אך חוקרים מערביים אינם נוטים לזהות יישובים בני אותה תקופה עם שושלת שאנג דווקא. כך למשל, ממצאים ארכאולוגיים מאותה עת באתר סָאנְשִׂינְגְדְווֵי מצביעים על חברה מתקדמת, השונה בתרבותה מזו שנתגלתה בְּאָנְיָאנְג. אין עדויות מכריעות במוגע לתחום שליטתה של שושלת שאנג. ההנחה המקובלת היא כי שושלת שאנג שבהיסטוריה הרשמית אכן שלטה בעיר אניאנג, תוך שהיא מקיימת קשרי מסחר עם יישובים שונים בסביבתה, שהיו שונים זה מזה מבחינה תרבותית.\n" +
+"\n" +
+"[עריכה] שושלת ג'וֹאוּ\n" +
+"\n" +
+"    ערך מורחב – שושלת ג'ואו\n" +
+"\n" +
+"שושלת ג'וֹאוּ (סינית: 周, פיניין: Zhōu), הייתה השושלת ששלטה את הזמן הארוך ביותר בסין, מ-1122 לפנה\"ס ועד 256 לפנה\"ס - 866 שנה. השושלת התחילה להתגלות בנהר הצהוב והתפשטה אל תוך גבולותיה של השאנג. השושלת התחילה את שליטתה כפיאודליזם. הג'ואו חיו מערבית לשאנג, ושליטם היה מכונה בפיהם של שאנג כ\"מגן המערבי\". שליט ג'ואו המלך ווּ, בעזרת דודו הדוכס של ג'ואו, הצליחו להכניע את אחרון קיסרי שאנג בקרב שקבל את השם הקרב של מויה. היה זה מלכה של ג'ואו באותו הזמן, שטבע את מושג מנדט השמים, רעיון לפיו השמים הם המחליטים מי יהיה הקעסר הבא, ודרכם להביע את זה היא הצלחתו של הקיסר בניהול מלכותו, כך שמרד נתפס כלגיטימי, כל עוד זכה להצלחה. הקיסר העביר את בירתו אל עבר מערב האזור, סמוך למקום המכונה כיום שיאן, לגדות הנהר הצהוב, אולם שליטתם התפרסה אל כל עבר מושבות נהר היאנגטסה. זו הייתה ההגירה הראשונה בגודל כזה מצפון סין לדרומה.\n" +
+"\n" +
+"[עריכה] תקופת האביב והסתיו\n" +
+"\n" +
+"    ערך מורחב – תקופת האביב והסתיו\n" +
+"\n" +
+"תקופת האביב והסתיו (בסינית: 春秋時代) הוא כינויה של תקופה בין השנים 722 לפנה\"ס ל 481 לפנה\"ס. שמה של התקופה לקוח משם הספר רשומות האביב והסתיו, תיעוד היסטורי של אותה תקופה אשר נכתב בידי קונפוציוס.\n" +
+"\n" +
+"במהלך התקופה נערכו מלחמות רבות בין המדינות שהרכיבו באותה תקופה את סין מה שהביא לביזור של הכח השלטוני בסין העתיקה. בעקבות המלחמות הודחו שליטים רבים מכסאם, ושכבת האצולה בסין התפוררה למעשה. עם התפשטותם של האצילים ברחבי הארץ נפוצה איתם גם ידיעת הקרוא וכתוב אשר הייתה נחלתם הכמעט בלעדית של האצילים עד לאותה תקופה. התפשטות הקריאה והכתיבה עודדה את חופש המחשבה וההתפתחות הטכנולוגית. לאחר תקופת האביב והסתיו החלה בסין תקופת מלחמת המדינות.\n" +
+"\n" +
+"[עריכה] תקופת המדינות הלוחמות\n" +
+"\n" +
+"    ערך מורחב – תקופת המדינות הלוחמות\n" +
+"\n" +
+"תקופת המדינות הלוחמות (סינית: 戰國, פיניין: Zhàn Guó) החלה במאה החמישית לפנה\"ס והסתיימה בשנת 221 לפנה\"ס באיחודה של סין על ידי שושלת צ'ין. רשמית, בתקופת המדינות הלוחמות, כמו גם בתקופה שקדמה לה, תקופת האביב והסתיו, הייתה סין תחת שלטונה של שושלת ג'וֹאוּ המזרחית, אך שליטה זו הייתה רק להלכה, ולשושלת לא הייתה השפעה ממשית, ולמעשה חדלה להתקיים 35 שנה לפני סיומה הרשמי של התקופה. את שמה קיבלה התקופה מ\"רשומות המדינות הלוחמות\", תיעוד היסטורי של התקופה, שנכתב בתקופת שושלת האן.\n" +
+"\n" +
+"תקופת המדינות הלוחמות, שלא כמו תקופת האביב והסתיו, הייתה תקופה בה שרי צבא ואריסטוקרטים מקומיים סיפחו לאחוזותיהם כפרים, ערים ומדינות זעירות סמוכות והשליטו עליהם את שלטונם. במאה השלישית לפנה\"ס הביא מצב זה ליצירת שבע מדינות עיקריות בסין: מדינות צִ'י (齊), צ'וּ (楚), יֵן (燕), הַאן (韓), גָ'או (趙), ווֶי (魏) וצִ'ין (秦). סימן נוסף לשינוי במעמדם של הגנרלים היה שינוי תארם הרשמי מגונג (公 - המקבילה הסינית לדוכס), הכפופים כביכול למלך של ג'ואו, לוואנג (王) - מלכים, השווים במעמדם למלך של ג'ואו.\n" +
+"\n" +
+"תקופת המדינות הלוחמות היא גם תחילתו של השימוש בברזל במקום ארד בסין כמתכת עיקרית בכל תחומי החיים האזרחיים והצבאיים. במהלך תקופה זו החלו להבנות החומות, שיגנו על הממלכות מפני פלישה של שבטים ברבריים מהצפון חומות, שהיוו את היסוד לחומה הסינית המאוחרת יותר. מאפיין תרבותי נוסף של התקופה היה הפיכתן של פילוסופיות שונות כגון קונפוציזם, דאואיזם, לגאליזם, ומוהיזם למעמד של דתות במדינות השונות.\n" +
+"\n" +
+"בתום התקופה, לאחר שממלכת צ'ין הצליחה להביס ולכבוש את שאר הממלכות, הפך המלך צ'ין לקיסר הראשון של סין המאוחדת.\n" +
+"\n" +
+"[עריכה] שושלת צ'ין: האימפריה הסינית הראשונה\n" +
+"\n" +
+"    ערך מורחב – שושלת צ'ין\n" +
+"\n" +
+"סין אוחדה לראשונה בשנת 212 לפנה\"ס בידי צִ'ין שְׁה-חְוָאנג, מייסד שושלת צ'ין. קדמה לאיחוד תקופת מלחמת המדינות ותקופת האביב והסתיו, שהתאפיינו שתיהן במספר ממלכות שהתקיימו במקביל ולחמו זו בזו. בשנת 212 לפנה\"ס עלה בידו של צ'ין להשתלט סופית על כל הממלכות בסין העתיקה ולשים קץ למלחמות הפנימיות.\n" +
+"\n" +
+"למרות שהאימפריה המאוחדת של הקיסר צ'ין התקיימה רק 12 שנים, הצליח הקיסר בזמן מועט זה למסד את רוב שטחה של המדינה כפי שאנו מכירים אותה כיום ולהשליט בה משטר ריכוזי המבוסס על לגאליזם אשר מושבו היה בשיאניאנג, שיאן של ימינו. שושלת צ'ין מפורסמת גם בשל תחילת בנייתה של החומה הסינית הגדולה (החומה הוגדלה בתקופת שושלת מינג). בניו של הקיסר לא היו מוצלחים כמוהו, ועם מותו של הקיסר תמה תקופת שלטונה של שושלתו.\n" +
+"\n" +
+"מקור המילה סין בשפה העברית וכן בשפה האנגלית (China), מגיע ככל הנראה מהמילה צ'ין (秦), שמה של השושלת הראשונה.\n" +
+"\n" +
+"[עריכה] שושלת האן: תקופה של שגשוג\n" +
+"\n" +
+"    ערך מורחב – שושלת האן\n" +
+"\n" +
+"שושלת האן הופיעה בסין בשנת 202 לפנה\"ס. בתקופת שלטונה הפכה הקונפוציוניזם לדת המדינה ולפילוסופיה המנחה אותה ואשר המשיכה להנחות את המשטר הסיני עד לסוף התקופה הקיסרית בתחילת המאה ה-20. תחת שלטון ההאן עשתה התרבות הסינית התקדמות אדירה בתחומי ההיסטוריוגפיה, האומנות והמדע. הקיסר וו חיזק והרחיב את הממלכה בהודפו את ה\"שׂיוֹנג-נוּ\" (שבטים שלעתים מזוהים עם ההונים) אל תוך מונגוליה של ימינו, תוך שהוא מספח לממלכתו את השטחים בהם ישבו שבטים אלו. שטחים חדשים אלו אפשרו לסין לראשונה לפתוח קשר מסחר עם המערב: דרך המשי.\n" +
+"\n" +
+"אולם, השתלטותן של משפחות אצולה על אדמות המדינה, עירערה את בסיס המיסוי של הממלכה, גורמות בכך חוסר יציבות שלטוני. חוסר היציבות הזה נוצל על ידי וואנג מנג, שהקים את שושלת שין שהחזיקה מעמד זמן קצר מאוד. וואנג החל לבצע רפורמות ענפות בהחזקת האדמות ובכלכלה. תומכיה העיקריים של הרפורמה היו האיכרים ובני המעמדות הנמוכים, אך משפחות האצולה שהחזיקו באדמות, התנגדות להן בכל תוקף. עקב כך נוצא מצב של כאוס והתקוממויות רבות במדינה. צאצאה של שושלת האן, הקיסר גואנגוו, ייסד מחדש את שושלת האן בתמיכתם של משפחות האצילים והסוחרים בלוו-יאנג, מזרחית לשיאן, מכאן קיבל העידן החדש שהחל אז את שמו: שושלת האן המזרחית. אולם ייסודה מחדש של השושלת לא הביא את השקט הרצוי לממלכה. עימותים עם בעלי הקרקעות, יחד עם פלישות מבחוץ ומאבקים פנימיים במיעוטים החלישו שוב את השלטון. מרד הטורבן הצהוב שפרץ בשנת 184, סימן את תחילתו של עידן בו שליטים צבאיים מובילים מלחמות בתוך המדינה ומחלקים את המדינה למספר מדינות קטנות. תקופה זו ידועה כתקופת שלוש הממלכות.\n" +
+"\n" +
+"[עריכה] ג'ין, שש עשרה הממלכות והשושלות הדרומית והצפונית: התקופה האפלה של סין\n" +
+"\n" +
+"    ערך מורחב – שושלת ג'ין\n" +
+"\n" +
+"שלוש הממלכות התאחדו בשנת 280 תחת שלטונה של שושלת ג'ין. אולם איחוד זה נמשך זמן קצר מאוד. בתחילת המאה ה-4 החלו המיעוטים בסין (כיום מכונים סינים לא בני האן ) להתמרד ולבתר את המדינה, גורמים בכך להגירה עצומה של סינים בני האן אל מדרום לנהר היאנגטסה. בשנת 303 החלו אנשי מיעוט הדאי במרד שבסופו הם כבשו את צ'נגדו שבסצ'ואן. השׂיוֹנְג-נוּ, שנהדפו מסין בתחילת שלטונה של שושלת האן, חזרו להלחם בסין, כבשו חלקים ממנה והוציאו להורג את שני קיסריה האחרונים של שושלת ג'ין. יותר משש-עשרה מדינות הוקמו על ידי המיעוטים האתניים בצפונה של סין. הצפון הכאוטי אוחד לזמן קצר על ידי פו ג'יאן, אך הוא הובס בנסיון פלישתו לדרום סין וממלכתו התפוררה. נסיון נוסף לאיחוד הצפון בוצע על ידי הקיסר טאיוון, שהקים את השושלות הצפוניות, סדרה של משטרים מקומיים ששלטו בסין שמצפון לנהר היאנג צה.\n" +
+"\n" +
+"עם הפליטים שנסו לדרומה של המדינה, היה גם הקיסר יואן, נצר לשושלת ג'ין, שחידש את שלטון השושלת בדרום המדינה . שושלת זו הייתה הראשונה מבין השושלות הדרומיות שכללו את שושלות סונג, צי, ליאנג וצ'ן. בירתן של השושלות הדרומיות הייתה ג'יאנקאנג, ליד ננג'ינג של ימינו. התקופה בה התקיימו במקביל שתי מדינות הנשלטות על ידי שושלות שונות בצפונה ובדרומה של הארץ נקראה תקופת השושלות הצפונית והדרומית. שושלת סוי קצרת המועד, הצליחה לאחד את המדינה ב589 לאחר כמעט 300 שנות פירוד.\n" +
+"\n" +
+"[עריכה] שושלת טאנג: חזרה לשיגשוג\n" +
+"\n" +
+"    ערך מורחב – שושלת טאנג\n" +
+"\n" +
+"בשנת 618 נוסדה שושלת טאנג, פותחת עידן חדש של שיגשוג וחידושים בתחומי האמנות והטכנולוגיה. בתקופה זו פעלו משוררים נודעים כלי באי ודו פו. הבודהיזם, שהחל חודר לסין כבר במאה ה-1, הוכרז כדת הרשמית של המדינה ואומץ על ידי המשפחה הקיסרית. צ'אנג-אן (שיאן של ימינו), בירת השושלת הייתה באותה תקופה העיר הגדולה ביותר בעולם. תקופות טאנג והאן נחשבות לרוב כתקופות השגשוג הממושכות ביותר בהיסטוריה של סין. אולם, על אף השגשוג, כוחה של שושלת טאנג החל להחלש והמדינה החלה נקרעת בשנית בידי שליטים מקומיים. תקופה נוספת של כאוס הגיעה למדינה: תקופת חמש השושלות ועשר הממלכות.\n" +
+"\n" +
+"[עריכה] שושלת סונג ושכנותיה הצפוניות, ליאו וג'ין\n" +
+"\n" +
+"    ערך מורחב – שושלת סונג\n" +
+"\n" +
+"בשנת 960 הצליחה שושלת סונג לאסוף מספיק כח כדי לאחד את סין תחת שלטונה. תחת שלטון סונג, שבירתו הייתה קאיפנג, החלה תקופת צמיחה חדשה בסין. אולם שושלת סונג לא הייתה הכח הפוליטי הגדול היחיד באזור. במנצ'וריה ובמזרח מונגוליה התהוותה ממלכתה של שושלת ליאו החיטאנית וב1115 עלתה לשלטון במנצ'וריה שושלת ג'ין הג'ורצ'נית (הג'ורצ'נים היו אבותיהם של המנצ'ורים) שתוך 10 שנים בלעה את שושלת ליאו לתוכה. שושלת ג'ין השתלטה גם על שטחים בצפון סין, בתוכם הבירה הסינית קאיפנג, מה שאילץ את שושלת סונג הסינית להעביר את בירתה לחאנגג'ואו. שושלת סונג גם אולצה על ידי שושלת ג'ין להכריז על הכרתה בשושלת ג'ין כשליטה העליונה שלה. בתקופה שלאחר מכן הוקמו שלוש ממלכות גדולות בשטחה של סין (ממלכת סונג, ממלכת ג'ין וממלכה שלישית של מיעוטים שנקראה ממלכת שיה המערבית). בתקופה זו נעשו פיתוחים משמעותיים בטכנולוגיה, ככל הנראה עקב הלחץ הצבאי שהופעל על ממלכת סונג מצד שכנותיה הצפוניות.\n" +
+"\n" +
+"[עריכה] המונגולים\n" +
+"\n" +
+"ממלכת ג'ין הייתה הראשונה מבין הממלכות בסין שהובסה על ידי המונגולים, שהמשיכו וכבשו גם את ממלכת סונג במלחמה ארוכה ועקובה מדם שהייתה המלחמה הראשונה בהיסטוריה בה נעשה שימוש מכריע בנשק חם. לאחר תום המלחמה החל עידן של שלום כמעט בכל אסיה (שהייתה נתונה לשלטון המונגולים), עידן שנקרא \"השלום המונגולי\" (Pax Mongolica). שלום זה איפשר לנוסעים מהמערב, דוגמת מרקו פולו, להגיע לסין ולחשוף לראשונה את אוצרתיה למערב. בסין, נחלקו המונגולים בין אלו שרצו להחיל בסין את מנהגי המונגולים ובין אלו שרצו לאמץ את המנהגים הסינים לעצמם. קובלאי חאן, שנמנה עם הקבוצה השנייה, הקים בסין את שושלת יואן (מילולית: \"השושלת הראשונה\") זו הייתה הממלכה הראשונה שהשתרעה על כל שטחה של סין ושבירתה הייתה בייג'ינג (בייג'ינג הייתה בירתה של שושלת גי'ן אך השושלת לא שלטה על סין כולה).\n" +
+"\n" +
+"[עריכה] תחייתה מחדש של התרבות הסינית\n" +
+"\n" +
+"בקרב העם בסין, הייתה התמרמרות רבה ביחס לשלטון ה\"זרים\" החדש, התמרמרות שלבסוף הובילה להתקוממויות איכרים במדינה שהתפתחו למאבק בשלטון שנדחף למעשה אל מחוץ לגבולותיה של סין. את השלטון המונגולי החליף שלטונה של שושלת מינג בשנת 1368. שושלת זו פתחה תקופה של פריחה והתחדשות תרבותית: האומנות, ובעיקר תעשיית הפורצלן, נסקה לגבהים שלא נודעו קודם לכן, סחורות סיניות נעו ברחבי האוקיינוס ההודי, מגיעות עד לחופיה המזרחיים של אפריקה במסעותיו של צ'נג חה. סין בנתה צי ספינות שהגדולות מבניהן שינעו 1,500 טונות של סחורות וחיילים מהצבא בן מיליון החיילים שהיה ברשותה באותה העת. יותר מ100,000 טונות ברזל יוצרו כל שנה וספרים רבים נדפסו. יש הטוענים כי שהאומה הסינית בתקופת מינג הייתה האומה המתקדמת ביותר בעולם.\n" +
+"\n" +
+"הקיסר חונג-וו, מייסד השושלת, הניח את היסודות לנטייתה של המדינה למעט במסחר ותעשייה ולהתמקד בעיקר בהגדלת הרווחים מהמגזר החקלאי, כנראה בשל מוצאו החקלאי של הקיסר. חברות פאודליות זעירות שהתפתחו במהלך שנות שלטונם של שושלת סונג ושל המונגולים פורקו ואדמותיהם הולאמו, חולקו והושכרו לאיכרים מחדש. כמו כן, הוטל חוק האוסר החזקת עבדים במדינה. החוקים נגד מסחר נשארו בממלכה עוד מתקופת שושלת סונג, אך כעת הם חלו גם על סוחרים זרים מה שהביא במהרה לגוויעת סחר החוץ בין סין לשאר העולם.\n" +
+"\n" +
+"ככל שחלף הזמן, שלטון הקיסר נעשה חזק יותר ויותר על אף שהחצר הקיסרית עשתה שימוש נרחב בפקידים ממשלתיים שהיו אחראיים לתפקודה השוטף של המדינה.\n" +
+"\n" +
+"במהלך שלטון המונגולים פחתה האוכלוסייה בכ-40% לכ-60 מיליון נפש. שתי מאות מאוחר יותר המספר הוכפל. הערים החלו להתפתח בקצב מואץ ובעקבות כך החלה להופיע גם תעשייה זעירה. כתוצאה מהתערבות שלטונית, נמנעה בסין התפתחותו של מרכז אורבני מצומצם ובמקום זאת צמחו מספר רב של ערים שהיוו מרכזים מקומיים לאזורים המקיפים אותן.\n" +
+"\n" +
+"[עריכה] תקופת מינג: מהתפתחות לבידוד\n" +
+"\n" +
+"    ערך מורחב – שושלת מינג\n" +
+"\n" +
+"למרות הסלידה ממסחר עם מדינות אחרות, וההתרכזות הפנימית בענייני המדינה, סין תחת שלטונה של שושלת מינג לא הייתה מבודדת. הסחר עם מדינות אחרות, ובעיקר עם יפן, המשיך להתקיים והקיסר יונגלה השתדל ככל יכולתו למסד קשרים דיפלומטיים עם המדינות הסובבות את סין. צבאה של סין כבש את אנאם והצי הימי שלה הפליג במסעותיו עד לחופי אפריקה. הסינים גם הצליחו לייצר השפעה מסוימת בטורקסטן.\n" +
+"\n" +
+"אחת הדרכים המרשימות ביותר בהן התבטאה מדיניות החוץ הסינית של אותה תקופה הייתה מסעותיו הימיים של צ'אנג חֶה, סריס מוסלמי ונצר למשפחה מונגולית, אשר הוביל שבעה מסעות ימיים מפוארים בין 1405 ל1433 שעברו בכל האוקיינוס ההודי והאיים שבו והגיעו עד לכף התקווה הטובה. מסעו הראשון של הה, כלל 62 ספינות שנשאו 28,000 מלחים – ללא ספק המסע הימי הגדול ביותר בהיסטוריה האנושית.\n" +
+"\n" +
+"אולם, לקראת סופה של המאה ה-15, הוטל איסור על אזרחי המדינה לבנות ספינות בעלות כושר הפלגה באוקיינוס וכן נאסר על כלל האזרחים לעזוב את המדינה. כיום קיימת הסכמה על כך שצעד זה ננקט כדי להגן על הקיסרות מפני התקפות של שודדי ים. הגבלות אלו בוטלו לבסוף באמצע המאה ה-17.\n" +
+"\n" +
+"[עריכה] שושלת צ'ינג\n" +
+"\n" +
+"    ערך מורחב – שושלת צ'ינג\n" +
+"\n" +
+"השושלת הקיסרית האחרונה בסין, נוסדה ב1644 כאשר המנצ'ורים כבשו את המדינה, הדיחו מהשלטון את שושלת מינג המקומית והקימו את שושלת צ'ינג שבירתה בייג'ינג. במשך חצי מאה נלחמו המנצ'ורים מלחמות עקובות מדם שבמהלכן השתלטו על האזורים שהיו בשליטת שושלת מינג ובכללם מחוז יונאן המרוחקת, טיבט ומונגוליה. את ההצלחה לה זכו המנצ'ורים בתחילת תקופת שלטונם יש לזקוף לזכות כוחם הצבאי האדיר והמיומן ששולב עם מיומנויות בירוקרטיות סיניות.\n" +
+"\n" +
+"חלק מההיסטוריונים רואים בתקופה של תחילת שלטון צ'ינג המשך רציף להתדרדרות התרבותית שחלה בסוף תקופת מינג. אך יש כאלה הרואים בתחילת שלטון צ'ינג תקופה של שיגשוג יותר מאשר נסיגה. בהוראת הקיסר קנגשי נכתב המילון המקיף והמפורט ביותר לשפה הסינית שנכתב עד אז ותחת שלטונו של הקיסר קיאנלונג חובר הקטלוג המלא של כל העבודות החשובות של התרבות הסינית. שושלת צ'ינג גם המשיכה בהרחבת אוצר הספרות העממית ובפיתוח החקלאות תוך יבוא גידולים חדשים מהעולם החדש דוגמת התירס. גם צמיחת האוכלוסייה המשיכה להאיץ בתקופת צ'ינג ואוכלוסיית המדינה, שבשנת 1700 מנתה 100 מיליון נפש, הגיעה לכדי 220 מליון בשנת 1800.\n" +
+"\n" +
+"\n" +
+"בקריקטורה צרפתית מפורסמת זו, נראית חלוקתה של סין בין בריטניה, גרמניה, רוסיה, צרפת ויפן\n" +
+"בקריקטורה צרפתית מפורסמת זו, נראית חלוקתה של סין בין בריטניה, גרמניה, רוסיה, צרפת ויפן\n" +
+"\n" +
+"במהלך המאה ה-19, נחלשה שליטתה של שושלת צ'ינג במדינה והשגשוג שהיה בה התפוגג. סין סבלה מרעב קשה, התפוצצות אוכלוסין וחדירה בלתי פוסקת של מדינות המערב בנסיון להשיג לעצמן השפעה במדינה. שאיפתה של בריטניה להמשיך בסחר הבלתי חוקי באופיום, נתקל בהתנגדות עזה של המשטר הקיסרי, מה שהביא לפריצתה של מלחמת האופיום הראשונה ב1840. סין, שהפסידה במלחמה, אולצה לבצע ויתורים כואבים ולפתוח את נמליה לסחר חפשי עם מדינות המערב. ויתוריה הטריטוריאלים של סין כללו את העברת הונג קונג לידיה של בריטניה ב1842 כחלק מחוזה נאנג'ינג. בנוסף מרד טאי פינג (1864-1851) ומרד ניאן (1868-1853), יחד עם תנועות לאומיות מוסלמיות ששאפו לעצמאות וחוזקו על ידי רוסיה ייבשו את קופת המדינה וכמעט שהביאו לנפילת השלטון בה.\n" +
+"\n" +
+"המרידות בשלטון דוכאו בעיקר על ידי כוחות המערב שבאותו הזמן עשו במדינה כבשלהם וניצלו את שווקיה ואת מערכתה הכלכלית.\n" +
+"\n" +
+"לאחר שוך המהומות בשנות השישים של המאה ה-19, החלה שושלת צ'ינג לטפל בבעיות המודרניזציה במדינה על ידי ביצוע רפורמות בכל תחומי שליטתה. אבל, הקיסרית האלמנה צישי, יחד עם גורמים שמרניים במדינה, ביצעה מעין הפיכה והדיחה את הקיסר הצעיר מהשלטון, מורידה בכך לטמיון את הרפורמות שאך החלו להתבצע. הרפורמות הצבאיות, שהושארו על כנן, היו חסרות ערך עקב השחיתות האיומה שהתפשטה בצמרת השלטון. חלק מספינות הקרב החדישות של הצבא כלל לא יכלו לבצע ירי, וזאת עקב מעילות גדולות בתקציבי בנייתן שלא השאירו די כסף לרכישת אבק שריפה. כתוצאה מכך כוחות \"הצבא הסיני החדש\" נחלו תבוסות משפילות הן במלחמת סין-צרפת (1885-1883) והן במלחמת סין-יפן הראשונה (1895-1894)\n" +
+"\n" +
+"עם תחילתה של המאה ה-20, הייתה החצר הקיסרית בסין הרוסה, שחיתות הייתה בכל והאוכלוסייה גדלה בקצב בלתי ניתן לעצירה. המדינה נשלטה על ידי הקיסרית צישי, דמות שמרנית ביותר שהתנגדה לכל סוג של רפורמה. מותו של הקיסר גוואנגשו יום אחד לפני מותה של הקיסרית (יש הטוענים שהוא הורעל על ידה) הרס את הסיכוי האחרון לביסוס הנהגה אפקטיבית במדינה.\n" +
+"\n" +
+"[עריכה] הרפובליקה הסינית\n" +
+"\n" +
+"    ערך מורחב – היסטוריה של הרפובליקה הסינית\n" +
+"\n" +
+"ביאושם מאוזלת ידו של השלטון, החלו פקידי ממשל צעירים, קציני צבא וסטודנטים, שהושפעו מרעיונותיו המהפכניים של סון יאט-סן להתארגן לקראת הפיכה במדינה שתסלק את שושלת צ'ינג מהשלטון ותהפוך את המדינה לרפובליקה. התקוממות ווצ'אנג, התקוממות מהפכנית צבאית, החלה ב10 באוקטובר 1911. כחצי שנה מאוחר יותר, ב12 בפברואר 1912 הוקמה הממשלה הזמנית של הרפובליקה הסינית בנאנג'ינג כשבראשה עומד סון יאט-סן כנשיאה הזמני. אך סון נאלץ לוותר על תפקידו לטובת יואן שיקאי אשר פיקד באותו הזמן על \"הצבא החדש\" והיה ראש הממשלה תחת שלטון צ'ינג, כחלק מהסכם שנחתם להדחת הקיסר האחרון – הילד הנרי פו-יי. בשנים שלאחר הכתרתו כנשיא, ניסה יואן שיקאי לעקוף את סמכויותיהן של הוועדות הפרובינציאליות של הרפובליקה ואף הכריז על עצמו קיסר ב1915. שאיפותיו הקיסריות של יואן נתקלו בהתנגדות עזה של המהפכנים שראו כיצד מהפכתם הולכת לכינונה מחדש של קיסרות במדינה ולא של רפובליקה, והם החלו מתמרדים נגד יואן עד למותו ב1916 שהשאיר ריק שלטוני בסין. סין שלאחר מותו של יואן נחלקה בין הממשל הרפובליקני החדש, ובין מצביאים מקומיים ששלטו באזוריהם עוד מתקופת צ'ינג.\n" +
+"\n" +
+"לאירוע חסר החשיבות (בעיני המעצמות מחוץ לסין) שהתרחש ב1919 הייתה השלכה מכריעה על המשך ההיסטוריה הסינית במאה ה-20, אירוע זה הוא תנועת הארבעה במאי. התנועה, שהוציאה שם רע לפילוסופיות המערביות המקובלות והאימוץ של קוי מחשבה קיצוניים יותר שבאו לאחר מכן זרעו את הזרעים לקונפליקט בלתי ניתן לגישור בין הימין והשמאל בסין, קונפליקט שהמשיך עד לסופה של המאה.\n" +
+"\n" +
+"ב1920, הקים סון יאט-סן בסיס לתנועתו המהפכנית בדרום סין, אשר ממנו הוא יצא לאיחוד האומה השסועה. בעזרתם של הסובייטים, הוא הקים ברית עם המפלגה הקומוניסטית הסינית, ברית שלחמה בשאריות המשטר הקיסרי שהיו מפוזרות בצפון המדינה. לאחר מותו של סון ב1925 השתלט יורשו צ'יאנג קאי שק על המפלגה הלאומנית (הקוומינטנג) והצליח לאחד תחת שלטונו את מרבית דרום המדינה ומרכזה במערכה צבאית שנקראה המשלחת הצפונית. לאחר שהצליח להביס גם את תומכי הקיסר בצפון, פנה צ'יאנג למלחמה באנשי המפלגה הקומוניסטית, שעד לאותה תקופה נלחמו יחד איתו. הקומוניסטים פרשו מהקוומינטנג ב1927 וברחו להרים שבדרום סין. ב1934 יצאו הקומוניסטים מההרים שבשליטתם (שם הקימו את הרפובליקה הסינית-סובייטית) למצעד הארוך, מסע צבאי מפרך באזורים הטרשיים ביותר במדינה אל עבר צפון מערבה של המדינה לפרובינציית שאאנסי שם הקימו לעצמם בסיסי לוחמת גרילה.\n" +
+"\n" +
+"במהלך המצעד הארוך, הכירו הקומוניסטים במנהיגם החדש מאו צה דונג. המאבק בין הקוומינטנג והמפלגה הקומוניסטית הסינית נמשך לעתים בגלוי ולעתים בחשאי תוך כדי מלחמת סין-יפן השנייה (1945-1931) על אף שהכוחות יצרו לכאורה חזית מאוחדת כנגד פלישת היפנים ב1937 כחלק ממלחמת העולם השנייה. הלחימה בין שתי המפלגות המשיכה לאחר תבוסתם של היפנים ב-1945, וב-1949 שלטו הקומוניסטים ברוב שטחה של המדינה.\n" +
+"\n" +
+"[עריכה] הרפובליקה העממית של סין\n" +
+"\n" +
+"    ערך מורחב – היסטוריה של הרפובליקה העממית של סין\n" +
+"\n" +
+"פרק זה לוקה בחסר. אתם מוזמנים לתרום לוויקיפדיה ולהשלים אותו. ראו פירוט בדף השיחה.\n" +
+"\n" +
+"צ'יאנג קאי שק נמלט עם שאריות ממשלתו וצבאו לטיוואן שם הוא הכריז על טייפה כבירה הזמנית של הרפובליקה עד להשלמת הכיבוש מחדש של סין היבשתית על ידי כוחותיו. הרפובליקה הסינית ממשיכה להתקיים עד ימינו (סוף 2004) בטיוואן אך היא טרם הכריזה עצמאות והיא אינה מוכרת רשמית כמדינה על ידי שאר העולם.\n" +
+"\n" +
+"עם ההכרזה על הקמתה של הרפובליקה העממית של סין ב1 באוקטובר 1949, חולקה סין שוב לרפובליקה העממית של סין בסין היבשתית ולרפובליקה הסינית שישבה בטיוואן ובמספר איים קטנים בסביבה, כאשר לכל רפובליקה יש ממשלה הרואה בעצמה את הממשלה הסינית האמיתית והמתייחסת אל הממשלה האחרת בבוז ובביטול. מצב זה נמשך עד לשנות התשעים של המאה ה-20, כאשר שינויים פוליטים ברפובליקה הסינית הביאו אותה להפסקת הטענה הפומבית להיותה ממשלת סין היחידה.\n" +
+"\n" +
+"[עריכה] ראו גם\n" +
+"\n" +
+"    * לוח זמנים של ההיסטוריה של סין – טבלה המתארת את האירועים והאישים החשובים בתולדותיה של סין.\n" +
+"\n" +
+"[עריכה] לקריאה נוספת\n" +
+"\n" +
+"    * עמנואל צ' י' שו, צמיחתה של סין המודרנית, הוצאת שוקן, 2005.\n" +
+"\n" +
+"[עריכה] קישורים חיצוניים\n" +
+"\n" +
+"    * ירדן ניר-בוכבינדר, סין אימנו, קונפוציוס אבינו, באתר \"האייל הקורא\"\n" +
+"\n" +
+"\n" +
+"[עריכה] הערות שוליים\n" +
+"\n" +
+"   1. ^ סין של תקופת הברונזה בגלריה הלאומית לאמנות של ארצות-הברית\n" +
+"   2. ^ כתב על חרסים מאתר ארליטואו (כתוב בסינית מפושטת)\n";
+
+
+var japanese =
+"中国の歴史\n" +
+"出典: フリー百科事典『ウィキペディア(Wikipedia)』\n" +
+"移動: ナビゲーション, 検索\n" +
+"中国歴史\n" +
+"中国の歴史\n" +
+"元謀・藍田・北京原人\n" +
+"神話伝説(三皇五帝)\n" +
+"黄河・長江文明\n" +
+"夏\n" +
+"殷\n" +
+"周   西周\n" +
+"東周        春秋\n" +
+"戦国\n" +
+"秦\n" +
+"漢   前漢\n" +
+"新\n" +
+"後漢\n" +
+"三国        魏     呉     蜀\n" +
+"晋   西晋\n" +
+"東晋        十六国\n" +
+"南北朝     宋     北魏\n" +
+"斉\n" +
+"梁   西魏  東魏\n" +
+"陳   北周  北斉\n" +
+"隋\n" +
+"唐\n" +
+"五代十国\n" +
+"宋   北宋  遼     西夏\n" +
+"南宋        金\n" +
+"元\n" +
+"明   北元\n" +
+"後金        南明  大順\n" +
+"清\n" +
+"中華民国\n" +
+"中華人民共和国         (参考:\n" +
+"台湾問題)\n" +
+"\n" +
+"中国の歴史(ちゅうごくのれきし)、或いは中国史(ちゅうごくし)\n" +
+"\n" +
+"中国の黄河文明は古代の四大文明の一つに数えられ、また黄河文明よりも更に遡る長江文明が存在した。\n" +
+"目次\n" +
+"[非表示]\n" +
+"\n" +
+"    * 1 王朝、政権の変遷\n" +
+"    * 2 概略\n" +
+"          o 2.1 先史人類史\n" +
+"          o 2.2 文明の萌芽\n" +
+"                + 2.2.1 黄河文明\n" +
+"                + 2.2.2 長江文明\n" +
+"                + 2.2.3 その他\n" +
+"          o 2.3 先秦時代\n" +
+"                + 2.3.1 三代\n" +
+"                + 2.3.2 春秋戦国\n" +
+"          o 2.4 秦漢帝国\n" +
+"          o 2.5 魏晋南北朝時代\n" +
+"          o 2.6 隋唐帝国\n" +
+"          o 2.7 五代十国・宋\n" +
+"          o 2.8 モンゴル帝国\n" +
+"          o 2.9 明清帝国\n" +
+"          o 2.10 中国の半植民地化\n" +
+"          o 2.11 中華民国\n" +
+"                + 2.11.1 革命後の中国の政局\n" +
+"                + 2.11.2 袁世凱の台頭と帝制運動(1913年~1916年)\n" +
+"                + 2.11.3 袁世凱死後の政局(1916年~1920年)\n" +
+"                + 2.11.4 国民革命(1920年~1928年)\n" +
+"                + 2.11.5 国民政府(1928年~1931年)\n" +
+"                + 2.11.6 抗日戦争(1931年~1937年)\n" +
+"                + 2.11.7 日中戦争(1937年~1945年)\n" +
+"                + 2.11.8 漢民族以外の民族の動向\n" +
+"                      # 2.11.8.1 モンゴルとチベットでの動き\n" +
+"                      # 2.11.8.2 東トルキスタン(新疆)での動き\n" +
+"          o 2.12 中華人民共和国\n" +
+"                + 2.12.1 社会主義国化と粛清(1949年~1957年)\n" +
+"                + 2.12.2 中国共産党の対ソ自立化(1958年~1965年)\n" +
+"                + 2.12.3 文化大革命前期(1966年~1969年)\n" +
+"                + 2.12.4 文化大革命後期(1969~1976年)\n" +
+"                + 2.12.5 改革開放以後の現在(1976年~)\n" +
+"                      # 2.12.5.1 一党独裁\n" +
+"                      # 2.12.5.2 少数民族問題\n" +
+"    * 3 人口の変遷\n" +
+"    * 4 地方行政制度\n" +
+"          o 4.1 封建制度(前1600年頃~前221年)\n" +
+"          o 4.2 郡県制度(前221年~249年)\n" +
+"          o 4.3 軍府による広域行政(249年~583年)\n" +
+"          o 4.4 州県制(583年~1276年)\n" +
+"    * 5 祭祀制度\n" +
+"    * 6 外交\n" +
+"          o 6.1 漢帝国\n" +
+"          o 6.2 魏晋南北朝時代\n" +
+"          o 6.3 隋唐帝国\n" +
+"    * 7 関連項目\n" +
+"    * 8 脚注\n" +
+"\n" +
+"[編集] 王朝、政権の変遷\n" +
+"現在の中国、すなわち中華人民共和国の領域\n" +
+"現在の中国、すなわち中華人民共和国の領域\n" +
+"\n" +
+"    * 長江文明\n" +
+"    * 黄河文明\n" +
+"    * 夏(紀元前2070年頃 - 紀元前1600年頃\n" +
+"    * 殷(紀元前1600年頃 - 紀元前12世紀・紀元前11世紀ごろ)\n" +
+"\n" +
+"    * 周(紀元前12世紀・紀元前11世紀ごろ - 紀元前256年)…殷を倒し、西周建国。克殷の年代については諸説あり、はっきりしない。\n" +
+"          o 春秋時代(紀元前770年 - 紀元前403年)…紀元前453年晋が韓魏趙に分割された時点、または紀元前403年韓魏趙が諸侯に列した時点をもって春秋時代の終わり、戦国時代の始まりとする。\n" +
+"          o 戦国時代(紀元前403年 - 紀元前221年)…晋が韓・趙・魏に分裂し、戦国時代突入。\n" +
+"    * 秦(紀元前221年 - 紀元前207年)…秦王・政が6国を滅ぼし中華統一。\n" +
+"    * 漢\n" +
+"          o 前漢(紀元前206年 - 8年)…秦滅亡後、楚の項羽との楚漢戦争に勝ち、劉邦が建国。\n" +
+"          o 新(8年 - 23年)…外戚の王莽が前漢皇帝から帝位を簒奪し建国。\n" +
+"          o 後漢(25年 - 220年)…前漢の景帝の子孫の劉秀(光武帝)が王莽軍を破り、漢を再興。\n" +
+"    * 三国時代(220年 - 280年)\n" +
+"          o 魏、蜀(蜀漢・漢)、呉…曹操の子曹丕が献帝から禅譲を受け即位すると、蜀の劉備も漢皇帝を名乗り即位、さらに呉の孫権も大帝として即位し、三国時代に入る。\n" +
+"    * 晋(265年 - 420年)\n" +
+"          o 西晋(265年 - 316年)…晋王司馬炎が魏の元帝より禅譲を受け即位し建国。だが、異民族五胡の侵入により衰退。異民族の漢に滅ぼされた。\n" +
+"          o 東晋(317年 - 420年)…皇族でただ一人生き残った琅邪王・司馬睿は江南に逃れ、建康で即位(元帝)。これを中原の晋と区別して東晋という。\n" +
+"          o 五胡十六国時代(304年 - 439年)\n" +
+"    * 南北朝時代(439年 - 589年)\n" +
+"          o 北魏、東魏、西魏、北斉、北周\n" +
+"          o 宋、斉、梁、陳\n" +
+"    * 隋(581年 - 619年)\n" +
+"    * 唐(618年 - 907年)\n" +
+"          o 武周\n" +
+"    * 五代十国時代\n" +
+"          o 後梁、後唐、後晋、後漢、後周……五代(中原を中心とする国)\n" +
+"          o 呉、南唐・閩・呉越・荊南・楚・南漢・前蜀・後蜀・北漢……十国(中華東西南北に拠る勢力)\n" +
+"    * 宋\n" +
+"          o 北宋(960年 - 1127年)\n" +
+"          o 南宋(1127年 - 1279年)\n" +
+"          o 遼、西夏、金\n" +
+"    * 元(1271年 - 1368年)\n" +
+"    * 明(1368年 - 1644年)\n" +
+"          o 南明\n" +
+"    * 清(1616年 - 1912年)(1616年 - 1636年は後金、それ以前はマンジュ国)\n" +
+"          o 太平天国、満州国\n" +
+"    * 中華民国(台湾)(1912年 - 現在)\n" +
+"    * 中華人民共和国(1949年 - 現在)\n" +
+"\n" +
+"[編集] 概略\n" +
+"\n" +
+"[編集] 先史人類史\n" +
+"\n" +
+"中国に現れた最初期の人類としては、元謀原人や藍田原人、そして北京原人が知られている。\n" +
+"\n" +
+"[編集] 文明の萌芽\n" +
+"\n" +
+"中国大陸では、古くから文明が発達した。中国文明と呼ばれるものは、大きく分けて黄河文明と長江文明の2つがある。黄河文明は、畑作が中心、長江文明は稲作が中心であった。黄河文明が、歴史時代の殷(商)や周などにつながっていき、中国大陸の歴史の中軸となった。長江文明は次第に、中央集権国家を創出した黄河文明に同化吸収されていった。\n" +
+"\n" +
+"[編集] 黄河文明\n" +
+"龍山文化時代の高杯。1976年山東省出土\n" +
+"龍山文化時代の高杯。1976年山東省出土\n" +
+"\n" +
+"黄河文明は、その後の中国の歴史の主軸となる。\n" +
+"\n" +
+"    * 裴李崗文化…紀元前7000?~紀元前5000?。一般的な「新石器時代」のはじまり。定住し、農業も行われていた。河南省(黄河中流)。土器は赤褐色\n" +
+"    * 老官台文化…紀元前6000?~紀元前5000?。土器作りや粟作りが行われていた。陝西省(黄河上流)。土器は赤色。\n" +
+"    * 北辛文化…紀元前6000?~紀元前5000?。土器は黄褐色。山東省(黄河下流)\n" +
+"    * 磁山文化…紀元前6000?~紀元前5000?。土器は赤褐色。河北省(黄河下流)\n" +
+"    * 仰韶文化…紀元前4800?~紀元前2500?。前期黄河文明における最大の文化。陝西省から河南省にかけて存在。このころは母系社会で、農村の階層化も始まった。文化後期になると、社会の階層化、分業化が進み、マルクス経済学でいうところの原始共産制は仰韶文化のころに終焉したと見られる。土器は赤色。\n" +
+"    * 後岡文化…紀元前5000?~紀元前4000?。北辛文化が発展。河南省。\n" +
+"    * 大汶口文化…紀元前4300?~紀元前2400?。土器は前期は赤色(彩陶)、後期は黒色(黒陶)。なお、この区分は黄河文明全体に見られる。山東省。\n" +
+"    * 龍山文化…紀元前2500?~紀元前2000?。大汶口文化から発展。後期黄河文明最大の文化。土器は黒色。山東省。\n" +
+"    * 二里頭文化…紀元前2000?~紀元前1600?。遺跡の中心部には二つの宮殿がある。河南省。\n" +
+"\n" +
+"[編集] 長江文明\n" +
+"母なる長江\n" +
+"母なる長江\n" +
+"\n" +
+"長江文明は黄河文明が萌芽する遥か前より栄えていた。夏王朝の始祖とされる禹が南方出身であるとされるため、この長江流域に夏王朝が存在したのではないかという説[1]がある。\n" +
+"\n" +
+"    * 玉蟾岩遺跡…湖南省(長江中流)。紀元前14000年?~紀元前12000年?の稲モミが見つかっているが、栽培したものかは確定できない。\n" +
+"    * 仙人洞・呂桶環遺跡…江西省(長江中流)。紀元前12000年ごろ?の栽培した稲が見つかっており、それまで他から伝播してきたと考えられていた中国の農耕が中国独自でかつ最も古いものの一つだと確かめられた。\n" +
+"    * 彭頭山文化…湖南省(長江中流)。紀元前7000年?~紀元前5000年?。散播農法が行われており、中国における最古の水稲とされる。\n" +
+"    * 大渓文化…四川省(長江上流)。紀元前4500年?~紀元前3300年?。彩文紅陶(紋様を付けた紅い土器)が特徴で、後期には黒陶・灰陶が登場。灌漑農法が確立され、住居地が水の補給のための水辺から大規模に農耕を行う事の出来る平野部へ移動した。\n" +
+"    * 屈家嶺文化…湖北省。紀元前3000年?~紀元前2500年?大渓文化を引き継いで、ろくろを使用した黒陶が特徴。河南地方の黄河文明にも影響を与えたと考えられる。\n" +
+"    * 石家河文化…屈家嶺文化から発展し、湖北省天門県石家河に大規模な都城を作った紀元前2500年頃を境として屈家嶺と区別する。この都城は南北1.3Km、東西1.1Kmという大きさで、上述の黄河流域の部族と抗争したのはこの頃と考えられる。\n" +
+"    * 河姆渡文化 …紀元前5000年?~紀元前4000年?下流域では最古の稲作。狩猟や漁労も合わせて行われ、ブタの家畜化なども行われた。\n" +
+"    * 良渚文化… 浙江省(銭塘江流域)。紀元前5260年?~紀元前4200年?(以前は文化形態から大汶口文化中期ごろにはじまったとされていたが、1977年出土木材の年輪分析で改められた)青銅器以前の文明。多数の玉器の他に、絹が出土している。分業や階層化も行われたと見られ、殉死者を伴う墓が発見されている。黄河文明の山東竜山文化とは相互に関係があったと見られ、同時期に衰退したことは何らかの共通の原因があると見られている。\n" +
+"    * 三星堆遺跡… 紀元前2600年?~紀元前850年?。大量の青銅器が出土し、前述の他に目が飛び出た仮面・縦目の仮面・黄金の杖などがあり、また子安貝や象牙なども集められており、権力の階層があったことがうかがい知れる。青銅器については原始的な部分が無いままに高度な青銅器を作っているため他の地域、おそらくは黄河流域からの技術の流入と考えられる。長江文明と同じく文字は発見されていないが、「巴蜀文字」と呼ばれる文字らしきものがあり、一部にこれをインダス文字と結びつける説もある。\n" +
+"\n" +
+"[編集] その他\n" +
+"\n" +
+"    * 新楽遺跡…遼寧省(遼河流域)。紀元前5200年?ごろの定住集落。母系社会が定着し、農業も行われていた。\n" +
+"\n" +
+"[編集] 先秦時代\n" +
+"\n" +
+"[編集] 三代\n" +
+"\n" +
+"史記では伝説と目される三皇五帝時代に続いて夏[2]王朝について記述されている。夏については実在が確かでなくまた定説もない。\n" +
+"\n" +
+"殷[3](商)が実在の確認されている最古の王朝である。殷では、王が占いによって政治を行っていた(神権政治)。殷は以前は山東で興ったとされたが、近年は河北付近に興ったとする見方が有力で、黄河文明で生まれた村のうち強大になり発展した都市国家の盟主であった[4]と考えられる。\n" +
+"\n" +
+"紀元前11世紀頃に殷を滅ぼした周は、各地の有力者や王族を諸侯として封建制をおこなった。しかし、周王朝は徐々に弱体化し、異民族に攻められ、紀元前770年には成周へ遷都した。その後、史記周本紀によれば犬戎の侵入により西周が滅び、洛陽に東周が再興されたされるが、同じく平勢隆郎の検討によれば幽王が殺害されたあと短期間携王が西、平王が東に並立し、紀元前759年平王が携王を滅ぼしたと考えられる。平王のもとで周は洛陽にあり、西周の故地には秦が入る。これ以降を春秋時代と呼ぶ。春秋時代には、周王朝の権威はまだ残っていたが、紀元前403年から始まるとされる戦国時代には、周王朝の権威は無視されるようになる。\n" +
+"\n" +
+"[編集] 春秋戦国\n" +
+"諸子百家の一、孔子\n" +
+"諸子百家の一、孔子\n" +
+"\n" +
+"春秋戦国時代は、諸侯が争う戦乱の時代であった。\n" +
+"\n" +
+"春秋時代は都市国家の盟主どうしの戦いだった。しかし春秋末期最強の都市国家晋が三分割されたころから様子が変わる。その当時の晋の有力な家臣六家が相争い、最初力が抜きん出ていた智氏が弱小な趙氏を攻めたものの、趙氏がよく農村を経済的ではなく封建的に支配し、それによって集めた食糧が多かったために城を守りきり、疲弊した智氏を魏氏、韓氏が攻め滅ぼしたために最終的に趙、魏、韓の三国が出来た。このこともあってそれまで人口多くてもせいぜい5万人程度だった都市国家が富国強兵に努め、商工業が発達し、貨幣も使用し始めやがて領土国家に変貌しその国都となった旧都市国家は30万人規模の都市に変貌する。また鉄器が普及したこともあいまって、農業生産も増大した。晋の分裂以後を一般に戦国時代という。\n" +
+"\n" +
+"また、このような戦乱の世をどのように過ごすべきかという思想がさまざまな人たちによって作られた。このような思想を説いた人たちを諸子百家(陰陽家、儒家、墨家、法家、名家、道家、兵家等が代表的)という。\n" +
+"\n" +
+"[編集] 秦漢帝国\n" +
+"始皇帝\n" +
+"\n" +
+"現在の陝西省あたりにあった秦は、戦国時代に着々と勢力を伸ばした。勢力を伸ばした背景には、厳格な法律で人々を統治しようとする法家の思想を採用して、富国強兵に努めたことにあった。秦王政は、他の6つの列強を次々と滅ぼし、紀元前221年には史上はじめての中国統一を成し遂げた。秦王政は、自らの偉業をたたえ、王を超える称号として皇帝を用い、自ら始皇帝と名乗った。\n" +
+"兵馬俑\n" +
+"\n" +
+"始皇帝は、法家の李斯を登用し、中央集権化を推し進めた。このとき、中央から派遣した役人が全国の各地方を支配する郡県制が施行された。また、文字・貨幣・度量衡の統一も行われた。さらに、当時モンゴル高原に勢力をもっていた遊牧民族の匈奴を防ぐために万里の長城を建設させた。さらに、軍隊を派遣して、匈奴の南下を抑えた。また、嶺南地方(現在の広東省)にも軍を派遣し、この地にいた百越諸族を制圧した。しかし、このような中央集権化や土木事業・軍事作戦は人々に多大な負担を与えた。そのため、紀元前210年に始皇帝が死ぬと、翌年には陳勝・呉広の乱という農民反乱がおきた。これに刺激され各地で反乱がおき、ついに秦は紀元前206年に滅びた。\n" +
+"漢の偉大な発明、紙\n" +
+"漢の偉大な発明、紙\n" +
+"\n" +
+"秦が滅びたあと、劉邦と項羽が覇権をめぐって争った(楚漢戦争)が、紀元前202年には、劉邦が項羽を破り、漢の皇帝となった。劉邦は、始皇帝が急速な中央集権化を推し進めて失敗したことから、一部の地域には親戚や臣下を王として治めさせ、ほかの地域を中央が直接管理できるようにした。これを郡国制という。しかし、紀元前154年には、各地の王が中央に対して呉楚七国の乱と呼ばれる反乱を起こした。この反乱は鎮圧され、結果として、中央集権化が進んだ。紀元前141年に即位した武帝は、国内の安定もあり、対外発展を推し進めた。武帝は匈奴を撃退し、シルクロードを通じた西方との貿易を直接行えるようにした。また、朝鮮半島北部、ベトナム北中部にも侵攻した。これらの地域はその後も強く中国文化の影響を受けることとなった。また、武帝は董仲舒の意見を聞いて、儒教を統治の基本とした。これ以降、中国の王朝は基本的に儒教を統治の基本としていく。一方で文帝の頃より貨幣経済が広汎に浸透しており、度重なる軍事行動と相まって、農民の生活を苦しめた。漢の宮廷では貨幣の浸透が農民に不利益であることがしばしば論じられており、農民の救済策が検討され、富商を中心に増税をおこなうなど大土地所有を抑制しようと努力した。また儒教の国教化に関連して儒教の教義論争がしばしば宮廷の重大問題とされるようになった。\n" +
+"\n" +
+"8年には、王莽が皇帝の位を奪って、一旦漢を滅ぼした。王莽は当初儒教主義的な徳治政治をおこなったが、相次ぐ貨幣の改鋳や頻繁な地名、官名の変更など理想主義的で恣意的な政策をおこなったため徐々に民心を失い、辺境異民族が頻繁に侵入し、赤眉の乱など漢の復興を求める反乱が起き、内乱状態に陥った。結局、漢の皇族の血を引く劉秀によって漢王朝が復興された。この劉秀が建てた漢を後漢という。王朝初期には雲南に進出し、また班超によって西域経営がおこなわれ、シルクロードをおさえた。初期の後漢王朝は豪族連合的な政権であったが、章帝の時代までは中央集権化につとめ安定した政治が行われた。しかし安帝時代以後外戚や宦官の権力の増大と官僚の党派対立に悩まされるようになった。\n" +
+"\n" +
+"[編集] 魏晋南北朝時代\n" +
+"三国決戦の地、赤壁\n" +
+"三国決戦の地、赤壁\n" +
+"\n" +
+"後漢末期の184年には、黄巾の乱と呼ばれる農民反乱がおきた。これ以降、隋が589年に中国を再統一するまで、一時期を除いて中国は分裂を続けた。この隋の再統一までの分裂の時代を魏晋南北朝時代という。また、この時期には日本や朝鮮など中国周辺の諸民族が独自の国家を形成し始めた時期でもある。\n" +
+"\n" +
+"さて、黄巾の乱が鎮圧されたあと、豪族が各地に独自政権を立てた。中でも有力であったのが、漢王朝の皇帝を擁していた曹操である。しかし、中国統一を目指していた曹操は、208年に赤壁の戦いで、江南の豪族孫権に敗れた。結局、曹操の死後、220年に曹操の子の曹丕が後漢の皇帝から皇帝の位を譲られ、魏を建国した。これに対して、221年には、現在の四川省に割拠していた劉備が皇帝となり、蜀を建国した。さらに、江南の孫権も229年に皇帝と称して、呉を建国した。この魏・呉・蜀の三国が並立した時代を三国時代という。\n" +
+"\n" +
+"三国の中で、もっとも有力であったのは魏であった。魏は後漢の半分以上の領土を継承したが、戦乱で荒廃した地域に積極的な屯田をおこない、支配地域の国力の回復につとめた。魏では官吏登用法として、九品官人法[5]がおこなわれた。\n" +
+"\n" +
+"三国は基本的に魏と呉・蜀同盟との争いを軸としてしばしば交戦したが、蜀がまず263年に魏に滅ぼされ、その魏も有力な臣下であった司馬炎に265年に皇帝の位を譲るという形で滅亡した。司馬炎は皇帝となって国号を晋と命名し、さらに280年に呉を滅ぼし、中国を統一した。しかし、300年から帝位をめぐって各地の皇族が戦争を起こした(八王の乱)。このとき、五胡と呼ばれる異民族を軍隊として用いたため、これらの五胡が非常に強い力を持つようになった。316年には、五胡の1つである匈奴が晋をいったん滅ぼした。これ以降、中国の北方は、五胡の建てた国々が支配し、南方は江南に避難した晋王朝(南に移ったあとの晋を東晋という)が支配した。この時期は、戦乱を憎み、宗教に頼る向きがあった。代表的な宗教が仏教と道教であり、この2つの宗教は時には激しく対立することがあった。\n" +
+"\n" +
+"さて、江南を中心とする中国の南方では、異民族を恐れて、中国の北方から人々が多く移住してきた。これらの人々によって、江南の開発が進んだ。それに伴い、貴族が大土地所有を行うということが一般的になり、貴族が国の政治を左右した。一部の貴族の権力は、しばしば皇帝権力よりも強かった。これらの貴族階層の者により散文、書画等の六朝文化と呼ばれる文化が発展した。東晋滅亡後、宋・斉・梁・陳という4つの王朝が江南地方を支配したが、貴族が強い力を握ることは変わらなかった。梁の武帝は仏教の保護に努めた。\n" +
+"\n" +
+"北方では、鮮卑族の王朝である北魏が台頭し、439年には、華北を統一した。471年に即位した孝文帝は漢化政策を推し進めた。また、土地を国家が民衆に割り振る均田制を始め、律令制の基礎付けをした。しかし、このような漢化政策に反対するものがいたこともあり、北魏は、西魏と東魏に分裂した。西魏は北周へと、東魏は北斉へと王朝が交代した。577年には北周が北斉を滅ぼしたが、581年に隋が北周にとって代わった。589年に隋は南方の陳を滅ぼし、中国を統一した。\n" +
+"\n" +
+"魏晋南北朝表も参照。\n" +
+"\n" +
+"[編集] 隋唐帝国\n" +
+"現在でも使用される世界最大の大運河\n" +
+"現在でも使用される世界最大の大運河\n" +
+"\n" +
+"中国を統一した隋の文帝は、均田制・租庸調制・府兵制などを進め、中央集権化を目指した。また同時に九品中正法を廃止し、試験によって実力を測る科挙を採用した。しかし、文帝の後を継いだ煬帝は、江南・華北を結ぶ大運河を建設したり、度重なる遠征を行ったために、民衆の負担が増大した。このため農民反乱が起き、618年に隋は滅亡した。\n" +
+"\n" +
+"隋に代わって、中国を支配したのが、唐である。唐は基本的に隋の支配システムを受け継いだ。626年に即位した太宗は、租庸調制を整備し、律令制を完成させた。唐の都の長安は、当時世界最大級の都市であり、各国の商人などが集まった。長安は、西方にはシルクロードによってイスラム帝国や東ローマ帝国などと結ばれ、ゾロアスター教・景教・マニ教をはじめとする各地の宗教が流入した。また、文化史上も唐時代の詩は最高のものとされる。\n" +
+"当時世界最大の都市だった長安のシンボルタワー・大雁塔\n" +
+"当時世界最大の都市だった長安のシンボルタワー・大雁塔\n" +
+"\n" +
+"太宗の死後着々と力を付けた太宗とその子の高宗の皇后武則天はついに690年皇帝に即位した。前にも後にも中国にはこれのほかに女帝はいない。\n" +
+"\n" +
+"712年に即位した玄宗は国内の安定を目指したが、すでに律令制は制度疲労を起こしていた。また、周辺諸民族の統治に失敗したため、辺境に強大な軍事力が置かれた。これを節度使という。節度使は、後に軍権以外にも、民政権・財政権をももつようになり、力を強めていく。763年には、節度使の安禄山たちが安史の乱と呼ばれる反乱を起こした。この反乱は郭子儀や僕固懐恩、ウイグル帝国の太子葉護らの活躍で何とか鎮圧されたが、反乱軍の投降者の勢力を無視できず、投降者を節度使に任じたことなどから各地で土地の私有(荘園)が進み、土地の国有を前提とする均田制が行えなくなっていった。結局、政府は土地の私有を認めざるを得なくなった。結果として、律令制度は崩壊した。875年から884年には黄巣の乱と呼ばれる農民反乱がおき、唐王朝の権威は失墜した。このような中、各地の節度使はますます権力を強めた。907年には、節度使の1人である朱全忠が唐を滅ぼした。\n" +
+"\n" +
+"[編集] 五代十国・宋\n" +
+"画像:Compass in a wooden frame.jpg\n" +
+"中国航海術の偉大な発明、羅針盤\n" +
+"\n" +
+"唐の滅亡後、各地で節度使があい争った。この時代を五代十国時代という。この戦乱を静めたのが、960年に皇帝となって宋を建国した趙匡胤である。ただし、完全に中国を宋が統一したのは趙匡胤の死後の976年である。\n" +
+"\n" +
+"趙匡胤は、節度使が強い権力をもっていたことで戦乱が起きていたことを考え、軍隊は文官が率いるという文治主義をとった。また、これらの文官は、科挙によって登用された。宋からは、科挙の最終試験は皇帝自らが行うものとされ、科挙で登用された官吏と皇帝の結びつきは深まった。また、多くの国家機関を皇帝直属のものとし、中央集権・皇帝権力強化を進めた。科挙を受験した人々は大体が、地主層であった。これらの地主層を士大夫と呼び、のちの清時代まで、この層が皇帝権力を支え、官吏を輩出し続けた。\n" +
+"杭州\n" +
+"杭州\n" +
+"\n" +
+"唐は、その強大な力によって、周辺諸民族を影響下においていたが、唐の衰退によってこれらの諸民族は自立し、独自文化を発達させた。また、宋は文治主義を採用していたたため、戦いに不慣れな文官が軍隊を統制したので、軍事力が弱く、周辺諸民族との戦いにも負け続けた。なかでも、契丹族の遼・タングート族の西夏・女真族の金は、中国本土にも侵入し、宋を圧迫した。これらの民族は、魏晋南北朝時代の五胡と違い、中国文化を唯一絶対なものとせず、独自文化を保持し続けた。このような王朝を征服王朝という。後代の元や清も征服王朝であり、以降、中国文化はこれらの周辺諸民族の影響を強く受けるようになった。\n" +
+"\n" +
+"1127年には、金の圧迫を受け、宋は、江南に移った。これ以前の宋を北宋、以降を南宋という。南宋時代には、江南の経済が急速に発展した。また、すでに唐代の終わりから、陸上の東西交易は衰退していたが、この時期には、ムスリム商人を中心とした海上の東西交易が発達した。当時の宋の特産品であった陶磁器から、この交易路は陶磁の道と呼ばれる。南宋の首都にして海上貿易の中心港だった杭州は経済都市として栄え、元時代に中国を訪れたマルコ・ポーロは杭州を「世界一繁栄し、世界一豊かな都市」と評している。\n" +
+"\n" +
+"文化的には、経済発展に伴って庶民文化が発達した。また、士大夫の中では新しい学問をもとめる動きが出て、儒教の一派として朱子学が生まれた。\n" +
+"\n" +
+"[編集] モンゴル帝国\n" +
+"\n" +
+"13世紀初頭にモンゴル高原で、チンギス・ハーンが、モンゴルの諸部族を統一し、ユーラシア大陸各地へと、征服運動を開始した。モンゴル人たちは、東ヨーロッパ、ロシア、小アジア、メソポタミア、ペルシャ、アフガニスタン、チベットに至る広大な領域を支配し、この帝国はモンゴル帝国と呼ばれる。中国もまた征服活動の例外ではなかった。当時、黄河が南流し、山東半島の南に流れていたため、漢民族は北方民族の攻勢を防げなかった。華北は満州系の女真族による金が、南部を南宋が支配していたが、金は1234年、南宋は1279年にモンゴルに滅ぼされた。\n" +
+"\n" +
+"モンゴル帝国は各地に王族や漢人有力者を分封した。モンゴル帝国の5代目の君主(ハーン)にクビライが即位すると、これに反発する者たちが、反乱を起こした。結局、モンゴル帝国西部に対する大ハーン直轄支配は消滅し、大ハーンの政権は中国に軸足を置くようになった。もっとも、西方が離反しても、帝国としての緩やかな連合は保たれ、ユーラシアには平和が訪れていた。1271年にクビライは元を国号として中国支配をすすめた。\n" +
+"宋代に発明された火薬は元寇の時使用され、日本の武士を驚かせた\n" +
+"宋代に発明された火薬は元寇の時使用され、日本の武士を驚かせた\n" +
+"\n" +
+"モンゴル帝国(元)は未だ征服していなかった南宋への牽制のためにも日本に対して通交を求めたが、日本側は断った。このため二度に渡り日本に侵攻したが、成功しなかった(元寇)。元は三度目の日本侵攻を計画したが、実現には至らなかった。\n" +
+"\n" +
+"中国南部を支配していた南宋を1279年に元が滅ぼしたのはすでに見たとおりである。\n" +
+"\n" +
+"元の中国支配は、伝統的な中国王朝とは大きく異なっていた。元は中国の伝統的な統治機構を採用せず、遊牧民の政治の仕組みを中国に移入したからである。元の支配階級の人々は、すでに西方の優れた文化に触れていたため、中国文化を無批判に取り入れることはなかった。それは政治においても同様だったのである。それに伴い、伝統的な統治機構を担ってきた、儒教的な教養を身に付けた士大夫層は冷遇され、政権から遠ざけられた。そのため、彼らは曲や小説などの娯楽性の強い文学作品の執筆に携わった。この時代の曲は元曲と呼ばれ、中国文学史上最高のものとされる。また、モンゴル帝国がユーラシア大陸を広く支配したために、この時期は東西交易が前代に増して盛んになった。\n" +
+"\n" +
+"元は、宮廷費用などを浪費しており、そのため塩の専売策や紙幣の濫発で収入を増やそうとした。しかし、これは経済を混乱させるだけであった。そして、庶民の生活は困窮した。こうした中、各地で反乱が発生した。中でも最大規模のものは1351年に勃発した紅巾党の乱であった。紅巾党の中から頭角をあらわした朱元璋は、1368年に南京で皇帝に即位して明を建国した。同年、朱元璋は元の都の大都を陥落させ、元の政府はモンゴル高原へと撤退した。撤退後の元のことを北元といい、明と北元はしばしば争った。明側は1388年に北元は滅んだと称しているが、実質的にはその後も両者の争いは続いた。\n" +
+"\n" +
+"[編集] 明清帝国\n" +
+"鄭和の南海大遠征の時の巨艦・「宝船」\n" +
+"鄭和の南海大遠征の時の巨艦・「宝船」\n" +
+"\n" +
+"洪武帝の死後、孫の建文帝が即位したが、洪武帝の四男である朱棣が反乱(靖難の変)を起こし、朱棣が永楽帝として皇帝になった。永楽帝は、モンゴルを攻撃するなど、積極的に対外進出を進めた。また、鄭和を南洋に派遣して、諸国に朝貢を求めた。この時の船が近年の研究によって長さ170m余、幅50m余という巨艦で、その約70年後の大航海時代の船の5倍から10倍近い船であったことが分かっている。\n" +
+"\n" +
+"また、永楽帝によって現在に至るまで世界最大の宮殿である紫禁城が北京に築かれた。\n" +
+"\n" +
+"永楽帝の死後、財政事情もあって、明は海禁政策をとり、貿易を著しく制限することとなる。このとき永楽帝を引き継いで、鄭和のようにずっと積極的に海外へ進出していれば、ヨーロッパのアジア・アフリカ支配も実現しなかっただろうと多くの歴史家は推測する。その後、モンゴルが再び勢力を強めはじめ、1449年には皇帝がモンゴルの捕虜になるという事件(土木の変)まで起きた。同じ頃、中国南部沿岸には、倭寇と呼ばれる海上の無法者たちが襲撃を重ねていた。これは、海禁政策で貿易が自由にできなくなっていたためである。倭寇とモンゴルを併称して北虜南倭というが、北虜南倭は明を強く苦しめた。\n" +
+"紫禁城の中心、太和殿\n" +
+"紫禁城の中心、太和殿\n" +
+"\n" +
+"また、皇帝による贅沢や多額の軍事費用の負担は民衆に重税となって圧し掛かってきた。これに対し、各地で反乱がおき、その中で頭角をあらわした李自成が1644年に明を滅ぼした。\n" +
+"\n" +
+"17世紀初頭には、現在の中国東北地方でヌルハチが女真族を統一した。その子のホンタイジは中国東北地方と内モンゴルを征服し、1636年にはモンゴル人から元の玉璽を譲られ、清を建国した。李自成が明を滅ぼすと清の軍隊は万里の長城を越えて、李自成の軍隊を打ち破り、中国全土を支配下に置いた。17世紀後半から18世紀にかけて、康熙帝・雍正帝・乾隆帝という3人の賢い皇帝の下で、清の支配領域は中国本土と中国東北地方・モンゴルのほかに、台湾・東トルキスタン・チベットにまで及んだ。\n" +
+"\n" +
+"この清の支配領域が大幅に広がった時期は、『四庫全書』の編纂など文化事業も盛んになった。しかし、これは学者をこのような事業に動員して、異民族支配に反抗する暇をなくそうとした面もあった。\n" +
+"\n" +
+"明代の後期には、メキシコや日本から大量の銀が中国に流入し、貨幣として基本的に銀が使われるようになった。そのため、政府も一条鞭法と呼ばれる税を銀で払わせる税法を始めた。また、清代に入ると、人頭税を廃止し土地課税のみとする地丁銀制が始まった。また明清両代ともに商品経済が盛んになり、農業生産も向上した。\n" +
+"\n" +
+"[編集] 中国の半植民地化\n" +
+"フランス人が描いた中国半植民地化の風刺画。イギリス、ドイツ、ロシア、フランス、日本が中国を分割している。\n" +
+"フランス人が描いた中国半植民地化の風刺画。イギリス、ドイツ、ロシア、フランス、日本が中国を分割している。\n" +
+"\n" +
+"18世紀が終わるまでには、清とヨーロッパとの貿易はイギリスがほぼ独占していた。しかし、当時イギリスの物産で中国に売れるものはほとんどなく、逆に中国の安いお茶はイギリスの労働者階級を中心に大きな需要があったこともあり、イギリスは貿易赤字に苦しんだ。そこで、イギリスは麻薬であるアヘンを中国に輸出し始めた。結果、イギリスは大幅な貿易黒字に転じた。しかし、中国にはアヘン中毒者が蔓延し、この事態を重く見た清朝政府は、1839年に林則徐に命じてアヘン貿易を取り締まらせた。しかし、これに反発したイギリス政府は清に対して翌1840年宣戦布告した。アヘン戦争と呼ばれるこの戦争では、工業化をとげ、近代兵器を持っていたイギリス軍が勝利した。これ以降、イギリスをはじめとするヨーロッパの列強は中国に対し、不平等条約(治外法権の承認、関税自主権の喪失、片務的最恵国待遇の承認、開港、租借といった)を締結させ、中国の半植民地化が進んだ。\n" +
+"\n" +
+"国内的には、太平天国の乱などの反乱もしばしば起きた。これに対し、同治帝(在位1861年 - 1875年)の治世の下で、ヨーロッパの技術の取り入れ(洋務運動)が行われた。\n" +
+"\n" +
+"1894年から翌1895年にかけて清と日本との間で行われた日清戦争にも清は敗退した。これは洋務運動の失敗を意味するものであった。この戦争の結果、日本と清との間で結んだ下関条約により、李氏朝鮮の独立が認められ、中国の王朝が長年続けてきた冊封体制が崩壊した。\n" +
+"\n" +
+"その後、清朝政府は改革を進めようとしたものの、沿岸地域を租借地とされるなどのイギリス・フランス・ロシア・ドイツ・アメリカ合衆国・日本による半植民地化の動きは止まらなかった。結局、1911年の武昌での軍隊蜂起をきっかけに辛亥革命が起こり、各地の省が清からの独立を宣言した。翌1912年1月1日、革命派の首領の孫文によって南京で中華民国の樹立が宣言された。北京にいた清の皇帝溥儀(宣統帝)は、清朝政府内部の実力者である袁世凱により2月12日に退位させられ、清は完全に滅亡した。\n" +
+"\n" +
+"[編集] 中華民国\n" +
+"\n" +
+"[編集] 革命後の中国の政局\n" +
+"\n" +
+"中華民国は成立したものの、清朝を打倒した時点で革命に参加した勢力どうしで利害をめぐって対立するようになり、政局は混乱した。各地の軍閥も民国政府の税金を横領したり勝手に新税を導入して独自の財源を持つようになり、自立化した。\n" +
+"\n" +
+"[編集] 袁世凱の台頭と帝制運動(1913年~1916年)\n" +
+"袁世凱\n" +
+"袁世凱\n" +
+"\n" +
+"臨時大総統であった袁世凱は大総統の権力強化を図って議会主義的な国民党の勢力削減を企てた。国民党の急進派はこれに反発、第二革命を起こしたが鎮圧された。1913年10月袁は正式な大総統となり、さらに11月には国民党を非合法化し、解散を命じた。1914年1月には国会を廃止、5月1日には立法府の権限を弱め大総統の権力を大幅に強化した中華民国約法を公布した。\n" +
+"\n" +
+"袁は列強から多額の借款を借り受けて積極的な軍備強化・経済政策に着手した。当初列強の袁政権に対する期待は高かった。しかしこのような外国依存の財政は、のちに列強による中国の半植民地化をますます進めることにもなった。第一次世界大戦が始まると、新規借款の望みがなくなったため、袁は財政的に行き詰まった。また日本が中国での権益拡大に積極的に動いた。\n" +
+"\n" +
+"1915年5月9日に、袁が大隈重信内閣の21ヶ条要求を受けたことは大きな外交的失敗と見られ、同日は国恥記念日とされ袁の外交姿勢は激しく非難された。袁は独裁を強化することでこの危機を乗り越えようとし、立憲君主制的な皇帝制度へ移行し、自身が皇帝となることを望んだ。日本も立憲君主制には当初賛成していたようだが、中国国内で帝制反対運動が激化すると反対に転じ外交圧力をかけた。1916年袁は失意のうちに没した。\n" +
+"\n" +
+"[編集] 袁世凱死後の政局(1916年~1920年)\n" +
+"\n" +
+"袁の死後、北京政府の実権を掌握したのは国務総理となった段祺瑞であった。段は当初国会[6]の国民党議員などと提携し、調整的な政策をとっていた。しかし、第一次世界戦に対独参戦しようとしたため徐々に国会と対立した。段は日本の援助の下に強硬な政策を断行した。1917年8月14日第一次世界大戦に対独参戦。軍備を拡張して国内の統一を進めた。また鉄道や通信などの業界を背景とする利権集団が段を支えた。1918年には国会議員改定選挙を強行した。国民党はこれに激しく対立し、南方の地方軍とともに孫文を首班とする広東軍政府をつくった。5月には日本と日中軍事協定[7]を結んだ。寺内正毅内閣失脚後に日本の外交方針が転回すると、段は急速に没落した。段の安徽派と対立関係にあった直隷派の馮国璋は徐世昌を大総統に推薦し、段もこれを受け入れた。親日的な安徽派は徐々に影響力を失っていった。1919年5月4日、山東半島での主権回復と反日を訴えるデモ行進が始まった。これを五・四運動という。なお山東半島は1922年に返還された。1920年7月の安直戦争で直隷派に敗れたことで段は失脚した。\n" +
+"\n" +
+"[編集] 国民革命(1920年~1928年)\n" +
+"革命家・孫文\n" +
+"革命家・孫文\n" +
+"\n" +
+"袁世凱により国民党が非合法化されたのち、孫文は1914年7月に中国革命党を東京で結成した。1919年には拠点を上海に移し、中国国民党と改称した。1921年には上海で中国共産党が成立した。これらの政党は1918年のロシア革命の影響を受けており、議会政党というよりも明確な計画性と組織性を備えた革命政党を目指した。1924年国民党は第一回全国大会をおこない、党の組織を改編するとともに共産党との合同(第一次国共合作)を打ち出した。孫文はこのころ全く機能していなかった国会に代わって国内の団体代表による国民会議を提唱し、これに呼応した馮国璋により北京に迎えられた。1925年には国民会議促成会が開かれたが、この会期中に孫文は没した。7月には広東軍政府で機構再編が進み、中華民国国民政府の成立が宣言された。一方で1924年6月には蒋介石を校長として黄埔軍官学校が設立された。1925年4月に国民革命軍が正式に発足され、国民党は蒋介石を指導者として軍事的な革命路線を推し進めることとなった。1926年に広州から北伐を開始した。1927年1月には武漢に政府を移し、武漢国民政府と呼ばれるようになった。この武漢国民政府では当初国民党左派と共産党が優位にあったが、蒋介石は同年4月12日上海クーデターを起こしてこれらを弾圧し、4月18日には反共を前面に打ち出した南京国民政府を成立させた。南京国民政府は主に上海系の資本家に支えられ、北京・武漢・南京に3つの政権が鼎立することになったが、9月ごろから武漢政府も反共に転じ、南京政府に吸収された。1928年6月南京政府の国民革命軍は北京の中華民国政府を打倒し、12月に張学良もこれを承認したことから、国民政府によって中国は再び統一された。\n" +
+"\n" +
+"[編集] 国民政府(1928年~1931年)\n" +
+"蒋介石\n" +
+"蒋介石\n" +
+"\n" +
+"国民政府においては基本的に国民党の一党独裁の立場が貫かれた。しかし一般党員の数は50万人以下であったとされており、4億をこえると考えられた中国国民のなかではかなり少数であった(国民の多くが「国民」として登録されておらず、しかも文盲のものも多かった)。そのため支配基盤は完全とは言えず、土地税を中心として地方政権の財源を確保する国地画分政策がおこなって、割拠的傾向がいまだに強い地方勢力に配慮したりした。1930年代前半には国民政府に叛旗を翻す形で地方政権が樹立される例が多くなり、軍事衝突なども起きた。1930年に閻錫山と汪兆銘が中心となった北平政府や1931年に孫科らがたてた広州政府などである。\n" +
+"\n" +
+"しかしこのような軍事的緊張は国民政府の中央軍を掌握していた蒋介石の立場を強めることにもなった。蒋介石は経済政策[8]でも手腕を発揮し影響力を増した。\n" +
+"\n" +
+"[編集] 抗日戦争(1931年~1937年)\n" +
+"満州国皇帝愛新覚羅溥儀\n" +
+"満州国皇帝愛新覚羅溥儀\n" +
+"\n" +
+"張作霖が関東軍に爆殺されたあとをついだ張学良は国民革命を支持しており、自身の支配していた中国東北地方を国民政府へ合流させた。このために反日運動が中国東北地方にも広がったが、日本は中国東北地方の権益を確保しようとしていたためにこれに大きく反発した。1931年9月、満州事変がおこり、関東軍によって日本政府の意向を無視して大規模な武力行動がおこなわれた。しかし列強はこれを傍観する姿勢をとったので、日本政府はこの行動を追認した。\n" +
+"\n" +
+"東北地方をほぼ制圧した日本軍は、1932年に上海事変を起こし、列強がそれに注目している間に傀儡政権として満州国を東北地方に樹立した。同年10月、リットン調査団が国際連盟によって派遣され、満州国を中国の主権の下に列強の共同管理による自治政府とするべきという妥協案を示したが、日本は採択に反対した。1933年5月日中間で停戦協定(塘沽協定)が結ばれた。1934年には満州国は帝制に移行し、満州帝国となった。\n" +
+"\n" +
+"1931年に瑞金に政権を樹立していた中国共産党は満州国建国時に日本に宣戦布告していたが、国民党との抗争に忙しく、中国国民で一致して日本の侵略に立ち向かうことはできなかった。1934年には瑞金は国民党により陥落し、打撃を受けた中国共産党は長征と称して西部に移動し、組織の再編をはかった。長征の結果中国共産党は延安に拠点を移した。\n" +
+"\n" +
+"[編集] 日中戦争(1937年~1945年)\n" +
+"\n" +
+"1937年には、盧溝橋事件を契機に、日本軍が中国本土に進出し、中華民国と全面戦争に入った(日中戦争)。これに対し、蒋介石は当初日本との戦いよりも中国共産党との戦いを優先していたが、西安事件により、二つの党が協力して日本と戦うことになった(第二次国共合作)。\n" +
+"カイロ会談に出席した蒋介石とアメリカのフランクリン・D・ルーズベルト大統領、イギリスのウィンストン・チャーチル首相\n" +
+"カイロ会談に出席した蒋介石とアメリカのフランクリン・D・ルーズベルト大統領、イギリスのウィンストン・チャーチル首相\n" +
+"\n" +
+"しかし日中戦争は当初日本軍優位に進み、日本軍は多くの都市を占領したが、各拠点支配はできても広大な中国において面での支配はできず、これを利用した国民党軍・共産党軍ともに各地でゲリラ戦を行い日本軍を苦しめ、戦線を膠着させた。日本は汪兆銘ら国民党左派を懐柔、南京国民政府を樹立させたが、国内外ともに支持は得られなかった。加えて1941年12月、日本はアメリカやイギリス(連合国)とも戦端を開いたが(太平洋戦争)、一方で中国で多くの戦力を釘付けにされるなど、苦しい状況に落ち込まされた。国民党政府は連合国側に所属し、アメリカやイギリスなどから豊富な援助を受けることとなった。\n" +
+"\n" +
+"結局、中国大陸戦線では終始日本側が優勢であったものの、1945年8月ポツダム宣言の受諾とともに日本が無条件降伏することで終結した。国民党政府は連合国の1国として大きな地位を占めていたこともあり、戦勝国として有利な立場を有することとなり、日本だけでなくヨーロッパ諸国も租界を返還するなど、中国の半植民地化は一応の終わりを見せた。\n" +
+"\n" +
+"しかしまもなく国民党と共産党との対立が激化して国共内戦が勃発し、結果として左派が力を持ったアメリカからの支援が減った国民党に対して、ソビエト連邦からの支援を受けていた中国共産党が勝利し、1949年10月1日に毛沢東が中華人民共和国の成立を宣言した。内戦に敗れた中国国民党率いる中華民国政府は台湾島に撤退し、現在に至るまで中国共産党率いる中華人民共和国と「中国を代表する正統な政府」の地位を争っている。\n" +
+"\n" +
+"[編集] 漢民族以外の民族の動向\n" +
+"\n" +
+"[編集] モンゴルとチベットでの動き\n" +
+"\n" +
+"辛亥革命により清国が消滅すると、その旧領をめぐって中国、モンゴル、チベットは、それぞれに自領域を主張した。\n" +
+"\n" +
+"中国は清領全域を主張した。これに対して、モンゴルとチベットは、自分たちは清朝の皇帝に服属していたのであって中国という国家に帰属するものではなく、服属先の清帝退位後は中国と対等の国家であると主張し独立を目指す動きが強まった。\n" +
+"ポタラ宮、当時のチベットの中心地\n" +
+"ポタラ宮、当時のチベットの中心地\n" +
+"\n" +
+"1913年、モンゴルではボグド・ハーンによって、チベットではダライ・ラマ13世よって中国からの独立が宣言され、両者はモンゴル・チベット相互承認条約を締結するなど国際的承認をもとめ、これを認めない中華民国とは戦火を交えた。 この状況は、モンゴル域への勢力浸透をはかるロシア、チベット域への進出をねらうイギリスの介入をゆるし、モンゴル・ロシア・中華民国はキャフタ協定に調印批准、チベット・イギリス・中華民国はシムラ協定(民国政府のみ調印、批准されなかった)が模索されたものの問題の解決には至らなかった。\n" +
+"\n" +
+"ダライ・ラマを補佐していたパンチェン・ラマは親中国的であったために、イギリスに接近するダライ・ラマに反発し、1925年に中国に亡命した。1933年、ダライ・ラマ13世が死去、中国の統治下にあったチベット東北部のアムド地方(青海省)で生まれたダライ・ラマ14世の即位式典に列席した国民政府の使節団は、式典が終了したのちも、蒙蔵委員会駐蔵弁事處を自称してラサにとどまった。1936年には長征中の中国共産党の労農紅軍が、カム地方東部(四川省西部、当時西康省)に滞留中、同地のチベット人に「チベット人人民共和国」(博巴人民共和国)[9]を組織させたが、紅軍の退出とともに、ほどなく消滅した。\n" +
+"\n" +
+"この問題は、モンゴルについては、1947年、外蒙古部分のみの独立を中華民国政府が承認することによって、チベットについては、1950年、十七ヶ条協定によってチベットの独立が否定され中華人民共和国の一地方となったことによって、一応の決着をみた。\n" +
+"\n" +
+"[編集] 東トルキスタン(新疆)での動き\n" +
+"\n" +
+"東トルキスタン(新疆)では、19世紀中に統治機構の中国化が達成されていた。すなわち、旗人の3将軍による軍政と、地元ムスリムによるベク官人制にかわり、省を頂点に府、州、県に行政区画された各地方に漢人科挙官僚が派遣されて統治する体制である。そのため、辛亥革命時、東トルキスタンでは、地元ムスリムがチベットやモンゴルと歩調をあわせて自身の独立国家を形成しようとする動きはみられず、新疆省の当局者たちは、すみやかに新共和国へ合流する姿勢を示した。この地では、楊増新が自立的な政権を維持し、またソ連と独自に難民や貿易の問題について交渉した。楊増新の暗殺後は金樹仁が実権が握ったが、彼は重税を課して腐敗した政治をおこなったため、1931年には大規模な内乱状態に陥った。その後金樹仁の部下であった盛世才が実権を握るようになり、彼はソ連にならった政策を打ち出して徐々に権力を強化した。一方で1933年には南部で東トルキスタン共和国の独立が宣言されたが、わずか6ヶ月で倒れた。\n" +
+"\n" +
+"[編集] 中華人民共和国\n" +
+"\n" +
+"[編集] 社会主義国化と粛清(1949年~1957年)\n" +
+"「建国宣言」を行なう毛沢東\n" +
+"「建国宣言」を行なう毛沢東\n" +
+"\n" +
+"1950年中ソ友好同盟相互援助条約が結ばれた。これは日本およびその同盟国との戦争を想定して締結されたものである。この条約でソ連が租借していた大連、旅順が返還され、ソ連の経済援助の下で復興を目指すこととなった。1953年より社会主義化が進み、人民政治協商会議に代わって全国人民代表大会が成立、農業生産合作社が組織された。\n" +
+"\n" +
+"1956年にソ連でフルシチョフによって「スターリン批判」がおこなわれると、東欧の社会主義国に動揺がはしった。中国共産党政府も共産圏にある国としてこの問題への対処を迫られ、この年初めて開催された党全国代表大会では、「毛沢東思想」という文言が党規約から消えた。そして全く一時的に(わずか2ヶ月)「百花斉放、百家争鳴」と称して民主党などの「ブルジョワ政党」の政治参加が試みられた。しかしブルジョワ政党が中国共産党政府による一党独裁に対して激しい批判を噴出させたため、逆に共産党による反右派闘争を惹起し、一党支配体制は強められた。一方で中ソ協定が結ばれ、軍事上の対ソ依存は強くなった。この時代の中華人民共和国をソ連のアメリカに対する緩衝国家あるいは衛星国家とみなすことも可能である。しかし徐々にデタント政策へと転回し始めていたソ連の対外政策は、中国共産党政府の中華民国に対する強硬政策と明らかに矛盾していた。\n" +
+"\n" +
+"[編集] 中国共産党の対ソ自立化(1958年~1965年)\n" +
+"\n" +
+"1958年に、毛沢東は大躍進政策を開始し、人民公社化を推進した。当初はかなりの効果をあげたかに見えた人民公社であったが、党幹部を意識した誇大報告の存在、極端な労働平均化などの問題が開始3ヶ月にしてすでに報告されていた。毛沢東はこのような報告を右派的な日和見主義であり、過渡的な問題に過ぎないと見ていたため、反対意見を封殺したが、あまりに急速な人民公社化は都市人口の異様な増大など深刻な問題を引き起こしていた。\n" +
+"\n" +
+"一方でこの年、中国共産党政府は台湾海峡で中華民国に対して大規模な軍事行動を起こし、アメリカ軍の介入を招いた。フルシチョフは中国共産党政府の強硬な姿勢を非難し、また自国がアメリカとの全面戦争に引きずり込まれないように努力した。ソ連はワルシャワ条約機構の東アジア版ともいうべき中ソの共同防衛体制を提案したが、中国共産党政府はソ連の対外政策への不信からこれを断った。その後1959年6月ソ連は中ソ協定を一方的に破棄した。1960年には経済技術援助条約も打ち切られ、この年の中国のGNPは1%も下落した。\n" +
+"\n" +
+"1959年と1960年に大規模な飢饉が中国を襲い、1500万人程度(2000万から5000万人以上とも)と言われる餓死者を出して大躍進政策も失敗に終わった。1960年代初頭には人民公社の縮小がおこなわれ、毛沢東自身が自己批判をおこなうなど、一見調整的な時期に入ったように思われた。劉少奇が第2次5ヶ年計画の失敗を人民公社による分権的傾向にあると指摘し、中央集権を目指した政治改革、個人経営を一部認めるなど官僚主義的な経済調整をおこなった。\n" +
+"\n" +
+"しかし党組織の中央集権化と個人経営に懐疑的であった毛沢東はこれを修正主義に陥るものであると見ていた。1963年に毛沢東は「社会主義教育運動」を提唱し、下部構造である「農村の基層組織の3分の1」は地主やブルジョワ分子によって簒奪されていると述べた。これは劉少奇ら「実権派」を暗に批判するものであった。またこのころ毛沢東は「文芸整風」運動と称して学術界、芸術界の刷新をはかっていたことも、のちの文化大革命の伏線となった。1964年中国は核実験に成功し、軍事的な自立化に大きな一歩を踏み出した。一方で1965年にアメリカによる北爆が始まりベトナム戦争が本格化すると、軍事的緊張も高まった。\n" +
+"\n" +
+"チベットでは独立運動が高まったが、政府はこれを運動家に対する拷問など暴力によって弾圧した。このため多数の難民がインドへ流入した。\n" +
+"\n" +
+"[編集] 文化大革命前期(1966年~1969年)\n" +
+"天安門広場は中華人民共和国時代にも多くの歴史の舞台となった\n" +
+"天安門広場は中華人民共和国時代にも多くの歴史の舞台となった\n" +
+"\n" +
+"1966年に毛沢東は文化大革命を提唱した。毛沢東の指示によって中央文化革命小組が設置され、北京の青少年によって革命に賛同する組織である紅衛兵が結成された。毛沢東は「造反有理」(反動派に対する謀反には道理がある)という言葉でこの運動を支持したので、紅衛兵は各地で組織されるようになった。\n" +
+"\n" +
+"毛沢東は文革の目的をブルジョワ的反動主義者と「実権派」であるとし、劉少奇とその支持者を攻撃対象とした。毛沢東は林彪の掌握する軍を背景として劉少奇を失脚させた。しかし文化大革命は政治だけにとどまることがなく、広く社会や文化一般にも批判の矛先が向けられ、反革命派とされた文化人をつるし上げたり、反動的とされた文物が破壊されたりした。\n" +
+"\n" +
+"1966年の末ごろから武力的な闘争が本格化し、地方では党組織と紅衛兵との間で武力を伴った激しい権力闘争がおこなわれた。毛沢東は秩序維持の目的から軍を介入させたが、軍は毛沢東の意向を汲んで紅衛兵などの中国共産党左派に加担した。中央では周恩来らと文革小組の間で権力闘争がおこなわれた。1967年の後半になると、毛沢東は内乱状態になった国内を鎮めるために軍を紅衛兵運動の基盤であった学校や工場に駐屯させた。\n" +
+"\n" +
+"この時期軍の影響力は極端に増大し、それに伴って林彪が急速に台頭した。1969年には中ソ国境の珍宝島で両国の軍事衝突があり(中ソ国境紛争)、軍事的緊張が高まったこともこれを推進した。同年採択された党規約で林彪は毛沢東の後継者であると定められた。\n" +
+"\n" +
+"[編集] 文化大革命後期(1969~1976年)\n" +
+"\n" +
+"文化大革命は後期になると国内の権力闘争や内乱状態を引き起こしたが、最終的に文化大革命は1976年の毛沢東死去で終結した。 文化大革命では各地で文化財破壊や大量の殺戮が行われ、その犠牲者の合計数は数百万人とも数千万人とも言われている。また学生たちが下放され農村で働くなど、生産現場や教育現場は混乱し、特に産業育成や高等教育などで長いブランクをもたらした。\n" +
+"\n" +
+"一方この時期、ソ連に敵対する中国共産党政府は、同じくソ連と敵対する日本やアメリカなどからの外交的承認を受け、この結果国連の常任理事国の議席も台湾島に遷都した中華民国政府(国民党政権)に変わって手にするなど、国際政治での存在感を高めつつあった。\n" +
+"\n" +
+"[編集] 改革開放以後の現在(1976年~)\n" +
+"返還された香港は中国経済の牽引都市になっている\n" +
+"返還された香港は中国経済の牽引都市になっている\n" +
+"\n" +
+"その後は一旦華国鋒が後を継いだが、1978年12月第11期三中全会で鄧小平が政権を握った。鄧小平は、政治体制は共産党一党独裁を堅持しつつ、資本主義経済導入などの改革開放政策を取り、近代化を進めた(社会主義市場経済、鄧小平理論)。この結果、香港ほか日米欧などの外資の流入が開始され、中国経済は離陸を始めた。\n" +
+"\n" +
+"[編集] 一党独裁\n" +
+"\n" +
+"冷戦崩壊後に、複数政党による選挙や言論の自由などの民主主義化を達成した中華民国と違い、いまだに中国共産党政府による一党独裁から脱却できない中華人民共和国には多数の問題が山積している。\n" +
+"\n" +
+"1989年には北京で、1980年代の改革開放政策を進めながら失脚していた胡耀邦の死を悼み、民主化を求める学生や市民の百万人規模のデモ(天安門事件)が起きたが、これは政府により武力鎮圧された。その一連の民主化運動の犠牲者数は中国共産党政府の報告と諸外国の調査との意見の違いがあるが、数百人から数万人に上るといわれている。しかし中国共産党政府はこの事件に関しては国内での正確な報道を許さず、事件後の国外からの非難についても虐殺の正当化に終始している。\n" +
+"\n" +
+"この事件以降も、中国共産党政府は情報や政策の透明化、民主化や法整備の充実などの国際市場が要求する近代化と、暴動や国家分裂につながる事態を避けるため、内外の報道機関やインターネットに統制を加え、反政府活動家に対する弾圧を加えるなどの前近代的な動きとの間で揺れている。この様な中、2003年には国内でSARSの大発生があったが、このときも政府は虚偽の発表を行なうなど問題の隠蔽を繰り返した。\n" +
+"\n" +
+"天安門事件で外資流入に急ブレーキがかかったが、1990年代には、江沢民政権のもとで、鄧小平路線に従い、経済の改革開放が進み、特に安い人件費を生かした工場誘致で「世界の工場」と呼ばれるほど経済は急成長した。なお、1997年にイギリスから香港が、1999年にポルトガルからマカオが、それぞれ中華人民共和国に返還され、植民地時代に整備された経済的、法的インフラを引き継ぎ、中華人民共和国の経済の大きな推進役となっている。また、敵対している中華民国との間にも経済的な交流が進み、両国の首都の間に直行便が就航するまでになっている。\n" +
+"\n" +
+"人口、面積ともに世界的な規模をもつことから、アメリカの証券会社であるゴールドマンサックスは、「中華人民共和国は2050年に世界最大の経済大国になる」と予想するなど、現在、中国経済の動向は良くも悪くも注目されているが、低賃金による大量生産を売り物にしてきた経済成長は賃金上昇・東南アジアやインドの追い上げなどで限界に達しており、産業の高度化や高付加価値化などの難題に迫られている。また、各種経済統計も中国共産党政府発表のそれは信憑性が乏しいと諸外国から指摘されている。各省など地方も独自の産業振興策に走り、中国共産党中央政府に対して経済統計の水増し発表や災害などの情報隠蔽を行うなど、統計や発表の信憑性不足に拍車をかけている。\n" +
+"\n" +
+"これらのことより、中国共産党の一党独裁による言論統制や貧富格差、地域格差など国内のひずみを放置し続ければ、いずれ内部崩壊を起こして再度混乱状態に陥り、ソ連同様に中華人民共和国という国家体制そのものが解体、消滅するという意見も多い。\n" +
+"\n" +
+"[編集] 少数民族問題\n" +
+"\n" +
+"なお、少数民族が住む新疆ウイグル自治区(東トルキスタン)では現在漢化政策の進展によって、漢民族が同地域へ大量に流入する、都市を中心として就職などに有利な中国語教育の充実によりウイグル語が廃れるなどの民族的なマイノリティ問題が発生している。またタクラマカン砂漠の石油資源利用や新疆南北の経済格差が広がっているなど、中国共産党政府の経済政策に対する批判も根強い。\n" +
+"\n" +
+"1997年には新疆ウイグル自治区で大規模な暴動が起きた。海外で東トルキスタン独立運動がおこなわれている一方国内でもウイグル人活動家の処刑などが行われているが、民族自治における権限拡大という現実主義的な主張もあらわれている。たとえば中国語教育を受けたウイグル人が中国共産党組織に参加する、新疆での中国共産党政府の経済政策に積極的に参加するといった事例も見られる。\n" +
+"\n" +
+"チベット自治区では歴史的なチベットの主権を主張するダライ・ラマの亡命政権が海外に存在し、中国共産党政府が不法な領土占拠をしていると訴えるとともに独立運動が継続されている。中国共産党政府はこれを武力で弾圧し続け、独立運動家への拷問などを行なったために、多数の難民が隣国のインドに流入した。\n" +
+"\n" +
+"[編集] 人口の変遷\n" +
+"\n" +
+"以下のデータは主に楊学通「計画生育是我国人口史発展的必然」(1980年)による。\n" +
+"時代        年代  戸数  人口  資料出所\n" +
+"(夏)     禹(前2205年とされる)                 13,553,923      『帝王世紀』\n" +
+"秦                   20,000,000?     \n" +
+"前漢        平帝元始2年(2年)      12,233,062      59,594,978      『漢書』地理志\n" +
+"新                   20,000,000?     \n" +
+"後漢        順帝建康元年(144年)  9,946,919       49,730,550      『冊府元亀』\n" +
+"晋   武帝泰康元年(280年)  2,459,804       16,163,863      『晋書』食貨志\n" +
+"隋   煬帝大業2年(606年)    8,907,536       46,019,056      『隋書』地理志・食貨志\n" +
+"唐   玄宗天宝14年(755年)   8,914,709       52,919,309      『通志』\n" +
+"宋   神宗元豊3年(1080年)   14,852,684      33,303,889      『宋史』地理志\n" +
+"金   章宗明昌6年(1195年)   7,223,400       48,490,400      『金史』食貨志\n" +
+"元   世祖至元27年(1290年)  13,196,206      58,834,711      『元史』地理志\n" +
+"明   神宗万暦6年(1570年)   10,621,436      60,692,850      『続文献通考』\n" +
+"清   清初(1644年)             45,000,000      \n" +
+"聖祖康熙50年(1711年)                100,000,000以上       \n" +
+"高宗乾隆27年(1762年)                200,000,000以上       \n" +
+"高宗乾隆55年(1790年)                300,000,000以上       \n" +
+"仁宗嘉慶17年(1812年)                333,700,560     『東華録』\n" +
+"宣宗道光14年(1834年)                400,000,000以上       \n" +
+"中華民国  民国36年(1947年)                455,590,000     『統計提要』\n" +
+"中華人民共和国         1995年                 1,211,210,000   『中国統計年鑑』\n" +
+"\n" +
+"[編集] 地方行政制度\n" +
+"\n" +
+"[編集] 封建制度(前1600年頃~前221年)\n" +
+"\n" +
+"殷・周の時代は封建制度[10]によって一定の直轄地以外は間接的に統治された。\n" +
+"\n" +
+"[編集] 郡県制度(前221年~249年)\n" +
+"\n" +
+"中国最初の統一王朝である秦は全国を郡とその下級単位である県に分ける郡県制度によって征服地を統治した。前漢初期においては、郡以上に広域な自治を認められた行政単位である国が一部の功臣や皇族のために設置された。しかし徐々に国の行政権限が回収されるとともに、推恩政策によって国の細分化が進められ、国は郡県と等しいものとなり、後漢時代には実質郡県制度そのままとなっていた。\n" +
+"\n" +
+"前漢時代に広域な監察制度としての刺史制度が始められると全国を13州[11]に分けた。これはいまだ行政的なものではない[12]と考えられている。後漢の後の魏王朝では官僚登用制度としての九品官人法が249年に司馬懿によって州単位でおこなわれるように適用されたので、行政単位として郡以上に広域な州が現実的な行政単位として確立したと考えられている。が、軍政面と官吏登用面のほかにどれほど地方行政に貢献したか[13]はあまり明確ではない。\n" +
+"\n" +
+"[編集] 軍府による広域行政(249年~583年)\n" +
+"\n" +
+"魏晋時代から都督府などの軍府の重要性が高まった。五胡十六国および南北朝時代になると、中国内部で複数の王朝が割拠し軍事的な緊張が高まったことから、とくに南朝において重要性が増した。これは本来特定の行政機関を持たなかったと思われる刺史に対して、軍事的に重要な地域の刺史に例外的に複数の州を統括できる行政権を与えたものであった。長官である府主(府の長官は一般的にさまざまな将軍号を帯び、呼称は一定ではないため便宜的に府主とする)は属僚の選定に対して大幅な裁量権が与えられており、そのため地方で自治的な支配を及ぼすことが出来た。また南朝では西晋末期から官吏登用において州は形骸化しており、吏部尚書によって官制における中央集権化が進行している。したがって中正官も単なる地方官吏に過ぎなくなり、広域行政単位としての州は官吏登用の面からは重要性が低下したが、地方行政単位としてはより実際性を帯びた。この時代州は一般に細分化傾向にあり、南北朝前期には中国全土で5,60州、南北朝末期に至ると中国全土で300州以上になり、ひとつの州がわずか2郡、ひとつの郡はわずか2,3県しか含まないという有様であった。\n" +
+"\n" +
+"[編集] 州県制(583年~1276年)\n" +
+"\n" +
+"南朝では都督制度が発達していたころ、北魏では州鎮制度が発達した。北魏では征服地にまず軍事的性格の強い鎮を置き、鎮は一般の平民と区別され軍籍に登録された鎮民を隷属させて支配した。鎮は徐々に州に改められたようであるが、北部辺境などでは鎮がずっと維持された。583年に隋の文帝が郡を廃止し、州県二級の行政制度を開始した。この際従来の軍府制度[14]にあった漢代地方制度的な旧州刺史系統の地方官は廃止され、軍府系統の地方官に統一されたと考えられている。595年には形骸化していた中正官も最終的に廃止されたという指摘もされている。またこれにより府主の属官任命権が著しく制限され、中央集権化がはかられた。唐では辺境を中心に広域な州鎮的軍府である総管府が置かれたが徐々に廃止され、刺史制度に基づいた地方軍的軍府、それに中央軍に対する吏部の人事権が強化・一元化され、軍事制度の中央集権化が完成された。特定の州に折衝府が置かれ、自営農民を中心として府兵が組織され常備地方軍[15]とされた。唐では州の上に10の道も設置されたが、これは監察区域で行政単位ではないと考えられている。\n" +
+"\n" +
+"[編集] 祭祀制度\n" +
+"\n" +
+"中国でおこなわれた国家祭祀については皇帝祭祀を参照。\n" +
+"\n" +
+"[編集] 外交\n" +
+"\n" +
+"中国大陸の諸王朝は前近代まで基本的に東アジアでの優越的な地位を主張し、外交的には大国として近隣諸国を従属的に扱う冊封体制が主流であった。\n" +
+"\n" +
+"[編集] 漢帝国\n" +
+"\n" +
+"漢代には南越、閩越、衛氏朝鮮などが漢の宗主権下にあったと考えられ、これらの国々は漢の冊封体制下にあったと考えられている。前漢武帝の時にこれらの諸国は征服され郡県に編入された。このことは漢の冊封が必ずしも永続的な冊封秩序を形成することを意図したものではなく、機会さえあれば実効支配を及ぼそうとしていたことを示す。また匈奴は基本的には冊封体制に組み込まれず、匈奴の単于と中国王朝の皇帝は原則的には対等であった。大秦(ローマ帝国のことを指すとされる)や大月氏などとの外交関係は冊封を前提とされていない。\n" +
+"\n" +
+"[編集] 魏晋南北朝時代\n" +
+"\n" +
+"魏晋南北朝時代には、中国王朝が分立する事態になったので、冊封体制は変質し実効支配を意図しない名目的な傾向が強くなったと考えられている。朝鮮半島では高句麗をはじめとして中小国家が分立する状態があらわれ、日本列島の古代国家[16] も半島の紛争に介入するようになったために、半島の紛争での外交的優位を得るため、これらの国々は積極的に中国王朝の冊封を求めた。しかし高句麗が北朝の実効支配には頑強に抵抗しているように、あくまで名目的関係にとどめようという努力がなされており、南越と閩越の紛争においておこなわれたような中国王朝の主導による紛争解決などは期待されていないという見方が主流である。\n" +
+"\n" +
+"[編集] 隋唐帝国\n" +
+"\n" +
+"再び中国大陸を統一した隋・唐の王朝の時代は東アジアの冊封体制がもっとも典型的となったという見方が主流である。隋は高句麗がみだりに突厥と通交し、辺境を侵したことからこれを討伐しようとしたが、遠征に失敗した。唐は、新羅と連合し、高句麗・百済を滅亡させ、朝鮮半島を州県支配しようとしたが、新羅に敗北し、願いは、叶わなかった。したがって隋・唐の冊封は実効支配とは無関係に形成されるようになった。唐の冊封体制の下では、律令的な政治体制・仏教的な文化が共有された。\n" +
+"\n" +
+"一方、突厥や西域諸国が服属すると、それらの地域に対する支配は直接支配としての州県、外交支配としての冊封とは異なった羈縻政策[17]がおこなわれた。\n" +
+"\n" +
+"[編集] 関連項目\n" +
+"\n" +
+"    * 中華人民共和国\n" +
+"    * 中華民国\n" +
+"    * 中国帝王一覧\n" +
+"    * 中国の首都\n" +
+"    * 中国史時代区分表\n" +
+"          o 夏商周年表\n" +
+"          o 魏晋南北朝表\n" +
+"    * 元号一覧\n" +
+"    * 二十四史(清によって公認された正史)\n" +
+"    * 中国史関係記事一覧\n" +
+"    * マカオの歴史\n" +
+"    * 香港の歴史\n" +
+"    * 台湾の歴史\n" +
+"    * 中国の通貨制度史\n" +
+"    * 中国の仏教\n" +
+"    * 中国法制史\n" +
+"    * 中国化\n" +
+"\n" +
+"Wikibooks\n" +
+"ウィキブックスに中国史関連の教科書や解説書があります。\n" +
+"[編集] 脚注\n" +
+"\n" +
+"   1. ^ 浙江省紹興市郊外にある陵墓が禹のものであるとされ、戦国時代同地を支配していた越王勾践が禹の子孫を標榜していること、夏の桀王が『史記』鄭玄注などで淮河と長江の中間にある南巣で死んだとしていることなどによる。\n" +
+"   2. ^ 河南省にある偃師二里頭遺跡が夏のものではないかとされているが、文書などが発見されていないため確定はされていない。また偃師二里頭遺跡での発掘結果から殷との連続性が確認されたが、細かい分析においては殷との非連続性も確認されているため、偃師二里頭遺跡が夏王朝のものであっても、夏が黄河流域起源の王朝であったかどうかは論争中である。\n" +
+"   3. ^ 代表的な遺跡殷墟が有名であるため日本では一般に殷と呼ばれるが、商の地が殷王朝の故郷とされており、商が自称であるという説もあるため、中国では商と呼ぶほうが一般的である。\n" +
+"   4. ^ ただし殷を北西から侵入してきた遊牧民族による征服王朝だとする説もある。これは偃師二里頭遺跡では青銅器が現地生産されているのに対し、殷時代の青銅器は主に蜀方面で生産されていたことが確認されていることによる。\n" +
+"   5. ^ 当初は漢魏革命の際に漢の官僚を魏宮廷に回収する目的で制定されたものであったが、優れたものであったために一般的な官吏登用に使用されるようになった。これは中正官を通して地方の世論を反映した人事政策をおこなうもので、地方で名望のあったものをその程度に応じて品位に分け官僚として登用するものであった。官僚は自身の品位と官職の官品に従って一定の官職を歴任した。地方の世論に基づくとはいえ、一般的に家柄が重視される傾向にあり、「上品に寒門なく、下品に勢族なし」といわれた。南北朝時代になると官職内で名誉的な清流官職と濁流官職が貴族意識によって明確に分けられ、また家柄によって官職が固定される傾向が顕著となった。このような傾向は専制支配を貫徹しようとする皇帝の意向と対立するものであったため、官品の整理をおこなって清濁の区別をなくす努力が続けられた。しかし皇帝も貴族社会の解体そのものを望んでおらず、貴族社会の上位に皇帝権力を位置づけることでヒエラルキーを維持しようとしていたから、官職制度の根幹的な改変には至らず、官職の家柄による独占傾向を抑えることは出来なかった。\n" +
+"   6. ^ 1916年8月に復活された。\n" +
+"   7. ^ これはロシア革命に対するシベリア出兵において日中両軍が協力するという秘密条約である。\n" +
+"   8. ^ 1928年~30年に各国と交渉して関税自主権を回復し、関税を引き上げ、塩税と統一消費税をさだめて財源を確保した。アメリカとイギリスの銀行資本に「法幣」という紙幣を使用させ、秤量貨幣であった銀両を廃止した。さらにアメリカ政府に銀を売ってドルを外為資金として貯蓄した。これにより国際的な銀価格の中国の国内経済に対する影響が大幅に緩和された。このような経済政策を積極的に推進したのは国民政府財政部長の宋子文で、彼は孫文の妻宋慶齢の弟で、妹はのちに蒋介石と結婚した宋美齢であった。\n" +
+"   9. ^ 博巴あるいは波巴とはチベット人の自称。日本語に訳せばチベット人の人民政府という意味である。博巴と波巴はともに「ぽぱ」と読む。\n" +
+"  10. ^ 封建制度は殷代からおこなわれているが、殷代封建制についてはあまり明確なことはわからない。殷では封建がおこなわれている地域と方国と呼ばれる、外様あるいは異民族の国家の存在が知られ、殷を方国の連盟の盟主であり、封建された国々は殷の同族国家であるとする説もあるが詳しいことはわからない。周では一定の城市を基準とした邑に基づいた封建制が広汎におこなわれたと考えられているが、この邑制国家の実態も不明である。邑をポリス的な都市国家とみる見方から、邑と周辺農地である鄙が一緒になって(これを邑土という)、貴族による大土地所有であるとする見方もある。明らかであるのは邑を支配した貴族が長子相続を根幹とした血族共同体をもっていたということで、このような共同体に基づいた支配形態を宗法制度という。宗法制度については殷代にさかのぼる見方もあるが、広汎におこなわれたのは春秋あるいは戦国時代であったとする説もある。周の封建制を宗法制度の延長にあるものと捉え、封建儀礼を宗族への加盟儀礼の延長として捉える見方もある。\n" +
+"  11. ^ 中国古来より中国世界を9つの地方に分ける考え方が漠然と存在した。中国王朝の支配領域を「九州」といい、それがすなわち「天下」であった。ただし九州の概念は後漢時代にいたるまでははっきりしたものではなく一様でない。\n" +
+"  12. ^ 前漢成帝のときに州の監察権が御史中丞へ移行され、刺史が行政官となったという見方もあるが、後漢末期に刺史に軍事権が認められると、広域行政単位としての州はにわかに現実化したとみる見方もある。\n" +
+"  13. ^ このころの州を行政単位ではなく、軍管区のような概念上の管理単位であるとする見方も強い。\n" +
+"  14. ^ 北周の宇文護が創始した二十四軍制をもっていわゆる府兵制の成立と見做す見方があるがこれについては詳しいことはわからない。\n" +
+"  15. ^ 折衝府の置かれた州と非設置州では当然差異があったのであるが、唐代はほかに募兵に基づく行軍制度もおこなわれており、大規模な対外戦争の際にはおもに折衝府非設置州を中心として兵が集められた。唐後期にはこの募兵制が常態化することで節度使制度がおこなわれるようになった。\n" +
+"  16. ^ なお、史書からうかがえる外交記録と日本国内での銅鏡など出土品に記載された年号の問題などから、日本の古代王朝は特に南朝との外交関係を重視していたという見方が主流であるが、北朝との通交事実を明らかにしようという研究は続けられている。\n" +
+"  17. ^ これは都護府を通じて服属民族を部族別に自治権を与えて間接支配するもので、羈縻政策がおこなわれた地域では現地民の国家は否定された。このことは羈縻州の住民が自発的に中国王朝の文化を受け入れることを阻害したと考えられており、羈縻政策のおこなわれた地域では冊封のおこなわれた地域とは異なり、漢字や律令などの文化の共有はおこなわれず、唐の支配が後退すると、唐の文化もこの地域では衰退することになった。冊封された国々で唐の支配が後退したあとも漢字文化が存続したことと対照的である。\n";
+
+
+var korean =
+"한국의 역사\n" +
+"위키백과 ― 우리 모두의 백과사전.\n" +
+" 이 문서는 남, 북으로 분단된 1945년 이전의 한국에 대한 역사를 주로 기술하고 있다.\n" +
+"\n" +
+"한국의 역사 (연표)\n" +
+"한국의 선사 시대 (유적)\n" +
+"환인 · 환웅 (신시)\n" +
+"    고조선 - 단군\n" +
+"진국\n" +
+"원\n" +
+"삼\n" +
+"국\n" +
+"|\n" +
+"삼\n" +
+"국\n" +
+"|\n" +
+"남\n" +
+"북\n" +
+"국\n" +
+"|\n" +
+"후\n" +
+"삼\n" +
+"국   삼한  옥\n" +
+"저   동\n" +
+"예   부\n" +
+"여\n" +
+"진\n" +
+"한   변\n" +
+"한   마\n" +
+"한\n" +
+"    가\n" +
+"야    \n" +
+" \n" +
+"백\n" +
+"제\n" +
+" \n" +
+"    고\n" +
+"구\n" +
+"려          \n" +
+"신\n" +
+"라          \n" +
+"     \n" +
+"후\n" +
+"백\n" +
+"제   태\n" +
+"봉   발\n" +
+"해\n" +
+" \n" +
+"고려\n" +
+" \n" +
+" \n" +
+"조선\n" +
+" \n" +
+"대한제국\n" +
+"대한민국임시정부\n" +
+"일제 강점기 (조선총독부)\n" +
+"군정기\n" +
+"대한민국  조선민주주의\n" +
+"인민공화국\n" +
+"한국의 인물\n" +
+"한국의 역사는 구석기 시대 이후의 주로 한반도와 만주, 넓게는 동아시아 지역을 배경으로 발전되어 온 한국인의 역사이다.\n" +
+"목차 [숨기기]\n" +
+"1 선사 시대\n" +
+"1.1 유적에 의한 구분\n" +
+"1.2 문헌에 의한 구분\n" +
+"2 상고 시대 (B.C. 2333년 ~ A.D. 1세기)\n" +
+"2.1 고조선 시대\n" +
+"2.2 고조선 멸망 이후 여러나라의 성장\n" +
+"3 고대 시대 (A.D. 1세기~A.D. 900)\n" +
+"3.1 삼국시대\n" +
+"3.1.1 삼국시대 경제\n" +
+"3.1.2 삼국시대 정치\n" +
+"3.2 남북국시대\n" +
+"4 중세시대 (A.D. 918년 ~ A.D. 1392년)\n" +
+"4.1 고려의 정치\n" +
+"4.2 고려의 경제\n" +
+"4.3 고려의 사회\n" +
+"4.4 고려의 문화\n" +
+"5 근세시대 (A.D. 1392년 ~ A.D. 1506년)\n" +
+"5.1 초기 조선의 정치\n" +
+"5.2 초기 조선의 경제\n" +
+"5.3 초기 조선의 사회\n" +
+"5.4 초기 조선의 문화\n" +
+"6 근대 태동기 (A.D. 1506년 ~ A.D. 1907년)\n" +
+"6.1 후기 조선의 정치\n" +
+"6.2 후기 조선의 경제\n" +
+"6.3 후기 조선의 사회\n" +
+"6.4 후기 조선의 문화\n" +
+"7 근현대시대 (A.D. 1907년 ~ )\n" +
+"7.1 개괄\n" +
+"7.2 근대시대\n" +
+"7.3 현대시대\n" +
+"8 주석\n" +
+"9 같이 보기\n" +
+"10 참고문헌 및 링크\n" +
+"10.1 역사 일반\n" +
+"10.2 재단, 기타, 정부 기관\n" +
+"[편집]\n" +
+"선사 시대\n" +
+"\n" +
+"[편집]\n" +
+"유적에 의한 구분\n" +
+"한국의 구석기 시대(20만 년 이전 ~ 약 1만 년 전)\n" +
+"한국의 신석기 시대(약 1만 년 전 ~ 약 4천 년 전)\n" +
+"참고>> 웅기 부포리와 평양 만달리 유적, 통영 상노대도의 조개더미 최하층, 거창 임불리, 홍천 화화계리 유적 등을 중석기 유적지로 보는 사학자도 있다.\n" +
+"[편집]\n" +
+"문헌에 의한 구분\n" +
+"환국시대 [1](비공식)\n" +
+"신시[2] 또는 배달국 시대 [3](비공식)\n" +
+"[편집]\n" +
+"상고 시대 (B.C. 2333년 ~ A.D. 1세기)\n" +
+"\n" +
+"농경의 발달로 잉여 생산물이 생기고 청동기가 사용되면서 사유 재산 제도와 계급이 발생하였고, 그 결과, 부와 권력을 가진 족장(군장)이 출현하였다고 추측된다. 이 시기의 대표적인 유적으로 고인돌, 비파형 동검, 미송리식 토기 등이 있다. 부족장은 세력을 키워 주변 지역을 아우르고, 마침내 국가를 이룩하였다. 이 시기에 성립된 한국 최초의 국가가 고조선이다. 기원전 4세기경 철기가 보급되었고, 이후, 고조선은 철기 문화를 수용하면서 중국과 대립할 정도로 크게 발전하였으며, 만주와 한반도 각지에는 부여, 고구려, 옥저, 동예, 삼한 등 여러 나라가 성립될 수 있는 터전이 마련되었다.\n" +
+"[편집]\n" +
+"고조선 시대\n" +
+"단군조선\n" +
+"위만조선\n" +
+"조선 시대 이전에는 은나라에서 건너온 기자가 세운 기자조선이 정식 역사로서 인정되었으나, 일제강점기를 전후로 점차 부인되어 현재에는 대한민국과 조선민주주의인민공화국의 역사학계 모두 이를 공식적으로 인정하지 않고 있으며, 사학자들도 대체적으로 이 설을 부정한다.\n" +
+"[편집]\n" +
+"고조선 멸망 이후 여러나라의 성장\n" +
+"철기문명을 받아들인 각 나라들은 철기를 이용하여 농업을 발전시키면서도 독특한 사회 풍습을 유지하였다. 많은 소국들이 경쟁하는 가운데 일부는 다른 나라를 병합되었고, 다시 연맹 왕국으로 발전하여 중앙 집권 국가를 형성할 수 있는 기반을 마련하게 되었다.\n" +
+"부여: 북부여, 동부여, 졸본부여\n" +
+"옥저\n" +
+"동예\n" +
+"삼한:\n" +
+"마한\n" +
+"변한\n" +
+"진한\n" +
+"[편집]\n" +
+"고대 시대 (A.D. 1세기~A.D. 900)\n" +
+"\n" +
+"[편집]\n" +
+"삼국시대\n" +
+"고구려\n" +
+"백제\n" +
+"신라\n" +
+"삼국시대 초반은 고구려와 백제가 주도했으나 진흥왕 이후 국력이 막강해진 신라가 삼국시대 후기를 주도 했다.\n" +
+"[편집]\n" +
+"삼국시대 경제\n" +
+"삼국의 경제는 기본적으로 물물교환 경제를 못 벗어난 체제였다고 한다.[출처 필요]\n" +
+"삼국사기에는 신라가 수도에 시전을 세웠다는 기록이 있다.\n" +
+"[편집]\n" +
+"삼국시대 정치\n" +
+"삼국의 정치는 기본적으로 중앙집권체제를 토대로 한 전제왕권 또는 귀족정치였다.\n" +
+"[편집]\n" +
+"남북국시대\n" +
+"신라\n" +
+"발해\n" +
+"[편집]\n" +
+"중세시대 (A.D. 918년 ~ A.D. 1392년)\n" +
+"\n" +
+"한국사에서는 고려시대를 중세시대로 보고 있다.\n" +
+"[편집]\n" +
+"고려의 정치\n" +
+"고려는 새로운 통일 왕조로서 커다란 역사적 의의를 지닌다. 고려의 성립은 고대 사회에서 중세 사회로 이행하는 우리 역사의 내재적 발전을 의미한다. 신라말의 득난(6두품 세력) 출신 지식인과 호족 출신을 중심으로 성립한 고려는 골품 위주의 신라 사회보다 개방적이었고, 통치 체제도 과거제를 실시하는 등 효율성과 합리성이 강화되는 방향으로 정비되었다. 특히, 사상적으로 유교 정치 이념을 수용하여 고대적 성격을 벗어날 수 있었다.\n" +
+"고려 시대는 외적의 침입이 유달리 많았던 시기였다. 그러나 고려는 줄기찬 항쟁으로 이를 극복할 수 있었다. 12세기 후반에 무신들이 일으킨 무신정변은 종전의 문신 귀족 중심의 사회를 변화 시키는 계기가 되어 신분이 낮은 사람도 정치적으로 진출할 수 있었다.\n" +
+"이후, 무신 집권기와 원나라 간섭기를 지나 고려 후기에 이르러서는 새롭게 성장한 신진 사대부를 중심으로 성리학이 수용되어 합리적이고 민본적인 정치 이념이 성립되었고, 이에 따른 사회 개혁이 진전되었다.\n" +
+"[편집]\n" +
+"고려의 경제\n" +
+"고려는 후삼국 시기의 혼란을 극복하고 전시과 제도를 만드는 등 토지 제도를 정비하여 통치 체제의 토대를 확립하였다. 또, 수취 체제를 정비하면서 토지와 인구를 파악하기 위하여 양전 사업을 실시하고 호적을 작성하였다. 아울러 국가가 주도하여 산업을 재편하면서 경작지를 확대시키고, 상업과 수공업의 체제를 확립하여 안정된 경제 기반을 확보하였다.\n" +
+"농업에서는 기술의 발달로 농업 생산력이 증대되었고, 상업은 시전을 중심으로 도시 상업이 발달하면서 점차 지방에서도 상업 활동이 증가하였다. 수공업도 관청 수공업 중심에서 점차 사원이나 농민을 중심으로한 민간 수공업을 중심으로 발전해 갔다.\n" +
+"[편집]\n" +
+"고려의 사회\n" +
+"고려의 사회 신분은 귀족, 중류층, 양민, 천민으로 구성되었다. 고려 지배층의 핵심은 귀족이었다. 신분은 세습되는 것이 원칙이었고, 각 신분에는 그에 따른 역이 부과되었다. 그러나 그렇지 않은 경우도 있었는데, 향리로부터 문반직에 오르는 경우와 군인이 군공을 쌓아 무반으로 출세하는 경우를 들 수 있다.\n" +
+"백성의 대부분을 이루는 양민은 군현에 거주하는 농민으로, 조세, 공납, 역을 부담하였다. 향, 부곡, 소 같은 특수 행정 구역에 거주하는 백성은 조세 부담에 있어서 군현민보다 차별받았으나, 고려 후기 이후 특수 행정 구역은 일반 군현으로 바뀌어 갔다. 흉년이나 재해 등으로 어려움을 겪는 백성들의 생활을 안정시키기 위하여 국가는 의창과 상평창을 설치하고, 여러 가지 사회 복지 시책을 실시 하였다.\n" +
+"[편집]\n" +
+"고려의 문화\n" +
+"고려 시대에 해당하는 중세 문화는 고대 문화의 기반 위에서 조상들의 노력과 슬기가 보태져 새로운 양상을 보였다.\n" +
+"유교가 정치 이념으로 채택, 적용됨으로써 유교에 대한 인식이 확대 되었으며, 후기에는 성리학도 전래 되었다. 불교는 그 저변이 확대되어 생활 전반에 영향을 끼쳤다. 이런 가운데 불교 사상이 심화되고, 교종과 선종의 통합운동이 꾸준히 추진되었다.\n" +
+"중세의 예술은 귀족 중심의 우아하고 세련된 특징을 드러내고 있다. 건축과 조각에서는 고대의 성격을 벗어나 중세적 양식을 창출하였으며, 청자와 인쇄술은 세계적인 수준을 자랑하고 있다. 그림과 문학에서도 중세의 품격 높은 멋을 찾아 볼 수 있다.\n" +
+"[편집]\n" +
+"근세시대 (A.D. 1392년 ~ A.D. 1506년)\n" +
+"\n" +
+"한국사에서는 초기 조선 시대를 근세시대로 보고 있다.\n" +
+"[편집]\n" +
+"초기 조선의 정치\n" +
+"조선은 왕과 양반 관료들에 의하여 통치되었다. 왕은 최고 명령권자로서 통치 체제의 중심이었다. 조선 초기에는 고려 말에 성리학을 정치 이념으로 하면서 지방에서 성장한 신진 사대부들이 지배층이 되어 정국을 이끌어 나갔다. 그러나 15세기 말부터 새롭게 성장한 사림이 16세기 후반 이후 정국을 주도해 나가면서 학파를 중심으로 사림이 분열하여 붕당을 이루었다. 이후 여러 붕당 사이에 서로 비판하며 견제하는 붕당 정치를 전개하였다.\n" +
+"정치 구조는 권력의 집중을 방지하면서 행정의 효율성을 높이는 방향으로 정비되었다. 관리 등용에 혈연이나 지연보다 능력을 중시하였고, 언로를 개방하여 독점적인 권력 행사를 견제하였다. 아울러 육조를 중심으로 행정을 분담하여 효율성을 높이면서 정책의 협의나 집행 과정에서 유기적인 연결이 가능하도록 하였다. 조선은 고려에 비하여 한 단계 발전된 모습을 보여 주면서 중세 사회에서 벗어나 근세 사회로 나아갔다.\n" +
+"[편집]\n" +
+"초기 조선의 경제\n" +
+"조선은 고려 말기의 파탄된 국가 재정과 민생 문제를 해결하고 재정 확충과 민생 안정을 위한 방안으로 농본주의 경제 정책을 내세웠다. 특히 애민사상을 주장하는 왕도 정치 사상에서 민생 안정은 가장 먼저 해결해야 할 과제였다.\n" +
+"조선 건국을 주도하였던 신진 사대부들은 중농 정책을 표방하면서 농경지를 확대하고 농업 생산력을 증가시키며, 농민의 조세 부담을 줄여 농민들의 생활을 안정시키려 하였다. 그리하여 건국 초부터 토지 개간을 장려하고 양전 사업을 실시한 결과 고려 말 50여만 결이었던 경지 면적이 15세기 중엽에는 160여만 결로 증가하였다. 또한 농업 생산력을 향상시키기 위하여 새로운 농업 기술과 농기구를 개발하여 민간에 널리 보급하였다.\n" +
+"반면 상공업자가 허가 없이 마음대로 영업 활동을 벌이는 것을 규제하였는데, 이는 당시 검약한 생활을 강조하는 유교적인 경제관을 가진 사대부들이 물화의 수량과 종류를 정부가 통제하지 않고 자유 활동에 맡겨 두면 사치와 낭비가 조장되며 농업이 피폐하여 빈부의 격차가 커지게 된다고 생각하였기 때문이다. 더욱이 당시 사회에서는 직업적인 차별이 있어 상공업자들이 제대로 대우받지 못하였다.\n" +
+"[편집]\n" +
+"초기 조선의 사회\n" +
+"조선은 사회 신분을 양인과 천민으로 구분하는 양천 제도를 법제화하였다. 양인은 과거에 응시하고 벼슬길에 오를 수 있는 자유민으로서 조세, 국역 등의 의무를 지녔다. 천민은 비(非)자유민으로서 개인이나 국가에 소속되어 천역을 담당하였다.\n" +
+"양천 제도는 갑오개혁 이전까지 조선 사회를 지탱해 온 기본적인 신분 제도였다. 그러나 실제로는 양천 제도의 원칙에만 입각하여 운영되지는 않았다. 세월이 흐를수록 관직을 가진 사람을 의미하던 양반은 하나의 신분으로 굳어져 갔고, 양반 관료들을 보좌하던 중인도 신분층으로 정착되어 갔다. 그리하여 지배층인 양반과 피지배층인 상민 간의 차별을 두는 반상 제도가 일반화되고 양반, 중인, 상민, 천민의 신분 제도가 점차 정착되었다.\n" +
+"조선 시대는 엄격한 신분제 사회였으나 신분 이동이 가능하였다. 법적으로 양인 이상이면 누구나 과거에 응시하여 관직에 오를 수 있었고, 양반도 죄를 지으면 노비가 되거나 경제적으로 몰락하여 중인이나 상민이 되기도 하였다.\n" +
+"[편집]\n" +
+"초기 조선의 문화\n" +
+"조선 초기에는 괄목할 만한 민족적이면서 실용적인 성격의 학문이 발달하여 다른 시기보다 민족 문화의 발전이 크게 이루어졌다. 당시의 집권층은 민생 안정과 부국강병을 위하여 과학 기술과 실용적 학문을 중시하여, 한글이 창제되고 역사책을 비롯한 각 분야의 서적들이 출반되는 등 민족 문화 발전의 기반이 형성되었다.\n" +
+"성리학이 정착, 발달하여 전 사회에 큰 영향을 끼쳤고, 여러 갈래의 학파가 나타났다. 15세기 문화를 주도한 관학파 계열의 관료들과 학자들은 성리학을 지도 이념으로 내세웠으나 성리학 이외의 학문과 사상이라도 좋은 점이 있으면 받아들이는 융통성을 보였다. 불교는 정부에 의하여 정비되면서 위축되었으나 민간에서는 여전히 신앙의 대상으로 자리 잡고 있었다.\n" +
+"천문학, 의학 등 과학 기술에 있어서도 큰 발전을 이룩하여 생활에 응용되었고, 농업 기술은 크게 향상되어 농업 생산력을 증대시켰다.\n" +
+"예술 분야에서도 민족적 특색이 돋보이는 발전을 나타내었고, 사대부들의 검소하고 소박한 생활이 반영된 그림과 필체 및 자기 공예가 두드러졌다.\n" +
+"[편집]\n" +
+"근대 태동기 (A.D. 1506년 ~ A.D. 1907년)\n" +
+"\n" +
+"한국사에서는 후기 조선 시대를 근대 태동기로 보고 있다.\n" +
+"[편집]\n" +
+"후기 조선의 정치\n" +
+"숙종 때에 이르러 붕당 정치가 변질되고 그 폐단이 심화되면서 특정 붕당이 정권을 독점하는 일당 전제화의 추세가 대두되었다. 붕당 정치가 변질되자 정치 집단 간의 세력 균형이 무너지고 왕권 자체도 불안하게 되었다. 이에 영조와 정조는 특정 붕당의 권력 장악을 견제하기 위하여 탕평 정치를 추진하였다. 탕평 정치는 특정 권력 집단을 억제하고 왕권을 강화하려는 방향으로 진행되어 어느 정도 성과를 거두었지만, 붕당 정치의 폐단을 일소하지는 못하였다.\n" +
+"탕평 정치로 강화된 왕권을 순조 이후의 왕들이 제대로 행사하지 못하면서 왕실의 외척을 중심으로 한 소수 가문에 권력이 집중되고 정치 기강이 문란해지는 세도 정치가 전개되었다. 이로써 부정부패가 만연해지고 정부의 백성들에 대한 수탈이 심해졌다.\n" +
+"[편집]\n" +
+"후기 조선의 경제\n" +
+"임진왜란과 병자호란을 거치면서 농촌 사회는 심각하게 파괴되었다. 수많은 농민들이 전란 중에 죽거나 피난을 가고 경작지는 황폐화되었다. 이에 정부는 수취 체제를 개편하여 농촌 사회를 안정시키고 재정 기반을 확대하려 하였다. 그것은 전세 제도, 공납 제도, 군역 제도의 개편으로 나타났다.\n" +
+"서민들은 생산력을 높이기 위하여 농기구와 시비법을 개량하는 등 새로운 영농 방법을 추구하였고, 상품 작물을 재배하여 소득을 늘리려 하였다. 상인들도 상업 활동에 적극적으로 참여하여 대자본을 가진 상인들도 출현하였다. 수공업 생산도 활발해져 민간에서 생산 활동을 주도하여 갔다. 이러한 과정에서 자본 축적이 이루어지고, 지방의 상공업 활동이 활기를 띠었으며, 상업 도시가 출현하기에 이르렀다.\n" +
+"[편집]\n" +
+"후기 조선의 사회\n" +
+"조선 후기 사회는 사회 경제적 변화로 인하여 신분 변동이 활발해져 양반 중심의 신분 체제가 크게 흔들렸다. 붕당 정치가 날이 갈수록 변질되어 가면서 양반 상호 간에 일어난 정치적 갈등은 양반층의 분화을 불러왔다. 이러한 현상은 일당 전제화가 전개되면서 더욱 두드러지고 권력을 장악한 소수의 양반을 제외한 다수의 양반들이 몰락하는 계기가 되었다. 이렇게 양반 계층의 도태 현상이 날로 심화되어 가면서도 양반의 수는 늘어나고 상민과 노비의 숫자는 줄어드는 경향을 보였다. 이는 부를 축적한 농민들이나 해방된 노비들이 자신들의 지위를 높이기 위하여 또는 역의 부담을 모면하기 위하여 양반 신분을 사는 경우가 많았기 때문이다.\n" +
+"이러한 급격한 사회 변화에 대한 집권층의 자세는 극히 보수적이고 임기응변적이었다. 이에 계층 간의 갈등은 더욱 심화되어 갔으며, 19세기에 들어와 평등 사상과 내세 신앙을 주장한 로마 가톨릭이 유포되면서 백성들의 의식이 점차 높아져서[출처 필요] 크고 작은 봉기가 전국적으로 일어나게 되었다. 정부는 로마 가톨릭이 점차 교세가 확장되자 양반 중심의 신분 질서 부정과 왕권에 대한 도전으로 받아들여[출처 필요] 사교로 규정하고 탄압을 가하기에 이르렀다.\n" +
+"[편집]\n" +
+"후기 조선의 문화\n" +
+"임진왜란과 병자호란 이후 사회 각 분야의 변화와 함께 문화에서는 새로운 기운이 나타났다. 양반층 뿐만 아니라 중인층과 서민층도 문화의 한 주역으로 등장하면서 문화의 질적 변화와 함께 문화의 폭이 확대되었다.\n" +
+"학문에서는 성리학의 교조화와 형식화를 비판하며 실천성을 강조한 양명학을 받아들였으며 민생 안정과 부국강병을 목표로 하여 비판적이면서 실증적인 논리로 사회 개혁론을 제시한 실학이 대두되어 개혁 추진을 주장하기도 하였다.\n" +
+"천문학의 의학 등 각 분야의 기술적 성과들이 농업과 상업 등 산업 발전을 촉진하였다. 서양 문물의 유입도 이러한 발전을 가속화하는 데 이바지하였다.\n" +
+"예술 분야에서는 판소리, 탈품, 서민 음악 등 서민 문화가 크게 유행하였고, 백자 등 공예도 생활 공예가 중심이 되었다. 자연 경치와 삶을 소재로 하는 문예 풍토가 진작되어 문학과 서화에 큰 영향을 끼쳤다.\n" +
+"[편집]\n" +
+"근현대시대 (A.D. 1907년 ~ )\n" +
+"\n" +
+"[편집]\n" +
+"개괄\n" +
+"조선 사회는 안에서 성장하고 있던 근대적인 요소를 충분히 발전시키지 못한 채 19C 후반 제국주의 열강에 문호를 개방하였다. 이후 정부와 각계(各界), 각당(各堂), 각단체(各單體), 각층(各層), 각파(各派)에서는 근대화하려는 노력을 하였으나, 성공하지 못하였다.\n" +
+"개항 이후 조선은 서구 문물을 수용하고 새로운 경제 정책을 펼치면서 자주적인 근대화를 모색하였다. 그러나 일본과 청을 비롯한 외세의 경제 침략이 본격화 되면서, 이러한 노력은 큰 성과를 거두지 못했다.\n" +
+"개항 이후, 사회 개혁이 진행되면서 신분 제도가 폐지되고 평등 의식도 점차 성장하였다. 또, 외국과의 교류를 통해 외래 문물과 제도 등이 수용됨에 따라 전통적인 생활 모습에도 많은 변화가 생겨났다.\n" +
+"개항 이후 서양 과학 기술에 대한 관심이 높아지자, 전기, 철도, 같은 근대 기술과 서양 의술 등 각종 근대 문물이 들어왔다. 근대 시설은 일상생활을 편리하게 해 주었으나, 열강의 침략 목적에 이용되기도 하였다.\n" +
+"일제는 강압적인 식민 통치를 통하여 우리 민족을 지배하였다. 이에 맞서 우리 민족은 국내외에서 무장 독립 투쟁, 민족 실력 양성 운동, 독립 외교 활동 등을 벌여 일제에 줄기차게 저항하였다. 이러한 우리 민족의 투쟁과 연합군의 승리로 1945년 8월에 광복을 맞이하였다.\n" +
+"일제 강점기에는 일제의 경제적 침략으로 경제 발전이 왜곡되어, 우리 민족은 고통을 겪게 되었다. 광복 이후 일제의 식민 지배를 벗어나면서부터는 새로운 경제 발전의 계기를 마련할 수 있었다. 그러나 분단과 전쟁으로 인한 경제적 어려움도 대단히 컸다.\n" +
+"일제 강점기에는 국권을 되찾으려는 독립 운동이 줄기차게 일어났고, 다른 한편에서는 근대화를 위한 각계(各界), 각당(各堂), 각단체(各單體), 각층(各層), 각파(各派)에서는 근대화하려는 노력이 펼쳐졌다. 이러한 가운데 근대 자본주의 문명이 본격적으로 유입되어 전통 사회는 점차 근대 사회로 변모해 갔는데, 식민지 현실 아래에서 근대화는 왜곡될 수밖에 없었다.\n" +
+"일제는 국권을 탈취한 후에 동화와 차별의 이중 정책을 바탕으로 황국 신민화를 강력하게 추진하였다. 특히, 우리 민족의 독립 의지를 꺾으려고 우리의 역사와 문화를 왜곡하였다. 이에 맞서 우리의 전통과 문화를 지키려는 움직임이 일어났다.\n" +
+"그런데, 미∙소의 한반도 분할 정책과 좌∙우익 세력의 갈등으로 남북이 분단되어 통일 국가를 세우지 못하였다. 특히, 6∙25 전쟁을 겪으면서 분단은 더욱 고착화되고 남북 사이의 상호 불신이 깊어 갔다.\n" +
+"대한민국 정부 수립 이후, 민주주의가 정착되는 과정에서 많은 시련을 겪었다. 그러나 4∙19혁명과 5∙18민주화 운동, 6월 민주 항쟁 등으로 민주주의가 점차 발전하였다. 이와 함께, 냉전 체제가 해체되면서 민족 통일을 위한 노력도 계속 되고 있다.\n" +
+"1960년대 이후 한국 경제는 비약적인 성장을 일구어 냈다. 한국은 이제 가난한 농업 국가가 아닌, 세계적인 경제 대국으로 변모하고 있다.\n" +
+"광복 후에 한국은 많은 어려움 속에서도 경제 발전을 이룩하였는데, 이는 커다란 사회 변화를 가져왔다. 농업 사회에서 산업 사회로, 다시 정보화 사회로 발전하면서 사람들의 생활양식과 가치관도 많이 변하였다.1980년대에 진행된 민주화 운동으로 권위주의적 정치 문화가 점차 극복되고, 사회의 민주화도 꾸준히 이루어 졌다.\n" +
+"광복 이후에는 학문 활동이 활발해지고 교육의 기회가 크게 확대되었다. 그러나 미국을 비롯한 서구 문화가 급속하게 유입되면서 가치관의 혼란과 전통문화의 위축 현상을 가져오기도 하였다.\n" +
+"민주화와 더불어 문화의 다양화가 촉진되고, 반도체 등 몇몇 과학 기술 분야는 세계적인 수준까지 도달하였다. 한편, 현대 사회의 윤리와 생명 과학 기술의 발달 사이에서 빚어지는 갈등을 해소하려는 노력도 펼쳐지고 있다.\n" +
+"[편집]\n" +
+"근대시대\n" +
+"대한 제국\n" +
+"일제강점기 : 일본의 제국주의 세력이 한반도를 강제적으로 식민지로 삼은 시기로서, 무단 통치 시기, 문화 통치 시기, 전시 체계 시기로 나뉜다.\n" +
+"무단 통치 시기 : 조선을 영구히 통치하기 위해 조선 총독부를 설치하고, 군대를 파견하여 의병 활동을 억누르고 국내의 저항 세력을 무단으로 통치한 시기이다. 언론, 집회, 출판, 결사의 자유같은 기본권을 박탈하고, 독립운동을 무자비하게 탄압하였다. 또, 헌병 경찰과 헌병 보조원을 전국에 배치하고 즉결 처분권을 부여하여 한국인을 태형에 처하기도 했다. 토지조사령을 공포하여 식민지 수탈을 시작하였고, 회사령을 공포하여 국내의 자본 세력을 억압하고 일본 자본 세력의 편의를 봐주었다. 이 시기의 한국인 노동자는 극악한 환경과 저임금, 민족적 차별까지 받으며 혹사 하였다.\n" +
+"문화 통치 시기 : 3·1 운동이 발발하자 일제는 무단통치로는 조선을 효과적으로 지배할 수 없다는 판단하에, 친일파를 육성하는 문화정책을 펼친다. 이 문화정치는 가혹한 식민 통치를 은폐하려는 술책에 불과 했다. 헌병 경찰제를 보통 경찰제로 전환하였지만, 경찰력은 오히려 증강되었다. 이 들은 교육의 기회를 늘리고 자본 운용의 기회와 참정권의 기회등을 제공하겠다고 선전 하였으나 소수의 친일 분자를 육성하고, 민족 운동가들을 회유하여 민족을 기만하고 분열을 획책하였다.\n" +
+"전시 체계 시기 : 1930년대 일제는 대륙침략을 본격적으로 시작하면서 한반도를 대륙 침략의 병참기지로 삼았다. 또한, 1941년 일제가 미국의 진주만을 불법적으로 기습하자 태평양 전쟁이 발발하였다. 조선에서는 일제의 강제 징용으로 한국인 노동력이 착취 되었고, 학도 지원병 제도, 징병 제도 등을 실시하여 수많은 젊은이를 전쟁에 동원하였다. 또, 젊은 여성을 정신대라는 이름으로 강제 동원하여 군수 공장 등에서 혹사시켰으며, 그 중 일부는 전선으로 끌고 가 일본군 위안부로 삼는 만행을 저질렀다.\n" +
+"[편집]\n" +
+"현대시대\n" +
+"군정기 : 미국과 소련의 군대가 진주하여 한반도에 정부가 세워지기 이전까지의 시기\n" +
+"대한민국\n" +
+"제1공화국\n" +
+"한국전쟁\n" +
+"제2공화국\n" +
+"제3공화국\n" +
+"제4공화국 - 유신헌법시기. 종신 대통령제 채택\n" +
+"제5공화국\n" +
+"1. 정치 : 전두환 정부(군사 쿠데타에 의한 정부 - 12.12 사태) 시기. 대통령 간접선거제도 채택. 이 시기에는 민주화에 대한 무자비한 탄압이 자행되었으나, 광범위한 대중들의 1987년 6월 혁명으로 6월29선언(대통령 직접선거제도 공약)을 이끌어 내기도 하였다.\n" +
+"2. 경제 : 1960~70년대에 닦아온 중공업, 경공업 기반을 첨단공업 수준으로 이끌어 올린 시기이다. 이 시기의 한국 경제는 세계에서 유래 없을 정도로 빠르게 성장했으며, 국내 물가가 가장 안정된 시기였다.\n" +
+"3. 문화 : 1986년 서울 아시안 게임을 개최하였고, 1988년 서울 올림픽 게임을 유치하는 데 성공했다.\n" +
+"제6공화국\n" +
+"노태우 정권\n" +
+"문민정부\n" +
+"국민의 정부\n" +
+"참여정부\n" +
+"조선민주주의인민공화국\n" +
+"조선민주주의인민공화국의 역사\n" +
+"[편집]\n" +
+"주석\n" +
+"\n" +
+"↑ 삼국유사 - 동경제국대학 1904년 판본, 환단고기 - 1979년 복원본\n" +
+"↑ 동사 - 허목 숙종조, 규원사화 - 북애자 숙종원년\n" +
+"↑ 환단고기 - 1979년 복원본\n" +
+"[편집]\n" +
+"같이 보기\n" +
+"\n" +
+"중국의 역사\n" +
+"일본의 역사\n" +
+"민족사관\n" +
+"식민사관\n" +
+"[편집]\n" +
+"참고문헌 및 링크\n" +
+"\n" +
+"[편집]\n" +
+"역사 일반\n" +
+"국사 편찬 위원회 : 한국사에 관한 정보를 수집, 정리, 편찬하는 국가 연구 기관, 소장 자료, 논문, 저서 검색, 한국사 관련 연구 기관. 소장 자료, 논문, 저서 검색, 한국사 관련 안내\n" +
+"국사 전자 교과서 : 현직 교사들이 연구.감수하고, 국사편찬위원회가 지원하였다. 2007년 개정된 국사교과서의 내용이 아직 반영되지 않았다.\n" +
+"한국 역사 정보 시스템 : 한국사 연표, 한국사 기초 사전 및 신문 자료, 문헌 자료, 문집 등을 제공\n" +
+"한국학 중앙 연구원 : 한국 문화 및 한국학 여러 분햐에 관한 연구와 교육을 수행하는 연구 기관. 디지털 한국학 개발, 정보 광장, 전자 도서관, 전통 문화 등 수록\n" +
+"역사 문제 연구소 : 순수 민간 연구 단체(역사적 중립성이 의심됨), 근현대사 자료실, 간행물 자료, 한국사 학습 자료 등 수록\n" +
+"[편집]\n" +
+"재단, 기타, 정부 기관\n" +
+"고구려 연구재단 : 고구려사를 비롯한 중국의 역사 왜곡에 학술적으로 대응하기 위하여 2004年 설립된 법인. 고구려, 발해를 비롯한 동아시아 역사 관련 자료의 조사, 수집, 정리, 정보화 자료 제공. 동북아역사재단으로 편입되어 더이상 유용하지 않다.\n" +
+"국가 기록 영상관 : 대한 뉴스, 문화 기록 영화, 대통령 기록 영상 등 멀티미디어 역사 자료 제공\n" +
+"국가 문화 유산 종합 정보 서비스 : 국보, 보물, 사적, 명승, 천연 기념물 지정 종목별, 시대별, 지역별, 유형별, 유물 정보, 검색 서비스 제공\n" +
+"국가 지식 정보 통합 검색 시스템 : 정보 통신부 제공, 과학 기술, 정보 통신, 교육, 학술, 문화, 역사 등의 포괄적이고 연동적인 학술 데이터 검색\n" +
+"국가기록유산 : 국가적 기록유산의 원본과 원문 열람 서비스 제공\n";
+
+
+var persian =
+"تاریخ ایران پیش از اسلام\n" +
+"از ویکی‌پدیا، دانشنامهٔ آزاد.\n" +
+"تمدنهای باستانی آسیای غربی\n" +
+"بین‌النهرین، سومر، اکد، آشور، بابل\n" +
+"هیتی‌ها، لیدیه\n" +
+"ایلام، اورارتو، ماننا، ماد، هخامنشی\n" +
+"امپراتوری‌ها / شهرها\n" +
+"سومر: اوروک – اور – اریدو\n" +
+"کیش – لاگاش – نیپور – اکد\n" +
+"بابل – ایسین – کلدانی\n" +
+"آشور: آسور، نینوا، نوزی، نمرود\n" +
+"ایلامیان – اموری‌ها – شوش\n" +
+"هوری‌ها – میتانی\n" +
+"کاسی‌ها – اورارتو\n" +
+"گاهشماری\n" +
+"شاهان سومر\n" +
+"شاهان ایلام\n" +
+"شاهان آشور\n" +
+"شاهان بابل\n" +
+"شاهان ماد\n" +
+"شاهان هخامنشی\n" +
+"زبان\n" +
+"خط میخی\n" +
+"سومری – اکدی\n" +
+"ایلامی – هوری\n" +
+"اساطیر بین‌النهرین\n" +
+"انوما الیش\n" +
+"گیل گمش – مردوخ\n" +
+"نیبیرو\n" +
+"اگر بخواهیم تاریخ ایران پیش از اسلام را بررسی ‌‌کنیم باید از مردمانی که در دوران نوسنگی در فلات ایران زندگی می‌‌کردند نام ببریم. پیش از مهاجرت آریائیان به فلات ایران، اقوامی با تمدن‌های متفاوت در ایران می‌زیستند که آثار زیادی از آنها در نقاط مختلف فلات ایران مانند تمدن جیرفت (در کرمانِ کنونی) و شهر سوخته در سیستان، و تمدن ساکنان تمدن تپه سیلک (در کاشان)، تمدن اورارتو و ماننا (در آذربایجان)، تپه گیان نهاوند و تمدن کاسی‌ها (در لرستان امروز) بجای مانده است. اما تمدن این اقوام کم کم با ورود آریائیان، در فرهنگ و تمدن آنها حل شد.\n" +
+"برای بررسی تاریخ ایران پیش از اسلام باید از دیگر تمدنهای باستانی آسیای غربی نیز نام ببریم. شناخت اوضاع و رابطه این مناطق ایران در رابطه با تمدن‌های دیگر نظیر سومر - اکد، کلده - بابل - آشور، و غیره نیز مهم است.\n" +
+"فهرست مندرجات [مخفی شود]\n" +
+"۱ ایلامیان\n" +
+"۲ مهاجرت آریائیان به ایران\n" +
+"۳ مادها\n" +
+"۴ هخامنشیان\n" +
+"۵ سلوکیان\n" +
+"۶ اشکانیان\n" +
+"۷ ساسانیان\n" +
+"۸ منابع\n" +
+"۹ جستارهای وابسته\n" +
+"۱۰ پیوند به بیرون\n" +
+"[ویرایش]\n" +
+"ایلامیان\n" +
+"\n" +
+"ایلامیان یا عیلامی‌ها اقوامی بودند که از هزاره سوم پ. م. تا هزاره نخست پ. م. ، بر بخش بزرگی از مناطق جنوب و غرب ایران فرمانروایی داشتند. بر حسب تقسیمات جغرافیای سیاسی امروز، ایلام باستان سرزمین‌های خوزستان، فارس، ایلام و بخش‌هایی از استان‌های بوشهر، کرمان، لرستان و کردستان را شامل می‌شد.\n" +
+"آثار كشف ‌شده تمدن ایلامیان، در شوش نمایانگر تمدن شهری قابل توجهی است. تمدن ایلامیان از راه شهر سوخته در سیستان، با تمدن پیرامون رود سند هند و از راه شوش با تمدن سومر مربوط می‌شده است. ایلامیان نخستین مخترعان خط در ایران هستند.\n" +
+"به قدرت رسیدن حكومت ایلامیان و قدرت یافتن سلسله عیلامی پادشاهی اوان در شمال دشت خوزستان مهم ‌ترین رویداد سیاسی ایران در هزاره سوم پ. م. است. پادشاهی اَوان یکی از دودمان‌های ایلامی باستان در جنوب غربی ایران بود. پادشاهی آوان پس از شکوه و قدرت کوتیک ـ این شوشینک همچون امپراتوری اکد، ناگهان فرو پاشید؛ این فروپاشی و هرج و مرج در منطقه در پی تاخت و تاز گوتیان زاگرس نشین رخ داد. تا پیش از ورود مادها و پارسها حدود یك هزار سال تاریخ سرزمین ایران منحصر به تاریخ عیلام است.\n" +
+"سرزمین اصلی عیلام در شمال دشت خوزستان بوده. فرهنگ و تمدن عیلامی از شرق رودخانه دجله تا شهر سوخته زابل و از ارتفاعات زاگرس مركزی تا بوشهر اثر گذار بوده است. عیلامیان نه سامی نژادند و نه آریایی آنان ساكنان اوليه دشت خوزستان هستند.\n" +
+"[ویرایش]\n" +
+"مهاجرت آریائیان به ایران\n" +
+"\n" +
+"آریائیان، مردمانی از نژاد هند و اروپایی بودند که در شمال فلات ایران می‌‌زیستند. دلیل اصلی مهاجرت آنها مشخص نیست اما به نظر می‌‌رسد دشوار شدن شرایط آب و هوایی و کمبود چراگاه ها، از دلایل آن باشد. مهاجرت آریائیان به فلات ایران یک مهاجرت تدریجی بوده است که در پایان دوران نوسنگی (7000 سال پیش از میلاد) آغاز شد و تا 4000 پیش از میلاد ادامه داشته است.\n" +
+"نخستین آریایی‌هایی که به ایران آمدند شامل کاسی‌ها (کانتوها ـ کاشی‌ها)، لولوبیان و گوتیان بودند. کا‌سی‌ها تمدنی را پایه گذاری کردند که امروزه ما آن را بنام تمدن تپه سیلک می‌‌شناسیم. لولوبیان و گوتیان نیز در زاگرس مرکزی اقامت گزیدند که بعدها با آمدن مادها بخشی از آنها شدند. در حدود 5000 سال پیش از میلاد، مهاجرت بزرگ آریائیان به ایران آغاز شد و سه گروه بزرگ آریایی به ایران آمدند و هر یک در قسمتی از ایران سکنی گزیدند: مادها در شمال غربی ایران، پارس‌ها در قسمت جنوبی و پارت‌ها در حدود خراسان امروزی.\n" +
+"شاخه‌های قومِ ایرانی در نیمه‌های هزاره‌ی اول قبل از مسیح عبارت بوده‌اند از: باختریان در باختریه (تاجیکستان و شمالشرق افغانستانِ کنونی)، سکاهای هوم‌کار در سگائیه (شرقِ ازبکستانِ کنونی)، سُغدیان در سغدیه (جنوب ازبکستان کنونی)، خوارزمیان در خوارزمیه (شمال ازبکستان و شمالشرق ترکمنستانِ کنونی)، مرغزیان در مرغوه یا مرو (جنوبغرب ازبکستان و شرق ترکمستان کنونی)، داهه در مرکز ترکمستان کنونی، هَرَیویان در هَرَیوَه یا هرات (غرب افغانستان کنونی)، دِرَنگِیان در درنگیانه یا سیستان (غرب افغانستان کنونی و شرق ایران کنونی)، مکائیان در مکائیه یا مَک‌کُران (بلوچستانِ ایران و پاکستان کنونی)، هیرکانیان در هیرکانیا یا گرگان (جنوبغربِ ترکمنستان کنونی و شمال ایرانِ کنونی)، پَرتُوَه‌ئیان در پارتیه (شمالشرق ایران کنونی)، تپوریان در تپوریه یا تپورستان (گیلان و مازندران کنونی)، آریازَنتا در اسپدانه در مرکزِ ایرانِ کنونی، سکاهای تیزخود در الانیه یا اران (آذربایجان مستقل کنونی)، آترپاتیگان در آذربایجان ایرانِ کنونی، مادایَه در ماد (غرب ایرانِ کنونی)، کُردوخ در کردستانِ (چهارپاره‌شده‌ی) کنونی، پارسَی در پارس و کرمانِ کنونی، انشان در لرستان و شمال خوزستان کنونی. قبایلی که در تاریخ با نامهای مانناها، لولوبیان‌ها، گوتیان‌ها، و کاسی‌ها شناسانده شده‌اند و در مناطق غربی ایران ساکن بوده‌اند تیره‌هائی از شاخه‌های قوم ایرانی بوده‌اند که زمانی برای خودشان اتحادیه‌های قبایلی و امیرنشین داشته‌اند، و سپس در پادشاهی ماد ادغام شده‌اند.\n" +
+"مادها در ایران نزدیک 150 سال (708- 550 ق.م) هخامنشی‌ها کمی بیش از دویست سال (550-330 ق.م) اسکندر و سلوکی‌ها در حدود صد سال (330 -250 ق.م) اشکانیان قریب پانصد سال (250 ق.م – 226 م) و ساسانیان قریب چهار صد و سی سال (226-651 م) فرمانروایی داشتند.\n" +
+"[ویرایش]\n" +
+"مادها\n" +
+"\n" +
+"\n" +
+"\n" +
+"ماد در 675 پیش از میلاد\n" +
+"\n" +
+"\n" +
+"ماد در 600 پیش از میلاد\n" +
+"مادها قومی ایرانی بودند از تبار آریایی که در بخش غربی فلات ایران ساکن شدند. سرزمین مادها دربرگیرنده بخش غربی فلات ایران بود. سرزمین آذربایجان در شمال غربی فلات ایران را با نام ماد کوچک و بقیهٔ ناحیه زاگرس را با نام ماد بزرگ می‌شناختند. پایتخت ماد هگمتانه است آنها توانستند در اوایل قرن هفتم قبل از میلاد اولین دولت ایرانی را تأسیس کنند\n" +
+"پس از حملات شدید و خونین آشوریان به مناطق مادنشین، گروهی از بزرگان ماد گرد رهبری به نام دیاکو جمع شدند.\n" +
+"از پادشاهان بزرگ این دودمان هووخشتره بود که با دولت بابل متحد شد و سرانجام امپراتوری آشور را منقرض کرد و پایه‌های نخستین شاهنشاهی آریایی‌تباران در ایران را بنیاد نهاد.\n" +
+"دولت ماد در ۵۵۰ پیش از میلاد به دست کوروش منقرض شد و سلطنت ایران به پارسی‌ها منتقل گشت. در زمان داریوش بزرگ، امپراتوری هخامنشی به منتهای بزرگی خود رسید: از هند تا دریای آدریاتیک و از دریای عمان تا کوه‌های قفقاز.\n" +
+"[ویرایش]\n" +
+"هخامنشیان\n" +
+"\n" +
+"\n" +
+"\n" +
+"شاهنشاهی بزرگ هخامنشی در 330 ق.م.\n" +
+"هخامنشیان نخست پادشاهان بومی پارس و سپس انشان بودند ولی با شکستی که کوروش بزرگ بزرگ بر ایشتوویگو واپسین پادشاه ماد وارد ساخت و سپس فتح لیدیه و بابل پادشاهی هخامنشیان تبدیل به شاهنشاهی بزرگی شد. از این رو کوروش بزرگ را بنیادگذار شاهنشاهی هخامنشی می‌دانند.\n" +
+"در ۵۲۹ پ.م کوروش بزرگ پایه گذار دولت هخامنشی در جنگ‌های شمال شرقی ایران با سکاها، کشته شد. لشکرکشی کمبوجیه جانشین او به مصر آخرین رمق کشاورزان و مردم مغلوب را کشید و زمینه را برای شورشی همگانی فراهم کرد. داریوش بزرگ در کتیبهً بیستون می‌‌گوید: \" بعد از رفتن او (کمبوجیه) به مصر مردم از او برگشتند...\"\n" +
+"شورش‌ها بزرگ شد و حتی پارس زادگاه شاهان هخامنشی را نیز در برگرفت. داریوش در کتیبه بیستون شمه‌ای از این قیام‌ها را در بند دوم چنین نقل می‌کند: \" زمانی که من در بابل بودم این ایالات از من برگشتند: پارس، خوزستان، ماد، آشور، مصر، پارت خراسان (مرو، گوش) افغانستان (مکائیه).\" داریوش از 9 مهر ماه 522 تا 19 اسفند 520 ق.م به سرکوبی این جنبش‌ها مشغول بود.\n" +
+"جنگ‌های ایران و یونان در زمان داریوش آغاز شد. دولت هخامنشی سر انجام در 330 ق. م به دست اسکندر مقدونی منقرض گشت و ایران به دست سپاهیان او افتاد.\n" +
+"اسکندر سلسله هخامنشیان را نابود کرد، دارا را کشت ولی در حرکت خود به شرق همه جا به مقاومت‌های سخت برخورد، از جمله سغد و باکتریا یکی از سرداران جنگی او بنام سپتامان 327- 329 ق. م در راس جنبش همگانی مردم بیش از دو سال علیه مهاجم خارجی مبارزه دلاورانه کرد. در این ناحیه مکرر مردم علیه ساتراپهای اسکندر قیام کردند. گرچه سرانجام نیروهای مجهز و ورزیده اسکندر این جنبش‌ها را سرکوب کردند ولی از این تاریخ اسکندر ناچار روش خشونت آمیز خود را به نرمش و خوشخویی بدل کرد.\n" +
+"\n" +
+"ایران\n" +
+"تاریخ ایران\n" +
+"ایران پیش از آریایی‌ها    \n" +
+"تاریخ ایران پیش از اسلام  \n" +
+"    | دودمان‌ها و حکومت‌ها\n" +
+"ایلامیان\n" +
+"ماد\n" +
+"هخامنشیان\n" +
+"سلوکیان\n" +
+"اشکانیان\n" +
+"ساسانیان\n" +
+"تاریخ ایران پس از اسلام    \n" +
+"    | دودمان‌ها و حکومت‌ها\n" +
+"خلفای راشدین\n" +
+"امویان\n" +
+"عباسیان\n" +
+"ایران در دوران حکومت‌های محلی       \n" +
+"    | دودمان‌ها و حکومت‌ها\n" +
+"طاهریان\n" +
+"صفاریان\n" +
+"سامانیان\n" +
+"آل زیار\n" +
+"آل بویه\n" +
+"غزنویان\n" +
+"سلجوقیان\n" +
+"خوارزمشاهیان\n" +
+"ایران در دوره مغول     \n" +
+"    | دودمان‌ها و حکومت‌ها\n" +
+"ایلخانیان\n" +
+"ایران در دوران ملوک‌الطوایفی        \n" +
+"    | دودمان‌ها و حکومت‌ها\n" +
+"سربداران\n" +
+"تیموریان\n" +
+"مرعشیان\n" +
+"کیائیان\n" +
+"قراقویونلو\n" +
+"آق‌قویونلو\n" +
+"ایران در دوران حکومت‌های ملی \n" +
+"    | دودمان‌ها و حکومت‌ها\n" +
+"صفوی\n" +
+"افشاریان\n" +
+"زند\n" +
+"قاجار\n" +
+"پهلوی\n" +
+"جمهوری اسلامی\n" +
+"موضوعی\n" +
+"تاریخ معاصر ایران\n" +
+"تاریخ مذاهب ایران\n" +
+"مهرپرستی\n" +
+"زرتشتی\n" +
+"تسنن\n" +
+"تصوف\n" +
+"تشیع\n" +
+"تاریخ اسلام\n" +
+"تاریخ زبان و ادبیات ایران\n" +
+"جغرافیای ایران\n" +
+"استان‌های تاریخی ایران\n" +
+"اقتصاد ایران\n" +
+"گاهشمار تاریخ ایران\n" +
+"پروژه ایران\n" +
+"[ویرایش]\n" +
+"سلوکیان\n" +
+"\n" +
+"\n" +
+"ایران در زمان سلوکیان (330 - 150 ق.م.)\n" +
+"پس از مرگ اسکندر (323 ق. م) فتوحاتش بین سردارانش تقسیم شد و بیشتر متصرفات آسیائی او که ایران هسته آن بود به سلوکوس اول رسید. به این ترتیب ایران تحت حکومت سلوکیان (330 - 150 ق.م.) در آمد. پس از مدتی پارت‌ها نفوذ خود را گسترش دادند و سرانجام توانستند سلوکیان را نابود و امپراتوری اشکانی را ایجاد کنند.\n" +
+"[ویرایش]\n" +
+"اشکانیان\n" +
+"\n" +
+"\n" +
+"\n" +
+"امپراتوری اشکانی 250 ق.م. 224 م.\n" +
+"اشکانیان (250 ق. م 224 م) که از تیره ایرانی پرنی و شاخه‌ای از طوایف وابسته به اتحادیه داهه از عشایر سکاهای حدود باختر بودند، از ایالت پارت که مشتمل بر خراسان فعلی بود برخاستند. نام سرزمین پارت در کتیبه‌های داریوش پرثوه آمده است که به زبان پارتی پهلوه می‌شود. چون پارتیان از اهل ایالت پهله بودند، از این جهت در نسبت به آن سرزمین ایشان را پهلوی نیز می‌‌توان خواند. ایالت پارتیها از مغرب به دامغان و سواحل جنوب شرقی دریای خزر و از شمال به ترکستان و از مشرق به رود تجن و از جنوب به کویر نمک و سیستان محدود می‌‌شد. قبایل پارتی در آغاز با قوم داهه که در مشرق دریای خزر می‌‌زیستند در یک جا سکونت داشتند و سپس از آنان جدا شده در ناحیه خراسان مسکن گزیدند.\n" +
+"این امپراتوری در دوره اقتدارش از رود فرات تا هندوکش و از کوه‌های قفقاز تا خلیج فارس توسعه یافت. در عهد اشکانی جنگ‌های ایران و روم آغاز شد. سلسله اشکانی در اثر اختلافات داخلی و جنگ‌های خارجی به تدریج ضعیف شد تا سر انجام به دست اردشیر اول ساسانی منقرض گردید.\n" +
+"[ویرایش]\n" +
+"ساسانیان\n" +
+"\n" +
+"\n" +
+"\n" +
+"شاهنشاهی ساسانی در سالهای ۲۲۴ تا ۶۵۱ م.\n" +
+"ساسانیان خاندان شاهنشاهی ایرانی در سالهای ۲۲۴ تا ۶۵۱ میلادی بودند. شاهنشاهان ساسانی که اصلیتشان از استان پارس بود بر بخش بزرگی از غرب قارهٔ آسیا چیرگی یافتند. پایتخت ساسانیان شهر تیسفون در نزدیکی بغداد در عراق امروزی بود.\n" +
+"سلسله اشکانی به دست اردشیر اول ساسانی منقرض گردید. وی سلسله ساسانیان را بنا نهاد که تا 652 میلادی در ایران ادامه یافت. دولت ساسانی حکومتی ملی و متکی به دین و تمدن ایرانی بود و قدرت بسیار زیادی کسب کرد. در این دوره نیز جنگ‌های ایران و روم ادامه یافت.\n" +
+"\n" +
+"در همين دوران مانی[1] (216 - 276 میلادی) به تبلیغ مذهب خود پرداخت. مانی پس از مسافرت به هند و آشنائی با مذهب بودائی سیستم جهان مذهبی مانوی خود را که التقاطی از مذهب زردشتی، بودائی و مسیحی و اسطوره بود با دقت تنظیم کرد و در کتاب \"شاهپورگان\" اصول آن‌ها را بیان و هنگام تاجگذاری شاپوراول به شاه هدیه کرد. مانی اصول اخلاقی خود را بر پایه فلسفی مثنویت: روشنائی و تاریکی که ازلی و ابدی هستند استوار نمود. در واقع این اصول) خودداری از قتل نفس حتی در مورد حیوانات، نخوردن می، دوری از زن و جمع نکردن مال (واکنش در مقابل زندگی پر تجمل و پر از لذت طبقات حاکم و عکس العمل منفی در برابر بحران اجتماعی پایان حکومت اشکانی و آغاز حکومت ساسانی است. شاپور و هرمزد، نشر چنین مذهبی را تجویز کردند، زیرا با وجود مخالفت آن با شهوت پرستی و غارتگری و سود جوئی طبقات حاکم، از جانبی مردم را به راه \"معنویت\" و \"آشتی‌خواهی\" سوق می‌‌داد و از جانب دیگر از قدرت مذهب زردشت می‌‌کاست.\n" +
+"جنبش معنوی مانی به سرعت در جهان آن روز گسترش یافت و تبدیل به نیروئی شد که با وجود جنبه منفی آن با هدف‌های شاهان و نجبا و پیشرفت جامعه آن روزی وفق نمی‌داد. پیشوایان زردتشتی و عیسوی که با هم دائما در نبرد بودند، متحد شدند و در دوران شاهی بهرام اول که شاهی تن آسا و شهوت پرست بود در جریان محاکمه او را محکوم و مقتول نمودند ( 276 میلادی). از آن پس مانی کشی آغاز شد و مغان مردم بسیاری را به نام زندک(زندیق) کشتند. مانویان درد و جانب شرق و غرب، در آسیای میانه تا سرحد چین و در غرب تا روم پراکنده شدند.\n" +
+"\n" +
+"امپراتوری پهناور ساسانی که از رود سند تا دریای سرخ وسعت داشت، در اثر مشکلات خارجی و داخلی ضعیف شد. آخرین پادشاه این سلسله یزدگرد سوم بود. در دوره او مسلمانان عرب به ایران حمله کردند و ایرانیان را در جنگ‌های قادسیه، مدائن، جلولاء و نهاوند شکست دادند و بدین ترتیب دولت ساسانی از میان رفت.\n" +
+"در پایان سده پنجم و آغاز قرن ششم میلادی جنبش بزرگی جامعه ایران را تکان داد که به صورت قیامی واقعی سی سال ( 24-494 م.) دوام آورد و تأثیر شگرفی در تکامل جامعه آن روزایران بخشید.\n" +
+"در چنین اوضاعی مزدک[2] پسر بامدادان به تبلیغ مذهب خود که گویند موسسش زردشت خورک بابوندس بوده، پرداخت. عقاید مزدک بر دو گانگی مانوی استوار است:\n" +
+"روشنائی دانا و تاریکی نادان، به عبارت دیگر نیکی با عقل و بدی جاهل، این دو نیرو با هم در نبردند و چون روشنائی داناست سرانجام پیروز خواهد شد.\n" +
+"اساس تعلیمات اجتماعی مزدک دو چیز است: یکی برابری و دیگری دادگری.\n" +
+"مردم بسیاری به سرعت پیرو مذهب مزدک شدند. جنبش مزدکی با قتل او و پیروانش به طرز وحشیانه‌ای سرکوب شد، اما افکار او اثر خود را حتی در قیام‌ها و جنبش‌های مردم ایران در دوران اسلام، باقی گذاشت.\n" +
+"[ویرایش]\n" +
+"منابع\n" +
+"\n" +
+"تاریخ ایران - دکتر خنجی\n" +
+"تاریخ اجتماعی ایران. مرتضی راوندی. ( جلد ۱ ) 1354\n" +
+"تاریخ ماد. ایگور میخائیلوویچ دیاکونوف. ترجمه کریم کشاورز، تهران: نشر امیرکبیر.\n" +
+"تاريخ ايران باستان. دياكونوف، ميخائيل ميخائيلوويچ. روحی ارباب. انتشارات علمی و فرهنگی، چاپ دوم 1380\n" +
+"سهم ایرانیان در پیدایش و آفرینش خط در جهان ،دکتر رکن الدین همایونفرخ، انتشارات اساطیر.\n" +
+"کمرون، جرج. ایران در سپیده دم تاریخ. ترجمه حسن انوشه. تهران، مرکز نشر دانشگاهی، 1379\n" +
+"تاریخ ایران از زمان باستان تا امروز، ا. آ. گرانتوسكی - م. آ. داندامایو، مترجم، كیخسرو كشاورزی، ناشر: مرواريد 1385\n" +
+"تاریخ ایران از عهد باستان تا قرن 18، پیگولووسکایا، ترجمه کریم کشاورز، تهران، 1353.\n" +
+"[ویرایش]\n" +
+"جستارهای وابسته\n" +
+"\n" +
+"ماد\n" +
+"کاسی\n" +
+"ایلامیان\n" +
+"تپه هگمتانه\n" +
+"تاریخ ایران\n" +
+"ایران پیش از آریایی‌ها\n" +
+"تمدنهای باستانی آسیای غربی\n" +
+"[ویرایش]\n" +
+"پیوند به بیرون\n" +
+"\n" +
+"ایران قبل از آریاها\n" +
+"ايران پيش از آريایی‌ها\n" +
+"تمدنهای قبل از آریایی ایران\n" +
+"ایران ازدیدگاه باستانشناسی\n" +
+"سنگ‌نبشته‌ی داریوش بزرگ در بیستون\n" +
+"شیوه آسیائی تولید در ایران\n" +
+"نیای اساطیری ایرانیان\n" +
+"قیام‌های ایرانیان در طول تاریخ\n" +
+"خلاصهٔ تاریخ ایران\n" +
+"شهر، شهرسازی و شهرنشينی در ايران پيش از اسلام\n" +
+"\n" +
+"[3]\n" +
+"[4]\n" +
+"[5]\n" +
+"[6]\n" +
+"[7]\n" +
+"\n" +
+"\n" +
+"\n" +
+" این نوشتار خُرد است. با گسترش آن به ویکی‌پدیا کمک کنید.\n" +
+"\n" +
+"این مقاله نیازمند ویکی‌سازی است. لطفاً با توجه به راهنمای ویرایش و شیوه‌نامه آن را تغییر دهید. در پایان، پس از ویکی‌سازی این الگوی پیامی را بردارید.\n";
+
+
+var source =
+("/*\n" +
+"  This is a version (aka dlmalloc) of malloc/free/realloc written by\n" +
+"  Doug Lea and released to the public domain.  Use, modify, and\n" +
+"  redistribute this code without permission or acknowledgement in any\n" +
+"  way you wish.  Send questions, comments, complaints, performance\n" +
+"  data, etc to dl@cs.oswego.edu\n" +
+"\n" +
+"* VERSION 2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)\n" +
+"\n" +
+"   Note: There may be an updated version of this malloc obtainable at\n" +
+"           ftp://gee.cs.oswego.edu/pub/misc/malloc.c\n" +
+"         Check before installing!\n" +
+"\n" +
+"* Quickstart\n" +
+"\n" +
+"  This library is all in one file to simplify the most common usage:\n" +
+"  ftp it, compile it (-O), and link it into another program. All\n" +
+"  of the compile-time options default to reasonable values for use on\n" +
+"  most unix platforms. Compile -DWIN32 for reasonable defaults on windows.\n" +
+"  You might later want to step through various compile-time and dynamic\n" +
+"  tuning options.\n" +
+"\n" +
+"  For convenience, an include file for code using this malloc is at:\n" +
+"     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.7.1.h\n" +
+"  You don't really need this .h file unless you call functions not\n" +
+"  defined in your system include files.  The .h file contains only the\n" +
+"  excerpts from this file needed for using this malloc on ANSI C/C++\n" +
+"  systems, so long as you haven't changed compile-time options about\n" +
+"  naming and tuning parameters.  If you do, then you can create your\n" +
+"  own malloc.h that does include all settings by cutting at the point\n" +
+"  indicated below.\n" +
+"\n" +
+"* Why use this malloc?\n" +
+"\n" +
+"  This is not the fastest, most space-conserving, most portable, or\n" +
+"  most tunable malloc ever written. However it is among the fastest\n" +
+"  while also being among the most space-conserving, portable and tunable.\n" +
+"  Consistent balance across these factors results in a good general-purpose\n" +
+"  allocator for malloc-intensive programs.\n" +
+"\n" +
+"  The main properties of the algorithms are:\n" +
+"  * For large (>= 512 bytes) requests, it is a pure best-fit allocator,\n" +
+"    with ties normally decided via FIFO (i.e. least recently used).\n" +
+"  * For small (<= 64 bytes by default) requests, it is a caching\n" +
+"    allocator, that maintains pools of quickly recycled chunks.\n" +
+"  * In between, and for combinations of large and small requests, it does\n" +
+"    the best it can trying to meet both goals at once.\n" +
+"  * For very large requests (>= 128KB by default), it relies on system\n" +
+"    memory mapping facilities, if supported.\n" +
+"\n" +
+"  For a longer but slightly out of date high-level description, see\n" +
+"     http://gee.cs.oswego.edu/dl/html/malloc.html\n" +
+"\n" +
+"  You may already by default be using a C library containing a malloc\n" +
+"  that is  based on some version of this malloc (for example in\n" +
+"  linux). You might still want to use the one in this file in order to\n" +
+"  customize settings or to avoid overheads associated with library\n" +
+"  versions.\n" +
+"\n" +
+"* Contents, described in more detail in \"description of public routines\" below.\n" +
+"\n" +
+"  Standard (ANSI/SVID/...)  functions:\n" +
+"    malloc(size_t n);\n" +
+"    calloc(size_t n_elements, size_t element_size);\n" +
+"    free(Void_t* p);\n" +
+"    realloc(Void_t* p, size_t n);\n" +
+"    memalign(size_t alignment, size_t n);\n" +
+"    valloc(size_t n);\n" +
+"    mallinfo()\n" +
+"    mallopt(int parameter_number, int parameter_value)\n" +
+"\n" +
+"  Additional functions:\n" +
+"    independent_calloc(size_t n_elements, size_t size, Void_t* chunks[]);\n" +
+"    independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);\n" +
+"    pvalloc(size_t n);\n" +
+"    cfree(Void_t* p);\n" +
+"    malloc_trim(size_t pad);\n" +
+"    malloc_usable_size(Void_t* p);\n" +
+"    malloc_stats();\n" +
+"\n" +
+"* Vital statistics:\n" +
+"\n" +
+"  Supported pointer representation:       4 or 8 bytes\n" +
+"  Supported size_t  representation:       4 or 8 bytes\n" +
+"       Note that size_t is allowed to be 4 bytes even if pointers are 8.\n" +
+"       You can adjust this by defining INTERNAL_SIZE_T\n" +
+"\n" +
+"  Alignment:                              2 * sizeof(size_t) (default)\n" +
+"       (i.e., 8 byte alignment with 4byte size_t). This suffices for\n" +
+"       nearly all current machines and C compilers. However, you can\n" +
+"       define MALLOC_ALIGNMENT to be wider than this if necessary.\n" +
+"\n" +
+"  Minimum overhead per allocated chunk:   4 or 8 bytes\n" +
+"       Each malloced chunk has a hidden word of overhead holding size\n" +
+"       and status information.\n" +
+"\n" +
+"  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)\n" +
+"                          8-byte ptrs:  24/32 bytes (including, 4/8 overhead)\n" +
+"\n" +
+"       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte\n" +
+"       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are\n" +
+"       needed; 4 (8) for a trailing size field and 8 (16) bytes for\n" +
+"       free list pointers. Thus, the minimum allocatable size is\n" +
+"       16/24/32 bytes.\n" +
+"\n" +
+"       Even a request for zero bytes (i.e., malloc(0)) returns a\n" +
+"       pointer to something of the minimum allocatable size.\n" +
+"\n" +
+"       The maximum overhead wastage (i.e., number of extra bytes\n" +
+"       allocated than were requested in malloc) is less than or equal\n" +
+"       to the minimum size, except for requests >= mmap_threshold that\n" +
+"       are serviced via mmap(), where the worst case wastage is 2 *\n" +
+"       sizeof(size_t) bytes plus the remainder from a system page (the\n" +
+"       minimal mmap unit); typically 4096 or 8192 bytes.\n" +
+"\n" +
+"  Maximum allocated size:  4-byte size_t: 2^32 minus about two pages\n" +
+"                           8-byte size_t: 2^64 minus about two pages\n" +
+"\n" +
+"       It is assumed that (possibly signed) size_t values suffice to\n" +
+"       represent chunk sizes. `Possibly signed' is due to the fact\n" +
+"       that `size_t' may be defined on a system as either a signed or\n" +
+"       an unsigned type. The ISO C standard says that it must be\n" +
+"       unsigned, but a few systems are known not to adhere to this.\n" +
+"       Additionally, even when size_t is unsigned, sbrk (which is by\n" +
+"       default used to obtain memory from system) accepts signed\n" +
+"       arguments, and may not be able to handle size_t-wide arguments\n" +
+"       with negative sign bit.  Generally, values that would\n" +
+"       appear as negative after accounting for overhead and alignment\n" +
+"       are supported only via mmap(), which does not have this\n" +
+"       limitation.\n" +
+"\n" +
+"       Requests for sizes outside the allowed range will perform an optional\n" +
+"       failure action and then return null. (Requests may also\n" +
+"       also fail because a system is out of memory.)\n" +
+"\n" +
+"  Thread-safety: NOT thread-safe unless USE_MALLOC_LOCK defined\n" +
+"\n" +
+"       When USE_MALLOC_LOCK is defined, wrappers are created to\n" +
+"       surround every public call with either a pthread mutex or\n" +
+"       a win32 spinlock (depending on WIN32). This is not\n" +
+"       especially fast, and can be a major bottleneck.\n" +
+"       It is designed only to provide minimal protection\n" +
+"       in concurrent environments, and to provide a basis for\n" +
+"       extensions.  If you are using malloc in a concurrent program,\n" +
+"       you would be far better off obtaining ptmalloc, which is\n" +
+"       derived from a version of this malloc, and is well-tuned for\n" +
+"       concurrent programs. (See http://www.malloc.de) Note that\n" +
+"       even when USE_MALLOC_LOCK is defined, you can can guarantee\n" +
+"       full thread-safety only if no threads acquire memory through\n" +
+"       direct calls to MORECORE or other system-level allocators.\n" +
+"\n" +
+"  Compliance: I believe it is compliant with the 1997 Single Unix Specification\n" +
+"       (See http://www.opennc.org). Also SVID/XPG, ANSI C, and probably\n" +
+"       others as well.\n" +
+"\n" +
+"* Synopsis of compile-time options:\n" +
+"\n" +
+"    People have reported using previous versions of this malloc on all\n" +
+"    versions of Unix, sometimes by tweaking some of the defines\n" +
+"    below. It has been tested most extensively on Solaris and\n" +
+"    Linux. It is also reported to work on WIN32 platforms.\n" +
+"    People also report using it in stand-alone embedded systems.\n" +
+"\n" +
+"    The implementation is in straight, hand-tuned ANSI C.  It is not\n" +
+"    at all modular. (Sorry!)  It uses a lot of macros.  To be at all\n" +
+"    usable, this code should be compiled using an optimizing compiler\n" +
+"    (for example gcc -O3) that can simplify expressions and control\n" +
+"    paths. (FAQ: some macros import variables as arguments rather than\n" +
+"    declare locals because people reported that some debuggers\n" +
+"    otherwise get confused.)\n" +
+"\n" +
+"    OPTION                     DEFAULT VALUE\n" +
+"\n" +
+"    Compilation Environment options:\n" +
+"\n" +
+"    __STD_C                    derived from C compiler defines\n" +
+"    WIN32                      NOT defined\n" +
+"    HAVE_MEMCPY                defined\n" +
+"    USE_MEMCPY                 1 if HAVE_MEMCPY is defined\n" +
+"    HAVE_MMAP                  defined as 1\n" +
+"    MMAP_CLEARS                1\n" +
+"    HAVE_MREMAP                0 unless linux defined\n" +
+"    malloc_getpagesize         derived from system #includes, or 4096 if not\n" +
+"    HAVE_USR_INCLUDE_MALLOC_H  NOT defined\n" +
+"    LACKS_UNISTD_H             NOT defined unless WIN32\n" +
+"    LACKS_SYS_PARAM_H          NOT defined unless WIN32\n" +
+"    LACKS_SYS_MMAN_H           NOT defined unless WIN32\n" +
+"    LACKS_FCNTL_H              NOT defined\n" +
+"\n" +
+"    Changing default word sizes:\n" +
+"\n" +
+"    INTERNAL_SIZE_T            size_t\n" +
+"    MALLOC_ALIGNMENT           2 * sizeof(INTERNAL_SIZE_T)\n" +
+"    PTR_UINT                   unsigned long\n" +
+"    CHUNK_SIZE_T               unsigned long\n" +
+"\n" +
+"    Configuration and functionality options:\n" +
+"\n" +
+"    USE_DL_PREFIX              NOT defined\n" +
+"    USE_PUBLIC_MALLOC_WRAPPERS NOT defined\n" +
+"    USE_MALLOC_LOCK            NOT defined\n" +
+"    DEBUG                      NOT defined\n" +
+"    REALLOC_ZERO_BYTES_FREES   NOT defined\n" +
+"    MALLOC_FAILURE_ACTION      errno = ENOMEM, if __STD_C defined, else no-op\n" +
+"    TRIM_FASTBINS              0\n" +
+"    FIRST_SORTED_BIN_SIZE      512\n" +
+"\n" +
+"    Options for customizing MORECORE:\n" +
+"\n" +
+"    MORECORE                   sbrk\n" +
+"    MORECORE_CONTIGUOUS        1\n" +
+"    MORECORE_CANNOT_TRIM       NOT defined\n" +
+"    MMAP_AS_MORECORE_SIZE      (1024 * 1024)\n" +
+"\n" +
+"    Tuning options that are also dynamically changeable via mallopt:\n" +
+"\n" +
+"    DEFAULT_MXFAST             64\n" +
+"    DEFAULT_TRIM_THRESHOLD     256 * 1024\n" +
+"    DEFAULT_TOP_PAD            0\n" +
+"    DEFAULT_MMAP_THRESHOLD     256 * 1024\n" +
+"    DEFAULT_MMAP_MAX           65536\n" +
+"\n" +
+"    There are several other #defined constants and macros that you\n" +
+"    probably don't want to touch unless you are extending or adapting malloc.\n" +
+"*/\n" +
+"\n" +
+"#define MORECORE_CONTIGUOUS 0\n" +
+"#define MORECORE_CANNOT_TRIM 1\n" +
+"#define MALLOC_FAILURE_ACTION abort()\n" +
+"\n" +
+"\n" +
+"namespace khtml {\n" +
+"\n" +
+"#ifndef NDEBUG\n" +
+"\n" +
+"// In debugging builds, use the system malloc for its debugging features.\n" +
+"\n" +
+"void *main_thread_malloc(size_t n)\n" +
+"{\n" +
+"    assert(pthread_main_np());\n" +
+"    return malloc(n);\n" +
+"}\n" +
+"\n" +
+"void *main_thread_calloc(size_t n_elements, size_t element_size)\n" +
+"{\n" +
+"    assert(pthread_main_np());\n" +
+"    return calloc(n_elements, element_size);\n" +
+"}\n" +
+"\n" +
+"void main_thread_free(void* p)\n" +
+"{\n" +
+"    // it's ok to main_thread_free on a non-main thread - the actual\n" +
+"    // free will be scheduled on the main thread in that case.\n" +
+"    free(p);\n" +
+"}\n" +
+"\n" +
+"void *main_thread_realloc(void* p, size_t n)\n" +
+"{\n" +
+"    assert(pthread_main_np());\n" +
+"    return realloc(p, n);\n" +
+"}\n" +
+"\n" +
+"#else\n" +
+"\n" +
+"/*\n" +
+"  WIN32 sets up defaults for MS environment and compilers.\n" +
+"  Otherwise defaults are for unix.\n" +
+"*/\n" +
+"\n" +
+"/* #define WIN32 */\n" +
+"\n" +
+"#ifdef WIN32\n" +
+"\n" +
+"#define WIN32_LEAN_AND_MEAN\n" +
+"#include <windows.h>\n" +
+"\n" +
+"/* Win32 doesn't supply or need the following headers */\n" +
+"#define LACKS_UNISTD_H\n" +
+"#define LACKS_SYS_PARAM_H\n" +
+"#define LACKS_SYS_MMAN_H\n" +
+"\n" +
+"/* Use the supplied emulation of sbrk */\n" +
+"#define MORECORE sbrk\n" +
+"#define MORECORE_CONTIGUOUS 1\n" +
+"#define MORECORE_FAILURE    ((void*)(-1))\n" +
+"\n" +
+"/* Use the supplied emulation of mmap and munmap */\n" +
+"#define HAVE_MMAP 1\n" +
+"#define MUNMAP_FAILURE  (-1)\n" +
+"#define MMAP_CLEARS 1\n" +
+"\n" +
+"/* These values don't really matter in windows mmap emulation */\n" +
+"#define MAP_PRIVATE 1\n" +
+"#define MAP_ANONYMOUS 2\n" +
+"#define PROT_READ 1\n" +
+"#define PROT_WRITE 2\n" +
+"\n" +
+"/* Emulation functions defined at the end of this file */\n" +
+"\n" +
+"/* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */\n" +
+"#ifdef USE_MALLOC_LOCK\n") +
+("static int slwait(int *sl);\n" +
+"static int slrelease(int *sl);\n" +
+"#endif\n" +
+"\n" +
+"static long getpagesize(void);\n" +
+"static long getregionsize(void);\n" +
+"static void *sbrk(long size);\n" +
+"static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg);\n" +
+"static long munmap(void *ptr, long size);\n" +
+"\n" +
+"static void vminfo (unsigned long*free, unsigned long*reserved, unsigned long*committed);\n" +
+"static int cpuinfo (int whole, unsigned long*kernel, unsigned long*user);\n" +
+"\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  __STD_C should be nonzero if using ANSI-standard C compiler, a C++\n" +
+"  compiler, or a C compiler sufficiently close to ANSI to get away\n" +
+"  with it.\n" +
+"*/\n" +
+"\n" +
+"#ifndef __STD_C\n" +
+"#if defined(__STDC__) || defined(_cplusplus)\n" +
+"#define __STD_C     1\n" +
+"#else\n" +
+"#define __STD_C     0\n" +
+"#endif\n" +
+"#endif /*__STD_C*/\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  Void_t* is the pointer type that malloc should say it returns\n" +
+"*/\n" +
+"\n" +
+"#ifndef Void_t\n" +
+"#if (__STD_C || defined(WIN32))\n" +
+"#define Void_t      void\n" +
+"#else\n" +
+"#define Void_t      char\n" +
+"#endif\n" +
+"#endif /*Void_t*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"#include <stddef.h>   /* for size_t */\n" +
+"#else\n" +
+"#include <sys/types.h>\n" +
+"#endif\n" +
+"\n" +
+"/* define LACKS_UNISTD_H if your system does not have a <unistd.h>. */\n" +
+"\n" +
+"/* #define  LACKS_UNISTD_H */\n" +
+"\n" +
+"#ifndef LACKS_UNISTD_H\n" +
+"#include <unistd.h>\n" +
+"#endif\n" +
+"\n" +
+"/* define LACKS_SYS_PARAM_H if your system does not have a <sys/param.h>. */\n" +
+"\n" +
+"/* #define  LACKS_SYS_PARAM_H */\n" +
+"\n" +
+"\n" +
+"#include <stdio.h>    /* needed for malloc_stats */\n" +
+"#include <errno.h>    /* needed for optional MALLOC_FAILURE_ACTION */\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  Debugging:\n" +
+"\n" +
+"  Because freed chunks may be overwritten with bookkeeping fields, this\n" +
+"  malloc will often die when freed memory is overwritten by user\n" +
+"  programs.  This can be very effective (albeit in an annoying way)\n" +
+"  in helping track down dangling pointers.\n" +
+"\n" +
+"  If you compile with -DDEBUG, a number of assertion checks are\n" +
+"  enabled that will catch more memory errors. You probably won't be\n" +
+"  able to make much sense of the actual assertion errors, but they\n" +
+"  should help you locate incorrectly overwritten memory.  The\n" +
+"  checking is fairly extensive, and will slow down execution\n" +
+"  noticeably. Calling malloc_stats or mallinfo with DEBUG set will\n" +
+"  attempt to check every non-mmapped allocated and free chunk in the\n" +
+"  course of computing the summmaries. (By nature, mmapped regions\n" +
+"  cannot be checked very much automatically.)\n" +
+"\n" +
+"  Setting DEBUG may also be helpful if you are trying to modify\n" +
+"  this code. The assertions in the check routines spell out in more\n" +
+"  detail the assumptions and invariants underlying the algorithms.\n" +
+"\n" +
+"  Setting DEBUG does NOT provide an automated mechanism for checking\n" +
+"  that all accesses to malloced memory stay within their\n" +
+"  bounds. However, there are several add-ons and adaptations of this\n" +
+"  or other mallocs available that do this.\n" +
+"*/\n" +
+"\n" +
+"/*\n" +
+"  The unsigned integer type used for comparing any two chunk sizes.\n" +
+"  This should be at least as wide as size_t, but should not be signed.\n" +
+"*/\n" +
+"\n" +
+"#ifndef CHUNK_SIZE_T\n" +
+"#define CHUNK_SIZE_T unsigned long\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  The unsigned integer type used to hold addresses when they are are\n" +
+"  manipulated as integers. Except that it is not defined on all\n" +
+"  systems, intptr_t would suffice.\n" +
+"*/\n" +
+"#ifndef PTR_UINT\n" +
+"#define PTR_UINT unsigned long\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  INTERNAL_SIZE_T is the word-size used for internal bookkeeping\n" +
+"  of chunk sizes.\n" +
+"\n" +
+"  The default version is the same as size_t.\n" +
+"\n" +
+"  While not strictly necessary, it is best to define this as an\n" +
+"  unsigned type, even if size_t is a signed type. This may avoid some\n" +
+"  artificial size limitations on some systems.\n" +
+"\n" +
+"  On a 64-bit machine, you may be able to reduce malloc overhead by\n" +
+"  defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the\n" +
+"  expense of not being able to handle more than 2^32 of malloced\n" +
+"  space. If this limitation is acceptable, you are encouraged to set\n" +
+"  this unless you are on a platform requiring 16byte alignments. In\n" +
+"  this case the alignment requirements turn out to negate any\n" +
+"  potential advantages of decreasing size_t word size.\n" +
+"\n" +
+"  Implementors: Beware of the possible combinations of:\n" +
+"     - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits,\n" +
+"       and might be the same width as int or as long\n" +
+"     - size_t might have different width and signedness as INTERNAL_SIZE_T\n" +
+"     - int and long might be 32 or 64 bits, and might be the same width\n" +
+"  To deal with this, most comparisons and difference computations\n" +
+"  among INTERNAL_SIZE_Ts should cast them to CHUNK_SIZE_T, being\n" +
+"  aware of the fact that casting an unsigned int to a wider long does\n" +
+"  not sign-extend. (This also makes checking for negative numbers\n" +
+"  awkward.) Some of these casts result in harmless compiler warnings\n" +
+"  on some systems.\n" +
+"*/\n" +
+"\n" +
+"#ifndef INTERNAL_SIZE_T\n" +
+"#define INTERNAL_SIZE_T size_t\n" +
+"#endif\n" +
+"\n" +
+"/* The corresponding word size */\n" +
+"#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))\n" +
+"\n" +
+"\n") +
+("\n" +
+"/*\n" +
+"  MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.\n" +
+"  It must be a power of two at least 2 * SIZE_SZ, even on machines\n" +
+"  for which smaller alignments would suffice. It may be defined as\n" +
+"  larger than this though. Note however that code and data structures\n" +
+"  are optimized for the case of 8-byte alignment.\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#ifndef MALLOC_ALIGNMENT\n" +
+"#define MALLOC_ALIGNMENT       (2 * SIZE_SZ)\n" +
+"#endif\n" +
+"\n" +
+"/* The corresponding bit mask value */\n" +
+"#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)\n" +
+"\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  REALLOC_ZERO_BYTES_FREES should be set if a call to\n" +
+"  realloc with zero bytes should be the same as a call to free.\n" +
+"  Some people think it should. Otherwise, since this malloc\n" +
+"  returns a unique pointer for malloc(0), so does realloc(p, 0).\n" +
+"*/\n" +
+"\n" +
+"/*   #define REALLOC_ZERO_BYTES_FREES */\n" +
+"\n" +
+"/*\n" +
+"  TRIM_FASTBINS controls whether free() of a very small chunk can\n" +
+"  immediately lead to trimming. Setting to true (1) can reduce memory\n" +
+"  footprint, but will almost always slow down programs that use a lot\n" +
+"  of small chunks.\n" +
+"\n" +
+"  Define this only if you are willing to give up some speed to more\n" +
+"  aggressively reduce system-level memory footprint when releasing\n" +
+"  memory in programs that use many small chunks.  You can get\n" +
+"  essentially the same effect by setting MXFAST to 0, but this can\n" +
+"  lead to even greater slowdowns in programs using many small chunks.\n" +
+"  TRIM_FASTBINS is an in-between compile-time option, that disables\n" +
+"  only those chunks bordering topmost memory from being placed in\n" +
+"  fastbins.\n" +
+"*/\n" +
+"\n" +
+"#ifndef TRIM_FASTBINS\n" +
+"#define TRIM_FASTBINS  0\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  USE_DL_PREFIX will prefix all public routines with the string 'dl'.\n" +
+"  This is necessary when you only want to use this malloc in one part\n" +
+"  of a program, using your regular system malloc elsewhere.\n" +
+"*/\n" +
+"\n" +
+"#define USE_DL_PREFIX\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  USE_MALLOC_LOCK causes wrapper functions to surround each\n" +
+"  callable routine with pthread mutex lock/unlock.\n" +
+"\n" +
+"  USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"/* #define USE_MALLOC_LOCK */\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is\n" +
+"  actually a wrapper function that first calls MALLOC_PREACTION, then\n" +
+"  calls the internal routine, and follows it with\n" +
+"  MALLOC_POSTACTION. This is needed for locking, but you can also use\n" +
+"  this, without USE_MALLOC_LOCK, for purposes of interception,\n" +
+"  instrumentation, etc. It is a sad fact that using wrappers often\n" +
+"  noticeably degrades performance of malloc-intensive programs.\n" +
+"*/\n" +
+"\n" +
+"#ifdef USE_MALLOC_LOCK\n" +
+"#define USE_PUBLIC_MALLOC_WRAPPERS\n" +
+"#else\n" +
+"/* #define USE_PUBLIC_MALLOC_WRAPPERS */\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"   Two-phase name translation.\n" +
+"   All of the actual routines are given mangled names.\n" +
+"   When wrappers are used, they become the public callable versions.\n" +
+"   When DL_PREFIX is used, the callable names are prefixed.\n" +
+"*/\n" +
+"\n" +
+"#ifndef USE_PUBLIC_MALLOC_WRAPPERS\n" +
+"#define cALLOc      public_cALLOc\n" +
+"#define fREe        public_fREe\n" +
+"#define cFREe       public_cFREe\n" +
+"#define mALLOc      public_mALLOc\n" +
+"#define mEMALIGn    public_mEMALIGn\n" +
+"#define rEALLOc     public_rEALLOc\n" +
+"#define vALLOc      public_vALLOc\n" +
+"#define pVALLOc     public_pVALLOc\n" +
+"#define mALLINFo    public_mALLINFo\n" +
+"#define mALLOPt     public_mALLOPt\n" +
+"#define mTRIm       public_mTRIm\n" +
+"#define mSTATs      public_mSTATs\n" +
+"#define mUSABLe     public_mUSABLe\n" +
+"#define iCALLOc     public_iCALLOc\n" +
+"#define iCOMALLOc   public_iCOMALLOc\n" +
+"#endif\n" +
+"\n" +
+"#ifdef USE_DL_PREFIX\n" +
+"#define public_cALLOc    main_thread_calloc\n" +
+"#define public_fREe      main_thread_free\n" +
+"#define public_cFREe     main_thread_cfree\n" +
+"#define public_mALLOc    main_thread_malloc\n" +
+"#define public_mEMALIGn  main_thread_memalign\n" +
+"#define public_rEALLOc   main_thread_realloc\n" +
+"#define public_vALLOc    main_thread_valloc\n" +
+"#define public_pVALLOc   main_thread_pvalloc\n" +
+"#define public_mALLINFo  main_thread_mallinfo\n" +
+"#define public_mALLOPt   main_thread_mallopt\n" +
+"#define public_mTRIm     main_thread_malloc_trim\n" +
+"#define public_mSTATs    main_thread_malloc_stats\n" +
+"#define public_mUSABLe   main_thread_malloc_usable_size\n" +
+"#define public_iCALLOc   main_thread_independent_calloc\n" +
+"#define public_iCOMALLOc main_thread_independent_comalloc\n" +
+"#else /* USE_DL_PREFIX */\n" +
+"#define public_cALLOc    calloc\n" +
+"#define public_fREe      free\n" +
+"#define public_cFREe     cfree\n" +
+"#define public_mALLOc    malloc\n" +
+"#define public_mEMALIGn  memalign\n" +
+"#define public_rEALLOc   realloc\n" +
+"#define public_vALLOc    valloc\n" +
+"#define public_pVALLOc   pvalloc\n" +
+"#define public_mALLINFo  mallinfo\n" +
+"#define public_mALLOPt   mallopt\n" +
+"#define public_mTRIm     malloc_trim\n" +
+"#define public_mSTATs    malloc_stats\n" +
+"#define public_mUSABLe   malloc_usable_size\n" +
+"#define public_iCALLOc   independent_calloc\n" +
+"#define public_iCOMALLOc independent_comalloc\n" +
+"#endif /* USE_DL_PREFIX */\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  HAVE_MEMCPY should be defined if you are not otherwise using\n" +
+"  ANSI STD C, but still have memcpy and memset in your C library\n" +
+"  and want to use them in calloc and realloc. Otherwise simple\n" +
+"  macro versions are defined below.\n" +
+"\n") +
+("  USE_MEMCPY should be defined as 1 if you actually want to\n" +
+"  have memset and memcpy called. People report that the macro\n" +
+"  versions are faster than libc versions on some systems.\n" +
+"\n" +
+"  Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks\n" +
+"  (of <= 36 bytes) are manually unrolled in realloc and calloc.\n" +
+"*/\n" +
+"\n" +
+"#define HAVE_MEMCPY\n" +
+"\n" +
+"#ifndef USE_MEMCPY\n" +
+"#ifdef HAVE_MEMCPY\n" +
+"#define USE_MEMCPY 1\n" +
+"#else\n" +
+"#define USE_MEMCPY 0\n" +
+"#endif\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"#if (__STD_C || defined(HAVE_MEMCPY))\n" +
+"\n" +
+"#ifdef WIN32\n" +
+"/* On Win32 memset and memcpy are already declared in windows.h */\n" +
+"#else\n" +
+"#if __STD_C\n" +
+"extern \"C\" {\n" +
+"void* memset(void*, int, size_t);\n" +
+"void* memcpy(void*, const void*, size_t);\n" +
+"}\n" +
+"#else\n" +
+"extern \"C\" {\n" +
+"Void_t* memset();\n" +
+"Void_t* memcpy();\n" +
+"}\n" +
+"#endif\n" +
+"#endif\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  MALLOC_FAILURE_ACTION is the action to take before \"return 0\" when\n" +
+"  malloc fails to be able to return memory, either because memory is\n" +
+"  exhausted or because of illegal arguments.\n" +
+"\n" +
+"  By default, sets errno if running on STD_C platform, else does nothing.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MALLOC_FAILURE_ACTION\n" +
+"#if __STD_C\n" +
+"#define MALLOC_FAILURE_ACTION \\n" +
+"   errno = ENOMEM;\n" +
+"\n" +
+"#else\n" +
+"#define MALLOC_FAILURE_ACTION\n" +
+"#endif\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  MORECORE-related declarations. By default, rely on sbrk\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#ifdef LACKS_UNISTD_H\n" +
+"#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)\n" +
+"#if __STD_C\n" +
+"extern Void_t*     sbrk(ptrdiff_t);\n" +
+"#else\n" +
+"extern Void_t*     sbrk();\n" +
+"#endif\n" +
+"#endif\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  MORECORE is the name of the routine to call to obtain more memory\n" +
+"  from the system.  See below for general guidance on writing\n" +
+"  alternative MORECORE functions, as well as a version for WIN32 and a\n" +
+"  sample version for pre-OSX macos.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MORECORE\n" +
+"#define MORECORE sbrk\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  MORECORE_FAILURE is the value returned upon failure of MORECORE\n" +
+"  as well as mmap. Since it cannot be an otherwise valid memory address,\n" +
+"  and must reflect values of standard sys calls, you probably ought not\n" +
+"  try to redefine it.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MORECORE_FAILURE\n" +
+"#define MORECORE_FAILURE (-1)\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  If MORECORE_CONTIGUOUS is true, take advantage of fact that\n" +
+"  consecutive calls to MORECORE with positive arguments always return\n" +
+"  contiguous increasing addresses.  This is true of unix sbrk.  Even\n" +
+"  if not defined, when regions happen to be contiguous, malloc will\n" +
+"  permit allocations spanning regions obtained from different\n" +
+"  calls. But defining this when applicable enables some stronger\n" +
+"  consistency checks and space efficiencies.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MORECORE_CONTIGUOUS\n" +
+"#define MORECORE_CONTIGUOUS 1\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  Define MORECORE_CANNOT_TRIM if your version of MORECORE\n" +
+"  cannot release space back to the system when given negative\n" +
+"  arguments. This is generally necessary only if you are using\n" +
+"  a hand-crafted MORECORE function that cannot handle negative arguments.\n" +
+"*/\n" +
+"\n" +
+"/* #define MORECORE_CANNOT_TRIM */\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  Define HAVE_MMAP as true to optionally make malloc() use mmap() to\n" +
+"  allocate very large blocks.  These will be returned to the\n" +
+"  operating system immediately after a free(). Also, if mmap\n" +
+"  is available, it is used as a backup strategy in cases where\n" +
+"  MORECORE fails to provide space from system.\n" +
+"\n" +
+"  This malloc is best tuned to work with mmap for large requests.\n" +
+"  If you do not have mmap, operations involving very large chunks (1MB\n" +
+"  or so) may be slower than you'd like.\n" +
+"*/\n" +
+"\n" +
+"#ifndef HAVE_MMAP\n" +
+"#define HAVE_MMAP 1\n" +
+"#endif\n" +
+"\n" +
+"#if HAVE_MMAP\n" +
+"/*\n" +
+"   Standard unix mmap using /dev/zero clears memory so calloc doesn't\n" +
+"   need to.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MMAP_CLEARS\n" +
+"#define MMAP_CLEARS 1\n" +
+"#endif\n" +
+"\n" +
+"#else /* no mmap */\n" +
+"#ifndef MMAP_CLEARS\n" +
+"#define MMAP_CLEARS 0\n" +
+"#endif\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/*\n") +
+("   MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if\n" +
+"   sbrk fails, and mmap is used as a backup (which is done only if\n" +
+"   HAVE_MMAP).  The value must be a multiple of page size.  This\n" +
+"   backup strategy generally applies only when systems have \"holes\" in\n" +
+"   address space, so sbrk cannot perform contiguous expansion, but\n" +
+"   there is still space available on system.  On systems for which\n" +
+"   this is known to be useful (i.e. most linux kernels), this occurs\n" +
+"   only when programs allocate huge amounts of memory.  Between this,\n" +
+"   and the fact that mmap regions tend to be limited, the size should\n" +
+"   be large, to avoid too many mmap calls and thus avoid running out\n" +
+"   of kernel resources.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MMAP_AS_MORECORE_SIZE\n" +
+"#define MMAP_AS_MORECORE_SIZE (1024 * 1024)\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate\n" +
+"  large blocks.  This is currently only possible on Linux with\n" +
+"  kernel versions newer than 1.3.77.\n" +
+"*/\n" +
+"\n" +
+"#ifndef HAVE_MREMAP\n" +
+"#ifdef linux\n" +
+"#define HAVE_MREMAP 1\n" +
+"#else\n" +
+"#define HAVE_MREMAP 0\n" +
+"#endif\n" +
+"\n" +
+"#endif /* HAVE_MMAP */\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  The system page size. To the extent possible, this malloc manages\n" +
+"  memory from the system in page-size units.  Note that this value is\n" +
+"  cached during initialization into a field of malloc_state. So even\n" +
+"  if malloc_getpagesize is a function, it is only called once.\n" +
+"\n" +
+"  The following mechanics for getpagesize were adapted from bsd/gnu\n" +
+"  getpagesize.h. If none of the system-probes here apply, a value of\n" +
+"  4096 is used, which should be OK: If they don't apply, then using\n" +
+"  the actual value probably doesn't impact performance.\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#ifndef malloc_getpagesize\n" +
+"\n" +
+"#ifndef LACKS_UNISTD_H\n" +
+"#  include <unistd.h>\n" +
+"#endif\n" +
+"\n" +
+"#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */\n" +
+"#    ifndef _SC_PAGE_SIZE\n" +
+"#      define _SC_PAGE_SIZE _SC_PAGESIZE\n" +
+"#    endif\n" +
+"#  endif\n" +
+"\n" +
+"#  ifdef _SC_PAGE_SIZE\n" +
+"#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)\n" +
+"#  else\n" +
+"#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)\n" +
+"       extern size_t getpagesize();\n" +
+"#      define malloc_getpagesize getpagesize()\n" +
+"#    else\n" +
+"#      ifdef WIN32 /* use supplied emulation of getpagesize */\n" +
+"#        define malloc_getpagesize getpagesize()\n" +
+"#      else\n" +
+"#        ifndef LACKS_SYS_PARAM_H\n" +
+"#          include <sys/param.h>\n" +
+"#        endif\n" +
+"#        ifdef EXEC_PAGESIZE\n" +
+"#          define malloc_getpagesize EXEC_PAGESIZE\n" +
+"#        else\n" +
+"#          ifdef NBPG\n" +
+"#            ifndef CLSIZE\n" +
+"#              define malloc_getpagesize NBPG\n" +
+"#            else\n" +
+"#              define malloc_getpagesize (NBPG * CLSIZE)\n" +
+"#            endif\n" +
+"#          else\n" +
+"#            ifdef NBPC\n" +
+"#              define malloc_getpagesize NBPC\n" +
+"#            else\n" +
+"#              ifdef PAGESIZE\n" +
+"#                define malloc_getpagesize PAGESIZE\n" +
+"#              else /* just guess */\n" +
+"#                define malloc_getpagesize (4096)\n" +
+"#              endif\n" +
+"#            endif\n" +
+"#          endif\n" +
+"#        endif\n" +
+"#      endif\n" +
+"#    endif\n" +
+"#  endif\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  This version of malloc supports the standard SVID/XPG mallinfo\n" +
+"  routine that returns a struct containing usage properties and\n" +
+"  statistics. It should work on any SVID/XPG compliant system that has\n" +
+"  a /usr/include/malloc.h defining struct mallinfo. (If you'd like to\n" +
+"  install such a thing yourself, cut out the preliminary declarations\n" +
+"  as described above and below and save them in a malloc.h file. But\n" +
+"  there's no compelling reason to bother to do this.)\n" +
+"\n" +
+"  The main declaration needed is the mallinfo struct that is returned\n" +
+"  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a\n" +
+"  bunch of fields that are not even meaningful in this version of\n" +
+"  malloc.  These fields are are instead filled by mallinfo() with\n" +
+"  other numbers that might be of interest.\n" +
+"\n" +
+"  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a\n" +
+"  /usr/include/malloc.h file that includes a declaration of struct\n" +
+"  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant\n" +
+"  version is declared below.  These must be precisely the same for\n" +
+"  mallinfo() to work.  The original SVID version of this struct,\n" +
+"  defined on most systems with mallinfo, declares all fields as\n" +
+"  ints. But some others define as unsigned long. If your system\n" +
+"  defines the fields using a type of different width than listed here,\n" +
+"  you must #include your system version and #define\n" +
+"  HAVE_USR_INCLUDE_MALLOC_H.\n" +
+"*/\n" +
+"\n" +
+"/* #define HAVE_USR_INCLUDE_MALLOC_H */\n" +
+"\n" +
+"#ifdef HAVE_USR_INCLUDE_MALLOC_H\n" +
+"#include \"/usr/include/malloc.h\"\n" +
+"#else\n" +
+"\n" +
+"/* SVID2/XPG mallinfo structure */\n" +
+"\n" +
+"struct mallinfo {\n" +
+"  int arena;    /* non-mmapped space allocated from system */\n" +
+"  int ordblks;  /* number of free chunks */\n" +
+"  int smblks;   /* number of fastbin blocks */\n" +
+"  int hblks;    /* number of mmapped regions */\n" +
+"  int hblkhd;   /* space in mmapped regions */\n" +
+"  int usmblks;  /* maximum total allocated space */\n" +
+"  int fsmblks;  /* space available in freed fastbin blocks */\n" +
+"  int uordblks; /* total allocated space */\n" +
+"  int fordblks; /* total free space */\n" +
+"  int keepcost; /* top-most, releasable (via malloc_trim) space */\n" +
+"};\n" +
+"\n" +
+"/*\n" +
+"  SVID/XPG defines four standard parameter numbers for mallopt,\n" +
+"  normally defined in malloc.h.  Only one of these (M_MXFAST) is used\n" +
+"  in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,\n" +
+"  so setting them has no effect. But this malloc also supports other\n" +
+"  options in mallopt described below.\n" +
+"*/\n") +
+("#endif\n" +
+"\n" +
+"\n" +
+"/* ---------- description of public routines ------------ */\n" +
+"\n" +
+"/*\n" +
+"  malloc(size_t n)\n" +
+"  Returns a pointer to a newly allocated chunk of at least n bytes, or null\n" +
+"  if no space is available. Additionally, on failure, errno is\n" +
+"  set to ENOMEM on ANSI C systems.\n" +
+"\n" +
+"  If n is zero, malloc returns a minumum-sized chunk. (The minimum\n" +
+"  size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit\n" +
+"  systems.)  On most systems, size_t is an unsigned type, so calls\n" +
+"  with negative arguments are interpreted as requests for huge amounts\n" +
+"  of space, which will often fail. The maximum supported value of n\n" +
+"  differs across systems, but is in all cases less than the maximum\n" +
+"  representable value of a size_t.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"Void_t*  public_mALLOc(size_t);\n" +
+"#else\n" +
+"Void_t*  public_mALLOc();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  free(Void_t* p)\n" +
+"  Releases the chunk of memory pointed to by p, that had been previously\n" +
+"  allocated using malloc or a related routine such as realloc.\n" +
+"  It has no effect if p is null. It can have arbitrary (i.e., bad!)\n" +
+"  effects if p has already been freed.\n" +
+"\n" +
+"  Unless disabled (using mallopt), freeing very large spaces will\n" +
+"  when possible, automatically trigger operations that give\n" +
+"  back unused memory to the system, thus reducing program footprint.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"void     public_fREe(Void_t*);\n" +
+"#else\n" +
+"void     public_fREe();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  calloc(size_t n_elements, size_t element_size);\n" +
+"  Returns a pointer to n_elements * element_size bytes, with all locations\n" +
+"  set to zero.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"Void_t*  public_cALLOc(size_t, size_t);\n" +
+"#else\n" +
+"Void_t*  public_cALLOc();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  realloc(Void_t* p, size_t n)\n" +
+"  Returns a pointer to a chunk of size n that contains the same data\n" +
+"  as does chunk p up to the minimum of (n, p's size) bytes, or null\n" +
+"  if no space is available.\n" +
+"\n" +
+"  The returned pointer may or may not be the same as p. The algorithm\n" +
+"  prefers extending p when possible, otherwise it employs the\n" +
+"  equivalent of a malloc-copy-free sequence.\n" +
+"\n" +
+"  If p is null, realloc is equivalent to malloc.\n" +
+"\n" +
+"  If space is not available, realloc returns null, errno is set (if on\n" +
+"  ANSI) and p is NOT freed.\n" +
+"\n" +
+"  if n is for fewer bytes than already held by p, the newly unused\n" +
+"  space is lopped off and freed if possible.  Unless the #define\n" +
+"  REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of\n" +
+"  zero (re)allocates a minimum-sized chunk.\n" +
+"\n" +
+"  Large chunks that were internally obtained via mmap will always\n" +
+"  be reallocated using malloc-copy-free sequences unless\n" +
+"  the system supports MREMAP (currently only linux).\n" +
+"\n" +
+"  The old unix realloc convention of allowing the last-free'd chunk\n" +
+"  to be used as an argument to realloc is not supported.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"Void_t*  public_rEALLOc(Void_t*, size_t);\n" +
+"#else\n" +
+"Void_t*  public_rEALLOc();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  memalign(size_t alignment, size_t n);\n" +
+"  Returns a pointer to a newly allocated chunk of n bytes, aligned\n" +
+"  in accord with the alignment argument.\n" +
+"\n" +
+"  The alignment argument should be a power of two. If the argument is\n" +
+"  not a power of two, the nearest greater power is used.\n" +
+"  8-byte alignment is guaranteed by normal malloc calls, so don't\n" +
+"  bother calling memalign with an argument of 8 or less.\n" +
+"\n" +
+"  Overreliance on memalign is a sure way to fragment space.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"Void_t*  public_mEMALIGn(size_t, size_t);\n" +
+"#else\n" +
+"Void_t*  public_mEMALIGn();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  valloc(size_t n);\n" +
+"  Equivalent to memalign(pagesize, n), where pagesize is the page\n" +
+"  size of the system. If the pagesize is unknown, 4096 is used.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"Void_t*  public_vALLOc(size_t);\n" +
+"#else\n" +
+"Void_t*  public_vALLOc();\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  mallopt(int parameter_number, int parameter_value)\n" +
+"  Sets tunable parameters The format is to provide a\n" +
+"  (parameter-number, parameter-value) pair.  mallopt then sets the\n" +
+"  corresponding parameter to the argument value if it can (i.e., so\n" +
+"  long as the value is meaningful), and returns 1 if successful else\n" +
+"  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,\n" +
+"  normally defined in malloc.h.  Only one of these (M_MXFAST) is used\n" +
+"  in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,\n" +
+"  so setting them has no effect. But this malloc also supports four\n" +
+"  other options in mallopt. See below for details.  Briefly, supported\n" +
+"  parameters are as follows (listed defaults are for \"typical\"\n" +
+"  configurations).\n" +
+"\n" +
+"  Symbol            param #   default    allowed param values\n" +
+"  M_MXFAST          1         64         0-80  (0 disables fastbins)\n" +
+"  M_TRIM_THRESHOLD -1         256*1024   any   (-1U disables trimming)\n" +
+"  M_TOP_PAD        -2         0          any\n" +
+"  M_MMAP_THRESHOLD -3         256*1024   any   (or 0 if no MMAP support)\n" +
+"  M_MMAP_MAX       -4         65536      any   (0 disables use of mmap)\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"int      public_mALLOPt(int, int);\n" +
+"#else\n" +
+"int      public_mALLOPt();\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  mallinfo()\n" +
+"  Returns (by copy) a struct containing various summary statistics:\n" +
+"\n") +
+("  arena:     current total non-mmapped bytes allocated from system\n" +
+"  ordblks:   the number of free chunks\n" +
+"  smblks:    the number of fastbin blocks (i.e., small chunks that\n" +
+"               have been freed but not use resused or consolidated)\n" +
+"  hblks:     current number of mmapped regions\n" +
+"  hblkhd:    total bytes held in mmapped regions\n" +
+"  usmblks:   the maximum total allocated space. This will be greater\n" +
+"                than current total if trimming has occurred.\n" +
+"  fsmblks:   total bytes held in fastbin blocks\n" +
+"  uordblks:  current total allocated space (normal or mmapped)\n" +
+"  fordblks:  total free space\n" +
+"  keepcost:  the maximum number of bytes that could ideally be released\n" +
+"               back to system via malloc_trim. (\"ideally\" means that\n" +
+"               it ignores page restrictions etc.)\n" +
+"\n" +
+"  Because these fields are ints, but internal bookkeeping may\n" +
+"  be kept as longs, the reported values may wrap around zero and\n" +
+"  thus be inaccurate.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"struct mallinfo public_mALLINFo(void);\n" +
+"#else\n" +
+"struct mallinfo public_mALLINFo();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  independent_calloc(size_t n_elements, size_t element_size, Void_t* chunks[]);\n" +
+"\n" +
+"  independent_calloc is similar to calloc, but instead of returning a\n" +
+"  single cleared space, it returns an array of pointers to n_elements\n" +
+"  independent elements that can hold contents of size elem_size, each\n" +
+"  of which starts out cleared, and can be independently freed,\n" +
+"  realloc'ed etc. The elements are guaranteed to be adjacently\n" +
+"  allocated (this is not guaranteed to occur with multiple callocs or\n" +
+"  mallocs), which may also improve cache locality in some\n" +
+"  applications.\n" +
+"\n" +
+"  The \"chunks\" argument is optional (i.e., may be null, which is\n" +
+"  probably the most typical usage). If it is null, the returned array\n" +
+"  is itself dynamically allocated and should also be freed when it is\n" +
+"  no longer needed. Otherwise, the chunks array must be of at least\n" +
+"  n_elements in length. It is filled in with the pointers to the\n" +
+"  chunks.\n" +
+"\n" +
+"  In either case, independent_calloc returns this pointer array, or\n" +
+"  null if the allocation failed.  If n_elements is zero and \"chunks\"\n" +
+"  is null, it returns a chunk representing an array with zero elements\n" +
+"  (which should be freed if not wanted).\n" +
+"\n" +
+"  Each element must be individually freed when it is no longer\n" +
+"  needed. If you'd like to instead be able to free all at once, you\n" +
+"  should instead use regular calloc and assign pointers into this\n" +
+"  space to represent elements.  (In this case though, you cannot\n" +
+"  independently free elements.)\n" +
+"\n" +
+"  independent_calloc simplifies and speeds up implementations of many\n" +
+"  kinds of pools.  It may also be useful when constructing large data\n" +
+"  structures that initially have a fixed number of fixed-sized nodes,\n" +
+"  but the number is not known at compile time, and some of the nodes\n" +
+"  may later need to be freed. For example:\n" +
+"\n" +
+"  struct Node { int item; struct Node* next; };\n" +
+"\n" +
+"  struct Node* build_list() {\n" +
+"    struct Node** pool;\n" +
+"    int n = read_number_of_nodes_needed();\n" +
+"    if (n <= 0) return 0;\n" +
+"    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);\n" +
+"    if (pool == 0) die();\n" +
+"    // organize into a linked list...\n" +
+"    struct Node* first = pool[0];\n" +
+"    for (i = 0; i < n-1; ++i)\n" +
+"      pool[i]->next = pool[i+1];\n" +
+"    free(pool);     // Can now free the array (or not, if it is needed later)\n" +
+"    return first;\n" +
+"  }\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"Void_t** public_iCALLOc(size_t, size_t, Void_t**);\n" +
+"#else\n" +
+"Void_t** public_iCALLOc();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);\n" +
+"\n" +
+"  independent_comalloc allocates, all at once, a set of n_elements\n" +
+"  chunks with sizes indicated in the \"sizes\" array.    It returns\n" +
+"  an array of pointers to these elements, each of which can be\n" +
+"  independently freed, realloc'ed etc. The elements are guaranteed to\n" +
+"  be adjacently allocated (this is not guaranteed to occur with\n" +
+"  multiple callocs or mallocs), which may also improve cache locality\n" +
+"  in some applications.\n" +
+"\n" +
+"  The \"chunks\" argument is optional (i.e., may be null). If it is null\n" +
+"  the returned array is itself dynamically allocated and should also\n" +
+"  be freed when it is no longer needed. Otherwise, the chunks array\n" +
+"  must be of at least n_elements in length. It is filled in with the\n" +
+"  pointers to the chunks.\n" +
+"\n" +
+"  In either case, independent_comalloc returns this pointer array, or\n" +
+"  null if the allocation failed.  If n_elements is zero and chunks is\n" +
+"  null, it returns a chunk representing an array with zero elements\n" +
+"  (which should be freed if not wanted).\n" +
+"\n" +
+"  Each element must be individually freed when it is no longer\n" +
+"  needed. If you'd like to instead be able to free all at once, you\n" +
+"  should instead use a single regular malloc, and assign pointers at\n" +
+"  particular offsets in the aggregate space. (In this case though, you\n" +
+"  cannot independently free elements.)\n" +
+"\n" +
+"  independent_comallac differs from independent_calloc in that each\n" +
+"  element may have a different size, and also that it does not\n" +
+"  automatically clear elements.\n" +
+"\n" +
+"  independent_comalloc can be used to speed up allocation in cases\n" +
+"  where several structs or objects must always be allocated at the\n" +
+"  same time.  For example:\n" +
+"\n" +
+"  struct Head { ... }\n" +
+"  struct Foot { ... }\n" +
+"\n" +
+"  void send_message(char* msg) {\n" +
+"    int msglen = strlen(msg);\n" +
+"    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };\n" +
+"    void* chunks[3];\n" +
+"    if (independent_comalloc(3, sizes, chunks) == 0)\n" +
+"      die();\n" +
+"    struct Head* head = (struct Head*)(chunks[0]);\n" +
+"    char*        body = (char*)(chunks[1]);\n" +
+"    struct Foot* foot = (struct Foot*)(chunks[2]);\n" +
+"    // ...\n" +
+"  }\n" +
+"\n" +
+"  In general though, independent_comalloc is worth using only for\n" +
+"  larger values of n_elements. For small values, you probably won't\n" +
+"  detect enough difference from series of malloc calls to bother.\n" +
+"\n" +
+"  Overuse of independent_comalloc can increase overall memory usage,\n" +
+"  since it cannot reuse existing noncontiguous small chunks that\n" +
+"  might be available for some of the elements.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"Void_t** public_iCOMALLOc(size_t, size_t*, Void_t**);\n" +
+"#else\n" +
+"Void_t** public_iCOMALLOc();\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/*\n") +
+("  pvalloc(size_t n);\n" +
+"  Equivalent to valloc(minimum-page-that-holds(n)), that is,\n" +
+"  round up n to nearest pagesize.\n" +
+" */\n" +
+"#if __STD_C\n" +
+"Void_t*  public_pVALLOc(size_t);\n" +
+"#else\n" +
+"Void_t*  public_pVALLOc();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  cfree(Void_t* p);\n" +
+"  Equivalent to free(p).\n" +
+"\n" +
+"  cfree is needed/defined on some systems that pair it with calloc,\n" +
+"  for odd historical reasons (such as: cfree is used in example\n" +
+"  code in the first edition of K&R).\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"void     public_cFREe(Void_t*);\n" +
+"#else\n" +
+"void     public_cFREe();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  malloc_trim(size_t pad);\n" +
+"\n" +
+"  If possible, gives memory back to the system (via negative\n" +
+"  arguments to sbrk) if there is unused memory at the `high' end of\n" +
+"  the malloc pool. You can call this after freeing large blocks of\n" +
+"  memory to potentially reduce the system-level memory requirements\n" +
+"  of a program. However, it cannot guarantee to reduce memory. Under\n" +
+"  some allocation patterns, some large free blocks of memory will be\n" +
+"  locked between two used chunks, so they cannot be given back to\n" +
+"  the system.\n" +
+"\n" +
+"  The `pad' argument to malloc_trim represents the amount of free\n" +
+"  trailing space to leave untrimmed. If this argument is zero,\n" +
+"  only the minimum amount of memory to maintain internal data\n" +
+"  structures will be left (one page or less). Non-zero arguments\n" +
+"  can be supplied to maintain enough trailing space to service\n" +
+"  future expected allocations without having to re-obtain memory\n" +
+"  from the system.\n" +
+"\n" +
+"  Malloc_trim returns 1 if it actually released any memory, else 0.\n" +
+"  On systems that do not support \"negative sbrks\", it will always\n" +
+"  rreturn 0.\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"int      public_mTRIm(size_t);\n" +
+"#else\n" +
+"int      public_mTRIm();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  malloc_usable_size(Void_t* p);\n" +
+"\n" +
+"  Returns the number of bytes you can actually use in\n" +
+"  an allocated chunk, which may be more than you requested (although\n" +
+"  often not) due to alignment and minimum size constraints.\n" +
+"  You can use this many bytes without worrying about\n" +
+"  overwriting other allocated objects. This is not a particularly great\n" +
+"  programming practice. malloc_usable_size can be more useful in\n" +
+"  debugging and assertions, for example:\n" +
+"\n" +
+"  p = malloc(n);\n" +
+"  assert(malloc_usable_size(p) >= 256);\n" +
+"\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"size_t   public_mUSABLe(Void_t*);\n" +
+"#else\n" +
+"size_t   public_mUSABLe();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  malloc_stats();\n" +
+"  Prints on stderr the amount of space obtained from the system (both\n" +
+"  via sbrk and mmap), the maximum amount (which may be more than\n" +
+"  current if malloc_trim and/or munmap got called), and the current\n" +
+"  number of bytes allocated via malloc (or realloc, etc) but not yet\n" +
+"  freed. Note that this is the number of bytes allocated, not the\n" +
+"  number requested. It will be larger than the number requested\n" +
+"  because of alignment and bookkeeping overhead. Because it includes\n" +
+"  alignment wastage as being in use, this figure may be greater than\n" +
+"  zero even when no user-level chunks are allocated.\n" +
+"\n" +
+"  The reported current and maximum system memory can be inaccurate if\n" +
+"  a program makes other calls to system memory allocation functions\n" +
+"  (normally sbrk) outside of malloc.\n" +
+"\n" +
+"  malloc_stats prints only the most commonly interesting statistics.\n" +
+"  More information can be obtained by calling mallinfo.\n" +
+"\n" +
+"*/\n" +
+"#if __STD_C\n" +
+"void     public_mSTATs();\n" +
+"#else\n" +
+"void     public_mSTATs();\n" +
+"#endif\n" +
+"\n" +
+"/* mallopt tuning options */\n" +
+"\n" +
+"/*\n" +
+"  M_MXFAST is the maximum request size used for \"fastbins\", special bins\n" +
+"  that hold returned chunks without consolidating their spaces. This\n" +
+"  enables future requests for chunks of the same size to be handled\n" +
+"  very quickly, but can increase fragmentation, and thus increase the\n" +
+"  overall memory footprint of a program.\n" +
+"\n" +
+"  This malloc manages fastbins very conservatively yet still\n" +
+"  efficiently, so fragmentation is rarely a problem for values less\n" +
+"  than or equal to the default.  The maximum supported value of MXFAST\n" +
+"  is 80. You wouldn't want it any higher than this anyway.  Fastbins\n" +
+"  are designed especially for use with many small structs, objects or\n" +
+"  strings -- the default handles structs/objects/arrays with sizes up\n" +
+"  to 16 4byte fields, or small strings representing words, tokens,\n" +
+"  etc. Using fastbins for larger objects normally worsens\n" +
+"  fragmentation without improving speed.\n" +
+"\n" +
+"  M_MXFAST is set in REQUEST size units. It is internally used in\n" +
+"  chunksize units, which adds padding and alignment.  You can reduce\n" +
+"  M_MXFAST to 0 to disable all use of fastbins.  This causes the malloc\n" +
+"  algorithm to be a closer approximation of fifo-best-fit in all cases,\n" +
+"  not just for larger requests, but will generally cause it to be\n" +
+"  slower.\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */\n" +
+"#ifndef M_MXFAST\n" +
+"#define M_MXFAST            1\n" +
+"#endif\n" +
+"\n" +
+"#ifndef DEFAULT_MXFAST\n" +
+"#define DEFAULT_MXFAST     64\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  M_TRIM_THRESHOLD is the maximum amount of unused top-most memory\n" +
+"  to keep before releasing via malloc_trim in free().\n" +
+"\n" +
+"  Automatic trimming is mainly useful in long-lived programs.\n" +
+"  Because trimming via sbrk can be slow on some systems, and can\n" +
+"  sometimes be wasteful (in cases where programs immediately\n" +
+"  afterward allocate more large chunks) the value should be high\n" +
+"  enough so that your overall system performance would improve by\n" +
+"  releasing this much memory.\n" +
+"\n") +
+("  The trim threshold and the mmap control parameters (see below)\n" +
+"  can be traded off with one another. Trimming and mmapping are\n" +
+"  two different ways of releasing unused memory back to the\n" +
+"  system. Between these two, it is often possible to keep\n" +
+"  system-level demands of a long-lived program down to a bare\n" +
+"  minimum. For example, in one test suite of sessions measuring\n" +
+"  the XF86 X server on Linux, using a trim threshold of 128K and a\n" +
+"  mmap threshold of 192K led to near-minimal long term resource\n" +
+"  consumption.\n" +
+"\n" +
+"  If you are using this malloc in a long-lived program, it should\n" +
+"  pay to experiment with these values.  As a rough guide, you\n" +
+"  might set to a value close to the average size of a process\n" +
+"  (program) running on your system.  Releasing this much memory\n" +
+"  would allow such a process to run in memory.  Generally, it's\n" +
+"  worth it to tune for trimming rather tham memory mapping when a\n" +
+"  program undergoes phases where several large chunks are\n" +
+"  allocated and released in ways that can reuse each other's\n" +
+"  storage, perhaps mixed with phases where there are no such\n" +
+"  chunks at all.  And in well-behaved long-lived programs,\n" +
+"  controlling release of large blocks via trimming versus mapping\n" +
+"  is usually faster.\n" +
+"\n" +
+"  However, in most programs, these parameters serve mainly as\n" +
+"  protection against the system-level effects of carrying around\n" +
+"  massive amounts of unneeded memory. Since frequent calls to\n" +
+"  sbrk, mmap, and munmap otherwise degrade performance, the default\n" +
+"  parameters are set to relatively high values that serve only as\n" +
+"  safeguards.\n" +
+"\n" +
+"  The trim value must be greater than page size to have any useful\n" +
+"  effect.  To disable trimming completely, you can set to\n" +
+"  (unsigned long)(-1)\n" +
+"\n" +
+"  Trim settings interact with fastbin (MXFAST) settings: Unless\n" +
+"  TRIM_FASTBINS is defined, automatic trimming never takes place upon\n" +
+"  freeing a chunk with size less than or equal to MXFAST. Trimming is\n" +
+"  instead delayed until subsequent freeing of larger chunks. However,\n" +
+"  you can still force an attempted trim by calling malloc_trim.\n" +
+"\n" +
+"  Also, trimming is not generally possible in cases where\n" +
+"  the main arena is obtained via mmap.\n" +
+"\n" +
+"  Note that the trick some people use of mallocing a huge space and\n" +
+"  then freeing it at program startup, in an attempt to reserve system\n" +
+"  memory, doesn't have the intended effect under automatic trimming,\n" +
+"  since that memory will immediately be returned to the system.\n" +
+"*/\n" +
+"\n" +
+"#define M_TRIM_THRESHOLD       -1\n" +
+"\n" +
+"#ifndef DEFAULT_TRIM_THRESHOLD\n" +
+"#define DEFAULT_TRIM_THRESHOLD (256 * 1024)\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  M_TOP_PAD is the amount of extra `padding' space to allocate or\n" +
+"  retain whenever sbrk is called. It is used in two ways internally:\n" +
+"\n" +
+"  * When sbrk is called to extend the top of the arena to satisfy\n" +
+"  a new malloc request, this much padding is added to the sbrk\n" +
+"  request.\n" +
+"\n" +
+"  * When malloc_trim is called automatically from free(),\n" +
+"  it is used as the `pad' argument.\n" +
+"\n" +
+"  In both cases, the actual amount of padding is rounded\n" +
+"  so that the end of the arena is always a system page boundary.\n" +
+"\n" +
+"  The main reason for using padding is to avoid calling sbrk so\n" +
+"  often. Having even a small pad greatly reduces the likelihood\n" +
+"  that nearly every malloc request during program start-up (or\n" +
+"  after trimming) will invoke sbrk, which needlessly wastes\n" +
+"  time.\n" +
+"\n" +
+"  Automatic rounding-up to page-size units is normally sufficient\n" +
+"  to avoid measurable overhead, so the default is 0.  However, in\n" +
+"  systems where sbrk is relatively slow, it can pay to increase\n" +
+"  this value, at the expense of carrying around more memory than\n" +
+"  the program needs.\n" +
+"*/\n" +
+"\n" +
+"#define M_TOP_PAD              -2\n" +
+"\n" +
+"#ifndef DEFAULT_TOP_PAD\n" +
+"#define DEFAULT_TOP_PAD        (0)\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  M_MMAP_THRESHOLD is the request size threshold for using mmap()\n" +
+"  to service a request. Requests of at least this size that cannot\n" +
+"  be allocated using already-existing space will be serviced via mmap.\n" +
+"  (If enough normal freed space already exists it is used instead.)\n" +
+"\n" +
+"  Using mmap segregates relatively large chunks of memory so that\n" +
+"  they can be individually obtained and released from the host\n" +
+"  system. A request serviced through mmap is never reused by any\n" +
+"  other request (at least not directly; the system may just so\n" +
+"  happen to remap successive requests to the same locations).\n" +
+"\n" +
+"  Segregating space in this way has the benefits that:\n" +
+"\n" +
+"   1. Mmapped space can ALWAYS be individually released back\n" +
+"      to the system, which helps keep the system level memory\n" +
+"      demands of a long-lived program low.\n" +
+"   2. Mapped memory can never become `locked' between\n" +
+"      other chunks, as can happen with normally allocated chunks, which\n" +
+"      means that even trimming via malloc_trim would not release them.\n" +
+"   3. On some systems with \"holes\" in address spaces, mmap can obtain\n" +
+"      memory that sbrk cannot.\n" +
+"\n" +
+"  However, it has the disadvantages that:\n" +
+"\n" +
+"   1. The space cannot be reclaimed, consolidated, and then\n" +
+"      used to service later requests, as happens with normal chunks.\n" +
+"   2. It can lead to more wastage because of mmap page alignment\n" +
+"      requirements\n" +
+"   3. It causes malloc performance to be more dependent on host\n" +
+"      system memory management support routines which may vary in\n" +
+"      implementation quality and may impose arbitrary\n" +
+"      limitations. Generally, servicing a request via normal\n" +
+"      malloc steps is faster than going through a system's mmap.\n" +
+"\n" +
+"  The advantages of mmap nearly always outweigh disadvantages for\n" +
+"  \"large\" chunks, but the value of \"large\" varies across systems.  The\n" +
+"  default is an empirically derived value that works well in most\n" +
+"  systems.\n" +
+"*/\n" +
+"\n" +
+"#define M_MMAP_THRESHOLD      -3\n" +
+"\n" +
+"#ifndef DEFAULT_MMAP_THRESHOLD\n" +
+"#define DEFAULT_MMAP_THRESHOLD (256 * 1024)\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  M_MMAP_MAX is the maximum number of requests to simultaneously\n" +
+"  service using mmap. This parameter exists because\n" +
+". Some systems have a limited number of internal tables for\n" +
+"  use by mmap, and using more than a few of them may degrade\n" +
+"  performance.\n" +
+"\n" +
+"  The default is set to a value that serves only as a safeguard.\n" +
+"  Setting to 0 disables use of mmap for servicing large requests.  If\n" +
+"  HAVE_MMAP is not set, the default value is 0, and attempts to set it\n" +
+"  to non-zero values in mallopt will fail.\n" +
+"*/\n" +
+"\n" +
+"#define M_MMAP_MAX             -4\n" +
+"\n") +
+("#ifndef DEFAULT_MMAP_MAX\n" +
+"#if HAVE_MMAP\n" +
+"#define DEFAULT_MMAP_MAX       (65536)\n" +
+"#else\n" +
+"#define DEFAULT_MMAP_MAX       (0)\n" +
+"#endif\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  ========================================================================\n" +
+"  To make a fully customizable malloc.h header file, cut everything\n" +
+"  above this line, put into file malloc.h, edit to suit, and #include it\n" +
+"  on the next line, as well as in programs that use this malloc.\n" +
+"  ========================================================================\n" +
+"*/\n" +
+"\n" +
+"/* #include \"malloc.h\" */\n" +
+"\n" +
+"/* --------------------- public wrappers ---------------------- */\n" +
+"\n" +
+"#ifdef USE_PUBLIC_MALLOC_WRAPPERS\n" +
+"\n" +
+"/* Declare all routines as internal */\n" +
+"#if __STD_C\n" +
+"static Void_t*  mALLOc(size_t);\n" +
+"static void     fREe(Void_t*);\n" +
+"static Void_t*  rEALLOc(Void_t*, size_t);\n" +
+"static Void_t*  mEMALIGn(size_t, size_t);\n" +
+"static Void_t*  vALLOc(size_t);\n" +
+"static Void_t*  pVALLOc(size_t);\n" +
+"static Void_t*  cALLOc(size_t, size_t);\n" +
+"static Void_t** iCALLOc(size_t, size_t, Void_t**);\n" +
+"static Void_t** iCOMALLOc(size_t, size_t*, Void_t**);\n" +
+"static void     cFREe(Void_t*);\n" +
+"static int      mTRIm(size_t);\n" +
+"static size_t   mUSABLe(Void_t*);\n" +
+"static void     mSTATs();\n" +
+"static int      mALLOPt(int, int);\n" +
+"static struct mallinfo mALLINFo(void);\n" +
+"#else\n" +
+"static Void_t*  mALLOc();\n" +
+"static void     fREe();\n" +
+"static Void_t*  rEALLOc();\n" +
+"static Void_t*  mEMALIGn();\n" +
+"static Void_t*  vALLOc();\n" +
+"static Void_t*  pVALLOc();\n" +
+"static Void_t*  cALLOc();\n" +
+"static Void_t** iCALLOc();\n" +
+"static Void_t** iCOMALLOc();\n" +
+"static void     cFREe();\n" +
+"static int      mTRIm();\n" +
+"static size_t   mUSABLe();\n" +
+"static void     mSTATs();\n" +
+"static int      mALLOPt();\n" +
+"static struct mallinfo mALLINFo();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  MALLOC_PREACTION and MALLOC_POSTACTION should be\n" +
+"  defined to return 0 on success, and nonzero on failure.\n" +
+"  The return value of MALLOC_POSTACTION is currently ignored\n" +
+"  in wrapper functions since there is no reasonable default\n" +
+"  action to take on failure.\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#ifdef USE_MALLOC_LOCK\n" +
+"\n" +
+"#ifdef WIN32\n" +
+"\n" +
+"static int mALLOC_MUTEx;\n" +
+"#define MALLOC_PREACTION   slwait(&mALLOC_MUTEx)\n" +
+"#define MALLOC_POSTACTION  slrelease(&mALLOC_MUTEx)\n" +
+"\n" +
+"#else\n" +
+"\n" +
+"#include <pthread.h>\n" +
+"\n" +
+"static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER;\n" +
+"\n" +
+"#define MALLOC_PREACTION   pthread_mutex_lock(&mALLOC_MUTEx)\n" +
+"#define MALLOC_POSTACTION  pthread_mutex_unlock(&mALLOC_MUTEx)\n" +
+"\n" +
+"#endif /* USE_MALLOC_LOCK */\n" +
+"\n" +
+"#else\n" +
+"\n" +
+"/* Substitute anything you like for these */\n" +
+"\n" +
+"#define MALLOC_PREACTION   (0)\n" +
+"#define MALLOC_POSTACTION  (0)\n" +
+"\n" +
+"#endif\n" +
+"\n" +
+"Void_t* public_mALLOc(size_t bytes) {\n" +
+"  Void_t* m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = mALLOc(bytes);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"\n" +
+"static pthread_once_t free_mutex_once = PTHREAD_ONCE_INIT;\n" +
+"static pthread_mutex_t free_mutex;\n" +
+"static int scheduled_free_size;\n" +
+"static int scheduled_free_capacity;\n" +
+"static int scheduled_free_list;\n" +
+"bool free_is_scheduled;\n" +
+"\n" +
+"static void initialize_scheduled_free_list()\n" +
+"{\n" +
+"    pthread_mutex_init(&free_mutex, NULL);\n" +
+"}\n" +
+"\n" +
+"static void drain_scheduled_free_list()\n" +
+"{\n" +
+"    pthread_mutex_lock(&free_mutex);\n" +
+"    if (free_is_scheduled) {\n" +
+"        for(int i = 0; i < scheduled_free_size; i++) {\n" +
+"            main_thread_free(scheduled_free_list[i]);\n" +
+"        }\n" +
+"        free(scheduled_free_list);\n" +
+"        scheduled_free_list = NULL;\n" +
+"        scheduled_free_size = 0;\n" +
+"        scheduled_free_capacity = 0;\n" +
+"        free_is_scheduled = false;\n" +
+"    }\n" +
+"    pthread_mutex_unlock(&free_mutex);\n" +
+"}\n" +
+"\n" +
+"static void schedule_free_on_main_thread(Void_t* m)\n" +
+"{\n" +
+"    pthread_once(&free_mutex_once, initialize_scheduled_free_list);\n" +
+"\n" +
+"    pthread_mutex_lock(&free_mutex);\n" +
+"    if (scheduled_free_size == scheduled_free_capacity) {\n" +
+"        scheduled_free_capacity = scheduled_free_capacity == 0 ? 16 : scheduled_free_capacity * 1.2;\n" +
+"        scheduled_free_list = (Void_t**)realloc(scheduled_free_list, sizeof(Void_t*) * scheduled_free_capacity);\n" +
+"    }\n" +
+"    scheduled_free_list[scheduled_free_size++] = m;\n" +
+"    if (!free_is_scheduled) {\n" +
+"        QTimer::immediateSingleShotOnMainThread(0, drain_scheduled_free_list);\n" +
+"        free_is_scheduled = true;\n" +
+"    }\n" +
+"    pthread_mutex_unlock(&free_mutex);\n" +
+"}\n") +
+("\n" +
+"void public_fREe(Void_t* m) {\n" +
+"  if (!pthread_main_np()) {\n" +
+"      schedule_free_on_main_thread(m);\n" +
+"      return;\n" +
+"  }\n" +
+"\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return;\n" +
+"  }\n" +
+"  fREe(m);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"}\n" +
+"\n" +
+"Void_t* public_rEALLOc(Void_t* m, size_t bytes) {\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = rEALLOc(m, bytes);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"Void_t* public_mEMALIGn(size_t alignment, size_t bytes) {\n" +
+"  Void_t* m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = mEMALIGn(alignment, bytes);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"Void_t* public_vALLOc(size_t bytes) {\n" +
+"  Void_t* m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = vALLOc(bytes);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"Void_t* public_pVALLOc(size_t bytes) {\n" +
+"  Void_t* m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = pVALLOc(bytes);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"Void_t* public_cALLOc(size_t n, size_t elem_size) {\n" +
+"  Void_t* m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = cALLOc(n, elem_size);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"\n" +
+"Void_t** public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks) {\n" +
+"  Void_t** m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = iCALLOc(n, elem_size, chunks);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"Void_t** public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks) {\n" +
+"  Void_t** m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  m = iCOMALLOc(n, sizes, chunks);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"void public_cFREe(Void_t* m) {\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return;\n" +
+"  }\n" +
+"  cFREe(m);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"}\n" +
+"\n" +
+"int public_mTRIm(size_t s) {\n" +
+"  int result;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  result = mTRIm(s);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return result;\n" +
+"}\n" +
+"\n" +
+"size_t public_mUSABLe(Void_t* m) {\n" +
+"  size_t result;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  result = mUSABLe(m);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return result;\n" +
+"}\n" +
+"\n" +
+"void public_mSTATs() {\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return;\n" +
+"  }\n" +
+"  mSTATs();\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"}\n" +
+"\n" +
+"struct mallinfo public_mALLINFo() {\n" +
+"  struct mallinfo m;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\n" +
+"    return nm;\n" +
+"  }\n" +
+"  m = mALLINFo();\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return m;\n" +
+"}\n" +
+"\n" +
+"int public_mALLOPt(int p, int v) {\n" +
+"  int result;\n" +
+"  if (MALLOC_PREACTION != 0) {\n" +
+"    return 0;\n" +
+"  }\n" +
+"  result = mALLOPt(p, v);\n" +
+"  if (MALLOC_POSTACTION != 0) {\n" +
+"  }\n" +
+"  return result;\n" +
+"}\n" +
+"\n") +
+("#endif\n" +
+"\n" +
+"\n" +
+"\n" +
+"/* ------------- Optional versions of memcopy ---------------- */\n" +
+"\n" +
+"\n" +
+"#if USE_MEMCPY\n" +
+"\n" +
+"/*\n" +
+"  Note: memcpy is ONLY invoked with non-overlapping regions,\n" +
+"  so the (usually slower) memmove is not needed.\n" +
+"*/\n" +
+"\n" +
+"#define MALLOC_COPY(dest, src, nbytes)  memcpy(dest, src, nbytes)\n" +
+"#define MALLOC_ZERO(dest, nbytes)       memset(dest, 0,   nbytes)\n" +
+"\n" +
+"#else /* !USE_MEMCPY */\n" +
+"\n" +
+"/* Use Duff's device for good zeroing/copying performance. */\n" +
+"\n" +
+"#define MALLOC_ZERO(charp, nbytes)                                            \\n" +
+"do {                                                                          \\n" +
+"  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \\n" +
+"  CHUNK_SIZE_T  mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T);                     \\n" +
+"  long mcn;                                                                   \\n" +
+"  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \\n" +
+"  switch (mctmp) {                                                            \\n" +
+"    case 0: for(;;) { *mzp++ = 0;                                             \\n" +
+"    case 7:           *mzp++ = 0;                                             \\n" +
+"    case 6:           *mzp++ = 0;                                             \\n" +
+"    case 5:           *mzp++ = 0;                                             \\n" +
+"    case 4:           *mzp++ = 0;                                             \\n" +
+"    case 3:           *mzp++ = 0;                                             \\n" +
+"    case 2:           *mzp++ = 0;                                             \\n" +
+"    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \\n" +
+"  }                                                                           \\n" +
+"} while(0)\n" +
+"\n" +
+"#define MALLOC_COPY(dest,src,nbytes)                                          \\n" +
+"do {                                                                          \\n" +
+"  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \\n" +
+"  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \\n" +
+"  CHUNK_SIZE_T  mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T);                     \\n" +
+"  long mcn;                                                                   \\n" +
+"  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \\n" +
+"  switch (mctmp) {                                                            \\n" +
+"    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \\n" +
+"    case 7:           *mcdst++ = *mcsrc++;                                    \\n" +
+"    case 6:           *mcdst++ = *mcsrc++;                                    \\n" +
+"    case 5:           *mcdst++ = *mcsrc++;                                    \\n" +
+"    case 4:           *mcdst++ = *mcsrc++;                                    \\n" +
+"    case 3:           *mcdst++ = *mcsrc++;                                    \\n" +
+"    case 2:           *mcdst++ = *mcsrc++;                                    \\n" +
+"    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \\n" +
+"  }                                                                           \\n" +
+"} while(0)\n" +
+"\n" +
+"#endif\n" +
+"\n" +
+"/* ------------------ MMAP support ------------------  */\n" +
+"\n" +
+"\n" +
+"#if HAVE_MMAP\n" +
+"\n" +
+"#ifndef LACKS_FCNTL_H\n" +
+"#include <fcntl.h>\n" +
+"#endif\n" +
+"\n" +
+"#ifndef LACKS_SYS_MMAN_H\n" +
+"#include <sys/mman.h>\n" +
+"#endif\n" +
+"\n" +
+"#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)\n" +
+"#define MAP_ANONYMOUS MAP_ANON\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"   Nearly all versions of mmap support MAP_ANONYMOUS,\n" +
+"   so the following is unlikely to be needed, but is\n" +
+"   supplied just in case.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MAP_ANONYMOUS\n" +
+"\n" +
+"static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */\n" +
+"\n" +
+"#define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \\n" +
+" (dev_zero_fd = open(\"/dev/zero\", O_RDWR), \\n" +
+"  mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \\n" +
+"   mmap((addr), (size), (prot), (flags), dev_zero_fd, 0))\n" +
+"\n" +
+"#else\n" +
+"\n" +
+"#define MMAP(addr, size, prot, flags) \\n" +
+" (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0))\n" +
+"\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"#endif /* HAVE_MMAP */\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  -----------------------  Chunk representations -----------------------\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  This struct declaration is misleading (but accurate and necessary).\n" +
+"  It declares a \"view\" into memory allowing access to necessary\n" +
+"  fields at known offsets from a given base. See explanation below.\n" +
+"*/\n" +
+"\n" +
+"struct malloc_chunk {\n" +
+"\n" +
+"  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */\n" +
+"  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */\n" +
+"\n" +
+"  struct malloc_chunk* fd;         /* double links -- used only if free. */\n" +
+"  struct malloc_chunk* bk;\n" +
+"};\n" +
+"\n" +
+"\n" +
+"typedef struct malloc_chunk* mchunkptr;\n" +
+"\n" +
+"/*\n" +
+"   malloc_chunk details:\n" +
+"\n" +
+"    (The following includes lightly edited explanations by Colin Plumb.)\n" +
+"\n" +
+"    Chunks of memory are maintained using a `boundary tag' method as\n" +
+"    described in e.g., Knuth or Standish.  (See the paper by Paul\n" +
+"    Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a\n" +
+"    survey of such techniques.)  Sizes of free chunks are stored both\n" +
+"    in the front of each chunk and at the end.  This makes\n" +
+"    consolidating fragmented chunks into bigger chunks very fast.  The\n" +
+"    size fields also hold bits representing whether chunks are free or\n" +
+"    in use.\n" +
+"\n" +
+"    An allocated chunk looks like this:\n" +
+"\n" +
+"\n" +
+"    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             Size of previous chunk, if allocated            | |\n" +
+"            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             Size of chunk, in bytes                         |P|\n" +
+"      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             User data starts here...                          .\n" +
+"            .                                                               .\n" +
+"            .             (malloc_usable_space() bytes)                     .\n" +
+"            .                                                               |\n" +
+"nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             Size of chunk                                     |\n" +
+"            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"\n") +
+("\n" +
+"    Where \"chunk\" is the front of the chunk for the purpose of most of\n" +
+"    the malloc code, but \"mem\" is the pointer that is returned to the\n" +
+"    user.  \"Nextchunk\" is the beginning of the next contiguous chunk.\n" +
+"\n" +
+"    Chunks always begin on even word boundries, so the mem portion\n" +
+"    (which is returned to the user) is also on an even word boundary, and\n" +
+"    thus at least double-word aligned.\n" +
+"\n" +
+"    Free chunks are stored in circular doubly-linked lists, and look like this:\n" +
+"\n" +
+"    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             Size of previous chunk                            |\n" +
+"            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"    `head:' |             Size of chunk, in bytes                         |P|\n" +
+"      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             Forward pointer to next chunk in list             |\n" +
+"            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             Back pointer to previous chunk in list            |\n" +
+"            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"            |             Unused space (may be 0 bytes long)                .\n" +
+"            .                                                               .\n" +
+"            .                                                               |\n" +
+"nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"    `foot:' |             Size of chunk, in bytes                           |\n" +
+"            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n" +
+"\n" +
+"    The P (PREV_INUSE) bit, stored in the unused low-order bit of the\n" +
+"    chunk size (which is always a multiple of two words), is an in-use\n" +
+"    bit for the *previous* chunk.  If that bit is *clear*, then the\n" +
+"    word before the current chunk size contains the previous chunk\n" +
+"    size, and can be used to find the front of the previous chunk.\n" +
+"    The very first chunk allocated always has this bit set,\n" +
+"    preventing access to non-existent (or non-owned) memory. If\n" +
+"    prev_inuse is set for any given chunk, then you CANNOT determine\n" +
+"    the size of the previous chunk, and might even get a memory\n" +
+"    addressing fault when trying to do so.\n" +
+"\n" +
+"    Note that the `foot' of the current chunk is actually represented\n" +
+"    as the prev_size of the NEXT chunk. This makes it easier to\n" +
+"    deal with alignments etc but can be very confusing when trying\n" +
+"    to extend or adapt this code.\n" +
+"\n" +
+"    The two exceptions to all this are\n" +
+"\n" +
+"     1. The special chunk `top' doesn't bother using the\n" +
+"        trailing size field since there is no next contiguous chunk\n" +
+"        that would have to index off it. After initialization, `top'\n" +
+"        is forced to always exist.  If it would become less than\n" +
+"        MINSIZE bytes long, it is replenished.\n" +
+"\n" +
+"     2. Chunks allocated via mmap, which have the second-lowest-order\n" +
+"        bit (IS_MMAPPED) set in their size fields.  Because they are\n" +
+"        allocated one-by-one, each must contain its own trailing size field.\n" +
+"\n" +
+"*/\n" +
+"\n" +
+"/*\n" +
+"  ---------- Size and alignment checks and conversions ----------\n" +
+"*/\n" +
+"\n" +
+"/* conversion from malloc headers to user pointers, and back */\n" +
+"\n" +
+"#define chunk2mem(p)   ((Void_t*)((char*)(p) + 2*SIZE_SZ))\n" +
+"#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))\n" +
+"\n" +
+"/* The smallest possible chunk */\n" +
+"#define MIN_CHUNK_SIZE        (sizeof(struct malloc_chunk))\n" +
+"\n" +
+"/* The smallest size we can malloc is an aligned minimal chunk */\n" +
+"\n" +
+"#define MINSIZE  \\n" +
+"  (CHUNK_SIZE_T)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))\n" +
+"\n" +
+"/* Check if m has acceptable alignment */\n" +
+"\n" +
+"#define aligned_OK(m)  (((PTR_UINT)((m)) & (MALLOC_ALIGN_MASK)) == 0)\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"   Check if a request is so large that it would wrap around zero when\n" +
+"   padded and aligned. To simplify some other code, the bound is made\n" +
+"   low enough so that adding MINSIZE will also not wrap around sero.\n" +
+"*/\n" +
+"\n" +
+"#define REQUEST_OUT_OF_RANGE(req)                                 \\n" +
+"  ((CHUNK_SIZE_T)(req) >=                                        \\n" +
+"   (CHUNK_SIZE_T)(INTERNAL_SIZE_T)(-2 * MINSIZE))\n" +
+"\n" +
+"/* pad request bytes into a usable size -- internal version */\n" +
+"\n" +
+"#define request2size(req)                                         \\n" +
+"  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \\n" +
+"   MINSIZE :                                                      \\n" +
+"   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)\n" +
+"\n" +
+"/*  Same, except also perform argument check */\n" +
+"\n" +
+"#define checked_request2size(req, sz)                             \\n" +
+"  if (REQUEST_OUT_OF_RANGE(req)) {                                \\n" +
+"    MALLOC_FAILURE_ACTION;                                        \\n" +
+"    return 0;                                                     \\n" +
+"  }                                                               \\n" +
+"  (sz) = request2size(req);\n" +
+"\n" +
+"/*\n" +
+"  --------------- Physical chunk operations ---------------\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */\n" +
+"#define PREV_INUSE 0x1\n" +
+"\n" +
+"/* extract inuse bit of previous chunk */\n" +
+"#define prev_inuse(p)       ((p)->size & PREV_INUSE)\n" +
+"\n" +
+"\n" +
+"/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */\n" +
+"#define IS_MMAPPED 0x2\n" +
+"\n" +
+"/* check for mmap()'ed chunk */\n" +
+"#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)\n" +
+"\n" +
+"/*\n" +
+"  Bits to mask off when extracting size\n" +
+"\n" +
+"  Note: IS_MMAPPED is intentionally not masked off from size field in\n" +
+"  macros for which mmapped chunks should never be seen. This should\n" +
+"  cause helpful core dumps to occur if it is tried by accident by\n" +
+"  people extending or adapting this malloc.\n" +
+"*/\n" +
+"#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)\n" +
+"\n" +
+"/* Get size, ignoring use bits */\n" +
+"#define chunksize(p)         ((p)->size & ~(SIZE_BITS))\n" +
+"\n" +
+"\n" +
+"/* Ptr to next physical malloc_chunk. */\n" +
+"#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))\n" +
+"\n" +
+"/* Ptr to previous physical malloc_chunk */\n" +
+"#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))\n" +
+"\n" +
+"/* Treat space at ptr + offset as a chunk */\n" +
+"#define chunk_at_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))\n" +
+"\n" +
+"/* extract p's inuse bit */\n" +
+"#define inuse(p)\\n" +
+"((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)\n" +
+"\n" +
+"/* set/clear chunk as being inuse without otherwise disturbing */\n" +
+"#define set_inuse(p)\\n" +
+"((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE\n" +
+"\n") +
+("#define clear_inuse(p)\\n" +
+"((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)\n" +
+"\n" +
+"\n" +
+"/* check/set/clear inuse bits in known places */\n" +
+"#define inuse_bit_at_offset(p, s)\\n" +
+" (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)\n" +
+"\n" +
+"#define set_inuse_bit_at_offset(p, s)\\n" +
+" (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)\n" +
+"\n" +
+"#define clear_inuse_bit_at_offset(p, s)\\n" +
+" (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))\n" +
+"\n" +
+"\n" +
+"/* Set size at head, without disturbing its use bit */\n" +
+"#define set_head_size(p, s)  ((p)->size = (((p)->size & PREV_INUSE) | (s)))\n" +
+"\n" +
+"/* Set size/use field */\n" +
+"#define set_head(p, s)       ((p)->size = (s))\n" +
+"\n" +
+"/* Set size at footer (only when chunk is not in use) */\n" +
+"#define set_foot(p, s)       (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  -------------------- Internal data structures --------------------\n" +
+"\n" +
+"   All internal state is held in an instance of malloc_state defined\n" +
+"   below. There are no other static variables, except in two optional\n" +
+"   cases:\n" +
+"   * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared above.\n" +
+"   * If HAVE_MMAP is true, but mmap doesn't support\n" +
+"     MAP_ANONYMOUS, a dummy file descriptor for mmap.\n" +
+"\n" +
+"   Beware of lots of tricks that minimize the total bookkeeping space\n" +
+"   requirements. The result is a little over 1K bytes (for 4byte\n" +
+"   pointers and size_t.)\n" +
+"*/\n" +
+"\n" +
+"/*\n" +
+"  Bins\n" +
+"\n" +
+"    An array of bin headers for free chunks. Each bin is doubly\n" +
+"    linked.  The bins are approximately proportionally (log) spaced.\n" +
+"    There are a lot of these bins (128). This may look excessive, but\n" +
+"    works very well in practice.  Most bins hold sizes that are\n" +
+"    unusual as malloc request sizes, but are more usual for fragments\n" +
+"    and consolidated sets of chunks, which is what these bins hold, so\n" +
+"    they can be found quickly.  All procedures maintain the invariant\n" +
+"    that no consolidated chunk physically borders another one, so each\n" +
+"    chunk in a list is known to be preceeded and followed by either\n" +
+"    inuse chunks or the ends of memory.\n" +
+"\n" +
+"    Chunks in bins are kept in size order, with ties going to the\n" +
+"    approximately least recently used chunk. Ordering isn't needed\n" +
+"    for the small bins, which all contain the same-sized chunks, but\n" +
+"    facilitates best-fit allocation for larger chunks. These lists\n" +
+"    are just sequential. Keeping them in order almost never requires\n" +
+"    enough traversal to warrant using fancier ordered data\n" +
+"    structures.\n" +
+"\n" +
+"    Chunks of the same size are linked with the most\n" +
+"    recently freed at the front, and allocations are taken from the\n" +
+"    back.  This results in LRU (FIFO) allocation order, which tends\n" +
+"    to give each chunk an equal opportunity to be consolidated with\n" +
+"    adjacent freed chunks, resulting in larger free chunks and less\n" +
+"    fragmentation.\n" +
+"\n" +
+"    To simplify use in double-linked lists, each bin header acts\n" +
+"    as a malloc_chunk. This avoids special-casing for headers.\n" +
+"    But to conserve space and improve locality, we allocate\n" +
+"    only the fd/bk pointers of bins, and then use repositioning tricks\n" +
+"    to treat these as the fields of a malloc_chunk*.\n" +
+"*/\n" +
+"\n" +
+"typedef struct malloc_chunk* mbinptr;\n" +
+"\n" +
+"/* addressing -- note that bin_at(0) does not exist */\n" +
+"#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1)))\n" +
+"\n" +
+"/* analog of ++bin */\n" +
+"#define next_bin(b)  ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1)))\n" +
+"\n" +
+"/* Reminders about list directionality within bins */\n" +
+"#define first(b)     ((b)->fd)\n" +
+"#define last(b)      ((b)->bk)\n" +
+"\n" +
+"/* Take a chunk off a bin list */\n" +
+"#define unlink(P, BK, FD) {                                            \\n" +
+"  FD = P->fd;                                                          \\n" +
+"  BK = P->bk;                                                          \\n" +
+"  FD->bk = BK;                                                         \\n" +
+"  BK->fd = FD;                                                         \\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  Indexing\n" +
+"\n" +
+"    Bins for sizes < 512 bytes contain chunks of all the same size, spaced\n" +
+"    8 bytes apart. Larger bins are approximately logarithmically spaced:\n" +
+"\n" +
+"    64 bins of size       8\n" +
+"    32 bins of size      64\n" +
+"    16 bins of size     512\n" +
+"     8 bins of size    4096\n" +
+"     4 bins of size   32768\n" +
+"     2 bins of size  262144\n" +
+"     1 bin  of size what's left\n" +
+"\n" +
+"    The bins top out around 1MB because we expect to service large\n" +
+"    requests via mmap.\n" +
+"*/\n" +
+"\n" +
+"#define NBINS              96\n" +
+"#define NSMALLBINS         32\n" +
+"#define SMALLBIN_WIDTH      8\n" +
+"#define MIN_LARGE_SIZE    256\n" +
+"\n" +
+"#define in_smallbin_range(sz)  \\n" +
+"  ((CHUNK_SIZE_T)(sz) < (CHUNK_SIZE_T)MIN_LARGE_SIZE)\n" +
+"\n" +
+"#define smallbin_index(sz)     (((unsigned)(sz)) >> 3)\n" +
+"\n" +
+"/*\n" +
+"  Compute index for size. We expect this to be inlined when\n" +
+"  compiled with optimization, else not, which works out well.\n" +
+"*/\n" +
+"static int largebin_index(unsigned int sz) {\n" +
+"  unsigned int  x = sz >> SMALLBIN_WIDTH;\n" +
+"  unsigned int m;            /* bit position of highest set bit of m */\n" +
+"\n" +
+"  if (x >= 0x10000) return NBINS-1;\n" +
+"\n" +
+"  /* On intel, use BSRL instruction to find highest bit */\n" +
+"#if defined(__GNUC__) && defined(i386)\n" +
+"\n" +
+"  __asm__(\"bsrl %1,%0\\n\\t\"\n" +
+"          : \"=r\" (m)\n" +
+"          : \"g\"  (x));\n" +
+"\n" +
+"#else\n" +
+"  {\n" +
+"    /*\n" +
+"      Based on branch-free nlz algorithm in chapter 5 of Henry\n" +
+"      S. Warren Jr's book \"Hacker's Delight\".\n" +
+"    */\n" +
+"\n" +
+"    unsigned int n = ((x - 0x100) >> 16) & 8;\n" +
+"    x <<= n;\n" +
+"    m = ((x - 0x1000) >> 16) & 4;\n" +
+"    n += m;\n" +
+"    x <<= m;\n" +
+"    m = ((x - 0x4000) >> 16) & 2;\n" +
+"    n += m;\n" +
+"    x = (x << m) >> 14;\n" +
+"    m = 13 - n + (x & ~(x>>1));\n" +
+"  }\n" +
+"#endif\n" +
+"\n") +
+(
+"  /* Use next 2 bits to create finer-granularity bins */\n" +
+"  return NSMALLBINS + (m << 2) + ((sz >> (m + 6)) & 3);\n" +
+"}\n" +
+"\n" +
+"#define bin_index(sz) \\n" +
+" ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz))\n" +
+"\n" +
+"/*\n" +
+"  FIRST_SORTED_BIN_SIZE is the chunk size corresponding to the\n" +
+"  first bin that is maintained in sorted order. This must\n" +
+"  be the smallest size corresponding to a given bin.\n" +
+"\n" +
+"  Normally, this should be MIN_LARGE_SIZE. But you can weaken\n" +
+"  best fit guarantees to sometimes speed up malloc by increasing value.\n" +
+"  Doing this means that malloc may choose a chunk that is\n" +
+"  non-best-fitting by up to the width of the bin.\n" +
+"\n" +
+"  Some useful cutoff values:\n" +
+"      512 - all bins sorted\n" +
+"     2560 - leaves bins <=     64 bytes wide unsorted\n" +
+"    12288 - leaves bins <=    512 bytes wide unsorted\n" +
+"    65536 - leaves bins <=   4096 bytes wide unsorted\n" +
+"   262144 - leaves bins <=  32768 bytes wide unsorted\n" +
+"       -1 - no bins sorted (not recommended!)\n" +
+"*/\n" +
+"\n" +
+"#define FIRST_SORTED_BIN_SIZE MIN_LARGE_SIZE\n" +
+"/* #define FIRST_SORTED_BIN_SIZE 65536 */\n" +
+"\n" +
+"/*\n" +
+"  Unsorted chunks\n" +
+"\n" +
+"    All remainders from chunk splits, as well as all returned chunks,\n" +
+"    are first placed in the \"unsorted\" bin. They are then placed\n" +
+"    in regular bins after malloc gives them ONE chance to be used before\n" +
+"    binning. So, basically, the unsorted_chunks list acts as a queue,\n" +
+"    with chunks being placed on it in free (and malloc_consolidate),\n" +
+"    and taken off (to be either used or placed in bins) in malloc.\n" +
+"*/\n" +
+"\n" +
+"/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */\n" +
+"#define unsorted_chunks(M)          (bin_at(M, 1))\n" +
+"\n" +
+"/*\n" +
+"  Top\n" +
+"\n" +
+"    The top-most available chunk (i.e., the one bordering the end of\n" +
+"    available memory) is treated specially. It is never included in\n" +
+"    any bin, is used only if no other chunk is available, and is\n" +
+"    released back to the system if it is very large (see\n" +
+"    M_TRIM_THRESHOLD).  Because top initially\n" +
+"    points to its own bin with initial zero size, thus forcing\n" +
+"    extension on the first malloc request, we avoid having any special\n" +
+"    code in malloc to check whether it even exists yet. But we still\n" +
+"    need to do so when getting memory from system, so we make\n" +
+"    initial_top treat the bin as a legal but unusable chunk during the\n" +
+"    interval between initialization and the first call to\n" +
+"    sYSMALLOc. (This is somewhat delicate, since it relies on\n" +
+"    the 2 preceding words to be zero during this interval as well.)\n" +
+"*/\n" +
+"\n" +
+"/* Conveniently, the unsorted bin can be used as dummy top on first call */\n" +
+"#define initial_top(M)              (unsorted_chunks(M))\n" +
+"\n" +
+"/*\n" +
+"  Binmap\n" +
+"\n" +
+"    To help compensate for the large number of bins, a one-level index\n" +
+"    structure is used for bin-by-bin searching.  `binmap' is a\n" +
+"    bitvector recording whether bins are definitely empty so they can\n" +
+"    be skipped over during during traversals.  The bits are NOT always\n" +
+"    cleared as soon as bins are empty, but instead only\n" +
+"    when they are noticed to be empty during traversal in malloc.\n" +
+"*/\n" +
+"\n" +
+"/* Conservatively use 32 bits per map word, even if on 64bit system */\n" +
+"#define BINMAPSHIFT      5\n" +
+"#define BITSPERMAP       (1U << BINMAPSHIFT)\n" +
+"#define BINMAPSIZE       (NBINS / BITSPERMAP)\n" +
+"\n" +
+"#define idx2block(i)     ((i) >> BINMAPSHIFT)\n" +
+"#define idx2bit(i)       ((1U << ((i) & ((1U << BINMAPSHIFT)-1))))\n" +
+"\n" +
+"#define mark_bin(m,i)    ((m)->binmap[idx2block(i)] |=  idx2bit(i))\n" +
+"#define unmark_bin(m,i)  ((m)->binmap[idx2block(i)] &= ~(idx2bit(i)))\n" +
+"#define get_binmap(m,i)  ((m)->binmap[idx2block(i)] &   idx2bit(i))\n" +
+"\n" +
+"/*\n" +
+"  Fastbins\n" +
+"\n" +
+"    An array of lists holding recently freed small chunks.  Fastbins\n" +
+"    are not doubly linked.  It is faster to single-link them, and\n" +
+"    since chunks are never removed from the middles of these lists,\n" +
+"    double linking is not necessary. Also, unlike regular bins, they\n" +
+"    are not even processed in FIFO order (they use faster LIFO) since\n" +
+"    ordering doesn't much matter in the transient contexts in which\n" +
+"    fastbins are normally used.\n" +
+"\n" +
+"    Chunks in fastbins keep their inuse bit set, so they cannot\n" +
+"    be consolidated with other free chunks. malloc_consolidate\n" +
+"    releases all chunks in fastbins and consolidates them with\n" +
+"    other free chunks.\n" +
+"*/\n" +
+"\n" +
+"typedef struct malloc_chunk* mfastbinptr;\n" +
+"\n" +
+"/* offset 2 to use otherwise unindexable first 2 bins */\n" +
+"#define fastbin_index(sz)        ((((unsigned int)(sz)) >> 3) - 2)\n" +
+"\n" +
+"/* The maximum fastbin request size we support */\n" +
+"#define MAX_FAST_SIZE     80\n" +
+"\n" +
+"#define NFASTBINS  (fastbin_index(request2size(MAX_FAST_SIZE))+1)\n" +
+"\n" +
+"/*\n" +
+"  FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free()\n" +
+"  that triggers automatic consolidation of possibly-surrounding\n" +
+"  fastbin chunks. This is a heuristic, so the exact value should not\n" +
+"  matter too much. It is defined at half the default trim threshold as a\n" +
+"  compromise heuristic to only attempt consolidation if it is likely\n" +
+"  to lead to trimming. However, it is not dynamically tunable, since\n" +
+"  consolidation reduces fragmentation surrounding loarge chunks even\n" +
+"  if trimming is not used.\n" +
+"*/\n" +
+"\n" +
+"#define FASTBIN_CONSOLIDATION_THRESHOLD  \\n" +
+"  ((unsigned long)(DEFAULT_TRIM_THRESHOLD) >> 1)\n" +
+"\n" +
+"/*\n" +
+"  Since the lowest 2 bits in max_fast don't matter in size comparisons,\n" +
+"  they are used as flags.\n" +
+"*/\n" +
+"\n" +
+"/*\n" +
+"  ANYCHUNKS_BIT held in max_fast indicates that there may be any\n" +
+"  freed chunks at all. It is set true when entering a chunk into any\n" +
+"  bin.\n" +
+"*/\n" +
+"\n" +
+"#define ANYCHUNKS_BIT        (1U)\n" +
+"\n" +
+"#define have_anychunks(M)     (((M)->max_fast &  ANYCHUNKS_BIT))\n" +
+"#define set_anychunks(M)      ((M)->max_fast |=  ANYCHUNKS_BIT)\n" +
+"#define clear_anychunks(M)    ((M)->max_fast &= ~ANYCHUNKS_BIT)\n" +
+"\n" +
+"/*\n" +
+"  FASTCHUNKS_BIT held in max_fast indicates that there are probably\n" +
+"  some fastbin chunks. It is set true on entering a chunk into any\n" +
+"  fastbin, and cleared only in malloc_consolidate.\n" +
+"*/\n" +
+"\n") +
+(
+"#define FASTCHUNKS_BIT        (2U)\n" +
+"\n" +
+"#define have_fastchunks(M)   (((M)->max_fast &  FASTCHUNKS_BIT))\n" +
+"#define set_fastchunks(M)    ((M)->max_fast |=  (FASTCHUNKS_BIT|ANYCHUNKS_BIT))\n" +
+"#define clear_fastchunks(M)  ((M)->max_fast &= ~(FASTCHUNKS_BIT))\n" +
+"\n" +
+"/*\n" +
+"   Set value of max_fast.\n" +
+"   Use impossibly small value if 0.\n" +
+"*/\n" +
+"\n" +
+"#define set_max_fast(M, s) \\n" +
+"  (M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \\n" +
+"  ((M)->max_fast &  (FASTCHUNKS_BIT|ANYCHUNKS_BIT))\n" +
+"\n" +
+"#define get_max_fast(M) \\n" +
+"  ((M)->max_fast & ~(FASTCHUNKS_BIT | ANYCHUNKS_BIT))\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  morecore_properties is a status word holding dynamically discovered\n" +
+"  or controlled properties of the morecore function\n" +
+"*/\n" +
+"\n" +
+"#define MORECORE_CONTIGUOUS_BIT  (1U)\n" +
+"\n" +
+"#define contiguous(M) \\n" +
+"        (((M)->morecore_properties &  MORECORE_CONTIGUOUS_BIT))\n" +
+"#define noncontiguous(M) \\n" +
+"        (((M)->morecore_properties &  MORECORE_CONTIGUOUS_BIT) == 0)\n" +
+"#define set_contiguous(M) \\n" +
+"        ((M)->morecore_properties |=  MORECORE_CONTIGUOUS_BIT)\n" +
+"#define set_noncontiguous(M) \\n" +
+"        ((M)->morecore_properties &= ~MORECORE_CONTIGUOUS_BIT)\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"   ----------- Internal state representation and initialization -----------\n" +
+"*/\n" +
+"\n" +
+"struct malloc_state {\n" +
+"\n" +
+"  /* The maximum chunk size to be eligible for fastbin */\n" +
+"  INTERNAL_SIZE_T  max_fast;   /* low 2 bits used as flags */\n" +
+"\n" +
+"  /* Fastbins */\n" +
+"  mfastbinptr      fastbins[NFASTBINS];\n" +
+"\n" +
+"  /* Base of the topmost chunk -- not otherwise kept in a bin */\n" +
+"  mchunkptr        top;\n" +
+"\n" +
+"  /* The remainder from the most recent split of a small request */\n" +
+"  mchunkptr        last_remainder;\n" +
+"\n" +
+"  /* Normal bins packed as described above */\n" +
+"  mchunkptr        bins[NBINS * 2];\n" +
+"\n" +
+"  /* Bitmap of bins. Trailing zero map handles cases of largest binned size */\n" +
+"  unsigned int     binmap[BINMAPSIZE+1];\n" +
+"\n" +
+"  /* Tunable parameters */\n" +
+"  CHUNK_SIZE_T     trim_threshold;\n" +
+"  INTERNAL_SIZE_T  top_pad;\n" +
+"  INTERNAL_SIZE_T  mmap_threshold;\n" +
+"\n" +
+"  /* Memory map support */\n" +
+"  int              n_mmaps;\n" +
+"  int              n_mmaps_max;\n" +
+"  int              max_n_mmaps;\n" +
+"\n" +
+"  /* Cache malloc_getpagesize */\n" +
+"  unsigned int     pagesize;\n" +
+"\n" +
+"  /* Track properties of MORECORE */\n" +
+"  unsigned int     morecore_properties;\n" +
+"\n" +
+"  /* Statistics */\n" +
+"  INTERNAL_SIZE_T  mmapped_mem;\n" +
+"  INTERNAL_SIZE_T  sbrked_mem;\n" +
+"  INTERNAL_SIZE_T  max_sbrked_mem;\n" +
+"  INTERNAL_SIZE_T  max_mmapped_mem;\n" +
+"  INTERNAL_SIZE_T  max_total_mem;\n" +
+"};\n" +
+"\n" +
+"typedef struct malloc_state *mstate;\n" +
+"\n" +
+"/*\n" +
+"   There is exactly one instance of this struct in this malloc.\n" +
+"   If you are adapting this malloc in a way that does NOT use a static\n" +
+"   malloc_state, you MUST explicitly zero-fill it before using. This\n" +
+"   malloc relies on the property that malloc_state is initialized to\n" +
+"   all zeroes (as is true of C statics).\n" +
+"*/\n" +
+"\n" +
+"static struct malloc_state av_;  /* never directly referenced */\n" +
+"\n" +
+"/*\n" +
+"   All uses of av_ are via get_malloc_state().\n" +
+"   At most one \"call\" to get_malloc_state is made per invocation of\n" +
+"   the public versions of malloc and free, but other routines\n" +
+"   that in turn invoke malloc and/or free may call more then once.\n" +
+"   Also, it is called in check* routines if DEBUG is set.\n" +
+"*/\n" +
+"\n" +
+"#define get_malloc_state() (&(av_))\n" +
+"\n" +
+"/*\n" +
+"  Initialize a malloc_state struct.\n" +
+"\n" +
+"  This is called only from within malloc_consolidate, which needs\n" +
+"  be called in the same contexts anyway.  It is never called directly\n" +
+"  outside of malloc_consolidate because some optimizing compilers try\n" +
+"  to inline it at all call points, which turns out not to be an\n" +
+"  optimization at all. (Inlining it in malloc_consolidate is fine though.)\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static void malloc_init_state(mstate av)\n" +
+"#else\n" +
+"static void malloc_init_state(av) mstate av;\n" +
+"#endif\n" +
+"{\n" +
+"  int     i;\n" +
+"  mbinptr bin;\n" +
+"\n" +
+"  /* Establish circular links for normal bins */\n" +
+"  for (i = 1; i < NBINS; ++i) {\n" +
+"    bin = bin_at(av,i);\n" +
+"    bin->fd = bin->bk = bin;\n" +
+"  }\n" +
+"\n" +
+"  av->top_pad        = DEFAULT_TOP_PAD;\n" +
+"  av->n_mmaps_max    = DEFAULT_MMAP_MAX;\n" +
+"  av->mmap_threshold = DEFAULT_MMAP_THRESHOLD;\n" +
+"  av->trim_threshold = DEFAULT_TRIM_THRESHOLD;\n" +
+"\n" +
+"#if MORECORE_CONTIGUOUS\n" +
+"  set_contiguous(av);\n" +
+"#else\n" +
+"  set_noncontiguous(av);\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"  set_max_fast(av, DEFAULT_MXFAST);\n" +
+"\n" +
+"  av->top            = initial_top(av);\n" +
+"  av->pagesize       = malloc_getpagesize;\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"   Other internal utilities operating on mstates\n" +
+"*/\n" +
+"\n") +
+(
+"#if __STD_C\n" +
+"static Void_t*  sYSMALLOc(INTERNAL_SIZE_T, mstate);\n" +
+"#ifndef MORECORE_CANNOT_TRIM\n" +
+"static int      sYSTRIm(size_t, mstate);\n" +
+"#endif\n" +
+"static void     malloc_consolidate(mstate);\n" +
+"static Void_t** iALLOc(size_t, size_t*, int, Void_t**);\n" +
+"#else\n" +
+"static Void_t*  sYSMALLOc();\n" +
+"static int      sYSTRIm();\n" +
+"static void     malloc_consolidate();\n" +
+"static Void_t** iALLOc();\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  Debugging support\n" +
+"\n" +
+"  These routines make a number of assertions about the states\n" +
+"  of data structures that should be true at all times. If any\n" +
+"  are not true, it's very likely that a user program has somehow\n" +
+"  trashed memory. (It's also possible that there is a coding error\n" +
+"  in malloc. In which case, please report it!)\n" +
+"*/\n" +
+"\n" +
+"#if ! DEBUG\n" +
+"\n" +
+"#define check_chunk(P)\n" +
+"#define check_free_chunk(P)\n" +
+"#define check_inuse_chunk(P)\n" +
+"#define check_remalloced_chunk(P,N)\n" +
+"#define check_malloced_chunk(P,N)\n" +
+"#define check_malloc_state()\n" +
+"\n" +
+"#else\n" +
+"#define check_chunk(P)              do_check_chunk(P)\n" +
+"#define check_free_chunk(P)         do_check_free_chunk(P)\n" +
+"#define check_inuse_chunk(P)        do_check_inuse_chunk(P)\n" +
+"#define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N)\n" +
+"#define check_malloced_chunk(P,N)   do_check_malloced_chunk(P,N)\n" +
+"#define check_malloc_state()        do_check_malloc_state()\n" +
+"\n" +
+"/*\n" +
+"  Properties of all chunks\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static void do_check_chunk(mchunkptr p)\n" +
+"#else\n" +
+"static void do_check_chunk(p) mchunkptr p;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  CHUNK_SIZE_T  sz = chunksize(p);\n" +
+"  /* min and max possible addresses assuming contiguous allocation */\n" +
+"  char* max_address = (char*)(av->top) + chunksize(av->top);\n" +
+"  char* min_address = max_address - av->sbrked_mem;\n" +
+"\n" +
+"  if (!chunk_is_mmapped(p)) {\n" +
+"\n" +
+"    /* Has legal address ... */\n" +
+"    if (p != av->top) {\n" +
+"      if (contiguous(av)) {\n" +
+"        assert(((char*)p) >= min_address);\n" +
+"        assert(((char*)p + sz) <= ((char*)(av->top)));\n" +
+"      }\n" +
+"    }\n" +
+"    else {\n" +
+"      /* top size is always at least MINSIZE */\n" +
+"      assert((CHUNK_SIZE_T)(sz) >= MINSIZE);\n" +
+"      /* top predecessor always marked inuse */\n" +
+"      assert(prev_inuse(p));\n" +
+"    }\n" +
+"\n" +
+"  }\n" +
+"  else {\n" +
+"#if HAVE_MMAP\n" +
+"    /* address is outside main heap  */\n" +
+"    if (contiguous(av) && av->top != initial_top(av)) {\n" +
+"      assert(((char*)p) < min_address || ((char*)p) > max_address);\n" +
+"    }\n" +
+"    /* chunk is page-aligned */\n" +
+"    assert(((p->prev_size + sz) & (av->pagesize-1)) == 0);\n" +
+"    /* mem is aligned */\n" +
+"    assert(aligned_OK(chunk2mem(p)));\n" +
+"#else\n" +
+"    /* force an appropriate assert violation if debug set */\n" +
+"    assert(!chunk_is_mmapped(p));\n" +
+"#endif\n" +
+"  }\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  Properties of free chunks\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static void do_check_free_chunk(mchunkptr p)\n" +
+"#else\n" +
+"static void do_check_free_chunk(p) mchunkptr p;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"\n" +
+"  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;\n" +
+"  mchunkptr next = chunk_at_offset(p, sz);\n" +
+"\n" +
+"  do_check_chunk(p);\n" +
+"\n" +
+"  /* Chunk must claim to be free ... */\n" +
+"  assert(!inuse(p));\n" +
+"  assert (!chunk_is_mmapped(p));\n" +
+"\n" +
+"  /* Unless a special marker, must have OK fields */\n" +
+"  if ((CHUNK_SIZE_T)(sz) >= MINSIZE)\n" +
+"  {\n" +
+"    assert((sz & MALLOC_ALIGN_MASK) == 0);\n" +
+"    assert(aligned_OK(chunk2mem(p)));\n" +
+"    /* ... matching footer field */\n" +
+"    assert(next->prev_size == sz);\n" +
+"    /* ... and is fully consolidated */\n" +
+"    assert(prev_inuse(p));\n" +
+"    assert (next == av->top || inuse(next));\n" +
+"\n" +
+"    /* ... and has minimally sane links */\n" +
+"    assert(p->fd->bk == p);\n" +
+"    assert(p->bk->fd == p);\n" +
+"  }\n" +
+"  else /* markers are always of size SIZE_SZ */\n" +
+"    assert(sz == SIZE_SZ);\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  Properties of inuse chunks\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static void do_check_inuse_chunk(mchunkptr p)\n" +
+"#else\n" +
+"static void do_check_inuse_chunk(p) mchunkptr p;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  mchunkptr next;\n" +
+"  do_check_chunk(p);\n" +
+"\n" +
+"  if (chunk_is_mmapped(p))\n" +
+"    return; /* mmapped chunks have no next/prev */\n" +
+"\n" +
+"  /* Check whether it claims to be in use ... */\n" +
+"  assert(inuse(p));\n" +
+"\n") +
+(
+"  next = next_chunk(p);\n" +
+"\n" +
+"  /* ... and is surrounded by OK chunks.\n" +
+"    Since more things can be checked with free chunks than inuse ones,\n" +
+"    if an inuse chunk borders them and debug is on, it's worth doing them.\n" +
+"  */\n" +
+"  if (!prev_inuse(p))  {\n" +
+"    /* Note that we cannot even look at prev unless it is not inuse */\n" +
+"    mchunkptr prv = prev_chunk(p);\n" +
+"    assert(next_chunk(prv) == p);\n" +
+"    do_check_free_chunk(prv);\n" +
+"  }\n" +
+"\n" +
+"  if (next == av->top) {\n" +
+"    assert(prev_inuse(next));\n" +
+"    assert(chunksize(next) >= MINSIZE);\n" +
+"  }\n" +
+"  else if (!inuse(next))\n" +
+"    do_check_free_chunk(next);\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  Properties of chunks recycled from fastbins\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)\n" +
+"#else\n" +
+"static void do_check_remalloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;\n" +
+"#endif\n" +
+"{\n" +
+"  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;\n" +
+"\n" +
+"  do_check_inuse_chunk(p);\n" +
+"\n" +
+"  /* Legal size ... */\n" +
+"  assert((sz & MALLOC_ALIGN_MASK) == 0);\n" +
+"  assert((CHUNK_SIZE_T)(sz) >= MINSIZE);\n" +
+"  /* ... and alignment */\n" +
+"  assert(aligned_OK(chunk2mem(p)));\n" +
+"  /* chunk is less than MINSIZE more than request */\n" +
+"  assert((long)(sz) - (long)(s) >= 0);\n" +
+"  assert((long)(sz) - (long)(s + MINSIZE) < 0);\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  Properties of nonrecycled chunks at the point they are malloced\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)\n" +
+"#else\n" +
+"static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;\n" +
+"#endif\n" +
+"{\n" +
+"  /* same as recycled case ... */\n" +
+"  do_check_remalloced_chunk(p, s);\n" +
+"\n" +
+"  /*\n" +
+"    ... plus,  must obey implementation invariant that prev_inuse is\n" +
+"    always true of any allocated chunk; i.e., that each allocated\n" +
+"    chunk borders either a previously allocated and still in-use\n" +
+"    chunk, or the base of its memory arena. This is ensured\n" +
+"    by making all allocations from the the `lowest' part of any found\n" +
+"    chunk.  This does not necessarily hold however for chunks\n" +
+"    recycled via fastbins.\n" +
+"  */\n" +
+"\n" +
+"  assert(prev_inuse(p));\n" +
+"}\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  Properties of malloc_state.\n" +
+"\n" +
+"  This may be useful for debugging malloc, as well as detecting user\n" +
+"  programmer errors that somehow write into malloc_state.\n" +
+"\n" +
+"  If you are extending or experimenting with this malloc, you can\n" +
+"  probably figure out how to hack this routine to print out or\n" +
+"  display chunk addresses, sizes, bins, and other instrumentation.\n" +
+"*/\n" +
+"\n" +
+"static void do_check_malloc_state()\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  unsigned int i;\n" +
+"  mchunkptr p;\n" +
+"  mchunkptr q;\n" +
+"  mbinptr b;\n" +
+"  unsigned int binbit;\n" +
+"  int empty;\n" +
+"  unsigned int idx;\n" +
+"  INTERNAL_SIZE_T size;\n" +
+"  CHUNK_SIZE_T  total = 0;\n" +
+"  int max_fast_bin;\n" +
+"\n" +
+"  /* internal size_t must be no wider than pointer type */\n" +
+"  assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*));\n" +
+"\n" +
+"  /* alignment is a power of 2 */\n" +
+"  assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0);\n" +
+"\n" +
+"  /* cannot run remaining checks until fully initialized */\n" +
+"  if (av->top == 0 || av->top == initial_top(av))\n" +
+"    return;\n" +
+"\n" +
+"  /* pagesize is a power of 2 */\n" +
+"  assert((av->pagesize & (av->pagesize-1)) == 0);\n" +
+"\n" +
+"  /* properties of fastbins */\n" +
+"\n" +
+"  /* max_fast is in allowed range */\n" +
+"  assert(get_max_fast(av) <= request2size(MAX_FAST_SIZE));\n" +
+"\n" +
+"  max_fast_bin = fastbin_index(av->max_fast);\n" +
+"\n" +
+"  for (i = 0; i < NFASTBINS; ++i) {\n" +
+"    p = av->fastbins[i];\n" +
+"\n" +
+"    /* all bins past max_fast are empty */\n" +
+"    if (i > max_fast_bin)\n" +
+"      assert(p == 0);\n" +
+"\n" +
+"    while (p != 0) {\n" +
+"      /* each chunk claims to be inuse */\n" +
+"      do_check_inuse_chunk(p);\n" +
+"      total += chunksize(p);\n" +
+"      /* chunk belongs in this bin */\n" +
+"      assert(fastbin_index(chunksize(p)) == i);\n" +
+"      p = p->fd;\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  if (total != 0)\n" +
+"    assert(have_fastchunks(av));\n" +
+"  else if (!have_fastchunks(av))\n" +
+"    assert(total == 0);\n" +
+"\n" +
+"  /* check normal bins */\n" +
+"  for (i = 1; i < NBINS; ++i) {\n" +
+"    b = bin_at(av,i);\n" +
+"\n" +
+"    /* binmap is accurate (except for bin 1 == unsorted_chunks) */\n" +
+"    if (i >= 2) {\n" +
+"      binbit = get_binmap(av,i);\n" +
+"      empty = last(b) == b;\n" +
+"      if (!binbit)\n" +
+"        assert(empty);\n" +
+"      else if (!empty)\n" +
+"        assert(binbit);\n" +
+"    }\n" +
+"\n") +
+(
+"    for (p = last(b); p != b; p = p->bk) {\n" +
+"      /* each chunk claims to be free */\n" +
+"      do_check_free_chunk(p);\n" +
+"      size = chunksize(p);\n" +
+"      total += size;\n" +
+"      if (i >= 2) {\n" +
+"        /* chunk belongs in bin */\n" +
+"        idx = bin_index(size);\n" +
+"        assert(idx == i);\n" +
+"        /* lists are sorted */\n" +
+"        if ((CHUNK_SIZE_T) size >= (CHUNK_SIZE_T)(FIRST_SORTED_BIN_SIZE)) {\n" +
+"          assert(p->bk == b ||\n" +
+"                 (CHUNK_SIZE_T)chunksize(p->bk) >=\n" +
+"                 (CHUNK_SIZE_T)chunksize(p));\n" +
+"        }\n" +
+"      }\n" +
+"      /* chunk is followed by a legal chain of inuse chunks */\n" +
+"      for (q = next_chunk(p);\n" +
+"           (q != av->top && inuse(q) &&\n" +
+"             (CHUNK_SIZE_T)(chunksize(q)) >= MINSIZE);\n" +
+"           q = next_chunk(q))\n" +
+"        do_check_inuse_chunk(q);\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  /* top chunk is OK */\n" +
+"  check_chunk(av->top);\n" +
+"\n" +
+"  /* sanity checks for statistics */\n" +
+"\n" +
+"  assert(total <= (CHUNK_SIZE_T)(av->max_total_mem));\n" +
+"  assert(av->n_mmaps >= 0);\n" +
+"  assert(av->n_mmaps <= av->max_n_mmaps);\n" +
+"\n" +
+"  assert((CHUNK_SIZE_T)(av->sbrked_mem) <=\n" +
+"         (CHUNK_SIZE_T)(av->max_sbrked_mem));\n" +
+"\n" +
+"  assert((CHUNK_SIZE_T)(av->mmapped_mem) <=\n" +
+"         (CHUNK_SIZE_T)(av->max_mmapped_mem));\n" +
+"\n" +
+"  assert((CHUNK_SIZE_T)(av->max_total_mem) >=\n" +
+"         (CHUNK_SIZE_T)(av->mmapped_mem) + (CHUNK_SIZE_T)(av->sbrked_mem));\n" +
+"}\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"/* ----------- Routines dealing with system allocation -------------- */\n" +
+"\n" +
+"/*\n" +
+"  sysmalloc handles malloc cases requiring more memory from the system.\n" +
+"  On entry, it is assumed that av->top does not have enough\n" +
+"  space to service request for nb bytes, thus requiring that av->top\n" +
+"  be extended or replaced.\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av)\n" +
+"#else\n" +
+"static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;\n" +
+"#endif\n" +
+"{\n" +
+"  mchunkptr       old_top;        /* incoming value of av->top */\n" +
+"  INTERNAL_SIZE_T old_size;       /* its size */\n" +
+"  char*           old_end;        /* its end address */\n" +
+"\n" +
+"  long            size;           /* arg to first MORECORE or mmap call */\n" +
+"  char*           brk;            /* return value from MORECORE */\n" +
+"\n" +
+"  long            correction;     /* arg to 2nd MORECORE call */\n" +
+"  char*           snd_brk;        /* 2nd return val */\n" +
+"\n" +
+"  INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */\n" +
+"  INTERNAL_SIZE_T end_misalign;   /* partial page left at end of new space */\n" +
+"  char*           aligned_brk;    /* aligned offset into brk */\n" +
+"\n" +
+"  mchunkptr       p;              /* the allocated/returned chunk */\n" +
+"  mchunkptr       remainder;      /* remainder from allocation */\n" +
+"  CHUNK_SIZE_T    remainder_size; /* its size */\n" +
+"\n" +
+"  CHUNK_SIZE_T    sum;            /* for updating stats */\n" +
+"\n" +
+"  size_t          pagemask  = av->pagesize - 1;\n" +
+"\n" +
+"  /*\n" +
+"    If there is space available in fastbins, consolidate and retry\n" +
+"    malloc from scratch rather than getting memory from system.  This\n" +
+"    can occur only if nb is in smallbin range so we didn't consolidate\n" +
+"    upon entry to malloc. It is much easier to handle this case here\n" +
+"    than in malloc proper.\n" +
+"  */\n" +
+"\n" +
+"  if (have_fastchunks(av)) {\n" +
+"    assert(in_smallbin_range(nb));\n" +
+"    malloc_consolidate(av);\n" +
+"    return mALLOc(nb - MALLOC_ALIGN_MASK);\n" +
+"  }\n" +
+"\n" +
+"\n" +
+"#if HAVE_MMAP\n" +
+"\n" +
+"  /*\n" +
+"    If have mmap, and the request size meets the mmap threshold, and\n" +
+"    the system supports mmap, and there are few enough currently\n" +
+"    allocated mmapped regions, try to directly map this request\n" +
+"    rather than expanding top.\n" +
+"  */\n" +
+"\n" +
+"  if ((CHUNK_SIZE_T)(nb) >= (CHUNK_SIZE_T)(av->mmap_threshold) &&\n" +
+"      (av->n_mmaps < av->n_mmaps_max)) {\n" +
+"\n" +
+"    char* mm;             /* return value from mmap call*/\n" +
+"\n" +
+"    /*\n" +
+"      Round up size to nearest page.  For mmapped chunks, the overhead\n" +
+"      is one SIZE_SZ unit larger than for normal chunks, because there\n" +
+"      is no following chunk whose prev_size field could be used.\n" +
+"    */\n" +
+"    size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask;\n" +
+"\n" +
+"    /* Don't try if size wraps around 0 */\n" +
+"    if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) {\n" +
+"\n" +
+"      mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));\n" +
+"\n" +
+"      if (mm != (char*)(MORECORE_FAILURE)) {\n" +
+"\n" +
+"        /*\n" +
+"          The offset to the start of the mmapped region is stored\n" +
+"          in the prev_size field of the chunk. This allows us to adjust\n" +
+"          returned start address to meet alignment requirements here\n" +
+"          and in memalign(), and still be able to compute proper\n" +
+"          address argument for later munmap in free() and realloc().\n" +
+"        */\n" +
+"\n" +
+"        front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK;\n" +
+"        if (front_misalign > 0) {\n" +
+"          correction = MALLOC_ALIGNMENT - front_misalign;\n" +
+"          p = (mchunkptr)(mm + correction);\n" +
+"          p->prev_size = correction;\n" +
+"          set_head(p, (size - correction) |IS_MMAPPED);\n" +
+"        }\n" +
+"        else {\n" +
+"          p = (mchunkptr)mm;\n" +
+"          p->prev_size = 0;\n" +
+"          set_head(p, size|IS_MMAPPED);\n" +
+"        }\n" +
+"\n" +
+"        /* update statistics */\n" +
+"\n" +
+"        if (++av->n_mmaps > av->max_n_mmaps)\n" +
+"          av->max_n_mmaps = av->n_mmaps;\n" +
+"\n") +
+(
+"        sum = av->mmapped_mem += size;\n" +
+"        if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem))\n" +
+"          av->max_mmapped_mem = sum;\n" +
+"        sum += av->sbrked_mem;\n" +
+"        if (sum > (CHUNK_SIZE_T)(av->max_total_mem))\n" +
+"          av->max_total_mem = sum;\n" +
+"\n" +
+"        check_chunk(p);\n" +
+"\n" +
+"        return chunk2mem(p);\n" +
+"      }\n" +
+"    }\n" +
+"  }\n" +
+"#endif\n" +
+"\n" +
+"  /* Record incoming configuration of top */\n" +
+"\n" +
+"  old_top  = av->top;\n" +
+"  old_size = chunksize(old_top);\n" +
+"  old_end  = (char*)(chunk_at_offset(old_top, old_size));\n" +
+"\n" +
+"  brk = snd_brk = (char*)(MORECORE_FAILURE);\n" +
+"\n" +
+"  /*\n" +
+"     If not the first time through, we require old_size to be\n" +
+"     at least MINSIZE and to have prev_inuse set.\n" +
+"  */\n" +
+"\n" +
+"  assert((old_top == initial_top(av) && old_size == 0) ||\n" +
+"         ((CHUNK_SIZE_T) (old_size) >= MINSIZE &&\n" +
+"          prev_inuse(old_top)));\n" +
+"\n" +
+"  /* Precondition: not enough current space to satisfy nb request */\n" +
+"  assert((CHUNK_SIZE_T)(old_size) < (CHUNK_SIZE_T)(nb + MINSIZE));\n" +
+"\n" +
+"  /* Precondition: all fastbins are consolidated */\n" +
+"  assert(!have_fastchunks(av));\n" +
+"\n" +
+"\n" +
+"  /* Request enough space for nb + pad + overhead */\n" +
+"\n" +
+"  size = nb + av->top_pad + MINSIZE;\n" +
+"\n" +
+"  /*\n" +
+"    If contiguous, we can subtract out existing space that we hope to\n" +
+"    combine with new space. We add it back later only if\n" +
+"    we don't actually get contiguous space.\n" +
+"  */\n" +
+"\n" +
+"  if (contiguous(av))\n" +
+"    size -= old_size;\n" +
+"\n" +
+"  /*\n" +
+"    Round to a multiple of page size.\n" +
+"    If MORECORE is not contiguous, this ensures that we only call it\n" +
+"    with whole-page arguments.  And if MORECORE is contiguous and\n" +
+"    this is not first time through, this preserves page-alignment of\n" +
+"    previous calls. Otherwise, we correct to page-align below.\n" +
+"  */\n" +
+"\n" +
+"  size = (size + pagemask) & ~pagemask;\n" +
+"\n" +
+"  /*\n" +
+"    Don't try to call MORECORE if argument is so big as to appear\n" +
+"    negative. Note that since mmap takes size_t arg, it may succeed\n" +
+"    below even if we cannot call MORECORE.\n" +
+"  */\n" +
+"\n" +
+"  if (size > 0)\n" +
+"    brk = (char*)(MORECORE(size));\n" +
+"\n" +
+"  /*\n" +
+"    If have mmap, try using it as a backup when MORECORE fails or\n" +
+"    cannot be used. This is worth doing on systems that have \"holes\" in\n" +
+"    address space, so sbrk cannot extend to give contiguous space, but\n" +
+"    space is available elsewhere.  Note that we ignore mmap max count\n" +
+"    and threshold limits, since the space will not be used as a\n" +
+"    segregated mmap region.\n" +
+"  */\n" +
+"\n" +
+"#if HAVE_MMAP\n" +
+"  if (brk == (char*)(MORECORE_FAILURE)) {\n" +
+"\n" +
+"    /* Cannot merge with old top, so add its size back in */\n" +
+"    if (contiguous(av))\n" +
+"      size = (size + old_size + pagemask) & ~pagemask;\n" +
+"\n" +
+"    /* If we are relying on mmap as backup, then use larger units */\n" +
+"    if ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(MMAP_AS_MORECORE_SIZE))\n" +
+"      size = MMAP_AS_MORECORE_SIZE;\n" +
+"\n" +
+"    /* Don't try if size wraps around 0 */\n" +
+"    if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) {\n" +
+"\n" +
+"      brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));\n" +
+"\n" +
+"      if (brk != (char*)(MORECORE_FAILURE)) {\n" +
+"\n" +
+"        /* We do not need, and cannot use, another sbrk call to find end */\n" +
+"        snd_brk = brk + size;\n" +
+"\n" +
+"        /*\n" +
+"           Record that we no longer have a contiguous sbrk region.\n" +
+"           After the first time mmap is used as backup, we do not\n" +
+"           ever rely on contiguous space since this could incorrectly\n" +
+"           bridge regions.\n" +
+"        */\n" +
+"        set_noncontiguous(av);\n" +
+"      }\n" +
+"    }\n" +
+"  }\n" +
+"#endif\n" +
+"\n" +
+"  if (brk != (char*)(MORECORE_FAILURE)) {\n" +
+"    av->sbrked_mem += size;\n" +
+"\n" +
+"    /*\n" +
+"      If MORECORE extends previous space, we can likewise extend top size.\n" +
+"    */\n" +
+"\n" +
+"    if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) {\n" +
+"      set_head(old_top, (size + old_size) | PREV_INUSE);\n" +
+"    }\n" +
+"\n" +
+"    /*\n" +
+"      Otherwise, make adjustments:\n" +
+"\n" +
+"      * If the first time through or noncontiguous, we need to call sbrk\n" +
+"        just to find out where the end of memory lies.\n" +
+"\n" +
+"      * We need to ensure that all returned chunks from malloc will meet\n" +
+"        MALLOC_ALIGNMENT\n" +
+"\n" +
+"      * If there was an intervening foreign sbrk, we need to adjust sbrk\n" +
+"        request size to account for fact that we will not be able to\n" +
+"        combine new space with existing space in old_top.\n" +
+"\n" +
+"      * Almost all systems internally allocate whole pages at a time, in\n" +
+"        which case we might as well use the whole last page of request.\n" +
+"        So we allocate enough more memory to hit a page boundary now,\n" +
+"        which in turn causes future contiguous calls to page-align.\n" +
+"    */\n" +
+"\n" +
+"    else {\n" +
+"      front_misalign = 0;\n" +
+"      end_misalign = 0;\n" +
+"      correction = 0;\n" +
+"      aligned_brk = brk;\n" +
+"\n") +
+(
+"      /*\n" +
+"        If MORECORE returns an address lower than we have seen before,\n" +
+"        we know it isn't really contiguous.  This and some subsequent\n" +
+"        checks help cope with non-conforming MORECORE functions and\n" +
+"        the presence of \"foreign\" calls to MORECORE from outside of\n" +
+"        malloc or by other threads.  We cannot guarantee to detect\n" +
+"        these in all cases, but cope with the ones we do detect.\n" +
+"      */\n" +
+"      if (contiguous(av) && old_size != 0 && brk < old_end) {\n" +
+"        set_noncontiguous(av);\n" +
+"      }\n" +
+"\n" +
+"      /* handle contiguous cases */\n" +
+"      if (contiguous(av)) {\n" +
+"\n" +
+"        /*\n" +
+"           We can tolerate forward non-contiguities here (usually due\n" +
+"           to foreign calls) but treat them as part of our space for\n" +
+"           stats reporting.\n" +
+"        */\n" +
+"        if (old_size != 0)\n" +
+"          av->sbrked_mem += brk - old_end;\n" +
+"\n" +
+"        /* Guarantee alignment of first new chunk made from this space */\n" +
+"\n" +
+"        front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK;\n" +
+"        if (front_misalign > 0) {\n" +
+"\n" +
+"          /*\n" +
+"            Skip over some bytes to arrive at an aligned position.\n" +
+"            We don't need to specially mark these wasted front bytes.\n" +
+"            They will never be accessed anyway because\n" +
+"            prev_inuse of av->top (and any chunk created from its start)\n" +
+"            is always true after initialization.\n" +
+"          */\n" +
+"\n" +
+"          correction = MALLOC_ALIGNMENT - front_misalign;\n" +
+"          aligned_brk += correction;\n" +
+"        }\n" +
+"\n" +
+"        /*\n" +
+"          If this isn't adjacent to existing space, then we will not\n" +
+"          be able to merge with old_top space, so must add to 2nd request.\n" +
+"        */\n" +
+"\n" +
+"        correction += old_size;\n" +
+"\n" +
+"        /* Extend the end address to hit a page boundary */\n" +
+"        end_misalign = (INTERNAL_SIZE_T)(brk + size + correction);\n" +
+"        correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign;\n" +
+"\n" +
+"        assert(correction >= 0);\n" +
+"        snd_brk = (char*)(MORECORE(correction));\n" +
+"\n" +
+"        if (snd_brk == (char*)(MORECORE_FAILURE)) {\n" +
+"          /*\n" +
+"            If can't allocate correction, try to at least find out current\n" +
+"            brk.  It might be enough to proceed without failing.\n" +
+"          */\n" +
+"          correction = 0;\n" +
+"          snd_brk = (char*)(MORECORE(0));\n" +
+"        }\n" +
+"        else if (snd_brk < brk) {\n" +
+"          /*\n" +
+"            If the second call gives noncontiguous space even though\n" +
+"            it says it won't, the only course of action is to ignore\n" +
+"            results of second call, and conservatively estimate where\n" +
+"            the first call left us. Also set noncontiguous, so this\n" +
+"            won't happen again, leaving at most one hole.\n" +
+"\n" +
+"            Note that this check is intrinsically incomplete.  Because\n" +
+"            MORECORE is allowed to give more space than we ask for,\n" +
+"            there is no reliable way to detect a noncontiguity\n" +
+"            producing a forward gap for the second call.\n" +
+"          */\n" +
+"          snd_brk = brk + size;\n" +
+"          correction = 0;\n" +
+"          set_noncontiguous(av);\n" +
+"        }\n" +
+"\n" +
+"      }\n" +
+"\n" +
+"      /* handle non-contiguous cases */\n" +
+"      else {\n" +
+"        /* MORECORE/mmap must correctly align */\n" +
+"        assert(aligned_OK(chunk2mem(brk)));\n" +
+"\n" +
+"        /* Find out current end of memory */\n" +
+"        if (snd_brk == (char*)(MORECORE_FAILURE)) {\n" +
+"          snd_brk = (char*)(MORECORE(0));\n" +
+"          av->sbrked_mem += snd_brk - brk - size;\n" +
+"        }\n" +
+"      }\n" +
+"\n" +
+"      /* Adjust top based on results of second sbrk */\n" +
+"      if (snd_brk != (char*)(MORECORE_FAILURE)) {\n" +
+"        av->top = (mchunkptr)aligned_brk;\n" +
+"        set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE);\n" +
+"        av->sbrked_mem += correction;\n" +
+"\n" +
+"        /*\n" +
+"          If not the first time through, we either have a\n" +
+"          gap due to foreign sbrk or a non-contiguous region.  Insert a\n" +
+"          double fencepost at old_top to prevent consolidation with space\n" +
+"          we don't own. These fenceposts are artificial chunks that are\n" +
+"          marked as inuse and are in any case too small to use.  We need\n" +
+"          two to make sizes and alignments work out.\n" +
+"        */\n" +
+"\n" +
+"        if (old_size != 0) {\n" +
+"          /*\n" +
+"             Shrink old_top to insert fenceposts, keeping size a\n" +
+"             multiple of MALLOC_ALIGNMENT. We know there is at least\n" +
+"             enough space in old_top to do this.\n" +
+"          */\n" +
+"          old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;\n" +
+"          set_head(old_top, old_size | PREV_INUSE);\n" +
+"\n" +
+"          /*\n" +
+"            Note that the following assignments completely overwrite\n" +
+"            old_top when old_size was previously MINSIZE.  This is\n" +
+"            intentional. We need the fencepost, even if old_top otherwise gets\n" +
+"            lost.\n" +
+"          */\n" +
+"          chunk_at_offset(old_top, old_size          )->size =\n" +
+"            SIZE_SZ|PREV_INUSE;\n" +
+"\n" +
+"          chunk_at_offset(old_top, old_size + SIZE_SZ)->size =\n" +
+"            SIZE_SZ|PREV_INUSE;\n" +
+"\n" +
+"          /*\n" +
+"             If possible, release the rest, suppressing trimming.\n" +
+"          */\n" +
+"          if (old_size >= MINSIZE) {\n" +
+"            INTERNAL_SIZE_T tt = av->trim_threshold;\n" +
+"            av->trim_threshold = (INTERNAL_SIZE_T)(-1);\n" +
+"            fREe(chunk2mem(old_top));\n" +
+"            av->trim_threshold = tt;\n" +
+"          }\n" +
+"        }\n" +
+"      }\n" +
+"    }\n" +
+"\n" +
+"    /* Update statistics */\n" +
+"    sum = av->sbrked_mem;\n" +
+"    if (sum > (CHUNK_SIZE_T)(av->max_sbrked_mem))\n" +
+"      av->max_sbrked_mem = sum;\n" +
+"\n") +
+(
+"    sum += av->mmapped_mem;\n" +
+"    if (sum > (CHUNK_SIZE_T)(av->max_total_mem))\n" +
+"      av->max_total_mem = sum;\n" +
+"\n" +
+"    check_malloc_state();\n" +
+"\n" +
+"    /* finally, do the allocation */\n" +
+"\n" +
+"    p = av->top;\n" +
+"    size = chunksize(p);\n" +
+"\n" +
+"    /* check that one of the above allocation paths succeeded */\n" +
+"    if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb + MINSIZE)) {\n" +
+"      remainder_size = size - nb;\n" +
+"      remainder = chunk_at_offset(p, nb);\n" +
+"      av->top = remainder;\n" +
+"      set_head(p, nb | PREV_INUSE);\n" +
+"      set_head(remainder, remainder_size | PREV_INUSE);\n" +
+"      check_malloced_chunk(p, nb);\n" +
+"      return chunk2mem(p);\n" +
+"    }\n" +
+"\n" +
+"  }\n" +
+"\n" +
+"  /* catch all failure paths */\n" +
+"  MALLOC_FAILURE_ACTION;\n" +
+"  return 0;\n" +
+"}\n" +
+"\n" +
+"\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  sYSTRIm is an inverse of sorts to sYSMALLOc.  It gives memory back\n" +
+"  to the system (via negative arguments to sbrk) if there is unused\n" +
+"  memory at the `high' end of the malloc pool. It is called\n" +
+"  automatically by free() when top space exceeds the trim\n" +
+"  threshold. It is also called by the public malloc_trim routine.  It\n" +
+"  returns 1 if it actually released any memory, else 0.\n" +
+"*/\n" +
+"\n" +
+"#ifndef MORECORE_CANNOT_TRIM\n" +
+"\n" +
+"#if __STD_C\n" +
+"static int sYSTRIm(size_t pad, mstate av)\n" +
+"#else\n" +
+"static int sYSTRIm(pad, av) size_t pad; mstate av;\n" +
+"#endif\n" +
+"{\n" +
+"  long  top_size;        /* Amount of top-most memory */\n" +
+"  long  extra;           /* Amount to release */\n" +
+"  long  released;        /* Amount actually released */\n" +
+"  char* current_brk;     /* address returned by pre-check sbrk call */\n" +
+"  char* new_brk;         /* address returned by post-check sbrk call */\n" +
+"  size_t pagesz;\n" +
+"\n" +
+"  pagesz = av->pagesize;\n" +
+"  top_size = chunksize(av->top);\n" +
+"\n" +
+"  /* Release in pagesize units, keeping at least one page */\n" +
+"  extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;\n" +
+"\n" +
+"  if (extra > 0) {\n" +
+"\n" +
+"    /*\n" +
+"      Only proceed if end of memory is where we last set it.\n" +
+"      This avoids problems if there were foreign sbrk calls.\n" +
+"    */\n" +
+"    current_brk = (char*)(MORECORE(0));\n" +
+"    if (current_brk == (char*)(av->top) + top_size) {\n" +
+"\n" +
+"      /*\n" +
+"        Attempt to release memory. We ignore MORECORE return value,\n" +
+"        and instead call again to find out where new end of memory is.\n" +
+"        This avoids problems if first call releases less than we asked,\n" +
+"        of if failure somehow altered brk value. (We could still\n" +
+"        encounter problems if it altered brk in some very bad way,\n" +
+"        but the only thing we can do is adjust anyway, which will cause\n" +
+"        some downstream failure.)\n" +
+"      */\n" +
+"\n" +
+"      MORECORE(-extra);\n" +
+"      new_brk = (char*)(MORECORE(0));\n" +
+"\n" +
+"      if (new_brk != (char*)MORECORE_FAILURE) {\n" +
+"        released = (long)(current_brk - new_brk);\n" +
+"\n" +
+"        if (released != 0) {\n" +
+"          /* Success. Adjust top. */\n" +
+"          av->sbrked_mem -= released;\n" +
+"          set_head(av->top, (top_size - released) | PREV_INUSE);\n" +
+"          check_malloc_state();\n" +
+"          return 1;\n" +
+"        }\n" +
+"      }\n" +
+"    }\n" +
+"  }\n" +
+"  return 0;\n" +
+"}\n" +
+"\n" +
+"#endif\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ malloc ------------------------------\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t* mALLOc(size_t bytes)\n" +
+"#else\n" +
+"  Void_t* mALLOc(bytes) size_t bytes;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"\n" +
+"  INTERNAL_SIZE_T nb;               /* normalized request size */\n" +
+"  unsigned int    idx;              /* associated bin index */\n" +
+"  mbinptr         bin;              /* associated bin */\n" +
+"  mfastbinptr*    fb;               /* associated fastbin */\n" +
+"\n" +
+"  mchunkptr       victim;           /* inspected/selected chunk */\n" +
+"  INTERNAL_SIZE_T size;             /* its size */\n" +
+"  int             victim_index;     /* its bin index */\n" +
+"\n" +
+"  mchunkptr       remainder;        /* remainder from a split */\n" +
+"  CHUNK_SIZE_T    remainder_size;   /* its size */\n" +
+"\n" +
+"  unsigned int    block;            /* bit map traverser */\n" +
+"  unsigned int    bit;              /* bit map traverser */\n" +
+"  unsigned int    map;              /* current word of binmap */\n" +
+"\n" +
+"  mchunkptr       fwd;              /* misc temp for linking */\n" +
+"  mchunkptr       bck;              /* misc temp for linking */\n" +
+"\n" +
+"  /*\n" +
+"    Convert request size to internal form by adding SIZE_SZ bytes\n" +
+"    overhead plus possibly more to obtain necessary alignment and/or\n" +
+"    to obtain a size of at least MINSIZE, the smallest allocatable\n" +
+"    size. Also, checked_request2size traps (returning 0) request sizes\n" +
+"    that are so large that they wrap around zero when padded and\n" +
+"    aligned.\n" +
+"  */\n" +
+"\n" +
+"  checked_request2size(bytes, nb);\n" +
+"\n" +
+"  /*\n" +
+"    Bypass search if no frees yet\n" +
+"   */\n" +
+"  if (!have_anychunks(av)) {\n" +
+"    if (av->max_fast == 0) /* initialization check */\n" +
+"      malloc_consolidate(av);\n" +
+"    goto use_top;\n" +
+"  }\n" +
+"\n") +
+(
+"  /*\n" +
+"    If the size qualifies as a fastbin, first check corresponding bin.\n" +
+"  */\n" +
+"\n" +
+"  if ((CHUNK_SIZE_T)(nb) <= (CHUNK_SIZE_T)(av->max_fast)) {\n" +
+"    fb = &(av->fastbins[(fastbin_index(nb))]);\n" +
+"    if ( (victim = *fb) != 0) {\n" +
+"      *fb = victim->fd;\n" +
+"      check_remalloced_chunk(victim, nb);\n" +
+"      return chunk2mem(victim);\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  /*\n" +
+"    If a small request, check regular bin.  Since these \"smallbins\"\n" +
+"    hold one size each, no searching within bins is necessary.\n" +
+"    (For a large request, we need to wait until unsorted chunks are\n" +
+"    processed to find best fit. But for small ones, fits are exact\n" +
+"    anyway, so we can check now, which is faster.)\n" +
+"  */\n" +
+"\n" +
+"  if (in_smallbin_range(nb)) {\n" +
+"    idx = smallbin_index(nb);\n" +
+"    bin = bin_at(av,idx);\n" +
+"\n" +
+"    if ( (victim = last(bin)) != bin) {\n" +
+"      bck = victim->bk;\n" +
+"      set_inuse_bit_at_offset(victim, nb);\n" +
+"      bin->bk = bck;\n" +
+"      bck->fd = bin;\n" +
+"\n" +
+"      check_malloced_chunk(victim, nb);\n" +
+"      return chunk2mem(victim);\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  /*\n" +
+"     If this is a large request, consolidate fastbins before continuing.\n" +
+"     While it might look excessive to kill all fastbins before\n" +
+"     even seeing if there is space available, this avoids\n" +
+"     fragmentation problems normally associated with fastbins.\n" +
+"     Also, in practice, programs tend to have runs of either small or\n" +
+"     large requests, but less often mixtures, so consolidation is not\n" +
+"     invoked all that often in most programs. And the programs that\n" +
+"     it is called frequently in otherwise tend to fragment.\n" +
+"  */\n" +
+"\n" +
+"  else {\n" +
+"    idx = largebin_index(nb);\n" +
+"    if (have_fastchunks(av))\n" +
+"      malloc_consolidate(av);\n" +
+"  }\n" +
+"\n" +
+"  /*\n" +
+"    Process recently freed or remaindered chunks, taking one only if\n" +
+"    it is exact fit, or, if this a small request, the chunk is remainder from\n" +
+"    the most recent non-exact fit.  Place other traversed chunks in\n" +
+"    bins.  Note that this step is the only place in any routine where\n" +
+"    chunks are placed in bins.\n" +
+"  */\n" +
+"\n" +
+"  while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) {\n" +
+"    bck = victim->bk;\n" +
+"    size = chunksize(victim);\n" +
+"\n" +
+"    /*\n" +
+"       If a small request, try to use last remainder if it is the\n" +
+"       only chunk in unsorted bin.  This helps promote locality for\n" +
+"       runs of consecutive small requests. This is the only\n" +
+"       exception to best-fit, and applies only when there is\n" +
+"       no exact fit for a small chunk.\n" +
+"    */\n" +
+"\n" +
+"    if (in_smallbin_range(nb) &&\n" +
+"        bck == unsorted_chunks(av) &&\n" +
+"        victim == av->last_remainder &&\n" +
+"        (CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb + MINSIZE)) {\n" +
+"\n" +
+"      /* split and reattach remainder */\n" +
+"      remainder_size = size - nb;\n" +
+"      remainder = chunk_at_offset(victim, nb);\n" +
+"      unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;\n" +
+"      av->last_remainder = remainder;\n" +
+"      remainder->bk = remainder->fd = unsorted_chunks(av);\n" +
+"\n" +
+"      set_head(victim, nb | PREV_INUSE);\n" +
+"      set_head(remainder, remainder_size | PREV_INUSE);\n" +
+"      set_foot(remainder, remainder_size);\n" +
+"\n" +
+"      check_malloced_chunk(victim, nb);\n" +
+"      return chunk2mem(victim);\n" +
+"    }\n" +
+"\n" +
+"    /* remove from unsorted list */\n" +
+"    unsorted_chunks(av)->bk = bck;\n" +
+"    bck->fd = unsorted_chunks(av);\n" +
+"\n" +
+"    /* Take now instead of binning if exact fit */\n" +
+"\n" +
+"    if (size == nb) {\n" +
+"      set_inuse_bit_at_offset(victim, size);\n" +
+"      check_malloced_chunk(victim, nb);\n" +
+"      return chunk2mem(victim);\n" +
+"    }\n" +
+"\n" +
+"    /* place chunk in bin */\n" +
+"\n" +
+"    if (in_smallbin_range(size)) {\n" +
+"      victim_index = smallbin_index(size);\n" +
+"      bck = bin_at(av, victim_index);\n" +
+"      fwd = bck->fd;\n" +
+"    }\n" +
+"    else {\n" +
+"      victim_index = largebin_index(size);\n" +
+"      bck = bin_at(av, victim_index);\n" +
+"      fwd = bck->fd;\n" +
+"\n" +
+"      if (fwd != bck) {\n" +
+"        /* if smaller than smallest, place first */\n" +
+"        if ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(bck->bk->size)) {\n" +
+"          fwd = bck;\n" +
+"          bck = bck->bk;\n" +
+"        }\n" +
+"        else if ((CHUNK_SIZE_T)(size) >=\n" +
+"                 (CHUNK_SIZE_T)(FIRST_SORTED_BIN_SIZE)) {\n" +
+"\n" +
+"          /* maintain large bins in sorted order */\n" +
+"          size |= PREV_INUSE; /* Or with inuse bit to speed comparisons */\n" +
+"          while ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(fwd->size))\n" +
+"            fwd = fwd->fd;\n" +
+"          bck = fwd->bk;\n" +
+"        }\n" +
+"      }\n" +
+"    }\n" +
+"\n" +
+"    mark_bin(av, victim_index);\n" +
+"    victim->bk = bck;\n" +
+"    victim->fd = fwd;\n" +
+"    fwd->bk = victim;\n" +
+"    bck->fd = victim;\n" +
+"  }\n" +
+"\n" +
+"  /*\n" +
+"    If a large request, scan through the chunks of current bin to\n" +
+"    find one that fits.  (This will be the smallest that fits unless\n" +
+"    FIRST_SORTED_BIN_SIZE has been changed from default.)  This is\n" +
+"    the only step where an unbounded number of chunks might be\n" +
+"    scanned without doing anything useful with them. However the\n" +
+"    lists tend to be short.\n" +
+"  */\n" +
+"\n") +
+(
+"  if (!in_smallbin_range(nb)) {\n" +
+"    bin = bin_at(av, idx);\n" +
+"\n" +
+"    for (victim = last(bin); victim != bin; victim = victim->bk) {\n" +
+"      size = chunksize(victim);\n" +
+"\n" +
+"      if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb)) {\n" +
+"        remainder_size = size - nb;\n" +
+"        unlink(victim, bck, fwd);\n" +
+"\n" +
+"        /* Exhaust */\n" +
+"        if (remainder_size < MINSIZE)  {\n" +
+"          set_inuse_bit_at_offset(victim, size);\n" +
+"          check_malloced_chunk(victim, nb);\n" +
+"          return chunk2mem(victim);\n" +
+"        }\n" +
+"        /* Split */\n" +
+"        else {\n" +
+"          remainder = chunk_at_offset(victim, nb);\n" +
+"          unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;\n" +
+"          remainder->bk = remainder->fd = unsorted_chunks(av);\n" +
+"          set_head(victim, nb | PREV_INUSE);\n" +
+"          set_head(remainder, remainder_size | PREV_INUSE);\n" +
+"          set_foot(remainder, remainder_size);\n" +
+"          check_malloced_chunk(victim, nb);\n" +
+"          return chunk2mem(victim);\n" +
+"        }\n" +
+"      }\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  /*\n" +
+"    Search for a chunk by scanning bins, starting with next largest\n" +
+"    bin. This search is strictly by best-fit; i.e., the smallest\n" +
+"    (with ties going to approximately the least recently used) chunk\n" +
+"    that fits is selected.\n" +
+"\n" +
+"    The bitmap avoids needing to check that most blocks are nonempty.\n" +
+"  */\n" +
+"\n" +
+"  ++idx;\n" +
+"  bin = bin_at(av,idx);\n" +
+"  block = idx2block(idx);\n" +
+"  map = av->binmap[block];\n" +
+"  bit = idx2bit(idx);\n" +
+"\n" +
+"  for (;;) {\n" +
+"\n" +
+"    /* Skip rest of block if there are no more set bits in this block.  */\n" +
+"    if (bit > map || bit == 0) {\n" +
+"      do {\n" +
+"        if (++block >= BINMAPSIZE)  /* out of bins */\n" +
+"          goto use_top;\n" +
+"      } while ( (map = av->binmap[block]) == 0);\n" +
+"\n" +
+"      bin = bin_at(av, (block << BINMAPSHIFT));\n" +
+"      bit = 1;\n" +
+"    }\n" +
+"\n" +
+"    /* Advance to bin with set bit. There must be one. */\n" +
+"    while ((bit & map) == 0) {\n" +
+"      bin = next_bin(bin);\n" +
+"      bit <<= 1;\n" +
+"      assert(bit != 0);\n" +
+"    }\n" +
+"\n" +
+"    /* Inspect the bin. It is likely to be non-empty */\n" +
+"    victim = last(bin);\n" +
+"\n" +
+"    /*  If a false alarm (empty bin), clear the bit. */\n" +
+"    if (victim == bin) {\n" +
+"      av->binmap[block] = map &= ~bit; /* Write through */\n" +
+"      bin = next_bin(bin);\n" +
+"      bit <<= 1;\n" +
+"    }\n" +
+"\n" +
+"    else {\n" +
+"      size = chunksize(victim);\n" +
+"\n" +
+"      /*  We know the first chunk in this bin is big enough to use. */\n" +
+"      assert((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb));\n" +
+"\n" +
+"      remainder_size = size - nb;\n" +
+"\n" +
+"      /* unlink */\n" +
+"      bck = victim->bk;\n" +
+"      bin->bk = bck;\n" +
+"      bck->fd = bin;\n" +
+"\n" +
+"      /* Exhaust */\n" +
+"      if (remainder_size < MINSIZE) {\n" +
+"        set_inuse_bit_at_offset(victim, size);\n" +
+"        check_malloced_chunk(victim, nb);\n" +
+"        return chunk2mem(victim);\n" +
+"      }\n" +
+"\n" +
+"      /* Split */\n" +
+"      else {\n" +
+"        remainder = chunk_at_offset(victim, nb);\n" +
+"\n" +
+"        unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;\n" +
+"        remainder->bk = remainder->fd = unsorted_chunks(av);\n" +
+"        /* advertise as last remainder */\n" +
+"        if (in_smallbin_range(nb))\n" +
+"          av->last_remainder = remainder;\n" +
+"\n" +
+"        set_head(victim, nb | PREV_INUSE);\n" +
+"        set_head(remainder, remainder_size | PREV_INUSE);\n" +
+"        set_foot(remainder, remainder_size);\n" +
+"        check_malloced_chunk(victim, nb);\n" +
+"        return chunk2mem(victim);\n" +
+"      }\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  use_top:\n" +
+"  /*\n" +
+"    If large enough, split off the chunk bordering the end of memory\n" +
+"    (held in av->top). Note that this is in accord with the best-fit\n" +
+"    search rule.  In effect, av->top is treated as larger (and thus\n" +
+"    less well fitting) than any other available chunk since it can\n" +
+"    be extended to be as large as necessary (up to system\n" +
+"    limitations).\n" +
+"\n" +
+"    We require that av->top always exists (i.e., has size >=\n" +
+"    MINSIZE) after initialization, so if it would otherwise be\n" +
+"    exhuasted by current request, it is replenished. (The main\n" +
+"    reason for ensuring it exists is that we may need MINSIZE space\n" +
+"    to put in fenceposts in sysmalloc.)\n" +
+"  */\n" +
+"\n" +
+"  victim = av->top;\n" +
+"  size = chunksize(victim);\n" +
+"\n" +
+"  if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb + MINSIZE)) {\n" +
+"    remainder_size = size - nb;\n" +
+"    remainder = chunk_at_offset(victim, nb);\n" +
+"    av->top = remainder;\n" +
+"    set_head(victim, nb | PREV_INUSE);\n" +
+"    set_head(remainder, remainder_size | PREV_INUSE);\n" +
+"\n" +
+"    check_malloced_chunk(victim, nb);\n" +
+"    return chunk2mem(victim);\n" +
+"  }\n" +
+"\n" +
+"  /*\n" +
+"     If no space in top, relay to handle system-dependent cases\n" +
+"  */\n" +
+"  return sYSMALLOc(nb, av);\n" +
+"}\n" +
+"\n") +
+(
+"/*\n" +
+"  ------------------------------ free ------------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"void fREe(Void_t* mem)\n" +
+"#else\n" +
+"void fREe(mem) Void_t* mem;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"\n" +
+"  mchunkptr       p;           /* chunk corresponding to mem */\n" +
+"  INTERNAL_SIZE_T size;        /* its size */\n" +
+"  mfastbinptr*    fb;          /* associated fastbin */\n" +
+"  mchunkptr       nextchunk;   /* next contiguous chunk */\n" +
+"  INTERNAL_SIZE_T nextsize;    /* its size */\n" +
+"  int             nextinuse;   /* true if nextchunk is used */\n" +
+"  INTERNAL_SIZE_T prevsize;    /* size of previous contiguous chunk */\n" +
+"  mchunkptr       bck;         /* misc temp for linking */\n" +
+"  mchunkptr       fwd;         /* misc temp for linking */\n" +
+"\n" +
+"  /* free(0) has no effect */\n" +
+"  if (mem != 0) {\n" +
+"    p = mem2chunk(mem);\n" +
+"    size = chunksize(p);\n" +
+"\n" +
+"    check_inuse_chunk(p);\n" +
+"\n" +
+"    /*\n" +
+"      If eligible, place chunk on a fastbin so it can be found\n" +
+"      and used quickly in malloc.\n" +
+"    */\n" +
+"\n" +
+"    if ((CHUNK_SIZE_T)(size) <= (CHUNK_SIZE_T)(av->max_fast)\n" +
+"\n" +
+"#if TRIM_FASTBINS\n" +
+"        /*\n" +
+"           If TRIM_FASTBINS set, don't place chunks\n" +
+"           bordering top into fastbins\n" +
+"        */\n" +
+"        && (chunk_at_offset(p, size) != av->top)\n" +
+"#endif\n" +
+"        ) {\n" +
+"\n" +
+"      set_fastchunks(av);\n" +
+"      fb = &(av->fastbins[fastbin_index(size)]);\n" +
+"      p->fd = *fb;\n" +
+"      *fb = p;\n" +
+"    }\n" +
+"\n" +
+"    /*\n" +
+"       Consolidate other non-mmapped chunks as they arrive.\n" +
+"    */\n" +
+"\n" +
+"    else if (!chunk_is_mmapped(p)) {\n" +
+"      set_anychunks(av);\n" +
+"\n" +
+"      nextchunk = chunk_at_offset(p, size);\n" +
+"      nextsize = chunksize(nextchunk);\n" +
+"\n" +
+"      /* consolidate backward */\n" +
+"      if (!prev_inuse(p)) {\n" +
+"        prevsize = p->prev_size;\n" +
+"        size += prevsize;\n" +
+"        p = chunk_at_offset(p, -((long) prevsize));\n" +
+"        unlink(p, bck, fwd);\n" +
+"      }\n" +
+"\n" +
+"      if (nextchunk != av->top) {\n" +
+"        /* get and clear inuse bit */\n" +
+"        nextinuse = inuse_bit_at_offset(nextchunk, nextsize);\n" +
+"        set_head(nextchunk, nextsize);\n" +
+"\n" +
+"        /* consolidate forward */\n" +
+"        if (!nextinuse) {\n" +
+"          unlink(nextchunk, bck, fwd);\n" +
+"          size += nextsize;\n" +
+"        }\n" +
+"\n" +
+"        /*\n" +
+"          Place the chunk in unsorted chunk list. Chunks are\n" +
+"          not placed into regular bins until after they have\n" +
+"          been given one chance to be used in malloc.\n" +
+"        */\n" +
+"\n" +
+"        bck = unsorted_chunks(av);\n" +
+"        fwd = bck->fd;\n" +
+"        p->bk = bck;\n" +
+"        p->fd = fwd;\n" +
+"        bck->fd = p;\n" +
+"        fwd->bk = p;\n" +
+"\n" +
+"        set_head(p, size | PREV_INUSE);\n" +
+"        set_foot(p, size);\n" +
+"\n" +
+"        check_free_chunk(p);\n" +
+"      }\n" +
+"\n" +
+"      /*\n" +
+"         If the chunk borders the current high end of memory,\n" +
+"         consolidate into top\n" +
+"      */\n" +
+"\n" +
+"      else {\n" +
+"        size += nextsize;\n" +
+"        set_head(p, size | PREV_INUSE);\n" +
+"        av->top = p;\n" +
+"        check_chunk(p);\n" +
+"      }\n" +
+"\n" +
+"      /*\n" +
+"        If freeing a large space, consolidate possibly-surrounding\n" +
+"        chunks. Then, if the total unused topmost memory exceeds trim\n" +
+"        threshold, ask malloc_trim to reduce top.\n" +
+"\n" +
+"        Unless max_fast is 0, we don't know if there are fastbins\n" +
+"        bordering top, so we cannot tell for sure whether threshold\n" +
+"        has been reached unless fastbins are consolidated.  But we\n" +
+"        don't want to consolidate on each free.  As a compromise,\n" +
+"        consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD\n" +
+"        is reached.\n" +
+"      */\n" +
+"\n" +
+"      if ((CHUNK_SIZE_T)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {\n" +
+"        if (have_fastchunks(av))\n" +
+"          malloc_consolidate(av);\n" +
+"\n" +
+"#ifndef MORECORE_CANNOT_TRIM\n" +
+"        if ((CHUNK_SIZE_T)(chunksize(av->top)) >=\n" +
+"            (CHUNK_SIZE_T)(av->trim_threshold))\n" +
+"          sYSTRIm(av->top_pad, av);\n" +
+"#endif\n" +
+"      }\n" +
+"\n" +
+"    }\n" +
+"    /*\n" +
+"      If the chunk was allocated via mmap, release via munmap()\n" +
+"      Note that if HAVE_MMAP is false but chunk_is_mmapped is\n" +
+"      true, then user must have overwritten memory. There's nothing\n" +
+"      we can do to catch this error unless DEBUG is set, in which case\n" +
+"      check_inuse_chunk (above) will have triggered error.\n" +
+"    */\n" +
+"\n" +
+"    else {\n" +
+"#if HAVE_MMAP\n" +
+"      int ret;\n" +
+"      INTERNAL_SIZE_T offset = p->prev_size;\n" +
+"      av->n_mmaps--;\n" +
+"      av->mmapped_mem -= (size + offset);\n" +
+"      ret = munmap((char*)p - offset, size + offset);\n" +
+"      /* munmap returns non-zero on failure */\n" +
+"      assert(ret == 0);\n" +
+"#endif\n" +
+"    }\n" +
+"  }\n" +
+"}\n" +
+"\n") +
+(
+"/*\n" +
+"  ------------------------- malloc_consolidate -------------------------\n" +
+"\n" +
+"  malloc_consolidate is a specialized version of free() that tears\n" +
+"  down chunks held in fastbins.  Free itself cannot be used for this\n" +
+"  purpose since, among other things, it might place chunks back onto\n" +
+"  fastbins.  So, instead, we need to use a minor variant of the same\n" +
+"  code.\n" +
+"\n" +
+"  Also, because this routine needs to be called the first time through\n" +
+"  malloc anyway, it turns out to be the perfect place to trigger\n" +
+"  initialization code.\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"static void malloc_consolidate(mstate av)\n" +
+"#else\n" +
+"static void malloc_consolidate(av) mstate av;\n" +
+"#endif\n" +
+"{\n" +
+"  mfastbinptr*    fb;                 /* current fastbin being consolidated */\n" +
+"  mfastbinptr*    maxfb;              /* last fastbin (for loop control) */\n" +
+"  mchunkptr       p;                  /* current chunk being consolidated */\n" +
+"  mchunkptr       nextp;              /* next chunk to consolidate */\n" +
+"  mchunkptr       unsorted_bin;       /* bin header */\n" +
+"  mchunkptr       first_unsorted;     /* chunk to link to */\n" +
+"\n" +
+"  /* These have same use as in free() */\n" +
+"  mchunkptr       nextchunk;\n" +
+"  INTERNAL_SIZE_T size;\n" +
+"  INTERNAL_SIZE_T nextsize;\n" +
+"  INTERNAL_SIZE_T prevsize;\n" +
+"  int             nextinuse;\n" +
+"  mchunkptr       bck;\n" +
+"  mchunkptr       fwd;\n" +
+"\n" +
+"  /*\n" +
+"    If max_fast is 0, we know that av hasn't\n" +
+"    yet been initialized, in which case do so below\n" +
+"  */\n" +
+"\n" +
+"  if (av->max_fast != 0) {\n" +
+"    clear_fastchunks(av);\n" +
+"\n" +
+"    unsorted_bin = unsorted_chunks(av);\n" +
+"\n" +
+"    /*\n" +
+"      Remove each chunk from fast bin and consolidate it, placing it\n" +
+"      then in unsorted bin. Among other reasons for doing this,\n" +
+"      placing in unsorted bin avoids needing to calculate actual bins\n" +
+"      until malloc is sure that chunks aren't immediately going to be\n" +
+"      reused anyway.\n" +
+"    */\n" +
+"\n" +
+"    maxfb = &(av->fastbins[fastbin_index(av->max_fast)]);\n" +
+"    fb = &(av->fastbins[0]);\n" +
+"    do {\n" +
+"      if ( (p = *fb) != 0) {\n" +
+"        *fb = 0;\n" +
+"\n" +
+"        do {\n" +
+"          check_inuse_chunk(p);\n" +
+"          nextp = p->fd;\n" +
+"\n" +
+"          /* Slightly streamlined version of consolidation code in free() */\n" +
+"          size = p->size & ~PREV_INUSE;\n" +
+"          nextchunk = chunk_at_offset(p, size);\n" +
+"          nextsize = chunksize(nextchunk);\n" +
+"\n" +
+"          if (!prev_inuse(p)) {\n" +
+"            prevsize = p->prev_size;\n" +
+"            size += prevsize;\n" +
+"            p = chunk_at_offset(p, -((long) prevsize));\n" +
+"            unlink(p, bck, fwd);\n" +
+"          }\n" +
+"\n" +
+"          if (nextchunk != av->top) {\n" +
+"            nextinuse = inuse_bit_at_offset(nextchunk, nextsize);\n" +
+"            set_head(nextchunk, nextsize);\n" +
+"\n" +
+"            if (!nextinuse) {\n" +
+"              size += nextsize;\n" +
+"              unlink(nextchunk, bck, fwd);\n" +
+"            }\n" +
+"\n" +
+"            first_unsorted = unsorted_bin->fd;\n" +
+"            unsorted_bin->fd = p;\n" +
+"            first_unsorted->bk = p;\n" +
+"\n" +
+"            set_head(p, size | PREV_INUSE);\n" +
+"            p->bk = unsorted_bin;\n" +
+"            p->fd = first_unsorted;\n" +
+"            set_foot(p, size);\n" +
+"          }\n" +
+"\n" +
+"          else {\n" +
+"            size += nextsize;\n" +
+"            set_head(p, size | PREV_INUSE);\n" +
+"            av->top = p;\n" +
+"          }\n" +
+"\n" +
+"        } while ( (p = nextp) != 0);\n" +
+"\n" +
+"      }\n" +
+"    } while (fb++ != maxfb);\n" +
+"  }\n" +
+"  else {\n" +
+"    malloc_init_state(av);\n" +
+"    check_malloc_state();\n" +
+"  }\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ realloc ------------------------------\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t* rEALLOc(Void_t* oldmem, size_t bytes)\n" +
+"#else\n" +
+"Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"\n" +
+"  INTERNAL_SIZE_T  nb;              /* padded request size */\n" +
+"\n" +
+"  mchunkptr        oldp;            /* chunk corresponding to oldmem */\n" +
+"  INTERNAL_SIZE_T  oldsize;         /* its size */\n" +
+"\n" +
+"  mchunkptr        newp;            /* chunk to return */\n" +
+"  INTERNAL_SIZE_T  newsize;         /* its size */\n" +
+"  Void_t*          newmem;          /* corresponding user mem */\n" +
+"\n" +
+"  mchunkptr        next;            /* next contiguous chunk after oldp */\n" +
+"\n" +
+"  mchunkptr        remainder;       /* extra space at end of newp */\n" +
+"  CHUNK_SIZE_T     remainder_size;  /* its size */\n" +
+"\n" +
+"  mchunkptr        bck;             /* misc temp for linking */\n" +
+"  mchunkptr        fwd;             /* misc temp for linking */\n" +
+"\n" +
+"  CHUNK_SIZE_T     copysize;        /* bytes to copy */\n" +
+"  unsigned int     ncopies;         /* INTERNAL_SIZE_T words to copy */\n" +
+"  INTERNAL_SIZE_T* s;               /* copy source */\n" +
+"  INTERNAL_SIZE_T* d;               /* copy destination */\n" +
+"\n" +
+"\n" +
+"#ifdef REALLOC_ZERO_BYTES_FREES\n" +
+"  if (bytes == 0) {\n" +
+"    fREe(oldmem);\n" +
+"    return 0;\n" +
+"  }\n" +
+"#endif\n" +
+"\n") +
+(
+"  /* realloc of null is supposed to be same as malloc */\n" +
+"  if (oldmem == 0) return mALLOc(bytes);\n" +
+"\n" +
+"  checked_request2size(bytes, nb);\n" +
+"\n" +
+"  oldp    = mem2chunk(oldmem);\n" +
+"  oldsize = chunksize(oldp);\n" +
+"\n" +
+"  check_inuse_chunk(oldp);\n" +
+"\n" +
+"  if (!chunk_is_mmapped(oldp)) {\n" +
+"\n" +
+"    if ((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb)) {\n" +
+"      /* already big enough; split below */\n" +
+"      newp = oldp;\n" +
+"      newsize = oldsize;\n" +
+"    }\n" +
+"\n" +
+"    else {\n" +
+"      next = chunk_at_offset(oldp, oldsize);\n" +
+"\n" +
+"      /* Try to expand forward into top */\n" +
+"      if (next == av->top &&\n" +
+"          (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >=\n" +
+"          (CHUNK_SIZE_T)(nb + MINSIZE)) {\n" +
+"        set_head_size(oldp, nb);\n" +
+"        av->top = chunk_at_offset(oldp, nb);\n" +
+"        set_head(av->top, (newsize - nb) | PREV_INUSE);\n" +
+"        return chunk2mem(oldp);\n" +
+"      }\n" +
+"\n" +
+"      /* Try to expand forward into next chunk;  split off remainder below */\n" +
+"      else if (next != av->top &&\n" +
+"               !inuse(next) &&\n" +
+"               (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >=\n" +
+"               (CHUNK_SIZE_T)(nb)) {\n" +
+"        newp = oldp;\n" +
+"        unlink(next, bck, fwd);\n" +
+"      }\n" +
+"\n" +
+"      /* allocate, copy, free */\n" +
+"      else {\n" +
+"        newmem = mALLOc(nb - MALLOC_ALIGN_MASK);\n" +
+"        if (newmem == 0)\n" +
+"          return 0; /* propagate failure */\n" +
+"\n" +
+"        newp = mem2chunk(newmem);\n" +
+"        newsize = chunksize(newp);\n" +
+"\n" +
+"        /*\n" +
+"          Avoid copy if newp is next chunk after oldp.\n" +
+"        */\n" +
+"        if (newp == next) {\n" +
+"          newsize += oldsize;\n" +
+"          newp = oldp;\n" +
+"        }\n" +
+"        else {\n" +
+"          /*\n" +
+"            Unroll copy of <= 36 bytes (72 if 8byte sizes)\n" +
+"            We know that contents have an odd number of\n" +
+"            INTERNAL_SIZE_T-sized words; minimally 3.\n" +
+"          */\n" +
+"\n" +
+"          copysize = oldsize - SIZE_SZ;\n" +
+"          s = (INTERNAL_SIZE_T*)(oldmem);\n" +
+"          d = (INTERNAL_SIZE_T*)(newmem);\n" +
+"          ncopies = copysize / sizeof(INTERNAL_SIZE_T);\n" +
+"          assert(ncopies >= 3);\n" +
+"\n" +
+"          if (ncopies > 9)\n" +
+"            MALLOC_COPY(d, s, copysize);\n" +
+"\n" +
+"          else {\n" +
+"            *(d+0) = *(s+0);\n" +
+"            *(d+1) = *(s+1);\n" +
+"            *(d+2) = *(s+2);\n" +
+"            if (ncopies > 4) {\n" +
+"              *(d+3) = *(s+3);\n" +
+"              *(d+4) = *(s+4);\n" +
+"              if (ncopies > 6) {\n" +
+"                *(d+5) = *(s+5);\n" +
+"                *(d+6) = *(s+6);\n" +
+"                if (ncopies > 8) {\n" +
+"                  *(d+7) = *(s+7);\n" +
+"                  *(d+8) = *(s+8);\n" +
+"                }\n" +
+"              }\n" +
+"            }\n" +
+"          }\n" +
+"\n" +
+"          fREe(oldmem);\n" +
+"          check_inuse_chunk(newp);\n" +
+"          return chunk2mem(newp);\n" +
+"        }\n" +
+"      }\n" +
+"    }\n" +
+"\n" +
+"    /* If possible, free extra space in old or extended chunk */\n" +
+"\n" +
+"    assert((CHUNK_SIZE_T)(newsize) >= (CHUNK_SIZE_T)(nb));\n" +
+"\n" +
+"    remainder_size = newsize - nb;\n" +
+"\n" +
+"    if (remainder_size < MINSIZE) { /* not enough extra to split off */\n" +
+"      set_head_size(newp, newsize);\n" +
+"      set_inuse_bit_at_offset(newp, newsize);\n" +
+"    }\n" +
+"    else { /* split remainder */\n" +
+"      remainder = chunk_at_offset(newp, nb);\n" +
+"      set_head_size(newp, nb);\n" +
+"      set_head(remainder, remainder_size | PREV_INUSE);\n" +
+"      /* Mark remainder as inuse so free() won't complain */\n" +
+"      set_inuse_bit_at_offset(remainder, remainder_size);\n" +
+"      fREe(chunk2mem(remainder));\n" +
+"    }\n" +
+"\n" +
+"    check_inuse_chunk(newp);\n" +
+"    return chunk2mem(newp);\n" +
+"  }\n" +
+"\n" +
+"  /*\n" +
+"    Handle mmap cases\n" +
+"  */\n" +
+"\n" +
+"  else {\n" +
+"#if HAVE_MMAP\n" +
+"\n" +
+"#if HAVE_MREMAP\n" +
+"    INTERNAL_SIZE_T offset = oldp->prev_size;\n" +
+"    size_t pagemask = av->pagesize - 1;\n" +
+"    char *cp;\n" +
+"    CHUNK_SIZE_T  sum;\n" +
+"\n" +
+"    /* Note the extra SIZE_SZ overhead */\n" +
+"    newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask;\n" +
+"\n" +
+"    /* don't need to remap if still within same page */\n" +
+"    if (oldsize == newsize - offset)\n" +
+"      return oldmem;\n" +
+"\n" +
+"    cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1);\n" +
+"\n" +
+"    if (cp != (char*)MORECORE_FAILURE) {\n" +
+"\n" +
+"      newp = (mchunkptr)(cp + offset);\n" +
+"      set_head(newp, (newsize - offset)|IS_MMAPPED);\n" +
+"\n" +
+"      assert(aligned_OK(chunk2mem(newp)));\n" +
+"      assert((newp->prev_size == offset));\n" +
+"\n") +
+(
+"      /* update statistics */\n" +
+"      sum = av->mmapped_mem += newsize - oldsize;\n" +
+"      if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem))\n" +
+"        av->max_mmapped_mem = sum;\n" +
+"      sum += av->sbrked_mem;\n" +
+"      if (sum > (CHUNK_SIZE_T)(av->max_total_mem))\n" +
+"        av->max_total_mem = sum;\n" +
+"\n" +
+"      return chunk2mem(newp);\n" +
+"    }\n" +
+"#endif\n" +
+"\n" +
+"    /* Note the extra SIZE_SZ overhead. */\n" +
+"    if ((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb + SIZE_SZ))\n" +
+"      newmem = oldmem; /* do nothing */\n" +
+"    else {\n" +
+"      /* Must alloc, copy, free. */\n" +
+"      newmem = mALLOc(nb - MALLOC_ALIGN_MASK);\n" +
+"      if (newmem != 0) {\n" +
+"        MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);\n" +
+"        fREe(oldmem);\n" +
+"      }\n" +
+"    }\n" +
+"    return newmem;\n" +
+"\n" +
+"#else\n" +
+"    /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */\n" +
+"    check_malloc_state();\n" +
+"    MALLOC_FAILURE_ACTION;\n" +
+"    return 0;\n" +
+"#endif\n" +
+"  }\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ memalign ------------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t* mEMALIGn(size_t alignment, size_t bytes)\n" +
+"#else\n" +
+"Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;\n" +
+"#endif\n" +
+"{\n" +
+"  INTERNAL_SIZE_T nb;             /* padded  request size */\n" +
+"  char*           m;              /* memory returned by malloc call */\n" +
+"  mchunkptr       p;              /* corresponding chunk */\n" +
+"  char*           brk;            /* alignment point within p */\n" +
+"  mchunkptr       newp;           /* chunk to return */\n" +
+"  INTERNAL_SIZE_T newsize;        /* its size */\n" +
+"  INTERNAL_SIZE_T leadsize;       /* leading space before alignment point */\n" +
+"  mchunkptr       remainder;      /* spare room at end to split off */\n" +
+"  CHUNK_SIZE_T    remainder_size; /* its size */\n" +
+"  INTERNAL_SIZE_T size;\n" +
+"\n" +
+"  /* If need less alignment than we give anyway, just relay to malloc */\n" +
+"\n" +
+"  if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);\n" +
+"\n" +
+"  /* Otherwise, ensure that it is at least a minimum chunk size */\n" +
+"\n" +
+"  if (alignment <  MINSIZE) alignment = MINSIZE;\n" +
+"\n" +
+"  /* Make sure alignment is power of 2 (in case MINSIZE is not).  */\n" +
+"  if ((alignment & (alignment - 1)) != 0) {\n" +
+"    size_t a = MALLOC_ALIGNMENT * 2;\n" +
+"    while ((CHUNK_SIZE_T)a < (CHUNK_SIZE_T)alignment) a <<= 1;\n" +
+"    alignment = a;\n" +
+"  }\n" +
+"\n" +
+"  checked_request2size(bytes, nb);\n" +
+"\n" +
+"  /*\n" +
+"    Strategy: find a spot within that chunk that meets the alignment\n" +
+"    request, and then possibly free the leading and trailing space.\n" +
+"  */\n" +
+"\n" +
+"\n" +
+"  /* Call malloc with worst case padding to hit alignment. */\n" +
+"\n" +
+"  m  = (char*)(mALLOc(nb + alignment + MINSIZE));\n" +
+"\n" +
+"  if (m == 0) return 0; /* propagate failure */\n" +
+"\n" +
+"  p = mem2chunk(m);\n" +
+"\n" +
+"  if ((((PTR_UINT)(m)) % alignment) != 0) { /* misaligned */\n" +
+"\n" +
+"    /*\n" +
+"      Find an aligned spot inside chunk.  Since we need to give back\n" +
+"      leading space in a chunk of at least MINSIZE, if the first\n" +
+"      calculation places us at a spot with less than MINSIZE leader,\n" +
+"      we can move to the next aligned spot -- we've allocated enough\n" +
+"      total room so that this is always possible.\n" +
+"    */\n" +
+"\n" +
+"    brk = (char*)mem2chunk((PTR_UINT)(((PTR_UINT)(m + alignment - 1)) &\n" +
+"                           -((signed long) alignment)));\n" +
+"    if ((CHUNK_SIZE_T)(brk - (char*)(p)) < MINSIZE)\n" +
+"      brk += alignment;\n" +
+"\n" +
+"    newp = (mchunkptr)brk;\n" +
+"    leadsize = brk - (char*)(p);\n" +
+"    newsize = chunksize(p) - leadsize;\n" +
+"\n" +
+"    /* For mmapped chunks, just adjust offset */\n" +
+"    if (chunk_is_mmapped(p)) {\n" +
+"      newp->prev_size = p->prev_size + leadsize;\n" +
+"      set_head(newp, newsize|IS_MMAPPED);\n" +
+"      return chunk2mem(newp);\n" +
+"    }\n" +
+"\n" +
+"    /* Otherwise, give back leader, use the rest */\n" +
+"    set_head(newp, newsize | PREV_INUSE);\n" +
+"    set_inuse_bit_at_offset(newp, newsize);\n" +
+"    set_head_size(p, leadsize);\n" +
+"    fREe(chunk2mem(p));\n" +
+"    p = newp;\n" +
+"\n" +
+"    assert (newsize >= nb &&\n" +
+"            (((PTR_UINT)(chunk2mem(p))) % alignment) == 0);\n" +
+"  }\n" +
+"\n" +
+"  /* Also give back spare room at the end */\n" +
+"  if (!chunk_is_mmapped(p)) {\n" +
+"    size = chunksize(p);\n" +
+"    if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb + MINSIZE)) {\n" +
+"      remainder_size = size - nb;\n" +
+"      remainder = chunk_at_offset(p, nb);\n" +
+"      set_head(remainder, remainder_size | PREV_INUSE);\n" +
+"      set_head_size(p, nb);\n" +
+"      fREe(chunk2mem(remainder));\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  check_inuse_chunk(p);\n" +
+"  return chunk2mem(p);\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ calloc ------------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t* cALLOc(size_t n_elements, size_t elem_size)\n" +
+"#else\n" +
+"Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size;\n" +
+"#endif\n" +
+"{\n" +
+"  mchunkptr p;\n" +
+"  CHUNK_SIZE_T  clearsize;\n" +
+"  CHUNK_SIZE_T  nclears;\n" +
+"  INTERNAL_SIZE_T* d;\n" +
+"\n") +
+(
+"  Void_t* mem = mALLOc(n_elements * elem_size);\n" +
+"\n" +
+"  if (mem != 0) {\n" +
+"    p = mem2chunk(mem);\n" +
+"\n" +
+"    if (!chunk_is_mmapped(p))\n" +
+"    {\n" +
+"      /*\n" +
+"        Unroll clear of <= 36 bytes (72 if 8byte sizes)\n" +
+"        We know that contents have an odd number of\n" +
+"        INTERNAL_SIZE_T-sized words; minimally 3.\n" +
+"      */\n" +
+"\n" +
+"      d = (INTERNAL_SIZE_T*)mem;\n" +
+"      clearsize = chunksize(p) - SIZE_SZ;\n" +
+"      nclears = clearsize / sizeof(INTERNAL_SIZE_T);\n" +
+"      assert(nclears >= 3);\n" +
+"\n" +
+"      if (nclears > 9)\n" +
+"        MALLOC_ZERO(d, clearsize);\n" +
+"\n" +
+"      else {\n" +
+"        *(d+0) = 0;\n" +
+"        *(d+1) = 0;\n" +
+"        *(d+2) = 0;\n" +
+"        if (nclears > 4) {\n" +
+"          *(d+3) = 0;\n" +
+"          *(d+4) = 0;\n" +
+"          if (nclears > 6) {\n" +
+"            *(d+5) = 0;\n" +
+"            *(d+6) = 0;\n" +
+"            if (nclears > 8) {\n" +
+"              *(d+7) = 0;\n" +
+"              *(d+8) = 0;\n" +
+"            }\n" +
+"          }\n" +
+"        }\n" +
+"      }\n" +
+"    }\n" +
+"#if ! MMAP_CLEARS\n" +
+"    else\n" +
+"    {\n" +
+"      d = (INTERNAL_SIZE_T*)mem;\n" +
+"      /*\n" +
+"        Note the additional SIZE_SZ\n" +
+"      */\n" +
+"      clearsize = chunksize(p) - 2*SIZE_SZ;\n" +
+"      MALLOC_ZERO(d, clearsize);\n" +
+"    }\n" +
+"#endif\n" +
+"  }\n" +
+"  return mem;\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ cfree ------------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"void cFREe(Void_t *mem)\n" +
+"#else\n" +
+"void cFREe(mem) Void_t *mem;\n" +
+"#endif\n" +
+"{\n" +
+"  fREe(mem);\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------- independent_calloc -------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t** iCALLOc(size_t n_elements, size_t elem_size, Void_t* chunks[])\n" +
+"#else\n" +
+"Void_t** iCALLOc(n_elements, elem_size, chunks) size_t n_elements; size_t elem_size; Void_t* chunks[];\n" +
+"#endif\n" +
+"{\n" +
+"  size_t sz = elem_size; /* serves as 1-element array */\n" +
+"  /* opts arg of 3 means all elements are same size, and should be cleared */\n" +
+"  return iALLOc(n_elements, &sz, 3, chunks);\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------- independent_comalloc -------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t** iCOMALLOc(size_t n_elements, size_t sizes[], Void_t* chunks[])\n" +
+"#else\n" +
+"Void_t** iCOMALLOc(n_elements, sizes, chunks) size_t n_elements; size_t sizes[]; Void_t* chunks[];\n" +
+"#endif\n" +
+"{\n" +
+"  return iALLOc(n_elements, sizes, 0, chunks);\n" +
+"}\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ ialloc ------------------------------\n" +
+"  ialloc provides common support for independent_X routines, handling all of\n" +
+"  the combinations that can result.\n" +
+"\n" +
+"  The opts arg has:\n" +
+"    bit 0 set if all elements are same size (using sizes[0])\n" +
+"    bit 1 set if elements should be zeroed\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#if __STD_C\n" +
+"static Void_t** iALLOc(size_t n_elements,\n" +
+"                       size_t* sizes,\n" +
+"                       int opts,\n" +
+"                       Void_t* chunks[])\n" +
+"#else\n" +
+"static Void_t** iALLOc(n_elements, sizes, opts, chunks) size_t n_elements; size_t* sizes; int opts; Void_t* chunks[];\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  INTERNAL_SIZE_T element_size;   /* chunksize of each element, if all same */\n" +
+"  INTERNAL_SIZE_T contents_size;  /* total size of elements */\n" +
+"  INTERNAL_SIZE_T array_size;     /* request size of pointer array */\n" +
+"  Void_t*         mem;            /* malloced aggregate space */\n" +
+"  mchunkptr       p;              /* corresponding chunk */\n" +
+"  INTERNAL_SIZE_T remainder_size; /* remaining bytes while splitting */\n" +
+"  Void_t**        marray;         /* either \"chunks\" or malloced ptr array */\n" +
+"  mchunkptr       array_chunk;    /* chunk for malloced ptr array */\n" +
+"  int             mmx;            /* to disable mmap */\n" +
+"  INTERNAL_SIZE_T size;\n" +
+"  size_t          i;\n" +
+"\n" +
+"  /* Ensure initialization */\n" +
+"  if (av->max_fast == 0) malloc_consolidate(av);\n" +
+"\n" +
+"  /* compute array length, if needed */\n" +
+"  if (chunks != 0) {\n" +
+"    if (n_elements == 0)\n" +
+"      return chunks; /* nothing to do */\n" +
+"    marray = chunks;\n" +
+"    array_size = 0;\n" +
+"  }\n" +
+"  else {\n" +
+"    /* if empty req, must still return chunk representing empty array */\n" +
+"    if (n_elements == 0)\n" +
+"      return (Void_t**) mALLOc(0);\n" +
+"    marray = 0;\n" +
+"    array_size = request2size(n_elements * (sizeof(Void_t*)));\n" +
+"  }\n" +
+"\n" +
+"  /* compute total element size */\n" +
+"  if (opts & 0x1) { /* all-same-size */\n" +
+"    element_size = request2size(*sizes);\n" +
+"    contents_size = n_elements * element_size;\n" +
+"  }\n" +
+"  else { /* add up all the sizes */\n" +
+"    element_size = 0;\n" +
+"    contents_size = 0;\n" +
+"    for (i = 0; i != n_elements; ++i)\n" +
+"      contents_size += request2size(sizes[i]);\n" +
+"  }\n" +
+"\n") +
+(
+"  /* subtract out alignment bytes from total to minimize overallocation */\n" +
+"  size = contents_size + array_size - MALLOC_ALIGN_MASK;\n" +
+"\n" +
+"  /*\n" +
+"     Allocate the aggregate chunk.\n" +
+"     But first disable mmap so malloc won't use it, since\n" +
+"     we would not be able to later free/realloc space internal\n" +
+"     to a segregated mmap region.\n" +
+" */\n" +
+"  mmx = av->n_mmaps_max;   /* disable mmap */\n" +
+"  av->n_mmaps_max = 0;\n" +
+"  mem = mALLOc(size);\n" +
+"  av->n_mmaps_max = mmx;   /* reset mmap */\n" +
+"  if (mem == 0)\n" +
+"    return 0;\n" +
+"\n" +
+"  p = mem2chunk(mem);\n" +
+"  assert(!chunk_is_mmapped(p));\n" +
+"  remainder_size = chunksize(p);\n" +
+"\n" +
+"  if (opts & 0x2) {       /* optionally clear the elements */\n" +
+"    MALLOC_ZERO(mem, remainder_size - SIZE_SZ - array_size);\n" +
+"  }\n" +
+"\n" +
+"  /* If not provided, allocate the pointer array as final part of chunk */\n" +
+"  if (marray == 0) {\n" +
+"    array_chunk = chunk_at_offset(p, contents_size);\n" +
+"    marray = (Void_t**) (chunk2mem(array_chunk));\n" +
+"    set_head(array_chunk, (remainder_size - contents_size) | PREV_INUSE);\n" +
+"    remainder_size = contents_size;\n" +
+"  }\n" +
+"\n" +
+"  /* split out elements */\n" +
+"  for (i = 0; ; ++i) {\n" +
+"    marray[i] = chunk2mem(p);\n" +
+"    if (i != n_elements-1) {\n" +
+"      if (element_size != 0)\n" +
+"        size = element_size;\n" +
+"      else\n" +
+"        size = request2size(sizes[i]);\n" +
+"      remainder_size -= size;\n" +
+"      set_head(p, size | PREV_INUSE);\n" +
+"      p = chunk_at_offset(p, size);\n" +
+"    }\n" +
+"    else { /* the final element absorbs any overallocation slop */\n" +
+"      set_head(p, remainder_size | PREV_INUSE);\n" +
+"      break;\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"#if DEBUG\n" +
+"  if (marray != chunks) {\n" +
+"    /* final element must have exactly exhausted chunk */\n" +
+"    if (element_size != 0)\n" +
+"      assert(remainder_size == element_size);\n" +
+"    else\n" +
+"      assert(remainder_size == request2size(sizes[i]));\n" +
+"    check_inuse_chunk(mem2chunk(marray));\n" +
+"  }\n" +
+"\n" +
+"  for (i = 0; i != n_elements; ++i)\n" +
+"    check_inuse_chunk(mem2chunk(marray[i]));\n" +
+"#endif\n" +
+"\n" +
+"  return marray;\n" +
+"}\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ valloc ------------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t* vALLOc(size_t bytes)\n" +
+"#else\n" +
+"Void_t* vALLOc(bytes) size_t bytes;\n" +
+"#endif\n" +
+"{\n" +
+"  /* Ensure initialization */\n" +
+"  mstate av = get_malloc_state();\n" +
+"  if (av->max_fast == 0) malloc_consolidate(av);\n" +
+"  return mEMALIGn(av->pagesize, bytes);\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ pvalloc ------------------------------\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"#if __STD_C\n" +
+"Void_t* pVALLOc(size_t bytes)\n" +
+"#else\n" +
+"Void_t* pVALLOc(bytes) size_t bytes;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  size_t pagesz;\n" +
+"\n" +
+"  /* Ensure initialization */\n" +
+"  if (av->max_fast == 0) malloc_consolidate(av);\n" +
+"  pagesz = av->pagesize;\n" +
+"  return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));\n" +
+"}\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ malloc_trim ------------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"int mTRIm(size_t pad)\n" +
+"#else\n" +
+"int mTRIm(pad) size_t pad;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  /* Ensure initialization/consolidation */\n" +
+"  malloc_consolidate(av);\n" +
+"\n" +
+"#ifndef MORECORE_CANNOT_TRIM\n" +
+"  return sYSTRIm(pad, av);\n" +
+"#else\n" +
+"  return 0;\n" +
+"#endif\n" +
+"}\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  ------------------------- malloc_usable_size -------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"size_t mUSABLe(Void_t* mem)\n" +
+"#else\n" +
+"size_t mUSABLe(mem) Void_t* mem;\n" +
+"#endif\n" +
+"{\n" +
+"  mchunkptr p;\n" +
+"  if (mem != 0) {\n" +
+"    p = mem2chunk(mem);\n" +
+"    if (chunk_is_mmapped(p))\n" +
+"      return chunksize(p) - 2*SIZE_SZ;\n" +
+"    else if (inuse(p))\n" +
+"      return chunksize(p) - SIZE_SZ;\n" +
+"  }\n" +
+"  return 0;\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ mallinfo ------------------------------\n" +
+"*/\n" +
+"\n") +
+(
+"struct mallinfo mALLINFo()\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  struct mallinfo mi;\n" +
+"  unsigned int i;\n" +
+"  mbinptr b;\n" +
+"  mchunkptr p;\n" +
+"  INTERNAL_SIZE_T avail;\n" +
+"  INTERNAL_SIZE_T fastavail;\n" +
+"  int nblocks;\n" +
+"  int nfastblocks;\n" +
+"\n" +
+"  /* Ensure initialization */\n" +
+"  if (av->top == 0)  malloc_consolidate(av);\n" +
+"\n" +
+"  check_malloc_state();\n" +
+"\n" +
+"  /* Account for top */\n" +
+"  avail = chunksize(av->top);\n" +
+"  nblocks = 1;  /* top always exists */\n" +
+"\n" +
+"  /* traverse fastbins */\n" +
+"  nfastblocks = 0;\n" +
+"  fastavail = 0;\n" +
+"\n" +
+"  for (i = 0; i < NFASTBINS; ++i) {\n" +
+"    for (p = av->fastbins[i]; p != 0; p = p->fd) {\n" +
+"      ++nfastblocks;\n" +
+"      fastavail += chunksize(p);\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  avail += fastavail;\n" +
+"\n" +
+"  /* traverse regular bins */\n" +
+"  for (i = 1; i < NBINS; ++i) {\n" +
+"    b = bin_at(av, i);\n" +
+"    for (p = last(b); p != b; p = p->bk) {\n" +
+"      ++nblocks;\n" +
+"      avail += chunksize(p);\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  mi.smblks = nfastblocks;\n" +
+"  mi.ordblks = nblocks;\n" +
+"  mi.fordblks = avail;\n" +
+"  mi.uordblks = av->sbrked_mem - avail;\n" +
+"  mi.arena = av->sbrked_mem;\n" +
+"  mi.hblks = av->n_mmaps;\n" +
+"  mi.hblkhd = av->mmapped_mem;\n" +
+"  mi.fsmblks = fastavail;\n" +
+"  mi.keepcost = chunksize(av->top);\n" +
+"  mi.usmblks = av->max_total_mem;\n" +
+"  return mi;\n" +
+"}\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ malloc_stats ------------------------------\n" +
+"*/\n" +
+"\n" +
+"void mSTATs()\n" +
+"{\n" +
+"  struct mallinfo mi = mALLINFo();\n" +
+"\n" +
+"#ifdef WIN32\n" +
+"  {\n" +
+"    CHUNK_SIZE_T  free, reserved, committed;\n" +
+"    vminfo (&free, &reserved, &committed);\n" +
+"    fprintf(stderr, \"free bytes       = %10lu\\n\",\n" +
+"            free);\n" +
+"    fprintf(stderr, \"reserved bytes   = %10lu\\n\",\n" +
+"            reserved);\n" +
+"    fprintf(stderr, \"committed bytes  = %10lu\\n\",\n" +
+"            committed);\n" +
+"  }\n" +
+"#endif\n" +
+"\n" +
+"\n" +
+"  fprintf(stderr, \"max system bytes = %10lu\\n\",\n" +
+"          (CHUNK_SIZE_T)(mi.usmblks));\n" +
+"  fprintf(stderr, \"system bytes     = %10lu\\n\",\n" +
+"          (CHUNK_SIZE_T)(mi.arena + mi.hblkhd));\n" +
+"  fprintf(stderr, \"in use bytes     = %10lu\\n\",\n" +
+"          (CHUNK_SIZE_T)(mi.uordblks + mi.hblkhd));\n" +
+"\n" +
+"#ifdef WIN32\n" +
+"  {\n" +
+"    CHUNK_SIZE_T  kernel, user;\n" +
+"    if (cpuinfo (TRUE, &kernel, &user)) {\n" +
+"      fprintf(stderr, \"kernel ms        = %10lu\\n\",\n" +
+"              kernel);\n" +
+"      fprintf(stderr, \"user ms          = %10lu\\n\",\n" +
+"              user);\n" +
+"    }\n" +
+"  }\n" +
+"#endif\n" +
+"}\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  ------------------------------ mallopt ------------------------------\n" +
+"*/\n" +
+"\n" +
+"#if __STD_C\n" +
+"int mALLOPt(int param_number, int value)\n" +
+"#else\n" +
+"int mALLOPt(param_number, value) int param_number; int value;\n" +
+"#endif\n" +
+"{\n" +
+"  mstate av = get_malloc_state();\n" +
+"  /* Ensure initialization/consolidation */\n" +
+"  malloc_consolidate(av);\n" +
+"\n" +
+"  switch(param_number) {\n" +
+"  case M_MXFAST:\n" +
+"    if (value >= 0 && value <= MAX_FAST_SIZE) {\n" +
+"      set_max_fast(av, value);\n" +
+"      return 1;\n" +
+"    }\n" +
+"    else\n" +
+"      return 0;\n" +
+"\n" +
+"  case M_TRIM_THRESHOLD:\n" +
+"    av->trim_threshold = value;\n" +
+"    return 1;\n" +
+"\n" +
+"  case M_TOP_PAD:\n" +
+"    av->top_pad = value;\n" +
+"    return 1;\n" +
+"\n" +
+"  case M_MMAP_THRESHOLD:\n" +
+"    av->mmap_threshold = value;\n" +
+"    return 1;\n" +
+"\n" +
+"  case M_MMAP_MAX:\n" +
+"#if !HAVE_MMAP\n" +
+"    if (value != 0)\n" +
+"      return 0;\n" +
+"#endif\n" +
+"    av->n_mmaps_max = value;\n" +
+"    return 1;\n" +
+"\n" +
+"  default:\n" +
+"    return 0;\n" +
+"  }\n" +
+"}\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  -------------------- Alternative MORECORE functions --------------------\n" +
+"*/\n" +
+"\n") +
+(
+"\n" +
+"/*\n" +
+"  General Requirements for MORECORE.\n" +
+"\n" +
+"  The MORECORE function must have the following properties:\n" +
+"\n" +
+"  If MORECORE_CONTIGUOUS is false:\n" +
+"\n" +
+"    * MORECORE must allocate in multiples of pagesize. It will\n" +
+"      only be called with arguments that are multiples of pagesize.\n" +
+"\n" +
+"    * MORECORE(0) must return an address that is at least\n" +
+"      MALLOC_ALIGNMENT aligned. (Page-aligning always suffices.)\n" +
+"\n" +
+"  else (i.e. If MORECORE_CONTIGUOUS is true):\n" +
+"\n" +
+"    * Consecutive calls to MORECORE with positive arguments\n" +
+"      return increasing addresses, indicating that space has been\n" +
+"      contiguously extended.\n" +
+"\n" +
+"    * MORECORE need not allocate in multiples of pagesize.\n" +
+"      Calls to MORECORE need not have args of multiples of pagesize.\n" +
+"\n" +
+"    * MORECORE need not page-align.\n" +
+"\n" +
+"  In either case:\n" +
+"\n" +
+"    * MORECORE may allocate more memory than requested. (Or even less,\n" +
+"      but this will generally result in a malloc failure.)\n" +
+"\n" +
+"    * MORECORE must not allocate memory when given argument zero, but\n" +
+"      instead return one past the end address of memory from previous\n" +
+"      nonzero call. This malloc does NOT call MORECORE(0)\n" +
+"      until at least one call with positive arguments is made, so\n" +
+"      the initial value returned is not important.\n" +
+"\n" +
+"    * Even though consecutive calls to MORECORE need not return contiguous\n" +
+"      addresses, it must be OK for malloc'ed chunks to span multiple\n" +
+"      regions in those cases where they do happen to be contiguous.\n" +
+"\n" +
+"    * MORECORE need not handle negative arguments -- it may instead\n" +
+"      just return MORECORE_FAILURE when given negative arguments.\n" +
+"      Negative arguments are always multiples of pagesize. MORECORE\n" +
+"      must not misinterpret negative args as large positive unsigned\n" +
+"      args. You can suppress all such calls from even occurring by defining\n" +
+"      MORECORE_CANNOT_TRIM,\n" +
+"\n" +
+"  There is some variation across systems about the type of the\n" +
+"  argument to sbrk/MORECORE. If size_t is unsigned, then it cannot\n" +
+"  actually be size_t, because sbrk supports negative args, so it is\n" +
+"  normally the signed type of the same width as size_t (sometimes\n" +
+"  declared as \"intptr_t\", and sometimes \"ptrdiff_t\").  It doesn't much\n" +
+"  matter though. Internally, we use \"long\" as arguments, which should\n" +
+"  work across all reasonable possibilities.\n" +
+"\n" +
+"  Additionally, if MORECORE ever returns failure for a positive\n" +
+"  request, and HAVE_MMAP is true, then mmap is used as a noncontiguous\n" +
+"  system allocator. This is a useful backup strategy for systems with\n" +
+"  holes in address spaces -- in this case sbrk cannot contiguously\n" +
+"  expand the heap, but mmap may be able to map noncontiguous space.\n" +
+"\n" +
+"  If you'd like mmap to ALWAYS be used, you can define MORECORE to be\n" +
+"  a function that always returns MORECORE_FAILURE.\n" +
+"\n" +
+"  Malloc only has limited ability to detect failures of MORECORE\n" +
+"  to supply contiguous space when it says it can. In particular,\n" +
+"  multithreaded programs that do not use locks may result in\n" +
+"  rece conditions across calls to MORECORE that result in gaps\n" +
+"  that cannot be detected as such, and subsequent corruption.\n" +
+"\n" +
+"  If you are using this malloc with something other than sbrk (or its\n" +
+"  emulation) to supply memory regions, you probably want to set\n" +
+"  MORECORE_CONTIGUOUS as false.  As an example, here is a custom\n" +
+"  allocator kindly contributed for pre-OSX macOS.  It uses virtually\n" +
+"  but not necessarily physically contiguous non-paged memory (locked\n" +
+"  in, present and won't get swapped out).  You can use it by\n" +
+"  uncommenting this section, adding some #includes, and setting up the\n" +
+"  appropriate defines above:\n" +
+"\n" +
+"      #define MORECORE osMoreCore\n" +
+"      #define MORECORE_CONTIGUOUS 0\n" +
+"\n" +
+"  There is also a shutdown routine that should somehow be called for\n" +
+"  cleanup upon program exit.\n" +
+"\n" +
+"  #define MAX_POOL_ENTRIES 100\n" +
+"  #define MINIMUM_MORECORE_SIZE  (64 * 1024)\n" +
+"  static int next_os_pool;\n" +
+"  void *our_os_pools[MAX_POOL_ENTRIES];\n" +
+"\n" +
+"  void *osMoreCore(int size)\n" +
+"  {\n" +
+"    void *ptr = 0;\n" +
+"    static void *sbrk_top = 0;\n" +
+"\n" +
+"    if (size > 0)\n" +
+"    {\n" +
+"      if (size < MINIMUM_MORECORE_SIZE)\n" +
+"         size = MINIMUM_MORECORE_SIZE;\n" +
+"      if (CurrentExecutionLevel() == kTaskLevel)\n" +
+"         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);\n" +
+"      if (ptr == 0)\n" +
+"      {\n" +
+"        return (void *) MORECORE_FAILURE;\n" +
+"      }\n" +
+"      // save ptrs so they can be freed during cleanup\n" +
+"      our_os_pools[next_os_pool] = ptr;\n" +
+"      next_os_pool++;\n" +
+"      ptr = (void *) ((((CHUNK_SIZE_T) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);\n" +
+"      sbrk_top = (char *) ptr + size;\n" +
+"      return ptr;\n" +
+"    }\n" +
+"    else if (size < 0)\n" +
+"    {\n" +
+"      // we don't currently support shrink behavior\n" +
+"      return (void *) MORECORE_FAILURE;\n" +
+"    }\n" +
+"    else\n" +
+"    {\n" +
+"      return sbrk_top;\n" +
+"    }\n" +
+"  }\n" +
+"\n" +
+"  // cleanup any allocated memory pools\n" +
+"  // called as last thing before shutting down driver\n" +
+"\n" +
+"  void osCleanupMem(void)\n" +
+"  {\n" +
+"    void **ptr;\n" +
+"\n" +
+"    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)\n" +
+"      if (*ptr)\n" +
+"      {\n" +
+"         PoolDeallocate(*ptr);\n" +
+"         *ptr = 0;\n" +
+"      }\n" +
+"  }\n" +
+"\n" +
+"*/\n" +
+"\n" +
+"\n" +
+"/*\n" +
+"  --------------------------------------------------------------\n" +
+"\n" +
+"  Emulation of sbrk for win32.\n" +
+"  Donated by J. Walter <Walter@GeNeSys-e.de>.\n" +
+"  For additional information about this code, and malloc on Win32, see\n" +
+"     http://www.genesys-e.de/jwalter/\n" +
+"*/\n" +
+"\n" +
+"\n") +
+(
+"#ifdef WIN32\n" +
+"\n" +
+"#ifdef _DEBUG\n" +
+"/* #define TRACE */\n" +
+"#endif\n" +
+"\n" +
+"/* Support for USE_MALLOC_LOCK */\n" +
+"#ifdef USE_MALLOC_LOCK\n" +
+"\n" +
+"/* Wait for spin lock */\n" +
+"static int slwait (int *sl) {\n" +
+"    while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0)\n" +
+"        Sleep (0);\n" +
+"    return 0;\n" +
+"}\n" +
+"\n" +
+"/* Release spin lock */\n" +
+"static int slrelease (int *sl) {\n" +
+"    InterlockedExchange (sl, 0);\n" +
+"    return 0;\n" +
+"}\n" +
+"\n" +
+"#ifdef NEEDED\n" +
+"/* Spin lock for emulation code */\n" +
+"static int g_sl;\n" +
+"#endif\n" +
+"\n" +
+"#endif /* USE_MALLOC_LOCK */\n" +
+"\n" +
+"/* getpagesize for windows */\n" +
+"static long getpagesize (void) {\n" +
+"    static long g_pagesize = 0;\n" +
+"    if (! g_pagesize) {\n" +
+"        SYSTEM_INFO system_info;\n" +
+"        GetSystemInfo (&system_info);\n" +
+"        g_pagesize = system_info.dwPageSize;\n" +
+"    }\n" +
+"    return g_pagesize;\n" +
+"}\n" +
+"static long getregionsize (void) {\n" +
+"    static long g_regionsize = 0;\n" +
+"    if (! g_regionsize) {\n" +
+"        SYSTEM_INFO system_info;\n" +
+"        GetSystemInfo (&system_info);\n" +
+"        g_regionsize = system_info.dwAllocationGranularity;\n" +
+"    }\n" +
+"    return g_regionsize;\n" +
+"}\n" +
+"\n" +
+"/* A region list entry */\n" +
+"typedef struct _region_list_entry {\n" +
+"    void *top_allocated;\n" +
+"    void *top_committed;\n" +
+"    void *top_reserved;\n" +
+"    long reserve_size;\n" +
+"    struct _region_list_entry *previous;\n" +
+"} region_list_entry;\n" +
+"\n" +
+"/* Allocate and link a region entry in the region list */\n" +
+"static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) {\n" +
+"    region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry));\n" +
+"    if (! next)\n" +
+"        return FALSE;\n" +
+"    next->top_allocated = (char *) base_reserved;\n" +
+"    next->top_committed = (char *) base_reserved;\n" +
+"    next->top_reserved = (char *) base_reserved + reserve_size;\n" +
+"    next->reserve_size = reserve_size;\n" +
+"    next->previous = *last;\n" +
+"    *last = next;\n" +
+"    return TRUE;\n" +
+"}\n" +
+"/* Free and unlink the last region entry from the region list */\n" +
+"static int region_list_remove (region_list_entry **last) {\n" +
+"    region_list_entry *previous = (*last)->previous;\n" +
+"    if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last))\n" +
+"        return FALSE;\n" +
+"    *last = previous;\n" +
+"    return TRUE;\n" +
+"}\n" +
+"\n" +
+"#define CEIL(size,to)   (((size)+(to)-1)&~((to)-1))\n" +
+"#define FLOOR(size,to)  ((size)&~((to)-1))\n" +
+"\n" +
+"#define SBRK_SCALE  0\n" +
+"/* #define SBRK_SCALE  1 */\n" +
+"/* #define SBRK_SCALE  2 */\n" +
+"/* #define SBRK_SCALE  4  */\n" +
+"\n" +
+"/* sbrk for windows */\n" +
+"static void *sbrk (long size) {\n" +
+"    static long g_pagesize, g_my_pagesize;\n" +
+"    static long g_regionsize, g_my_regionsize;\n" +
+"    static region_list_entry *g_last;\n" +
+"    void *result = (void *) MORECORE_FAILURE;\n" +
+"#ifdef TRACE\n" +
+"    printf (\"sbrk %d\\n\", size);\n" +
+"#endif\n" +
+"#if defined (USE_MALLOC_LOCK) && defined (NEEDED)\n" +
+"    /* Wait for spin lock */\n" +
+"    slwait (&g_sl);\n" +
+"#endif\n" +
+"    /* First time initialization */\n" +
+"    if (! g_pagesize) {\n" +
+"        g_pagesize = getpagesize ();\n" +
+"        g_my_pagesize = g_pagesize << SBRK_SCALE;\n" +
+"    }\n" +
+"    if (! g_regionsize) {\n" +
+"        g_regionsize = getregionsize ();\n" +
+"        g_my_regionsize = g_regionsize << SBRK_SCALE;\n" +
+"    }\n" +
+"    if (! g_last) {\n" +
+"        if (! region_list_append (&g_last, 0, 0))\n" +
+"           goto sbrk_exit;\n" +
+"    }\n" +
+"    /* Assert invariants */\n" +
+"    assert (g_last);\n" +
+"    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&\n" +
+"            g_last->top_allocated <= g_last->top_committed);\n" +
+"    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&\n" +
+"            g_last->top_committed <= g_last->top_reserved &&\n" +
+"            (unsigned) g_last->top_committed % g_pagesize == 0);\n" +
+"    assert ((unsigned) g_last->top_reserved % g_regionsize == 0);\n" +
+"    assert ((unsigned) g_last->reserve_size % g_regionsize == 0);\n" +
+"    /* Allocation requested? */\n" +
+"    if (size >= 0) {\n" +
+"        /* Allocation size is the requested size */\n" +
+"        long allocate_size = size;\n" +
+"        /* Compute the size to commit */\n" +
+"        long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;\n" +
+"        /* Do we reach the commit limit? */\n" +
+"        if (to_commit > 0) {\n" +
+"            /* Round size to commit */\n" +
+"            long commit_size = CEIL (to_commit, g_my_pagesize);\n" +
+"            /* Compute the size to reserve */\n" +
+"            long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved;\n" +
+"            /* Do we reach the reserve limit? */\n" +
+"            if (to_reserve > 0) {\n" +
+"                /* Compute the remaining size to commit in the current region */\n" +
+"                long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed;\n" +
+"                if (remaining_commit_size > 0) {\n" +
+"                    /* Assert preconditions */\n" +
+"                    assert ((unsigned) g_last->top_committed % g_pagesize == 0);\n" +
+"                    assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); {\n" +
+"                        /* Commit this */\n" +
+"                        void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size,\n" +
+"                                                             MEM_COMMIT, PAGE_READWRITE);\n" +
+"                        /* Check returned pointer for consistency */\n" +
+"                        if (base_committed != g_last->top_committed)\n" +
+"                            goto sbrk_exit;\n") +
+(
+"                        /* Assert postconditions */\n" +
+"                        assert ((unsigned) base_committed % g_pagesize == 0);\n" +
+"#ifdef TRACE\n" +
+"                        printf (\"Commit %p %d\\n\", base_committed, remaining_commit_size);\n" +
+"#endif\n" +
+"                        /* Adjust the regions commit top */\n" +
+"                        g_last->top_committed = (char *) base_committed + remaining_commit_size;\n" +
+"                    }\n" +
+"                } {\n" +
+"                    /* Now we are going to search and reserve. */\n" +
+"                    int contiguous = -1;\n" +
+"                    int found = FALSE;\n" +
+"                    MEMORY_BASIC_INFORMATION memory_info;\n" +
+"                    void *base_reserved;\n" +
+"                    long reserve_size;\n" +
+"                    do {\n" +
+"                        /* Assume contiguous memory */\n" +
+"                        contiguous = TRUE;\n" +
+"                        /* Round size to reserve */\n" +
+"                        reserve_size = CEIL (to_reserve, g_my_regionsize);\n" +
+"                        /* Start with the current region's top */\n" +
+"                        memory_info.BaseAddress = g_last->top_reserved;\n" +
+"                        /* Assert preconditions */\n" +
+"                        assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);\n" +
+"                        assert (0 < reserve_size && reserve_size % g_regionsize == 0);\n" +
+"                        while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {\n" +
+"                            /* Assert postconditions */\n" +
+"                            assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);\n" +
+"#ifdef TRACE\n" +
+"                            printf (\"Query %p %d %s\\n\", memory_info.BaseAddress, memory_info.RegionSize,\n" +
+"                                    memory_info.State == MEM_FREE ? \"FREE\":\n" +
+"                                    (memory_info.State == MEM_RESERVE ? \"RESERVED\":\n" +
+"                                     (memory_info.State == MEM_COMMIT ? \"COMMITTED\": \"?\")));\n" +
+"#endif\n" +
+"                            /* Region is free, well aligned and big enough: we are done */\n" +
+"                            if (memory_info.State == MEM_FREE &&\n" +
+"                                (unsigned) memory_info.BaseAddress % g_regionsize == 0 &&\n" +
+"                                memory_info.RegionSize >= (unsigned) reserve_size) {\n" +
+"                                found = TRUE;\n" +
+"                                break;\n" +
+"                            }\n" +
+"                            /* From now on we can't get contiguous memory! */\n" +
+"                            contiguous = FALSE;\n" +
+"                            /* Recompute size to reserve */\n" +
+"                            reserve_size = CEIL (allocate_size, g_my_regionsize);\n" +
+"                            memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;\n" +
+"                            /* Assert preconditions */\n" +
+"                            assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);\n" +
+"                            assert (0 < reserve_size && reserve_size % g_regionsize == 0);\n" +
+"                        }\n" +
+"                        /* Search failed? */\n" +
+"                        if (! found)\n" +
+"                            goto sbrk_exit;\n" +
+"                        /* Assert preconditions */\n" +
+"                        assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0);\n" +
+"                        assert (0 < reserve_size && reserve_size % g_regionsize == 0);\n" +
+"                        /* Try to reserve this */\n" +
+"                        base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size,\n" +
+"                                                      MEM_RESERVE, PAGE_NOACCESS);\n" +
+"                        if (! base_reserved) {\n" +
+"                            int rc = GetLastError ();\n" +
+"                            if (rc != ERROR_INVALID_ADDRESS)\n" +
+"                                goto sbrk_exit;\n" +
+"                        }\n" +
+"                        /* A null pointer signals (hopefully) a race condition with another thread. */\n" +
+"                        /* In this case, we try again. */\n" +
+"                    } while (! base_reserved);\n" +
+"                    /* Check returned pointer for consistency */\n" +
+"                    if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress)\n" +
+"                        goto sbrk_exit;\n" +
+"                    /* Assert postconditions */\n" +
+"                    assert ((unsigned) base_reserved % g_regionsize == 0);\n" +
+"#ifdef TRACE\n" +
+"                    printf (\"Reserve %p %d\\n\", base_reserved, reserve_size);\n" +
+"#endif\n" +
+"                    /* Did we get contiguous memory? */\n" +
+"                    if (contiguous) {\n" +
+"                        long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated;\n" +
+"                        /* Adjust allocation size */\n" +
+"                        allocate_size -= start_size;\n" +
+"                        /* Adjust the regions allocation top */\n" +
+"                        g_last->top_allocated = g_last->top_committed;\n" +
+"                        /* Recompute the size to commit */\n" +
+"                        to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;\n" +
+"                        /* Round size to commit */\n" +
+"                        commit_size = CEIL (to_commit, g_my_pagesize);\n" +
+"                    }\n" +
+"                    /* Append the new region to the list */\n" +
+"                    if (! region_list_append (&g_last, base_reserved, reserve_size))\n" +
+"                        goto sbrk_exit;\n" +
+"                    /* Didn't we get contiguous memory? */\n" +
+"                    if (! contiguous) {\n" +
+"                        /* Recompute the size to commit */\n" +
+"                        to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;\n" +
+"                        /* Round size to commit */\n" +
+"                        commit_size = CEIL (to_commit, g_my_pagesize);\n" +
+"                    }\n" +
+"                }\n" +
+"            }\n" +
+"            /* Assert preconditions */\n" +
+"            assert ((unsigned) g_last->top_committed % g_pagesize == 0);\n" +
+"            assert (0 < commit_size && commit_size % g_pagesize == 0); {\n" +
+"                /* Commit this */\n" +
+"                void *base_committed = VirtualAlloc (g_last->top_committed, commit_size,\n" +
+"                                                     MEM_COMMIT, PAGE_READWRITE);\n" +
+"                /* Check returned pointer for consistency */\n" +
+"                if (base_committed != g_last->top_committed)\n" +
+"                    goto sbrk_exit;\n" +
+"                /* Assert postconditions */\n" +
+"                assert ((unsigned) base_committed % g_pagesize == 0);\n" +
+"#ifdef TRACE\n" +
+"                printf (\"Commit %p %d\\n\", base_committed, commit_size);\n" +
+"#endif\n" +
+"                /* Adjust the regions commit top */\n" +
+"                g_last->top_committed = (char *) base_committed + commit_size;\n" +
+"            }\n" +
+"        }\n" +
+"        /* Adjust the regions allocation top */\n" +
+"        g_last->top_allocated = (char *) g_last->top_allocated + allocate_size;\n" +
+"        result = (char *) g_last->top_allocated - size;\n" +
+"    /* Deallocation requested? */\n" +
+"    } else if (size < 0) {\n" +
+"        long deallocate_size = - size;\n" +
+"        /* As long as we have a region to release */\n" +
+"        while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) {\n" +
+"            /* Get the size to release */\n" +
+"            long release_size = g_last->reserve_size;\n" +
+"            /* Get the base address */\n" +
+"            void *base_reserved = (char *) g_last->top_reserved - release_size;\n" +
+"            /* Assert preconditions */\n" +
+"            assert ((unsigned) base_reserved % g_regionsize == 0);\n" +
+"            assert (0 < release_size && release_size % g_regionsize == 0); {\n" +
+"                /* Release this */\n" +
+"                int rc = VirtualFree (base_reserved, 0,\n" +
+"                                      MEM_RELEASE);\n" +
+"                /* Check returned code for consistency */\n" +
+"                if (! rc)\n" +
+"                    goto sbrk_exit;\n" +
+"#ifdef TRACE\n" +
+"                printf (\"Release %p %d\\n\", base_reserved, release_size);\n" +
+"#endif\n" +
+"            }\n" +
+"            /* Adjust deallocation size */\n" +
+"            deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved;\n" +
+"            /* Remove the old region from the list */\n" +
+"            if (! region_list_remove (&g_last))\n" +
+"                goto sbrk_exit;\n" +
+"        } {\n") +
+(
+"            /* Compute the size to decommit */\n" +
+"            long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size);\n" +
+"            if (to_decommit >= g_my_pagesize) {\n" +
+"                /* Compute the size to decommit */\n" +
+"                long decommit_size = FLOOR (to_decommit, g_my_pagesize);\n" +
+"                /*  Compute the base address */\n" +
+"                void *base_committed = (char *) g_last->top_committed - decommit_size;\n" +
+"                /* Assert preconditions */\n" +
+"                assert ((unsigned) base_committed % g_pagesize == 0);\n" +
+"                assert (0 < decommit_size && decommit_size % g_pagesize == 0); {\n" +
+"                    /* Decommit this */\n" +
+"                    int rc = VirtualFree ((char *) base_committed, decommit_size,\n" +
+"                                          MEM_DECOMMIT);\n" +
+"                    /* Check returned code for consistency */\n" +
+"                    if (! rc)\n" +
+"                        goto sbrk_exit;\n" +
+"#ifdef TRACE\n" +
+"                    printf (\"Decommit %p %d\\n\", base_committed, decommit_size);\n" +
+"#endif\n" +
+"                }\n" +
+"                /* Adjust deallocation size and regions commit and allocate top */\n" +
+"                deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed;\n" +
+"                g_last->top_committed = base_committed;\n" +
+"                g_last->top_allocated = base_committed;\n" +
+"            }\n" +
+"        }\n" +
+"        /* Adjust regions allocate top */\n" +
+"        g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size;\n" +
+"        /* Check for underflow */\n" +
+"        if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated ||\n" +
+"            g_last->top_allocated > g_last->top_committed) {\n" +
+"            /* Adjust regions allocate top */\n" +
+"            g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size;\n" +
+"            goto sbrk_exit;\n" +
+"        }\n" +
+"        result = g_last->top_allocated;\n" +
+"    }\n" +
+"    /* Assert invariants */\n" +
+"    assert (g_last);\n" +
+"    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&\n" +
+"            g_last->top_allocated <= g_last->top_committed);\n" +
+"    assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&\n" +
+"            g_last->top_committed <= g_last->top_reserved &&\n" +
+"            (unsigned) g_last->top_committed % g_pagesize == 0);\n" +
+"    assert ((unsigned) g_last->top_reserved % g_regionsize == 0);\n" +
+"    assert ((unsigned) g_last->reserve_size % g_regionsize == 0);\n" +
+"\n" +
+"sbrk_exit:\n" +
+"#if defined (USE_MALLOC_LOCK) && defined (NEEDED)\n" +
+"    /* Release spin lock */\n" +
+"    slrelease (&g_sl);\n" +
+"#endif\n" +
+"    return result;\n" +
+"}\n" +
+"\n" +
+"/* mmap for windows */\n" +
+"static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) {\n" +
+"    static long g_pagesize;\n" +
+"    static long g_regionsize;\n" +
+"#ifdef TRACE\n" +
+"    printf (\"mmap %d\\n\", size);\n" +
+"#endif\n" +
+"#if defined (USE_MALLOC_LOCK) && defined (NEEDED)\n" +
+"    /* Wait for spin lock */\n" +
+"    slwait (&g_sl);\n" +
+"#endif\n" +
+"    /* First time initialization */\n" +
+"    if (! g_pagesize)\n" +
+"        g_pagesize = getpagesize ();\n" +
+"    if (! g_regionsize)\n" +
+"        g_regionsize = getregionsize ();\n" +
+"    /* Assert preconditions */\n" +
+"    assert ((unsigned) ptr % g_regionsize == 0);\n" +
+"    assert (size % g_pagesize == 0);\n" +
+"    /* Allocate this */\n" +
+"    ptr = VirtualAlloc (ptr, size,\n" +
+"                        MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);\n" +
+"    if (! ptr) {\n" +
+"        ptr = (void *) MORECORE_FAILURE;\n" +
+"        goto mmap_exit;\n" +
+"    }\n" +
+"    /* Assert postconditions */\n" +
+"    assert ((unsigned) ptr % g_regionsize == 0);\n" +
+"#ifdef TRACE\n" +
+"    printf (\"Commit %p %d\\n\", ptr, size);\n" +
+"#endif\n" +
+"mmap_exit:\n" +
+"#if defined (USE_MALLOC_LOCK) && defined (NEEDED)\n" +
+"    /* Release spin lock */\n" +
+"    slrelease (&g_sl);\n" +
+"#endif\n" +
+"    return ptr;\n" +
+"}\n" +
+"\n" +
+"/* munmap for windows */\n" +
+"static long munmap (void *ptr, long size) {\n" +
+"    static long g_pagesize;\n" +
+"    static long g_regionsize;\n" +
+"    int rc = MUNMAP_FAILURE;\n" +
+"#ifdef TRACE\n" +
+"    printf (\"munmap %p %d\\n\", ptr, size);\n" +
+"#endif\n" +
+"#if defined (USE_MALLOC_LOCK) && defined (NEEDED)\n" +
+"    /* Wait for spin lock */\n" +
+"    slwait (&g_sl);\n" +
+"#endif\n" +
+"    /* First time initialization */\n" +
+"    if (! g_pagesize)\n" +
+"        g_pagesize = getpagesize ();\n" +
+"    if (! g_regionsize)\n" +
+"        g_regionsize = getregionsize ();\n" +
+"    /* Assert preconditions */\n" +
+"    assert ((unsigned) ptr % g_regionsize == 0);\n" +
+"    assert (size % g_pagesize == 0);\n" +
+"    /* Free this */\n" +
+"    if (! VirtualFree (ptr, 0,\n" +
+"                       MEM_RELEASE))\n" +
+"        goto munmap_exit;\n" +
+"    rc = 0;\n" +
+"#ifdef TRACE\n" +
+"    printf (\"Release %p %d\\n\", ptr, size);\n" +
+"#endif\n" +
+"munmap_exit:\n" +
+"#if defined (USE_MALLOC_LOCK) && defined (NEEDED)\n" +
+"    /* Release spin lock */\n" +
+"    slrelease (&g_sl);\n" +
+"#endif\n" +
+"    return rc;\n" +
+"}\n" +
+"\n" +
+"static void vminfo (CHUNK_SIZE_T  *free, CHUNK_SIZE_T  *reserved, CHUNK_SIZE_T  *committed) {\n" +
+"    MEMORY_BASIC_INFORMATION memory_info;\n" +
+"    memory_info.BaseAddress = 0;\n" +
+"    *free = *reserved = *committed = 0;\n" +
+"    while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {\n" +
+"        switch (memory_info.State) {\n" +
+"        case MEM_FREE:\n" +
+"            *free += memory_info.RegionSize;\n" +
+"            break;\n" +
+"        case MEM_RESERVE:\n" +
+"            *reserved += memory_info.RegionSize;\n" +
+"            break;\n" +
+"        case MEM_COMMIT:\n" +
+"            *committed += memory_info.RegionSize;\n" +
+"            break;\n" +
+"        }\n" +
+"        memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;\n" +
+"    }\n" +
+"}\n" +
+"\n") +
+(
+"static int cpuinfo (int whole, CHUNK_SIZE_T  *kernel, CHUNK_SIZE_T  *user) {\n" +
+"    if (whole) {\n" +
+"        __int64 creation64, exit64, kernel64, user64;\n" +
+"        int rc = GetProcessTimes (GetCurrentProcess (),\n" +
+"                                  (FILETIME *) &creation64,\n" +
+"                                  (FILETIME *) &exit64,\n" +
+"                                  (FILETIME *) &kernel64,\n" +
+"                                  (FILETIME *) &user64);\n" +
+"        if (! rc) {\n" +
+"            *kernel = 0;\n" +
+"            *user = 0;\n" +
+"            return FALSE;\n" +
+"        }\n" +
+"        *kernel = (CHUNK_SIZE_T) (kernel64 / 10000);\n" +
+"        *user = (CHUNK_SIZE_T) (user64 / 10000);\n" +
+"        return TRUE;\n" +
+"    } else {\n" +
+"        __int64 creation64, exit64, kernel64, user64;\n" +
+"        int rc = GetThreadTimes (GetCurrentThread (),\n" +
+"                                 (FILETIME *) &creation64,\n" +
+"                                 (FILETIME *) &exit64,\n" +
+"                                 (FILETIME *) &kernel64,\n" +
+"                                 (FILETIME *) &user64);\n" +
+"        if (! rc) {\n" +
+"            *kernel = 0;\n" +
+"            *user = 0;\n" +
+"            return FALSE;\n" +
+"        }\n" +
+"        *kernel = (CHUNK_SIZE_T) (kernel64 / 10000);\n" +
+"        *user = (CHUNK_SIZE_T) (user64 / 10000);\n" +
+"        return TRUE;\n" +
+"    }\n" +
+"}\n" +
+"\n" +
+"#endif /* WIN32 */\n" +
+"\n" +
+"#endif // NDEBUG\n" +
+"\n" +
+"};  /* end of namespace KJS */\n");
+
+
+var thai =
+"ประเทศไทย\n" +
+"จากวิกิพีเดีย สารานุกรมเสรี\n" +
+"ไปที่: ป้ายบอกทาง, ค้นหา\n" +
+"      \n" +
+"\n" +
+"เนื่องจากบทความนี้ถูกล็อกเนื่องจาก ถูกก่อกวนหลายครั้งติดต่อกัน การแก้ไขจากผู้ที่ไม่ได้ลงทะเบียน หรือผู้ใช้ใหม่ไม่สามารถทำได้ขณะนี้\n" +
+"คุณสามารถแสดงความเห็น เสนอข้อความ หรือขอให้ยกเลิกการป้องกันได้ในหน้าอภิปราย หรือลงทะเบียนโดยสร้างชื่อผู้ใช้\n" +
+"   \n" +
+"วิกิพีเดีย:บทความคัดสรร\n" +
+"\n" +
+"    \"ไทย\" เปลี่ยนทางมาที่นี่ สำหรับความหมายอื่น ดูที่ ไทย (แก้ความกำกวม)\n" +
+"\n" +
+"ราชอาณาจักรไทย\n" +
+"ธงชาติไทย   ตราแผ่นดินของไทย\n" +
+"ธงชาติ    ตราแผ่นดิน\n" +
+"คำขวัญ: ชาติ ศาสนา พระมหากษัตริย์\n" +
+"เพลงชาติ: เพลงชาติไทย\n" +
+"แผนที่แสดงที่ตั้งของประเทศไทย\n" +
+"เมืองหลวง   กรุงเทพมหานคร\n" +
+"13°44′N 100°30′E\n" +
+"เมืองใหญ่สุด  กรุงเทพมหานคร\n" +
+"ภาษาราชการ        ภาษาไทย\n" +
+"รัฐบาล    เผด็จการทหาร\n" +
+" - ประมุขแห่งรัฐ    พระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดช\n" +
+" - นายกรัฐมนตรี       พลเอกสุรยุทธ์ จุลานนท์\n" +
+" - ประธานคณะมนตรีความมั่นคงแห่งชาติ   พลอากาศเอก ชลิต พุกผาสุข (รักษาการ)\n" +
+"สถาปนาเป็น\n" +
+"• สุโขทัย\n" +
+"• กรุงศรีอยุธยา\n" +
+"• กรุงธนบุรี\n" +
+"• กรุงรัตนโกสินทร์  \n" +
+"พ.ศ. 1781–1911\n" +
+"1893–2310\n" +
+"2310–6 เมษายน 2325\n" +
+"6 เมษายน 2325–ปัจจุบัน\n" +
+"เนื้อที่\n" +
+" - ทั้งหมด\n" +
+" \n" +
+" - พื้นน้ำ (%)   \n" +
+"514,000 กม.² (อันดับที่ 49)\n" +
+"198,457 ไมล์² \n" +
+"0.4%\n" +
+"ประชากร\n" +
+" - 2548 ประมาณ\n" +
+" - 2543\n" +
+" - ความหนาแน่น   \n" +
+"62,418,054 (อันดับที่ 19)\n" +
+"60,916,441\n" +
+"122/กม² (อันดับที่ 59)\n" +
+"{{{population_densitymi²}}}/ไมล์² \n" +
+"GDP (PPP)\n" +
+" - รวม\n" +
+" - ต่อประชากร     2548 ค่าประมาณ\n" +
+"$559.5 billion (อันดับที่ 21)\n" +
+"$8,542 (อันดับที่ 72)\n" +
+"HDI (2546)    0.778 (อันดับที่ 73) – ปานกลาง\n" +
+"สกุลเงิน      บาท (฿) (THB)\n" +
+"เขตเวลา         (UTC+7)\n" +
+"รหัสอินเทอร์เน็ต      .th\n" +
+"รหัสโทรศัพท์  +66\n" +
+"\n" +
+"ประเทศไทย หรือ ราชอาณาจักรไทย ตั้งอยู่ในเอเชียตะวันออกเฉียงใต้ มีพรมแดนทางทิศตะวันออกติดลาวและกัมพูชา ทิศใต้ติดอ่าวไทยและมาเลเซีย ทิศตะวันตกติดทะเลอันดามันและพม่า และทิศเหนือติดพม่าและลาว โดยมีแม่น้ำโขงกั้นเป็นบางช่วง\n" +
+"\n" +
+"ประเทศไทยเป็นสมาชิกของสหประชาชาติ เอเปค และ อาเซียน มีศูนย์รวมการปกครองอยู่ที่ กรุงเทพมหานคร ซึ่งเป็นเมืองหลวงของประเทศ\n" +
+"\n" +
+"พระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดช ทรงเป็นพระมหากษัตริย์ที่ครองราชย์ ในฐานะประมุขแห่งรัฐ ยาวนานที่สุดในโลกถึง 60 ปี\n" +
+"\n" +
+"\n" +
+"เนื้อหา\n" +
+"[ซ่อน]\n" +
+"\n" +
+"    * 1 ประวัติศาสตร์\n" +
+"          o 1.1 ชื่อประเทศไทย\n" +
+"    * 2 การเมืองการปกครอง\n" +
+"          o 2.1 เขตการปกครอง\n" +
+"          o 2.2 เมืองใหญ่ / จังหวัดใหญ่\n" +
+"    * 3 ภูมิอากาศและภูมิประเทศ\n" +
+"          o 3.1 ภูมิประเทศ\n" +
+"          o 3.2 ภูมิอากาศ\n" +
+"    * 4 เศรษฐกิจ\n" +
+"          o 4.1 เศรษฐกิจหลักของประเทศ\n" +
+"          o 4.2 การคมนาคม\n" +
+"          o 4.3 การสื่อสาร\n" +
+"    * 5 สังคม\n" +
+"          o 5.1 ชนชาติ\n" +
+"          o 5.2 ศาสนา\n" +
+"          o 5.3 การศึกษา\n" +
+"          o 5.4 ภาษา\n" +
+"          o 5.5 ศิลปะและวัฒนธรรม\n" +
+"          o 5.6 กีฬา\n" +
+"          o 5.7 วันสำคัญ\n" +
+"    * 6 ลำดับที่สำคัญ\n" +
+"    * 7 อ้างอิง\n" +
+"    * 8 แหล่งข้อมูลอื่น\n" +
+"\n" +
+"ประวัติศาสตร์\n" +
+"\n" +
+"    ดูบทความหลักที่ ประวัติศาสตร์ไทย\n" +
+"\n" +
+"ประเทศไทยมีประวัติศาสตร์ยาวนานมากนับเริ่มแต่การล่มสลายของราชอาณาจักรขอม-จักรวรรดินครวัต นครธม เมื่อต้นๆ คริสต์ศตวรรษที่ 13 [1]โดยมีความสืบเนื่องและคาบเกี่ยวระหว่างอาณาจักรโบราณหลายแห่ง เช่น อาณาจักรทวารวดี ศรีวิชัย ละโว้ เขมร ฯลฯ โดยเริ่มมีความชัดเจนในอาณาจักรสุโขทัยตั้งแต่ปี พ.ศ. 1781 อาณาจักรล้านนาทางภาคเหนือ กระทั่งเสื่อมอำนาจลงในช่วงต้นพุทธศตวรรษที่ 19 แล้วความรุ่งเรืองได้ปรากฏขึ้นในอาณาจักรทางใต้ ณ กรุงศรีอยุธยา โดยยังมีอาณาเขตที่ไม่แน่ชัด ครั้นเมื่อเสียกรุงศรีอยุธยาเป็นครั้งที่สองในปี พ.ศ. 2310 พระเจ้าตากสินจึงได้ย้ายราชธานีมาอยู่ที่กรุงธนบุรี\n" +
+"\n" +
+"ภายหลังสิ้นสุดอำนาจและมีการสถาปนากรุงรัตนโกสินทร์เมื่อ พ.ศ. 2325 อาณาจักรสยามเริ่มมีความเป็นปึกแผ่น มีการผนวกดินแดนบางส่วนของอาณาจักรล้านช้าง ครั้นในรัชกาลที่ 5 ได้ผนวกดินแดนของเมืองเชียงใหม่ หรืออาณาจักรล้านนาส่วนล่าง (ส่วนบนอยู่บริเวณเชียงตุง) เป็นการรวบรวมดินแดนครั้งใหญ่ครั้งสุดท้าย วันที่ 24 มิถุนายน พ.ศ. 2475 ได้เปลี่ยนแปลงการปกครองมาเป็นระบอบประชาธิปไตยแต่ก็ต้องรออีกถึง 41 ปี กว่าจะได้นายกรัฐมนตรีที่มาจากการเลือกตั้งครั้งแรกเมื่อ พ.ศ. 2516 หลังจากเหตุการณ์ 14 ตุลา หลังจากนั้นมีเหตุการณ์เรียกร้องประชาธิปไตยอีกสองครั้งคือ เหตุการณ์ 6 ตุลา และ เหตุการณ์พฤษภาทมิฬ ล่าสุดได้เกิดรัฐประหารขึ้นอีกครั้งในเดือนกันยายน พ.ศ. 2549 ซึ่งเป็นการยึดอำนาจจากรัฐบาลรักษาการ หลังจากได้มีการยุบสภาผู้แทนราษฎรเมื่อเดือนกุมภาพันธ์ 2549\n" +
+"\n" +
+"ชื่อประเทศไทย\n" +
+"\n" +
+"คำว่า ไทย มีความหมายในภาษาไทยว่า อิสรภาพ เสรีภาพ หรืออีกความหมายคือ ใหญ่ ยิ่งใหญ่ เพราะการจะเป็นอิสระได้จะต้องมีกำลังที่มากกว่า แข็งแกร่งกว่า เพื่อป้องกันการรุกรานจากข้าศึก เดิมประเทศไทยใช้ชื่อ สยาม (Siam) แต่ได้เปลี่ยนมาเป็นชื่อปัจจุบัน เมื่อปี พ.ศ. 2482 ตามประกาศรัฐนิยม ฉบับที่ 1 ของรัฐบาลจอมพล ป. พิบูลสงคราม ให้ใช้ชื่อ ประเทศ ประชาชน และสัญชาติว่า \"ไทย\" โดยในช่วงต่อมาได้เปลี่ยนกลับเป็นสยามเมื่อปี พ.ศ. 2488 ในช่วงเปลี่ยนนายกรัฐมนตรี แต่ในที่สุดได้เปลี่ยนกลับมาชื่อไทยอีกครั้งในปี พ.ศ. 2491 ซึ่งเป็นช่วงที่จอมพล ป. พิบูลสงครามเป็นนายกรัฐมนตรีในสมัยต่อมา ช่วงแรกเปลี่ยนเฉพาะชื่อภาษาไทยเท่านั้น ชื่อภาษาฝรั่งเศส[2]และอังกฤษคงยังเป็น \"Siam\" อยู่จนกระทั่งเดือนเมษายน พ.ศ. 2491 จึงได้เปลี่ยนชื่อภาษาฝรั่งเศสเป็น \"Thaïlande\" และภาษาอังกฤษเป็น \"Thailand\" อย่างในปัจจุบัน อย่างไรก็ตาม ชื่อ สยาม ยังเป็นที่รู้จักแพร่หลายทั้งในและต่างประเทศ.\n" +
+"\n" +
+"การเมืองการปกครอง\n" +
+"\n" +
+"เดิมประเทศไทยมีการปกครองระบอบสมบูรณาญาสิทธิราชย์ จนกระทั่งวันที่ 24 มิถุนายน พ.ศ. 2475 คณะราษฎรได้ทำการเปลี่ยนแปลงการปกครองเป็นราชาธิปไตยภายใต้รัฐธรรมนูญ โดยแบ่งอำนาจเป็นสามฝ่าย ได้แก่ ฝ่ายบริหาร ฝ่ายนิติบัญญัติและฝ่ายตุลาการ โดยฝ่ายบริหารจะมีนายกรัฐมนตรีเป็นหัวหน้ารัฐบาลซึ่งมากจากการแต่งตั้ง ฝ่ายนิติบัญญัติ ได้แก่ สภานิติบัญญัติแห่งชาติ และฝ่ายตุลาการ คือ ศาลยุติธรรม ศาลรัฐธรรมนูญ และศาลปกครอง\n" +
+"\n" +
+"ปัจจุบัน ประเทศไทยอยู่ภายใต้การปกครองระบอบเผด็จการทหาร โดยมีรัฐบาลชั่วคราวซึ่งแต่งตั้งโดยคณะมนตรีความมั่นคงแห่งชาติ หลังเกิดเหตุการณ์รัฐประหารเมื่อคืนวันที่ 19 กันยายน พ.ศ. 2549\n" +
+"\n" +
+"เขตการปกครอง\n" +
+"\n" +
+"ประเทศไทยแบ่งเขตการบริหารออกเป็น การบริหารราชการส่วนภูมิภาค ได้แก่จังหวัด 75 จังหวัด นอกจากนั้นยังมีการปกครองส่วนท้องถิ่น ได้แก่ กรุงเทพมหานคร เมืองพัทยา องค์การบริหารส่วนจังหวัด เทศบาล และองค์การบริหารส่วนตำบล ส่วน'สุขาภิบาล'นั้นถูกยกฐานะไปเป็นเทศบาลทั้งหมดในปี พ.ศ. 2542\n" +
+"\n" +
+"    รายชื่อจังหวัดทั้งหมดดูเพิ่มเติมที่ จังหวัดในประเทศไทย\n" +
+"\n" +
+"เมืองใหญ่ / จังหวัดใหญ่\n" +
+"ประเทศไทย จังหวัดในประเทศไทย\n" +
+"ประเทศไทย จังหวัดในประเทศไทย\n" +
+"กรุงเทพมหานครริมแม่น้ำเจ้าพระยา\n" +
+"กรุงเทพมหานครริมแม่น้ำเจ้าพระยา\n" +
+"\n" +
+"นอกจากกรุงเทพมหานครแล้ว มีหลายเมืองที่มีประชากรอยู่เป็นจำนวนมาก (ข้อมูลเดือนตุลาคม พ.ศ. 2549 ของ กรมการปกครอง กระทรวงมหาดไทย ) โดยเรียงลำดับตามตารางด้านล่าง โดยดูจากจำนวนประชากรในเขตเทศบาลและกรุงเทพมหานคร ซึ่งจะแสดงประชากรในเขตเมืองได้อย่างแท้จริง\n" +
+"อันดับ    เมือง / เทศบาล    จำนวนประชากร    จังหวัด\n" +
+"1     กรุงเทพมหานคร         6,121,672       กรุงเทพมหานคร\n" +
+"2     นนทบุรี   266,941         นนทบุรี\n" +
+"3     ปากเกร็ด        167,138         นนทบุรี\n" +
+"4     หาดใหญ่   157,678         สงขลา\n" +
+"5     เชียงใหม่     150,805         เชียงใหม่\n" +
+"6     นครราชสีมา  149,938         นครราชสีมา\n" +
+"7     อุดรธานี        142,670         อุดรธานี\n" +
+"8     สุราษฎร์ธานี    124,665         สุราษฎร์ธานี\n" +
+"9     ขอนแก่น   121,283         ขอนแก่น\n" +
+"10    นครศรีธรรมราช         106,293         นครศรีธรรมราช\n" +
+"\n" +
+"นอกจากนี้ยังมีการเรียงลำดับประชากรตามจังหวัดได้ดังต่อไปนี้\n" +
+"อันดับ    จังหวัด   จำนวนประชากร    ภาค\n" +
+"1     กรุงเทพมหานคร         6,121,672       ภาคกลาง\n" +
+"2     นครราชสีมา  2,546,763       ภาคตะวันออกเฉียงเหนือ\n" +
+"3     อุบลราชธานี       1,774,808       ภาคตะวันออกเฉียงเหนือ\n" +
+"4     ขอนแก่น   1,747,542       ภาคตะวันออกเฉียงเหนือ\n" +
+"5     เชียงใหม่     1,650,009       ภาคเหนือ\n" +
+"6     บุรีรัมย์     1,531,430       ภาคตะวันออกเฉียงเหนือ\n" +
+"7     อุดรธานี        1,523,802       ภาคตะวันออกเฉียงเหนือ\n" +
+"8     นครศรีธรรมราช         1,504,420       ภาคใต้\n" +
+"9     ศรีสะเกษ        1,443,975       ภาคตะวันออกเฉียงเหนือ\n" +
+"10    สุรินทร์        1,374,700       ภาคตะวันออกเฉียงเหนือ\n" +
+"\n" +
+"    ดูข้อมูลทั้งหมดที่ เมืองใหญ่ของประเทศไทยเรียงตามจำนวนประชากร และ จังหวัดในประเทศไทยเรียงตามจำนวนประชากร\n" +
+"\n" +
+"ภูมิอากาศและภูมิประเทศ\n" +
+"\n" +
+"ภูมิประเทศ\n" +
+"ประเทศไทย สภาพทางภูมิศาสตร์\n" +
+"ประเทศไทย สภาพทางภูมิศาสตร์\n" +
+"\n" +
+"ประเทศไทยมีสภาพทางภูมิศาสตร์ที่หลากหลาย ภาคเหนือประกอบด้วยเทือกเขาจำนวนมาก จุดที่สูงที่สุด คือ ดอยอินทนนท์ (2,576 เมตร) ในจังหวัดเชียงใหม่ ภาคตะวันออกเฉียงเหนือเป็นที่ราบสูงโคราชติดกับแม่น้ำโขงทางด้านตะวันออก ภาคกลางเป็นที่ราบลุ่มแม่น้ำเจ้าพระยา ซึ่งสายน้ำไหลลงสู่อ่าวไทย ภาคใต้มีจุดที่แคบลง ณ คอคอดกระแล้วขยายใหญ่เป็นคาบสมุทรมลายู\n" +
+"\n" +
+"    * เมื่อเปรียบเทียบพื้นที่ของประเทศไทย กับ ประเทศอื่น จะได้ดังนี้\n" +
+"          o ประเทศพม่า ใหญ่กว่าประเทศไทยประมาณ 1.3 เท่า\n" +
+"          o ประเทศอินโดนีเซีย ใหญ่กว่าประมาณ 3.7 เท่า\n" +
+"          o ประเทศอินเดีย ใหญ่กว่าประมาณ 6.4 เท่า\n" +
+"          o ประเทศจีน และ สหรัฐอเมริกา ใหญ่กว่าประมาณ 19 เท่า\n" +
+"          o ประเทศรัสเซีย ใหญ่กว่าประมาณ 33 เท่า\n" +
+"          o ขนาดใกล้เคียงกับ ประเทศฝรั่งเศส ประเทศสวีเดน และ ประเทศสเปน\n" +
+"\n" +
+"วันที่ 26 ธันวาคม พ.ศ. 2547 ได้มีเหตุการณ์คลื่นสึนามิเกิดขึ้นก่อความเสียหายในเขตภาคใต้ของประเทศไทย\n" +
+"\n" +
+"ภูมิอากาศ\n" +
+"\n" +
+"ภูมิอากาศของไทยเป็นแบบเขตร้อน อากาศร้อนที่สุดในเดือนเมษายน-พฤษภาคม โดยจะมีฝนตกและเมฆมากจากลมมรสุมตะวันตกเฉียงใต้ในช่วงกลางเดือนพฤษภาคม-เดือนตุลาคม ส่วนในเดือนพฤศจิกายนถึงกลางเดือนมีนาคม อากาศแห้ง และหนาวเย็นจากลมมรสุมตะวันออกเฉียงเหนือ ยกเว้นภาคใต้ที่มีอากาศร้อนชื้นตลอดทั้งปี\n" +
+"\n" +
+"เศรษฐกิจ\n" +
+"\n" +
+"เศรษฐกิจหลักของประเทศ\n" +
+"\n" +
+"เกษตรกรรม อุตสาหกรรม การท่องเที่ยว การบริการ และ ทรัพยากรธรรมชาติ ถือเป็นเศรษฐกิจหลักที่ทำรายได้ให้กับคนในประเทศ โดยภาพรวมทางเศรษฐกิจอ้างอิงเมื่อ พ.ศ. 2546 มี GDP 5,930.4 พันล้านบาท ส่งออกมูลค่า 78.1 พันล้านเหรียญสหรัฐ ในขณะที่นำเข้า 74.3 พันล้านเหรียญสหรัฐ[3]\n" +
+"ภาพพันธุ์ข้าวจากกรมวิชาการเกษตร\n" +
+"ภาพพันธุ์ข้าวจากกรมวิชาการเกษตร\n" +
+"ภาพยางพาราจากกรมวิชาการเกษตร\n" +
+"ภาพยางพาราจากกรมวิชาการเกษตร\n" +
+"\n" +
+"ในด้านเกษตรกรรม ข้าว ถือเป็นผลผลิตที่สำคัญที่สุด เป็นผู้ผลิตและส่งออกข้าว เป็นอันดับหนึ่งของโลก ด้วยสัดส่วนการส่งออก ร้อยละ 36 รองลงมาคือ เวียดนาม ร้อยละ 20 อินเดีย ร้อยละ 18 สหรัฐอเมริกา ร้อยละ14 ปากีสถาน ร้อยละ 12 ตามลำดับ [4] พืชผลทางการเกษตรอื่นๆ ได้แก่ ยางพารา ผักและผลไม้ต่างๆ มีการเพาะเลี้ยงปศุสัตว์เช่น วัว สุกร เป็ด ไก่ สัตว์น้ำทั้งปลาน้ำจืด ปลาน้ำเค็มในกระชัง นากุ้ง เลี้ยงหอย รวมถึงการประมงทางทะเล ปี 2549 ไทยมีการส่งออกกุ้งไปสหรัฐฯ 177,717.29 ตัน มูลค่า 45,434.57 ล้านบาท [5]\n" +
+"\n" +
+"อุตสาหกรรมที่สำคัญ ได้แก่ อุตสาหกรรมแปรรูปทางการเกษตร สิ่งทอ อิเล็กทรอนิกส์ รถยนต์ ส่วนทรัพยากรธรรมชาติที่สำคัญเช่น ดีบุก ก๊าซธรรมชาติ จากข้อมูลปี พ.ศ. 2547 มีการผลิตสิ่งทอมูลค่า 211.4 พันล้านบาท แผงวงจรรวม 196.4 พันล้านบาท อาหารทะเลกระป๋อง 36.5 พันล้านบาท สับปะรดกระป๋อง 11.1 พันล้านบาท รถยนต์ส่วนบุคคล 2.99 แสนคัน รถบรรทุก รถกระบะ และอื่นๆ รวม 6.28 แสนคัน จักรยานยนต์ 2.28 ล้านคัน ดีบุก 694 ตัน ก๊าซธรรมชาติ 789 พันล้านลูกบาศก์ฟุต น้ำมันดิบ]] 31.1 ล้านบาร์เรล [6]\n" +
+"เกาะพีพี สถานท่องเที่ยวที่สำคัญแห่งหนึ่งของประเทศ\n" +
+"เกาะพีพี สถานท่องเที่ยวที่สำคัญแห่งหนึ่งของประเทศ\n" +
+"\n" +
+"ส่วนด้านการท่องเที่ยว การบริการและโรงแรม ในปี พ.ศ. 2547 มีนักท่องเที่ยวรวม 11.65 ล้านคน 56.52% มาจากเอเชียตะวันออกและอาเซียน (โดยเฉพาะมาเลเซียคิดเป็น 11.97% ญี่ปุ่น 10.33%) ยุโรป 24.29% ทวีปอเมริกาเหนือและใต้รวมกัน 7.02% [7] สถานที่ท่องเที่ยวที่สำคัญได้แก่ กรุงเทพมหานคร พัทยา ภาคใต้ฝั่งทะเลอันดามัน จังหวัดเชียงใหม่\n" +
+"\n" +
+"การคมนาคม\n" +
+"\n" +
+"ดูบทความหลัก การคมนาคมในประเทศไทย\n" +
+"\n" +
+"การคมนาคมในประเทศไทย ส่วนใหญ่ประกอบด้วย การเดินทางโดยรถยนต์ และ จักรยานยนต์ ทางหลวงสายหลักในประเทศไทย ได้แก่ ถนนพหลโยธิน (ทางหลวงหมายเลข 1) ถนนมิตรภาพ (ทางหลวงหมายเลข 2) ถนนสุขุมวิท (ทางหลวงหมายเลข 3) และถนนเพชรเกษม (ทางหลวงหมายเลข 4) และยังมีทางหลวงพิเศษระหว่างเมือง (มอเตอร์เวย์) ใน 2 เส้นทางคือ มอเตอร์เวย์กรุงเทพฯ-ชลบุรี (ทางหลวงหมายเลข 7) และถนนกาญจนาภิเษก (วงแหวนรอบนอกกรุงเทพมหานคร - ทางหลวงหมายเลข 9) นอกจากนี้ระบบขนส่งมวลชนจะมีการบริการตามเมืองใหญ่ต่างๆ ได้แก่ระบบรถเมล์ และรถไฟ รวมถึงระบบที่เริ่มมีการใช้งาน รถไฟลอยฟ้า และรถไฟใต้ดิน และในหลายพื้นที่จะมีการบริการรถสองแถว รวมถึงรถรับจ้างต่างๆ ได้แก่ แท็กซี่ เมลเครื่อง มอเตอร์ไซค์รับจ้าง และ รถตุ๊กตุ๊ก ในบางพื้นที่ ที่อยู่ริมน้ำจะมีเรือรับจ้าง และแพข้ามฟาก บริการ\n" +
+"รถไฟฟ้าบีทีเอส สถานีอโศก\n" +
+"รถไฟฟ้าบีทีเอส สถานีอโศก\n" +
+"\n" +
+"สำหรับการคมนาคมทางอากาศนั้น ปัจจุบันประเทศไทยได้เปิดใช้ท่าอากาศยานสุวรรณภูมิ ซึ่งเป็นท่าอากาศยานที่มีขนาดตัวอาคารที่ใหญ่ที่สุดในโลก และมีหอบังคับการบินที่สูงที่สุดในโลก ด้วยความสูง 132.2 เมตร ซึ่งรองรับผู้โดยสารได้ 45 ล้านคนต่อปี โดยเปิดอย่างเป็นทางการตั้งแต่วันที่ 29 กันยายน พ.ศ. 2549 ทดแทนท่าอากาศยานนานาชาติกรุงเทพ (ดอนเมือง) ที่เปิดใช้งานมานานถึง 92 ปี\n" +
+"\n" +
+"ส่วนการคมนาคมทางน้ำ ประเทศไทยมีท่าเรือหลักๆ คือ ท่าเรือกรุงเทพ(คลองเตย) และท่าเรือแหลมฉบัง\n" +
+"\n" +
+"การสื่อสาร\n" +
+"\n" +
+"    * ระบบโทรศัพท์ในประเทศไทยมีโทรศัพท์พื้นฐาน 7.035 ล้านหมายเลข (2548) และโทรศัพท์มือถือ 27.4 ล้านหมายเลข (2548) [8]\n" +
+"    * สถานีวิทยุ: คลื่นเอฟเอ็ม 334 สถานี , คลื่นเอเอ็ม 204 สถานี และ คลื่นสั้น 6 สถานี (2542) โดยมีจำนวนผู้ใช้วิทยุ 13.96 ล้านคน (2540) [8]\n" +
+"    * สถานีโทรทัศน์ มี 6 ช่องสถานี (โดยทุกช่องสถานีแม่ข่ายอยู่ในกรุงเทพ) มีสถานีเครือข่ายทั้งหมด 111 สถานี และจำนวนผู้ใช้โทรทัศน์ 15.19 ล้านคน (2540) [8]\n" +
+"    * รหัสโดเมนอินเทอร์เน็ตใช้รหัส th\n" +
+"\n" +
+"สังคม\n" +
+"วัดพระศรีรัตนศาสดาราม กรุงเทพมหานคร\n" +
+"วัดพระศรีรัตนศาสดาราม กรุงเทพมหานคร\n" +
+"\n" +
+"ชนชาติ\n" +
+"\n" +
+"ในประเทศไทย ถือได้ว่า มีความหลากหลายทางเชื้อชาติ มีทั้ง ชาวไทย ชาวไทยเชื้อสายลาว ชาวไทยเชื้อสายมอญ ชาวไทยเชื้อสายเขมร รวมไปถึงกลุ่มชาวไทยเชื้อสายจีน ชาวไทยเชื้อสายมลายู ชาวชวา(แขกแพ) ชาวจาม(แขกจาม) ชาวเวียด ไปจนถึงชาวพม่า และชาวไทยภูเขาเผ่าต่างๆ เช่น ชาวกะเหรี่ยง ชาวลีซอ ชาวอ่าข่า ชาวอีก้อ ชาวม้ง ชาวเย้า รวมไปจนถึงชาวส่วย ชาวกูบ ชาวกวย ชาวจะราย ชาวระแดว์ ชาวข่า ชาวขมุ ซึ่งมีในปัจจุบันก็มีความสำคัญมาก ต่อวิถีชีวิต และวัฒนธรรมไทยในปัจจุบัน\n" +
+"\n" +
+"ประชากรชาวไทย 75% ชาวไทยเชื้อสายจีน 14% และอื่นๆ 11% [8]\n" +
+"\n" +
+"    ดูเพิ่มที่ ชาวไทย\n" +
+"\n" +
+"ศาสนา\n" +
+"พระพุทธชินราช วัดพระศรีรัตนมหาธาตุวรมหาวิหาร จังหวัดพิษณุโลก\n" +
+"พระพุทธชินราช วัดพระศรีรัตนมหาธาตุวรมหาวิหาร จังหวัดพิษณุโลก\n" +
+"\n" +
+"ประมาณร้อยละ 95 ของประชากรไทยนับถือศาสนาพุทธซึ่งเป็นศาสนาประจำชาติ(โดยพฤตินัย) นิกายเถรวาท ศาสนาอิสลามประมาณร้อยละ 4 (ส่วนใหญ่เป็นชาวไทยทางภาคใต้ตอนล่าง) ศาสนาคริสต์และศาสนาอื่นประมาณร้อยละ 1\n" +
+"\n" +
+"    ดูเพิ่มที่ พระพุทธศาสนาในประเทศไทย\n" +
+"\n" +
+"การศึกษา\n" +
+"\n" +
+"ในทางกฎหมาย รัฐบาลจะต้องจัดการศึกษาให้ขั้นพื้นฐานสิบสองปี แต่การศึกษาขั้นบังคับของประเทศไทยในปัจจุบันคือเก้าปี บุคคลทั่วไปจะเริ่มจากระดับชั้นอนุบาล เป็นการเตรียมความพร้อมก่อนการเรียนตามหลักสูตรพื้นฐาน ต่อเนื่องด้วยระดับประถมศึกษาและมัธยมศึกษาตอนต้น หลังจากจบการศึกษาระดับมัธยมต้น สามารถเลือกได้ระหว่างศึกษาต่อสายสามัญ ระดับมัธยมศึกษาตอนปลายเพื่อศึกษาต่อในระดับมหาวิทยาลัย หรือเลือกศึกษาต่อสายวิชาชีพ ในวิทยาลัยเทคนิค หรือพาณิชยการ หรือเลือกศึกษาต่อในสถาบันทางทหารหรือตำรวจ\n" +
+"\n" +
+"โรงเรียนและมหาวิทยาลัยในประเทศไทย แบ่งออกเป็น 2 ประเภทหลักได้แก่ โรงเรียนรัฐบาล และโรงเรียนเอกชน และ มหาวิทยาลัยรัฐบาล และมหาวิทยาลัยเอกชน โดยโรงเรียนรัฐบาลและมหาวิทยาลัยรัฐบาล จะเสียค่าเล่าเรียนน้อยกว่า โรงเรียนเอกชนและมหาวิทยาลัยเอกชน\n" +
+"\n" +
+"    ดูเพิ่มที่ รายชื่อสถาบันอุดมศึกษาในประเทศไทย\n" +
+"\n" +
+"ภาษา\n" +
+"\n" +
+"    ดูบทความหลักที่ ภาษาในประเทศไทย\n" +
+"\n" +
+"ภาษาไทย ประเทศไทยมีภาษาไทยเป็นภาษาราชการ ภาษาพูดของคนไทยมีมาแต่เมื่อไรยังไม่เป็นที่ทราบแน่ชัด แต่จากการสันนิฐานน่าจะมีมากว่า 4,000 ปีแล้ว ส่วนตัวอักษรนั้นเพิ่งมีการประดิษฐ์ขึ้นอย่างเป็นทางการในสมัยสุโขทัยโดย พ่อขุนรามคำแหงมหาราช ส่วนภาษาอื่นที่มีการใช้อยู่บ้าง เช่น ภาษาอังกฤษ ภาษาจีน เป็นต้น\n" +
+"\n" +
+"ศิลปะและวัฒนธรรม\n" +
+"พระที่นั่งไอศวรรย์ทิพย์อาสน์ พระราชวังบางปะอิน จังหวัดพระนครศรีอยุธยา\n" +
+"พระที่นั่งไอศวรรย์ทิพย์อาสน์ พระราชวังบางปะอิน จังหวัดพระนครศรีอยุธยา\n" +
+"\n" +
+"ศิลปะไทยมีลักษณะเฉพาะตัวค่อนข้างสูง โดยมีความกลมกลืนและคล้ายคลึงกับศิลปวัฒนธรรมเพื่อนบ้านอยู่บ้าง แต่ด้วยการสืบทอดและการสร้างสรรค์ใหม่ ทำให้ศิลปะไทยมีเอกลักษณ์สูง\n" +
+"\n" +
+"    * จิตรกรรม งานจิตรกรรมไทยนับว่าเป็นงานศิลปะชั้นสูง ได้รับการสืบทอดมาช้านาน มักปรากฏในงานจิตรกรรมฝาผนัง ตามวัดวาอาราม รวมทั้งในสมุดข่อยโบราณ งานจิตรกรรมไทยยังเกี่ยวข้องกับงานศิลปะแขนงอื่นๆ เช่น งานลงรักปิดทอง ภาพวาดพระบฏ เป็นต้น\n" +
+"    * ประติมากรรม เดิมนั้นช่างไทยทำงานประติมากรรมเฉพาะสิ่งศักดิ์สิทธิ์ เช่น พระพุทธรูป เทวรูป โดยมีสกุลช่างต่างๆ นับตั้งแต่ก่อนสมัยสุโขทัย เรียกว่า สกุลช่างเชียงแสน สกุลช่างสุโขทัย อยุธยา และกระทั่งรัตนโกสินทร์ โดยใช้ทองสำริดเป็นวัสดุหลักในงานประติมากรรม เนื่องจากสามารถแกะแบบด้วยขี้ผึ้งและตกแต่งได้ แล้วจึงนำไปหล่อโลหะ เมื่อเทียบกับประติมากรรมศิลาในยุคก่อนนั้น งานสำริดนับว่าอ่อนช้อยงดงามกว่ามาก\n" +
+"    * สถาปัตยกรรม สถาปัตยกรรมไทยมีปรากฏให้เห็นในชั้นหลัง เนื่องจากงานสถาปัตยกรรมส่วนใหญ่ชำรุดทรุดโทรมได้ง่าย โดยเฉพาะงานไม้ ไม่ปรากฏร่องรอยสมัยโบราณเลย สถาปัตยกรรมไทยมีให้เห็นอยู่ในรูปของบ้านเรือนไทย โบสถ์ วัด และปราสาทราชวัง ซึ่งล้วนแต่สร้างขึ้นให้เหมาะสมกับสภาพอากาศและการใช้สอยจริง\n" +
+"\n" +
+"    ดูเพิ่มที่ ศิลปะไทย\n" +
+"\n" +
+"กีฬา\n" +
+"ราชมังคลากีฬาสถาน การกีฬาแห่งประเทศไทย\n" +
+"ราชมังคลากีฬาสถาน การกีฬาแห่งประเทศไทย\n" +
+"\n" +
+"กีฬาที่นิยมมากที่สุดในประเทศไทยได้แก่ ฟุตบอล โดยในการแข่งขันระหว่างประเทศ ทีมชาติไทยได้เข้าเล่นและได้อันดับสูงสุดในเอเชียนคัพ ได้อันดับ 3 ใน เอเชียนคัพ 1972 กีฬาอื่นที่นิยมเล่นได้แก่ บาสเกตบอล มวย และแบดมินตัน โดยในประเทศไทยมีการจัดฟุตบอลอาชีพ โดยแบ่งแยกตามทีมประจำจังหวัด สำหรับกีฬาไทย ได้แก่ มวยไทย และ ตะกร้อ แม้จะมีความนิยมไม่เท่ากีฬาทั่วไป แต่ยังมีการเล่นโดยทั่วไปรวมถึงการเปิดสอนในโรงเรียน\n" +
+"\n" +
+"ประเทศไทยเป็นตัวแทนจัดงานเอเชียนเกมส์ 4 ครั้ง และซีเกมส์ ทั้งหมด 5 ครั้ง โดยจัดครั้งแรกที่ประเทศไทย\n" +
+"\n" +
+"นักกีฬาไทยที่มีชื่อเสียงมาก ได้แก่\n" +
+"\n" +
+"    * นักมวย - เขาทราย แกแล็คซี่, สด จิตรลดา, สามารถ พยัคฆ์อรุณ, สมรักษ์ คำสิงห์\n" +
+"    * นักเทนนิส - ภราดร ศรีชาพันธุ์, แทมมารีน ธนสุกาญจน์, ดนัย อุดมโชค\n" +
+"    * นักว่ายน้ำ - รัฐพงษ์ ศิริสานนท์(ฉลามนุ้ก), ต่อวัย เสฎฐโสธร, ต่อลาภ เสฎฐโสธร\n" +
+"    * นักฟุตบอล - ปิยะพงษ์ ผิวอ่อน, เกียรติศักดิ์ เสนาเมือง\n" +
+"    * นักสนุกเกอร์ - ต๋อง ศิษย์ฉ่อย\n" +
+"    * นักกรีฑา - เรวดี ศรีท้าว\n" +
+"    * นักเทควันโด - เยาวภา บุรพลชัย\n" +
+"    * นักยกน้ำหนัก - อุดมพร พลศักดิ์, ปวีณา ทองสุก\n" +
+"    * นักกอล์ฟ - ธงชัย ใจดี\n" +
+"\n" +
+"วันสำคัญ\n" +
+"\n" +
+"วันสำคัญในประเทศไทยจะมีจำนวนมากโดยเฉพาะวันที่ไม่ใช่วันหยุดราชการ ซึ่งจะตั้งขึ้นหลังจากมีเหตุการณ์สำคัญเกิดขึ้น โดยวันชาติของประเทศไทยตรงกับวันที่ 5 ธันวาคม เป็น ตามวันพระราชสมภพ ของพระบาทสมเด็จพระเจ้าอยู่หัว ภูมิพลอดุลยเดช\n" +
+"\n" +
+"    ดูบทความหลักที่ วันสำคัญในประเทศไทย\n" +
+"\n" +
+"ลำดับที่สำคัญ\n" +
+"\n" +
+"    * พระมหากษัตริย์ไทยพระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดช เป็นพระมหากษัตริย์ที่ครองราชย์ในฐานะประมุขแห่งรัฐที่นานที่สุดในโลก\n" +
+"    * กรุงเทพฯ เป็นเมืองหลวงที่มีชื่อยาวที่สุดในโลก (169 ตัวอักษร)\n" +
+"    * ดัชนีเศรษฐกิจของประเทศไทย อยู่อันดับที่ 71 จาก 155 เขตเศรษฐกิจ ตาม Index of Economic Freedom\n" +
+"    * จังหวัดหนองคายได้รับการจัดอันดับจากนิตยสาร Modern Maturity ของสหรัฐเมื่อ พ.ศ. 2544 ว่าเป็นเมืองที่น่าอยู่สำหรับผู้สูงอายุชาวอเมริกันอันดับที่ 7 ของโลก [9]\n" +
+"    * Growth Competitiveness Index Ranking พ.ศ. 2546 อยู่อันดับที่ 34 จาก 104 [10]\n" +
+"    * ตึกใบหยก 2 เป็นตึกที่สูงที่สุดในประเทศไทย และสูงเป็นอันดับ 30 ของโลก พ.ศ. 2549\n" +
+"\n" +
+"อ้างอิง\n" +
+"\n" +
+"   1. ↑ 4th edition \"ANKOR an introduction to the temples\" Dawn Rooney ISBN: 962-217-683-6\n" +
+"   2. ↑ ในสมัยก่อนนั้น (ตั้งแต่คริสต์ศตวรรษที่ 17 ในยุโรป) ภาษาสากลในการติดต่อระหว่างประเทศ (lingua franca) คือ ภาษาฝรั่งเศส เอกสารระหว่างประเทศจะใช้ภาษาฝรั่งเศสเป็นหลัก รวมถึงหนังสือเดินทางไทยรุ่นแรกๆ ด้วย\n" +
+"   3. ↑ ดัชนีเศรษฐกิจประเทศไทย จากเว็บไซต์ธนาคารแห่งประเทศไทย\n" +
+"   4. ↑ ข้าวไทย ย่างก้าวพัฒนา สร้างไทยเป็นศูนย์กลางข้าวโลก โดย เทคโนโลยีชาวบ้าน มติชน วันที่ 01 มิถุนายน พ.ศ. 2550 ปีที่ 19 ฉบับที่ 408\n" +
+"   5. ↑ http://www.thairath.co.th/news.php?section=agriculture&content=52868\n" +
+"   6. ↑ ผลผลิตของประเทศไทย จากเว็บไซต์ธนาคารแห่งประเทศไทย\n" +
+"   7. ↑ ข้อมูลการท่องเที่ยว จากการท่องเที่ยวแห่งประเทศไทย (ข้อมูลเป็นไฟล์เอกเซล)\n" +
+"   8. ↑ 8.0 8.1 8.2 8.3 รายละเอียดประเทศไทยจากเว็บซีไอเอ\n" +
+"   9. ↑ http://207.5.46.81/tat_news/detail.asp?id=963\n" +
+"  10. ↑ ข้อมูลจาก Webforum.org พ.ศ. 2546\n" +
+"\n" +
+"แหล่งข้อมูลอื่น\n" +
+"Commons\n" +
+"คอมมอนส์ มีภาพและสื่ออื่นๆ เกี่ยวกับ:\n" +
+"ประเทศไทย\n" +
+"ฟลิคเกอร์\n" +
+"ฟลิคเกอร์ มีรูปภาพเกี่ยวกับ: ประเทศไทย\n" +
+"\n" +
+"    * รัฐบาลไทย\n" +
+"    * การท่องเที่ยวแห่งประเทศไทย\n" +
+"    * ประเทศไทยศึกษา ห้องสมุดรัฐสภา สหรัฐอเมริกา\n" +
+"    * พจนานุกรมท่องเที่ยวไทย\n" +
+"    * แผนที่ประเทศไทย Longdo Map\n";
+
+function get_most_popular(text) {
+  var i;
+  var frequencies = new Object();
+  var letter;
+  for (i = 0; i < text.length; i++) {
+    letter = text.charAt(i);
+    if (typeof(frequencies[letter]) == 'undefined')
+      frequencies[letter] = 0;
+    frequencies[letter]++;
+  }
+  var most = [];
+  for (letter in frequencies) {
+    if (frequencies[letter] > 50) {
+      most.push(letter);
+    }
+  }
+  most.sort();
+  return most;
+}
+
+
+var languages = new Array(
+    chinese,     // 1
+    cyrillic,    // 2
+    devanagari,  // 3
+    english,     // 4
+    greek,       // 5
+    hebrew,      // 6
+    japanese,    // 7
+    korean,      // 8
+    persian,     // 9
+    source,      // 10
+    thai);       // 11
+
+
+var number_re = /[0-9]/;
+var latin_lc = "[a-zA\u0631]";
+assertEquals(7, latin_lc.length);
+var latin_lc_re = new RegExp(latin_lc);
+var latin_lc_re2 = new RegExp(/[a-zA\u0631]/);
+
+assertEquals(13793, chinese.length, "chinese utf8 in source");
+assertEquals(60606, cyrillic.length, "cyrillic utf8 in source");
+assertEquals(20203, devanagari.length, "devanagari utf8 in source");
+assertEquals(37505, english.length, "english utf8 in source");
+assertEquals(30052, greek.length, "greek utf8 in source");
+assertEquals(25640, hebrew.length, "hebrew utf8 in source");
+assertEquals(31082, japanese.length, "japanese utf8 in source");
+assertEquals(12291, korean.length, "korean utf8 in source");
+assertEquals(13851, persian.length, "persian utf8 in source");
+assertEquals(177470, source.length, "source utf8 in source");
+assertEquals(18315, thai.length, "thai utf8 in source");
+
+munged_sizes = new Array(17197, 2511, 2645, 3820, 3086, 2609,
+                         27231, 12972, 2014, 24943, 2773);
+
+
+var i = 0;
+for (idx in languages) {
+  i++;
+  var text = languages[idx];
+  assertTrue(latin_lc_re.test(text), "latin_lc" + i);
+  assertTrue(latin_lc_re2.test(text), "latin_lc" + i);
+  assertTrue(number_re.test(text), "number " + i);
+  var most_popular = get_most_popular(text);
+  var idx;
+  var re = "([x";
+  var last_c = -9999;
+  for (idx in most_popular) {
+    var c = most_popular[idx];
+    if ("^]-\n\\".indexOf(c) == -1) {
+      if (c.charCodeAt(0) > last_c &&
+          c.charCodeAt(0) - 20 < last_c) {
+        re += "-" + c;
+        last_c = -9999;
+      } else {
+        re += c;
+        last_c = c.charCodeAt(0);
+      }
+    }
+  }
+  re += "]+)";
+  var char_class = new RegExp(re, "g");
+  var munged = text.replace(char_class, "foo");
+  assertEquals(munged_sizes[i - 1], munged.length, "munged size " + i);
+}
+
+var thai_l_thingy = "\u0e44";
+var thai_l_regexp = new RegExp(thai_l_thingy);
+var thai_l_regexp2 = new RegExp("[" + thai_l_thingy + "]");
+assertTrue(thai_l_regexp.test(thai_l_thingy));
+assertTrue(thai_l_regexp2.test(thai_l_thingy));
+
+
diff --git a/regexp2000/test/mjsunit/unusual-constructor.js b/regexp2000/test/mjsunit/unusual-constructor.js
new file mode 100644 (file)
index 0000000..4e1ec2e
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var obj = new (Function.__proto__)();
+
+
+var threw = false;
+try {
+  obj.toString();
+} catch (e) {
+  assertInstanceof(e, TypeError);
+  threw = true;
+}
+assertTrue(threw);
diff --git a/regexp2000/test/mjsunit/uri.js b/regexp2000/test/mjsunit/uri.js
new file mode 100644 (file)
index 0000000..178ff1f
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests of URI encoding and decoding.
+
+assertEquals("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.!~*'();/?:@&=+$,#",
+             encodeURI("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.!~*'();/?:@&=+$,#"));
+
+var cc1 = 0x007D;
+var s1 = String.fromCharCode(cc1);
+var cc2 = 0x0000;
+var s2 = String.fromCharCode(cc2);
+var cc3 = 0x0080;
+var s3 = String.fromCharCode(cc3);
+var cc4 = 0x0555;
+var s4 = String.fromCharCode(cc4);
+var cc5 = 0x07FF;
+var s5 = String.fromCharCode(cc5);
+var cc6 = 0x0800;
+var s6 = String.fromCharCode(cc6);
+var cc7 = 0xAEEE;
+var s7 = String.fromCharCode(cc7);
+var cc8_1 = 0xD800;
+var cc8_2 = 0xDC00;
+var s8 = String.fromCharCode(cc8_1)+String.fromCharCode(cc8_2);
+var cc9_1 = 0xDBFF;
+var cc9_2 = 0xDFFF;
+var s9 = String.fromCharCode(cc9_1)+String.fromCharCode(cc9_2);
+var cc10 = 0xE000;
+var s10 = String.fromCharCode(cc10);
+
+assertEquals('%7D', encodeURI(s1));
+assertEquals('%00', encodeURI(s2));
+assertEquals('%C2%80', encodeURI(s3));
+assertEquals('%D5%95', encodeURI(s4));
+assertEquals('%DF%BF', encodeURI(s5));
+assertEquals('%E0%A0%80', encodeURI(s6));
+assertEquals('%EA%BB%AE', encodeURI(s7));
+assertEquals('%F0%90%80%80', encodeURI(s8));
+assertEquals('%F4%8F%BF%BF', encodeURI(s9));
+assertEquals('%EE%80%80', encodeURI(s10));
+
+assertEquals(cc1, decodeURI(encodeURI(s1)).charCodeAt(0));
+assertEquals(cc2, decodeURI(encodeURI(s2)).charCodeAt(0));
+assertEquals(cc3, decodeURI(encodeURI(s3)).charCodeAt(0));
+assertEquals(cc4, decodeURI(encodeURI(s4)).charCodeAt(0));
+assertEquals(cc5, decodeURI(encodeURI(s5)).charCodeAt(0));
+assertEquals(cc6, decodeURI(encodeURI(s6)).charCodeAt(0));
+assertEquals(cc7, decodeURI(encodeURI(s7)).charCodeAt(0));
+assertEquals(cc8_1, decodeURI(encodeURI(s8)).charCodeAt(0));
+assertEquals(cc8_2, decodeURI(encodeURI(s8)).charCodeAt(1));
+assertEquals(cc9_1, decodeURI(encodeURI(s9)).charCodeAt(0));
+assertEquals(cc9_2, decodeURI(encodeURI(s9)).charCodeAt(1));
+assertEquals(cc10, decodeURI(encodeURI(s10)).charCodeAt(0));
diff --git a/regexp2000/test/mjsunit/value-callic-prototype-change.js b/regexp2000/test/mjsunit/value-callic-prototype-change.js
new file mode 100644 (file)
index 0000000..52f0629
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that the inline caches correctly detect that constant
+// functions on value prototypes change.
+
+function testString() {
+  function f(s, expected) {
+    var result = s.toString();
+    assertEquals(expected, result);
+  };
+
+  for (var i = 0; i < 10; i++) {
+    var s = String.fromCharCode(i);
+    f(s, s);
+  }
+
+  String.prototype.toString = function() { return "ostehaps"; };
+
+  for (var i = 0; i < 10; i++) {
+    var s = String.fromCharCode(i);
+    f(s, "ostehaps");
+  }
+}
+
+testString();
+
+
+function testNumber() {
+  Number.prototype.toString = function() { return 0; };
+
+  function f(n, expected) {
+    var result = n.toString();
+    assertEquals(expected, result);
+  };
+
+  for (var i = 0; i < 10; i++) {
+    f(i, 0);
+  }
+
+  Number.prototype.toString = function() { return 42; };
+
+  for (var i = 0; i < 10; i++) {
+    f(i, 42);
+  }
+}
+
+testNumber();
+
+
+function testBoolean() {
+  Boolean.prototype.toString = function() { return 0; };
+
+  function f(b, expected) {
+    var result = b.toString();
+    assertEquals(expected, result);
+  };
+
+  for (var i = 0; i < 10; i++) {
+    f((i % 2 == 0), 0);
+  }
+
+  Boolean.prototype.toString = function() { return 42; };
+
+  for (var i = 0; i < 10; i++) {
+    f((i % 2 == 0), 42);
+  }
+}
+
+testBoolean();
diff --git a/regexp2000/test/mjsunit/var.js b/regexp2000/test/mjsunit/var.js
new file mode 100644 (file)
index 0000000..5999d70
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertTrue(!x && typeof x == 'undefined');
+assertTrue(!y && typeof y == 'undefined');
+if (false) { var x = 42; }
+if (true)  { var y = 87; }
+assertTrue(!x && typeof x == 'undefined');
+assertEquals(87, y);
+
+assertTrue(!z && typeof z == 'undefined');
+if (false) { var z; }
+assertTrue(!z && typeof z == 'undefined');
diff --git a/regexp2000/test/mjsunit/with-function-expression.js b/regexp2000/test/mjsunit/with-function-expression.js
new file mode 100644 (file)
index 0000000..17de817
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var source = "(function x() { with({}) { return '' + x; } })()";
+
+// Don't throw exceptions.
+assertDoesNotThrow(source);
+
+// Check that the return value is a function.  Use regexp to avoid
+// depending on the exact printing of the function.
+var regexp = /function/;
+var res = assertTrue(eval(source).match(regexp) == 'function');
diff --git a/regexp2000/test/mjsunit/with-leave.js b/regexp2000/test/mjsunit/with-leave.js
new file mode 100644 (file)
index 0000000..ded62ca
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+L: with ({x:12}) {
+  assertEquals(12, x);
+  break L;
+  assertTrue(false);
+}
+
+do {
+  with ({x:15}) {
+    assertEquals(15, x);
+    continue;
+    assertTrue(false);
+  }
+} while (false);
+
+var caught = false;
+try {
+  with ({x:18}) { throw 25; assertTrue(false); }
+} catch (e) {
+  caught = true;
+  assertEquals(25, e);
+  with ({y:19}) {
+    assertEquals(19, y);
+    try {
+      // NOTE: This checks that the object containing x has been
+      // removed from the context chain.
+      x;
+      assertTrue(false);  // should not reach here
+    } catch (e2) {
+      assertTrue(e2 instanceof ReferenceError);
+    }
+  }
+}
+assertTrue(caught);
+
diff --git a/regexp2000/test/mjsunit/with-parameter-access.js b/regexp2000/test/mjsunit/with-parameter-access.js
new file mode 100644 (file)
index 0000000..747da22
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Return a parameter from inside a with statement.
+function f(x) {
+  with ({}) {
+    return x;
+  }
+}
+
+assertEquals(5, f(5));
+
+
+function g(x) {
+  function h() {
+    with ({}) {
+      return x;
+    }
+  }
+  return h();
+}
+
+assertEquals(7, g(7));
diff --git a/regexp2000/test/mjsunit/with-value.js b/regexp2000/test/mjsunit/with-value.js
new file mode 100644 (file)
index 0000000..a4da1fa
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Values used in 'with' statements should be wrapped in an object
+// before establishing the context.
+(function() {
+  // 7 should be converted to an number object
+  with (7) { assertTrue(typeof valueOf == 'function'); }
+})();
+
+/* This should be fairly easy again. May need some work in the
+compiler's VisitWith() function, or perhaps the runtime routine's
+PushContextForWith().
+*/
\ No newline at end of file
diff --git a/regexp2000/test/mozilla/mozilla.status b/regexp2000/test/mozilla/mozilla.status
new file mode 100644 (file)
index 0000000..46ecc48
--- /dev/null
@@ -0,0 +1,801 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This file is up to date with respect to Mozilla's CVS repository as of
+# 2008-09-02.  If new tests are added to Mozilla's CVS it may need to be
+# updated.
+
+# To get the mozilla tests:
+# cd /path/to/checkout/test/mozilla
+# rm -rf data
+# cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -D 2008-09-02 mozilla/js/tests
+# mv mozilla/js/tests data
+# rm -rf mozilla
+
+# --------------------------------------------------------------------
+# If you add a test case to this file, please try to provide
+# an explanation of why the test fails; this may ease future
+# debugging.
+# --------------------------------------------------------------------
+
+prefix mozilla
+def FAIL_OK = FAIL, OKAY
+
+##################### SKIPPED TESTS #####################
+
+# This test checks that we behave properly in an out-of-memory
+# situation.  The test fails in V8 with an exception and takes a long
+# time to do so.
+js1_5/Regress/regress-271716-n: SKIP
+
+
+##################### SLOW TESTS #####################
+
+# This takes a long time to run (~100 seconds). It should only be run
+# by the really patient.
+js1_5/GC/regress-324278: SLOW
+
+# This takes a long time to run because our indexOf operation is
+# pretty slow - it causes a lot of GCs; see issue
+# #926379. We could consider marking this SKIP because it takes a
+# while to run to completion.
+js1_5/GC/regress-338653: SLOW
+
+# This test is designed to run until it runs out of memory. This takes
+# a very long time because it builds strings character by character
+# and compiles a lot of regular expressions. We could consider marking
+# this SKIP because it takes a while to run to completion.
+js1_5/GC/regress-346794: SLOW
+
+# Runs out of memory while trying to build huge string of 'x'
+# characters. This takes a long time to run (~32 seconds).
+js1_5/GC/regress-348532: SLOW
+
+
+##################### FLAKY TESTS #####################
+
+# These tests time out in debug mode but pass in product mode
+js1_5/Regress/regress-280769-3: PASS || FAIL if $mode == debug
+js1_5/Regress/regress-203278-1: PASS || FAIL if $mode == debug
+js1_5/GC/regress-203278-2: PASS || FAIL if $mode == debug
+js1_5/Regress/regress-244470: PASS || FAIL if $mode == debug
+ecma_3/RegExp/regress-209067: PASS || FAIL if $mode == debug
+js1_5/GC/regress-278725: PASS || FAIL if $mode == debug
+js1_5/Regress/regress-360969-03: PASS || FAIL if $mode == debug
+js1_5/Regress/regress-360969-04: PASS || FAIL if $mode == debug
+js1_5/Regress/regress-360969-05: PASS || FAIL if $mode == debug
+js1_5/Regress/regress-360969-06: PASS || FAIL if $mode == debug
+js1_5/extensions/regress-365527: PASS || FAIL if $mode == debug
+# http://b/issue?id=1206983
+js1_5/Regress/regress-367561-03: PASS || FAIL if $mode == debug
+ecma/Date/15.9.5.10-2: PASS || FAIL if $mode == debug
+
+# These tests create two Date objects just after each other and
+# expects them to match.  Sometimes this happens on the border
+# between one second and the next.
+ecma/Date/15.9.2.1: PASS || FAIL
+ecma/Date/15.9.2.2-1: PASS || FAIL
+ecma/Date/15.9.2.2-2: PASS || FAIL
+ecma/Date/15.9.2.2-3: PASS || FAIL
+ecma/Date/15.9.2.2-4: PASS || FAIL
+ecma/Date/15.9.2.2-5: PASS || FAIL
+ecma/Date/15.9.2.2-6: PASS || FAIL
+
+# 1026139: These date tests fail on arm
+ecma/Date/15.9.5.29-1: PASS || ($ARM && FAIL)
+ecma/Date/15.9.5.34-1: PASS || ($ARM && FAIL)
+ecma/Date/15.9.5.28-1: PASS || ($ARM && FAIL)
+
+# 1050186: Arm vm is broken; probably unrelated to dates
+ecma/Array/15.4.4.5-3: PASS || ($ARM && FAIL)
+ecma/Date/15.9.5.22-2: PASS || ($ARM && FAIL)
+
+# Severely brain-damaged test. Access to local variables must not
+# be more than 2.5 times faster than access to global variables? WTF?
+js1_5/Regress/regress-169559: PASS || FAIL
+
+
+# Test that rely on specific timezone (not working in Denmark).
+js1_5/Regress/regress-58116: PASS || FAIL
+
+
+# Flaky random() test. Tests the distribution of calls to Math.random().
+js1_5/Regress/regress-211590: PASS || FAIL
+
+
+# Flaky tests; expect BigO-order computations to yield 1, but the code
+# cannot handle outliers. See bug #925864.
+ecma_3/RegExp/regress-311414: PASS || FAIL
+ecma_3/RegExp/regress-289669: PASS || FAIL
+js1_5/String/regress-314890: PASS || FAIL
+js1_5/String/regress-56940-01: PASS || FAIL
+js1_5/String/regress-56940-02: PASS || FAIL
+js1_5/String/regress-157334-01: PASS || FAIL
+js1_5/String/regress-322772: PASS || FAIL
+js1_5/Array/regress-99120-01: PASS || FAIL
+js1_5/Array/regress-99120-02: PASS || FAIL
+js1_5/Regress/regress-347306-01: PASS || FAIL
+js1_5/Regress/regress-416628: PASS || FAIL
+
+
+# The following two tests assume that daylight savings time starts first Sunday
+# in April. This is not true when executing the tests outside California!
+# In Denmark the adjustment starts one week earlier!.
+# Tests based on shell that use dates in this gap are flaky.
+ecma/Date/15.9.5.10-1: PASS || FAIL
+ecma/Date/15.9.5.12-1: PASS || FAIL
+ecma/Date/15.9.5.14: PASS || FAIL
+ecma/Date/15.9.5.34-1: PASS || FAIL
+
+
+# These tests sometimes pass (in particular on Windows). They build up
+# a lot of stuff on the stack, which normally causes a stack overflow,
+# but sometimes it makes it through?
+js1_5/Regress/regress-290575: PASS || FAIL
+js1_5/Regress/regress-98901: PASS || FAIL
+
+
+# Tests that sorting arrays of ints is less than 3 times as fast
+# as sorting arrays of strings.
+js1_5/extensions/regress-371636: PASS || FAIL
+
+
+# Tests depend on GC timings. Inherently flaky.
+js1_5/GC/regress-383269-01: PASS || FAIL
+js1_5/GC/regress-383269-02: PASS || FAIL
+js1_5/Regress/regress-404755: PASS || FAIL
+
+
+# Test that depends on timer resolution. Fails every now and then
+# if we're unlucky enough to get a context switch at a bad time.
+js1_5/extensions/regress-363258: PASS || FAIL
+
+
+
+##################### INCOMPATIBLE TESTS #####################
+
+# This section is for tests that fail in both V8 and KJS.  Thus they
+# have been determined to be incompatible between Mozilla and V8/KJS.
+
+# Fail because of toLowerCase and toUpperCase conversion.
+ecma/String/15.5.4.11-2: FAIL_OK
+ecma/String/15.5.4.11-5: FAIL_OK
+ecma/String/15.5.4.12-1: FAIL_OK
+ecma/String/15.5.4.12-4: FAIL_OK
+
+# This test uses an older version of the unicode standard that fails
+# us because we correctly convert the armenian small ligature ech-yiwn
+# to the two upper-case characters ECH and YIWN, whereas the older
+# unicode version converts it to itself.
+ecma/String/15.5.4.12-5: FAIL_OK
+
+# Creates a linked list of arrays until we run out of memory.
+js1_5/Regress/regress-312588: FAIL_OK
+
+
+# Runs out of memory because it compiles huge functions.
+js1_5/Function/regress-338001: FAIL_OK
+js1_5/Function/regress-338121-01: FAIL_OK
+js1_5/Function/regress-338121-02: FAIL_OK
+js1_5/Function/regress-338121-03: FAIL_OK
+
+
+# Length of objects whose prototype chain includes a function
+ecma_3/Function/regress-313570: FAIL_OK
+
+
+#:=== RegExp:=== 
+# To be compatible with KJS we silently ignore flags that do not make
+# sense.  This test expects us to throw exceptions.  
+ecma_3/RegExp/regress-57631: FAIL_OK
+
+# PCRE doesn't allow subpattern nesting deeper than 200, this tests
+# depth 500.  KJS detects the case, and return null from the match,
+# and passes this test (the test doesn't check for a correct return
+# value).
+ecma_3/RegExp/regress-119909: FAIL_OK
+
+
+# Difference in the way capturing subpatterns work.  In JS, when the
+# 'minimum repeat count' is reached, the empty string must not match.
+# In this case, we are similar but not identical to KJS.  Hard to
+# support the JS behavior with PCRE, so maybe emulate KJS?
+#
+# Note: We do not support toSource currently so we cannot run this
+# test. We should make an isolated test case for the regexp issue.
+ecma_3/RegExp/regress-209919: FAIL_OK
+
+
+# PCRE's match limit is reached.  SpiderMonkey hangs on the first one,
+# KJS returns true somehow.  Maybe they up the match limit?  There is
+# an open V8 bug 676063 about this.
+ecma_3/RegExp/regress-330684: FAIL_OK
+
+
+# We do not detect overflow in bounds for back references and {}
+# quantifiers.  Might fix by parsing numbers differently?
+js1_5/Regress/regress-230216-2: FAIL_OK
+
+
+# According to ECMA-262, \b is a 'word' boundary, where words are only
+# ASCII characters.  PCRE supports non-ASCII word characters.
+js1_5/Regress/regress-247179: FAIL_OK
+
+
+# Regexp too long for PCRE.
+js1_5/Regress/regress-280769: FAIL_OK
+js1_5/Regress/regress-280769-1: FAIL_OK
+js1_5/Regress/regress-280769-2: FAIL_OK
+js1_5/Regress/regress-280769-4: FAIL_OK
+js1_5/Regress/regress-280769-5: FAIL_OK
+
+
+# We do not support static RegExp.multiline - should we?.
+js1_2/regexp/RegExp_multiline: FAIL_OK
+js1_2/regexp/RegExp_multiline_as_array: FAIL_OK
+js1_2/regexp/beginLine: FAIL_OK
+js1_2/regexp/endLine: FAIL_OK
+
+
+# Date trouble?
+js1_5/Date/regress-301738-02: FAIL_OK
+
+
+# This test fails for all browsers on in the CET timezone.
+ecma/Date/15.9.5.35-1: PASS || FAIL_OK
+
+
+# Spidermonkey allows stuff in parenthesis directly after the minutes
+# in a date.  KJS does not, so we don't either.
+js1_5/Date/regress-309925-02: FAIL_OK
+
+
+# Print string after deleting array element?
+js1_5/Expressions/regress-96526-delelem: FAIL_OK
+
+
+# Stack overflows should be InternalError: too much recursion?
+js1_5/Regress/regress-234389: FAIL_OK
+
+
+# This may very well be a bogus test. I'm not sure yet.
+js1_5/Regress/regress-320119: FAIL_OK
+
+
+# We do not support explicit global evals through <global>.eval(...).
+js1_5/Regress/regress-68498-003: FAIL_OK
+
+
+# No support for toSource().
+js1_5/Regress/regress-248444: FAIL_OK
+js1_5/Regress/regress-313967-01: FAIL_OK
+js1_5/Regress/regress-313967-02: FAIL_OK
+
+# This fails because we don't have stack space for Function.prototype.apply
+# with very large numbers of arguments.  The test uses 2^24 arguments.
+js1_5/Array/regress-350256-03: FAIL_OK
+
+
+# Extra arguments not handled properly in String.prototype.match
+js1_5/Regress/regress-179524: FAIL_OK
+
+
+# Uncategorized failures. Please help categorize (or fix) these failures.
+js1_5/Regress/regress-172699: FAIL_OK
+
+
+# Calls regexp objects with function call syntax; non-ECMA behavior.
+js1_2/Objects/toString-001: FAIL_OK
+
+
+# Assumes that the prototype of a function is enumerable. Non-ECMA,
+# see section 15.3.3.1, page 86.
+ecma/GlobalObject/15.1.2.2-1: FAIL_OK
+ecma/GlobalObject/15.1.2.3-1: FAIL_OK
+ecma/GlobalObject/15.1.2.4: FAIL_OK
+ecma/GlobalObject/15.1.2.5-1: FAIL_OK
+ecma/GlobalObject/15.1.2.6: FAIL_OK
+ecma/GlobalObject/15.1.2.7: FAIL_OK
+
+
+# Tests that rely on specific details of function decompilation or
+# print strings for errors. Non-ECMA behavior.
+js1_2/function/tostring-2: FAIL_OK
+js1_5/Exceptions/regress-332472: FAIL_OK
+js1_5/Regress/regress-173067: FAIL_OK
+js1_5/Regress/regress-355556: FAIL_OK
+js1_5/Regress/regress-328664: FAIL_OK
+js1_5/Regress/regress-252892: FAIL_OK
+js1_5/Regress/regress-352208: FAIL_OK
+ecma_3/Array/15.4.5.1-01: FAIL_OK
+ecma_3/Array/regress-387501: FAIL_OK
+ecma_3/LexicalConventions/7.9.1: FAIL_OK
+ecma_3/RegExp/regress-375711: FAIL_OK
+ecma_3/Unicode/regress-352044-01: FAIL_OK
+ecma_3/extensions/regress-274152: FAIL_OK
+js1_5/Regress/regress-372364: FAIL_OK
+js1_5/Regress/regress-420919: FAIL_OK
+js1_5/Regress/regress-422348: FAIL_OK
+js1_5/Regress/regress-410852: FAIL_OK
+ecma_3/RegExp/regress-375715-04: FAIL_OK
+
+
+# Tests that use uneval.  Non-ECMA.
+js1_5/GC/regress-418128: FAIL_OK
+
+
+# Tests that use __count__.  Non-ECMA.
+js1_5/extensions/regress-434837-01: FAIL_OK
+
+
+# Tests that use the watch method.  Non-ECMA.
+js1_5/extensions/regress-435345-01: FAIL_OK
+
+
+# The spec specifies reverse evaluation order for < and >=.
+# See section 11.8.2 and 11.8.5.
+# We implement the spec here but the test tests the more straigtforward order.
+ecma_3/Operators/order-01: FAIL_OK
+
+
+# Uses Mozilla-specific QName, XML, XMLList and Iterator.
+js1_5/Regress/regress-407323: FAIL_OK
+js1_5/Regress/regress-407957: FAIL_OK
+
+
+# Relies on JavaScript 1.2 / 1.3 deprecated features.
+js1_2/function/String: FAIL_OK
+js1_2/operator/equality: FAIL_OK
+js1_2/version120/boolean-001: FAIL_OK
+js1_2/String/concat: FAIL_OK
+js1_2/function/Function_object: FAIL_OK
+js1_2/function/tostring-1: FAIL_OK
+js1_2/version120/regress-99663: FAIL_OK
+js1_2/regexp/RegExp_lastIndex: FAIL_OK
+js1_2/regexp/string_split: FAIL_OK
+
+
+# We do not check for bad surrogate pairs when quoting strings.
+js1_5/Regress/regress-315974: FAIL_OK
+
+
+# Use unsupported "watch".
+js1_5/Regress/regress-213482: FAIL_OK
+js1_5/Regress/regress-240577: FAIL_OK
+js1_5/Regress/regress-355344: FAIL_OK
+js1_5/Object/regress-362872-01: FAIL_OK
+js1_5/Object/regress-362872-02: FAIL_OK
+js1_5/Regress/regress-361467: FAIL_OK
+js1_5/Regress/regress-385393-06: FAIL_OK
+
+
+# Use special Mozilla getter/setter syntax
+js1_5/Regress/regress-354924: FAIL_OK
+js1_5/Regress/regress-355341: FAIL_OK
+js1_5/GC/regress-316885-01: FAIL_OK
+js1_5/GetSet/getset-002: FAIL_OK
+js1_5/GetSet/regress-353264: FAIL_OK
+js1_5/Regress/regress-361617: FAIL_OK
+js1_5/Regress/regress-362583: FAIL_OK
+js1_5/extensions/regress-356378: FAIL_OK
+
+
+# 'native' *is* a keyword in V8.
+js1_5/Regress/regress-240317: FAIL_OK
+
+
+# Requires Mozilla-specific strict mode or options() function.
+ecma_3/Object/8.6.1-01: FAIL_OK
+js1_5/Exceptions/regress-315147: FAIL_OK
+js1_5/Regress/regress-106244: FAIL_OK
+js1_5/Regress/regress-317533: FAIL_OK
+js1_5/Regress/regress-323314-1: FAIL_OK
+js1_5/Regress/regress-352197: FAIL_OK
+js1_5/Regress/regress-115436: FAIL_OK
+js1_5/Regress/regress-214761: FAIL_OK
+js1_5/Regress/regress-253150: FAIL_OK
+js1_5/Regress/regress-306727: FAIL_OK
+js1_5/Regress/regress-308566: FAIL_OK
+js1_5/Regress/regress-312260: FAIL_OK
+js1_5/Regress/regress-322430: FAIL_OK
+js1_5/Regress/regress-383674: FAIL_OK
+
+
+# Equivalent to assert(false).
+ecma_2/RegExp/exec-001: FAIL_OK
+ecma_2/String/replace-001: FAIL_OK
+
+
+# We do not strip unicode format control characters. This is really
+# required for working with non-latin character sets.  We match KJS
+# and IE here.  Firefox matches the spec (section 7.1).
+ecma_3/Unicode/uc-001: FAIL_OK
+
+
+# A non-breaking space doesn't match \s in a regular expression.  This behaviour
+# matches KJS.  All the VMs have different behaviours in which characters match
+# \s so we do the same as KJS until they change.
+ecma_3/Unicode/uc-002: FAIL_OK
+
+
+# String.prototype.split on empty strings always returns an array
+# with one element (as specified in ECMA-262).
+js1_2/Array/array_split_1: FAIL_OK
+
+
+# The concat() method is defined in Array.prototype; not Array.
+js1_5/Array/regress-313153: FAIL_OK
+
+
+# Properties stack, fileName, and lineNumber of Error instances are
+# not supported. Mozilla specific extension.
+js1_5/Exceptions/errstack-001: FAIL_OK
+js1_5/Exceptions/regress-257751: FAIL_OK
+js1_5/Regress/regress-119719: FAIL_OK
+js1_5/Regress/regress-139316: FAIL_OK
+js1_5/Regress/regress-167328: FAIL_OK
+js1_5/Regress/regress-243869: FAIL_OK
+
+
+# Unsupported import/export and <xml> literals. Mozilla extensions.
+js1_5/Regress/regress-249211: FAIL_OK
+js1_5/Regress/regress-309242: FAIL_OK
+js1_5/Regress/regress-350692: FAIL_OK
+
+
+# The length of Error functions is 1 not 3.
+js1_5/Exceptions/regress-123002: FAIL_OK
+
+
+# Reserved keywords as function names, etc is not supported.
+js1_5/LexicalConventions/regress-343675: FAIL_OK
+
+
+# Unsupported list comprehensions: [ ... for ... ] and for each.
+js1_5/Regress/regress-352009: FAIL_OK
+js1_5/Regress/regress-349648: FAIL_OK
+
+
+# Expects top level arguments (passed on command line?) to be
+# the empty string?
+js1_5/Regress/regress-336100: FAIL_OK
+
+
+# Regular expression test failures due to PCRE. We match KJS (ie, perl)
+# behavior and not the ECMA spec.
+ecma_3/RegExp/15.10.2-1: FAIL_OK
+ecma_3/RegExp/perlstress-001: FAIL_OK
+ecma_3/RegExp/regress-334158: FAIL_OK
+
+
+# This test requires a failure if we try to compile a function with more
+# than 65536 arguments.  This seems to be a Mozilla restriction.
+js1_5/Regress/regress-290575: FAIL_OK
+
+
+# Fails because of the way function declarations are
+# handled in V8/KJS. V8 follows IE behavior and introduce
+# all nested function declarations when entering the
+# surrounding function, whereas Spidermonkey declares
+# them dynamically when the statement is executed.
+ecma_3/Function/scope-001: FAIL_OK
+ecma_3/FunExpr/fe-001: FAIL_OK
+js1_5/Scope/regress-184107: FAIL_OK
+
+
+# Function is deletable in V8 and KJS.
+js1_5/Regress/regress-352604: FAIL_OK
+
+
+# Cannot call strings as functions. Expects not to crash.
+js1_5/Regress/regress-417893: FAIL_OK
+
+
+
+##################### FAILING TESTS #####################
+
+# This section is for tests that fail in V8 and pass in KJS.
+# Tests that fail in both V8 and KJS belong in the FAIL_OK
+# category.
+
+# This fails because we don't handle Function.prototype.apply with very large
+# numbers of arguments (depending on max stack size).  350256-02 needs more than
+# 4Mbytes of stack space.
+js1_5/Array/regress-350256-02: FAIL
+
+
+# This fails because 'delete arguments[i]' does not disconnect the
+# argument from the arguments array.  See issue #900066.
+ecma_3/Function/regress-137181: FAIL
+
+
+# Calls regexp objects with function call syntax; non-ECMA behavior.
+ecma_2/RegExp/regress-001: FAIL
+js1_2/regexp/regress-6359: FAIL
+js1_2/regexp/regress-9141: FAIL
+js1_5/Regress/regress-224956: FAIL
+js1_5/Regress/regress-325925: FAIL
+js1_2/regexp/simple_form: FAIL
+
+
+# Tests that rely on specific details of function decompilation or
+# print strings for errors. Non-ECMA behavior.
+js1_4/Regress/function-003: FAIL
+
+
+# Relies on JavaScript 1.2 / 1.3 deprecated features.
+js1_2/function/regexparg-1: FAIL
+
+
+# 'export' and 'import' are not keywords in V8.
+ecma_2/Exceptions/lexical-010: FAIL
+ecma_2/Exceptions/lexical-022: FAIL
+
+
+# Requires Mozilla-specific strict mode.
+ecma_2/Exceptions/lexical-011: FAIL
+ecma_2/Exceptions/lexical-014: FAIL
+ecma_2/Exceptions/lexical-016: FAIL
+ecma_2/Exceptions/lexical-021: FAIL
+ecma_2/LexicalConventions/keywords-001: FAIL
+js1_5/Regress/regress-306633: FAIL
+
+
+# This test seems designed to fail (it produces a 700Mbyte string).
+# We fail on out of memory.  The important thing is not to crash.
+js1_5/Regress/regress-303213: FAIL
+
+
+# Bug 1193440: Ignore Unicode BOM characters when scanning.
+ecma_3/extensions/regress-368516: FAIL
+
+# Bug 1202592:New ecma_3/String/15.5.4.11 is failing.
+ecma_3/String/15.5.4.11: FAIL
+
+# Bug 1202597: New js1_5/Expressions/regress-394673 is failing.
+# Marked as: Will not fix. V8 throws an acceptable RangeError.
+js1_5/Expressions/regress-394673: FAIL
+
+# Bug 1202598: New mozilla test js1_5/Regress/regress-383682 fails.
+js1_5/Regress/regress-383682: FAIL
+
+
+##################### MOZILLA EXTENSION TESTS #####################
+
+ecma/extensions/15.1.2.1-1: FAIL_OK
+ecma_3/extensions/regress-385393-03: FAIL_OK
+ecma_3/extensions/7.9.1: FAIL_OK
+js1_5/extensions/catchguard-001: FAIL_OK
+js1_5/extensions/catchguard-002: FAIL_OK
+js1_5/extensions/catchguard-003: FAIL_OK
+js1_5/extensions/getset-001: FAIL_OK
+js1_5/extensions/getset-003: FAIL_OK
+js1_5/extensions/no-such-method: FAIL_OK
+js1_5/extensions/regress-104077: FAIL_OK
+js1_5/extensions/regress-226078: FAIL_OK
+js1_5/extensions/regress-303277: FAIL_OK
+js1_5/extensions/regress-304897: FAIL_OK
+js1_5/extensions/regress-306738: FAIL_OK
+js1_5/extensions/regress-311161: FAIL_OK
+js1_5/extensions/regress-311583: FAIL_OK
+js1_5/extensions/regress-311792-01: FAIL_OK
+js1_5/extensions/regress-312278: FAIL_OK
+js1_5/extensions/regress-313630: FAIL_OK
+js1_5/extensions/regress-313763: FAIL_OK
+js1_5/extensions/regress-313803: FAIL_OK
+js1_5/extensions/regress-314874: FAIL_OK
+js1_5/extensions/regress-322957: FAIL_OK
+js1_5/extensions/regress-328556: FAIL_OK
+js1_5/extensions/regress-330569: FAIL_OK
+js1_5/extensions/regress-333541: FAIL_OK
+js1_5/extensions/regress-335700: FAIL_OK
+js1_5/extensions/regress-336409-1: FAIL_OK
+js1_5/extensions/regress-336409-2: FAIL_OK
+js1_5/extensions/regress-336410-1: FAIL_OK
+js1_5/extensions/regress-336410-2: FAIL_OK
+js1_5/extensions/regress-341956-01: FAIL_OK
+js1_5/extensions/regress-341956-02: FAIL_OK
+js1_5/extensions/regress-341956-03: FAIL_OK
+js1_5/extensions/regress-342960: FAIL_OK
+js1_5/extensions/regress-345967: FAIL_OK
+js1_5/extensions/regress-346494-01: FAIL_OK
+js1_5/extensions/regress-346494: FAIL_OK
+js1_5/extensions/regress-347306-02: FAIL_OK
+js1_5/extensions/regress-348986: FAIL_OK
+js1_5/extensions/regress-349616: FAIL_OK
+js1_5/extensions/regress-350312-02: FAIL_OK
+js1_5/extensions/regress-350312-03: FAIL_OK
+js1_5/extensions/regress-350531: FAIL_OK
+js1_5/extensions/regress-351102-01: FAIL_OK
+js1_5/extensions/regress-351102-02: FAIL_OK
+js1_5/extensions/regress-351102-06: FAIL_OK
+js1_5/extensions/regress-351448: FAIL_OK
+js1_5/extensions/regress-351973: FAIL_OK
+js1_5/extensions/regress-352060: FAIL_OK
+js1_5/extensions/regress-352094: FAIL_OK
+js1_5/extensions/regress-352261: FAIL_OK
+js1_5/extensions/regress-352281: FAIL_OK
+js1_5/extensions/regress-352372: FAIL_OK
+js1_5/extensions/regress-352455: FAIL_OK
+js1_5/extensions/regress-352604: FAIL_OK
+js1_5/extensions/regress-353214: FAIL_OK
+js1_5/extensions/regress-355339: FAIL_OK
+js1_5/extensions/regress-355497: FAIL_OK
+js1_5/extensions/regress-355622: FAIL_OK
+js1_5/extensions/regress-355736: FAIL_OK
+js1_5/extensions/regress-356085: FAIL_OK
+js1_5/extensions/regress-356106: FAIL_OK
+js1_5/extensions/regress-358594-01: FAIL_OK
+js1_5/extensions/regress-358594-02: FAIL_OK
+js1_5/extensions/regress-358594-03: FAIL_OK
+js1_5/extensions/regress-358594-04: FAIL_OK
+js1_5/extensions/regress-358594-05: FAIL_OK
+js1_5/extensions/regress-358594-06: FAIL_OK
+js1_5/extensions/regress-361346: FAIL_OK
+js1_5/extensions/regress-361360: FAIL_OK
+js1_5/extensions/regress-361558: FAIL_OK
+js1_5/extensions/regress-361571: FAIL_OK
+js1_5/extensions/regress-361856: FAIL_OK
+js1_5/extensions/regress-361964: FAIL_OK
+js1_5/extensions/regress-363988: FAIL_OK
+js1_5/extensions/regress-365869: FAIL_OK
+js1_5/extensions/regress-367630: FAIL_OK
+js1_5/extensions/regress-367923: FAIL_OK
+js1_5/extensions/regress-368859: FAIL_OK
+js1_5/extensions/regress-374589: FAIL_OK
+js1_5/extensions/regress-375801: FAIL_OK
+js1_5/extensions/regress-376052: FAIL_OK
+js1_5/extensions/regress-379523: FAIL_OK
+js1_5/extensions/regress-380581: FAIL_OK
+js1_5/extensions/regress-380831: FAIL_OK
+js1_5/extensions/regress-381205: FAIL_OK
+js1_5/extensions/regress-381211: FAIL_OK
+js1_5/extensions/regress-381304: FAIL_OK
+js1_5/extensions/regress-382509: FAIL_OK
+js1_5/extensions/regress-383965: FAIL_OK
+js1_5/extensions/regress-384680: FAIL_OK
+js1_5/extensions/regress-385393-09: FAIL_OK
+js1_5/extensions/regress-407501: FAIL_OK
+js1_5/extensions/regress-418730: FAIL_OK
+js1_5/extensions/regress-420612: FAIL_OK
+js1_5/extensions/regress-420869-01: FAIL_OK
+js1_5/extensions/regress-424257: FAIL_OK
+js1_5/extensions/regress-424683-01: FAIL_OK
+js1_5/extensions/regress-44009: FAIL_OK
+js1_5/extensions/regress-50447-1: FAIL_OK
+js1_5/extensions/regress-50447: FAIL_OK
+js1_5/extensions/regress-90596-001: FAIL_OK
+js1_5/extensions/regress-90596-002: FAIL_OK
+js1_5/extensions/regress-96284-001: FAIL_OK
+js1_5/extensions/regress-96284-002: FAIL_OK
+js1_5/extensions/scope-001: FAIL_OK
+js1_5/extensions/toLocaleFormat-01: FAIL_OK
+js1_5/extensions/toLocaleFormat-02: FAIL_OK
+
+
+##################### DECOMPILATION TESTS #####################
+
+# We don't really about the outcome of running the
+# decompilation tests as long as they don't crash or
+# timeout.
+
+js1_5/decompilation/regress-344120: PASS || FAIL
+js1_5/decompilation/regress-346892: PASS || FAIL
+js1_5/decompilation/regress-346902: PASS || FAIL
+js1_5/decompilation/regress-346904: PASS || FAIL
+js1_5/decompilation/regress-346915: PASS || FAIL
+js1_5/decompilation/regress-349484: PASS || FAIL
+js1_5/decompilation/regress-349489: PASS || FAIL
+js1_5/decompilation/regress-349491: PASS || FAIL
+js1_5/decompilation/regress-349596: PASS || FAIL
+js1_5/decompilation/regress-349650: PASS || FAIL
+js1_5/decompilation/regress-349663: PASS || FAIL
+js1_5/decompilation/regress-350242: PASS || FAIL
+js1_5/decompilation/regress-350263: PASS || FAIL
+js1_5/decompilation/regress-350271: PASS || FAIL
+js1_5/decompilation/regress-350666: PASS || FAIL
+js1_5/decompilation/regress-350670: PASS || FAIL
+js1_5/decompilation/regress-351104: PASS || FAIL
+js1_5/decompilation/regress-351219: PASS || FAIL
+js1_5/decompilation/regress-351336: PASS || FAIL
+js1_5/decompilation/regress-351597: PASS || FAIL
+js1_5/decompilation/regress-351625: PASS || FAIL
+js1_5/decompilation/regress-351626: PASS || FAIL
+js1_5/decompilation/regress-351693: PASS || FAIL
+js1_5/decompilation/regress-351705: PASS || FAIL
+js1_5/decompilation/regress-351793: PASS || FAIL
+js1_5/decompilation/regress-352013: PASS || FAIL
+js1_5/decompilation/regress-352022: PASS || FAIL
+js1_5/decompilation/regress-352073: PASS || FAIL
+js1_5/decompilation/regress-352202: PASS || FAIL
+js1_5/decompilation/regress-352312: PASS || FAIL
+js1_5/decompilation/regress-352360: PASS || FAIL
+js1_5/decompilation/regress-352375: PASS || FAIL
+js1_5/decompilation/regress-352453: PASS || FAIL
+js1_5/decompilation/regress-352649: PASS || FAIL
+js1_5/decompilation/regress-352873-01: PASS || FAIL
+js1_5/decompilation/regress-352873-02: PASS || FAIL
+js1_5/decompilation/regress-353000: PASS || FAIL
+js1_5/decompilation/regress-353120: PASS || FAIL
+js1_5/decompilation/regress-353146: PASS || FAIL
+js1_5/decompilation/regress-354878: PASS || FAIL
+js1_5/decompilation/regress-354910: PASS || FAIL
+js1_5/decompilation/regress-355992: PASS || FAIL
+js1_5/decompilation/regress-356083: PASS || FAIL
+js1_5/decompilation/regress-356248: PASS || FAIL
+js1_5/decompilation/regress-371692: PASS || FAIL
+js1_5/decompilation/regress-373678: PASS || FAIL
+js1_5/decompilation/regress-375639: PASS || FAIL
+js1_5/decompilation/regress-375882: PASS || FAIL
+js1_5/decompilation/regress-376564: PASS || FAIL
+js1_5/decompilation/regress-383721: PASS || FAIL
+js1_5/decompilation/regress-406555: PASS || FAIL
+
+
+[ $FAST == yes ]
+
+# These tests take an unreasonable amount of time so we skip them
+# in fast mode.
+
+js1_5/Regress/regress-312588: SKIP
+js1_5/Regress/regress-271716-n: SKIP
+
+
+[ $FAST == yes && $ARCH == arm ]
+
+# In fast mode on arm we try to skip all tests that would time out,
+# since running the tests takes so long in the first place.
+
+js1_5/Regress/regress-280769-2: SKIP
+js1_5/Regress/regress-280769-3: SKIP
+js1_5/Regress/regress-244470: SKIP
+js1_5/Regress/regress-203278-1: SKIP
+js1_5/Regress/regress-290575: SKIP
+js1_5/Regress/regress-159334: SKIP
+js1_5/Regress/regress-321971: SKIP
+js1_5/Regress/regress-347306-01: SKIP
+js1_5/Regress/regress-280769-1: SKIP
+js1_5/Regress/regress-280769-5: SKIP
+js1_5/GC/regress-306788: SKIP
+js1_5/GC/regress-203278-2: SKIP
+js1_5/GC/regress-278725: SKIP
+js1_5/GC/regress-203278-3: SKIP
+js1_5/GC/regress-311497: SKIP
+js1_5/Array/regress-99120-02: SKIP
+ecma/Date/15.9.5.22-1: SKIP
+ecma/Date/15.9.5.20: SKIP
+ecma/Date/15.9.5.12-2: SKIP
+ecma/Date/15.9.5.8: SKIP
+ecma/Date/15.9.5.9: SKIP
+ecma/Date/15.9.5.10-2: SKIP
+ecma/Date/15.9.5.11-2: SKIP
+ecma/Expressions/11.7.2: SKIP
+ecma/Expressions/11.10-2: SKIP
+ecma/Expressions/11.7.3: SKIP
+ecma/Expressions/11.10-3: SKIP
+ecma/Expressions/11.7.1: SKIP
+ecma_3/RegExp/regress-209067: SKIP
diff --git a/regexp2000/test/mozilla/testcfg.py b/regexp2000/test/mozilla/testcfg.py
new file mode 100644 (file)
index 0000000..8193b82
--- /dev/null
@@ -0,0 +1,134 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import test
+import os
+from os.path import join, exists
+
+
+EXCLUDED = ['CVS']
+
+
+FRAMEWORK = """
+  browser.js
+  shell.js
+  jsref.js
+  template.js
+""".split()
+
+
+TEST_DIRS = """
+  ecma
+  ecma_2
+  ecma_3
+  js1_1
+  js1_2
+  js1_3
+  js1_4
+  js1_5
+""".split()
+
+
+class MozillaTestCase(test.TestCase):
+
+  def __init__(self, filename, path, context, mode, framework):
+    super(MozillaTestCase, self).__init__(context, path)
+    self.filename = filename
+    self.mode = mode
+    self.framework = framework
+
+  def IsNegative(self):
+    return self.filename.endswith('-n.js')
+
+  def GetLabel(self):
+    return "%s mozilla %s" % (self.mode, self.GetName())
+
+  def IsFailureOutput(self, output):
+    if output.exit_code != 0:
+      return True
+    return 'FAILED!' in output.stdout
+
+  def GetCommand(self):
+    result = [self.context.GetVm(self.mode), '--expose-gc']
+    result += self.framework
+    result.append(self.filename)
+    return result
+
+  def GetName(self):
+    return self.path[-1]
+
+  def GetSource(self):
+    return open(self.filename).read()
+
+
+class MozillaTestConfiguration(test.TestConfiguration):
+
+  def __init__(self, context, root):
+    super(MozillaTestConfiguration, self).__init__(context, root)
+
+  def ListTests(self, current_path, path, mode):
+    tests = []
+    for test_dir in TEST_DIRS:
+      current_root = join(self.root, 'data', test_dir)
+      for root, dirs, files in os.walk(current_root):
+        for dotted in [x  for x in dirs if x.startswith('.')]:
+          dirs.remove(dotted)
+        for excluded in EXCLUDED:
+          if excluded in dirs:
+            dirs.remove(excluded)
+        root_path = root[len(self.root):].split(os.path.sep)
+        root_path = current_path + [x for x in root_path if x]
+        framework = []
+        for i in xrange(len(root_path)):
+          if i == 0: dir = root_path[1:]
+          else: dir = root_path[1:-i]
+          script = join(self.root, reduce(join, dir, ''), 'shell.js')
+          if exists(script):
+            framework.append(script)
+        framework.reverse()
+        for file in files:
+          if (not file in FRAMEWORK) and file.endswith('.js'):
+            full_path = root_path + [file[:-3]]
+            full_path = [x for x in full_path if x != 'data']
+            if self.Contains(path, full_path):
+              test = MozillaTestCase(join(root, file), full_path, self.context,
+                                     mode, framework)
+              tests.append(test)
+    return tests
+
+  def GetBuildRequirements(self):
+    return ['sample', 'sample=shell']
+
+  def GetTestStatus(self, sections, defs):
+    status_file = join(self.root, 'mozilla.status')
+    if exists(status_file):
+      test.ReadConfigurationInto(status_file, sections, defs)
+
+
+def GetConfiguration(context, root):
+  return MozillaTestConfiguration(context, root)
diff --git a/regexp2000/tools/js2c.py b/regexp2000/tools/js2c.py
new file mode 100755 (executable)
index 0000000..fb6d6c5
--- /dev/null
@@ -0,0 +1,357 @@
+#!/usr/bin/env python
+#
+# Copyright 2006-2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This is a utility for converting JavaScript source code into C-style
+# char arrays. It is used for embedded JavaScript code in the V8
+# library.
+
+import os, re, sys, string
+
+
+def ToCArray(lines):
+  result = []
+  for chr in lines:
+    value = ord(chr)
+    assert value < 128
+    result.append(str(value))
+  result.append("0")
+  return ", ".join(result)
+
+
+def CompressScript(lines):
+  # Remove stuff from the source that we don't want to appear when
+  # people print the source code using Function.prototype.toString().
+  # Note that we could easily compress the scripts mode but don't
+  # since we want it to remain readable.
+  lines = re.sub('//.*\n', '\n', lines) # end-of-line comments
+  lines = re.sub('\s+\n+', '\n', lines) # trailing whitespace
+  return lines
+
+
+def ReadFile(filename):
+  file = open(filename, "rt")
+  try:
+    lines = file.read()
+  finally:
+    file.close()
+  return lines
+
+
+def ReadLines(filename):
+  result = []
+  for line in open(filename, "rt"):
+    if '#' in line:
+      line = line[:line.index('#')]
+    line = line.strip()
+    if len(line) > 0:
+      result.append(line)
+  return result
+
+
+def LoadConfigFrom(name):
+  import ConfigParser
+  config = ConfigParser.ConfigParser()
+  config.read(name)
+  return config
+
+
+def ParseValue(string):
+  string = string.strip()
+  if string.startswith('[') and string.endswith(']'):
+    return string.lstrip('[').rstrip(']').split()
+  else:
+    return string
+
+
+def ExpandConstants(lines, constants):
+  for key, value in constants.items():
+    lines = lines.replace(key, str(value))
+  return lines
+
+
+def ExpandMacros(lines, macros):
+  for name, macro in macros.items():
+    start = lines.find(name, 0)
+    while start != -1:
+      # Scan over the arguments
+      assert lines[start + len(name)] == '('
+      height = 1
+      end = start + len(name) + 1
+      last_match = end
+      arg_index = 0
+      mapping = { }
+      def add_arg(str):
+        # Remember to expand recursively in the arguments
+        replacement = ExpandMacros(str.strip(), macros)
+        mapping[macro.args[arg_index]] = replacement
+      while end < len(lines) and height > 0:
+        # We don't count commas at higher nesting levels.
+        if lines[end] == ',' and height == 1:
+          add_arg(lines[last_match:end])
+          last_match = end + 1
+        elif lines[end] in ['(', '{', '[']:
+          height = height + 1
+        elif lines[end] in [')', '}', ']']:
+          height = height - 1
+        end = end + 1
+      # Remember to add the last match.
+      add_arg(lines[last_match:end-1])
+      result = macro.expand(mapping)
+      # Replace the occurrence of the macro with the expansion
+      lines = lines[:start] + result + lines[end:]
+      start = lines.find(name, end)
+  return lines
+
+class TextMacro:
+  def __init__(self, args, body):
+    self.args = args
+    self.body = body
+  def expand(self, mapping):
+    result = self.body
+    for key, value in mapping.items():
+        result = result.replace(key, value)
+    return result
+
+class PythonMacro:
+  def __init__(self, args, fun):
+    self.args = args
+    self.fun = fun
+  def expand(self, mapping):
+    args = []
+    for arg in self.args:
+      args.append(mapping[arg])
+    return str(self.fun(*args))
+
+CONST_PATTERN = re.compile('^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$')
+MACRO_PATTERN = re.compile('^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
+PYTHON_MACRO_PATTERN = re.compile('^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
+
+def ReadMacros(lines):
+  constants = { }
+  macros = { }
+  for line in lines:
+    hash = line.find('#')
+    if hash != -1: line = line[:hash]
+    line = line.strip()
+    if len(line) is 0: continue
+    const_match = CONST_PATTERN.match(line)
+    if const_match:
+      name = const_match.group(1)
+      value = const_match.group(2).strip()
+      constants[name] = value
+    else:
+      macro_match = MACRO_PATTERN.match(line)
+      if macro_match:
+        name = macro_match.group(1)
+        args = map(string.strip, macro_match.group(2).split(','))
+        body = macro_match.group(3).strip()
+        macros[name] = TextMacro(args, body)
+      else:
+        python_match = PYTHON_MACRO_PATTERN.match(line)
+        if python_match:
+          name = python_match.group(1)
+          args = map(string.strip, python_match.group(2).split(','))
+          body = python_match.group(3).strip()
+          fun = eval("lambda " + ",".join(args) + ': ' + body)
+          macros[name] = PythonMacro(args, fun)
+        else:
+          raise ("Illegal line: " + line)
+  return (constants, macros)
+
+
+HEADER_TEMPLATE = """\
+// Copyright 2008 Google Inc. All Rights Reserved.
+
+// This file was generated from .js source files by SCons.  If you
+// want to make changes to this file you should either change the
+// javascript source files or the SConstruct script.
+
+#include "v8.h"
+#include "natives.h"
+
+namespace v8 {
+namespace internal {
+
+%(source_lines)s\
+
+  template <>
+  int NativesCollection<%(type)s>::GetBuiltinsCount() {
+    return %(builtin_count)i;
+  }
+
+  template <>
+  int NativesCollection<%(type)s>::GetDelayCount() {
+    return %(delay_count)i;
+  }
+
+  template <>
+  int NativesCollection<%(type)s>::GetIndex(const char* name) {
+%(get_index_cases)s\
+    return -1;
+  }
+
+  template <>
+  Vector<const char> NativesCollection<%(type)s>::GetScriptSource(int index) {
+%(get_script_source_cases)s\
+    return Vector<const char>("", 0);
+  }
+
+  template <>
+  Vector<const char> NativesCollection<%(type)s>::GetScriptName(int index) {
+%(get_script_name_cases)s\
+    return Vector<const char>("", 0);
+  }
+
+}  // internal
+}  // v8
+"""
+
+
+SOURCE_DECLARATION = """\
+  static const char %(id)s[] = { %(data)s };
+"""
+
+
+GET_DELAY_INDEX_CASE = """\
+    if (strcmp(name, "%(id)s") == 0) return %(i)i;
+"""
+
+
+GET_DELAY_SCRIPT_SOURCE_CASE = """\
+    if (index == %(i)i) return Vector<const char>(%(id)s, %(length)i);
+"""
+
+
+GET_DELAY_SCRIPT_NAME_CASE = """\
+    if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i);
+"""
+
+def JS2C(source, target, env):
+  ids = []
+  delay_ids = []
+  modules = []
+  # Locate the macros file name.
+  consts = {}
+  macros = {}
+  for s in source:
+    if 'macros.py' == (os.path.split(str(s))[1]):
+      (consts, macros) = ReadMacros(ReadLines(str(s)))
+    else:
+      modules.append(s)
+
+  # Build source code lines
+  source_lines = [ ]
+  source_lines_empty = []
+  for s in modules:
+    delay = str(s).endswith('-delay.js')
+    lines = ReadFile(str(s))
+    lines = ExpandConstants(lines, consts)
+    lines = ExpandMacros(lines, macros)
+    lines = CompressScript(lines)
+    data = ToCArray(lines)
+    id = (os.path.split(str(s))[1])[:-3]
+    if delay: id = id[:-6]
+    if delay:
+      delay_ids.append((id, len(lines)))
+    else:
+      ids.append((id, len(lines)))
+    source_lines.append(SOURCE_DECLARATION % { 'id': id, 'data': data })
+    source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': 0 })
+  
+  # Build delay support functions
+  get_index_cases = [ ]
+  get_script_source_cases = [ ]
+  get_script_name_cases = [ ]
+
+  i = 0
+  for (id, length) in delay_ids:
+    native_name = "native %s.js" % id
+    get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
+    get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
+      'id': id,
+      'length': length,
+      'i': i
+    })
+    get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
+      'name': native_name,
+      'length': len(native_name),
+      'i': i
+    });
+    i = i + 1
+
+  for (id, length) in ids:
+    native_name = "native %s.js" % id
+    get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
+    get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
+      'id': id,
+      'length': length,
+      'i': i
+    })
+    get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
+      'name': native_name,
+      'length': len(native_name),
+      'i': i
+    });
+    i = i + 1
+
+  # Emit result
+  output = open(str(target[0]), "w")
+  output.write(HEADER_TEMPLATE % {
+    'builtin_count': len(ids) + len(delay_ids),
+    'delay_count': len(delay_ids),
+    'source_lines': "\n".join(source_lines),
+    'get_index_cases': "".join(get_index_cases),
+    'get_script_source_cases': "".join(get_script_source_cases),
+    'get_script_name_cases': "".join(get_script_name_cases),
+    'type': env['TYPE']
+  })
+  output.close()
+
+  if len(target) > 1:
+    output = open(str(target[1]), "w")
+    output.write(HEADER_TEMPLATE % {
+      'builtin_count': len(ids) + len(delay_ids),
+      'delay_count': len(delay_ids),
+      'source_lines': "\n".join(source_lines_empty),
+      'get_index_cases': "".join(get_index_cases),
+      'get_script_source_cases': "".join(get_script_source_cases),
+      'get_script_name_cases': "".join(get_script_name_cases),
+      'type': env['TYPE']
+    })
+    output.close()
+
+def main():
+  natives = sys.argv[1]
+  natives_empty = sys.argv[2]
+  type = sys.argv[3]
+  source_files = sys.argv[4:]
+  JS2C(source_files, [natives, natives_empty], { 'TYPE': type })
+
+if __name__ == "__main__":
+  main()
diff --git a/regexp2000/tools/linux-tick-processor.py b/regexp2000/tools/linux-tick-processor.py
new file mode 100755 (executable)
index 0000000..d2cabac
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Usage: process-ticks.py <logfile>
+# Where <logfile> is the log file name (eg, v8.log).
+
+import subprocess, re, sys, tickprocessor, getopt
+
+class LinuxTickProcessor(tickprocessor.TickProcessor):
+
+  def ParseVMSymbols(self, filename, start, end):
+    """Extract symbols and add them to the cpp entries."""
+    # Extra both dynamic and non-dynamic symbols.
+    command = 'nm -C -n "%s"; nm -C -n -D "%s"' % (filename, filename)
+    process = subprocess.Popen(command, shell=True,
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
+    pipe = process.stdout
+    try:
+      for line in pipe:
+        row = re.match('^([0-9a-fA-F]{8}) . (.*)$', line)
+        if row:
+          addr = int(row.group(1), 16)
+          if addr < start and addr < end - start:
+            addr += start
+          self.cpp_entries.Insert(addr, tickprocessor.CodeEntry(addr, row.group(2)))
+    finally:
+      pipe.close()
+
+
+def Usage():
+  print("Usage: linux-tick-processor.py --{js,gc,compiler,other}  logfile-name");
+  sys.exit(2)
+
+def Main():
+  # parse command line options
+  state = None;
+  try:
+    opts, args = getopt.getopt(sys.argv[1:], "jgco", ["js", "gc", "compiler", "other"])
+  except getopt.GetoptError:
+    usage()
+  # process options.
+  for key, value in opts:
+    if key in ("-j", "--js"):
+      state = 0
+    if key in ("-g", "--gc"):
+      state = 1
+    if key in ("-c", "--compiler"):
+      state = 2
+    if key in ("-o", "--other"):
+      state = 3
+  # do the processing.
+  if len(args) != 1:
+      Usage();
+  tick_processor = LinuxTickProcessor()
+  tick_processor.ProcessLogfile(args[0], state)
+  tick_processor.PrintResults()
+
+if __name__ == '__main__':
+  Main()
diff --git a/regexp2000/tools/presubmit.py b/regexp2000/tools/presubmit.py
new file mode 100755 (executable)
index 0000000..65812ec
--- /dev/null
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import optparse
+import os
+from os.path import abspath, join, dirname, basename
+import re
+import sys
+import subprocess
+
+
+ENABLED_LINT_RULES = """
+build/class
+build/deprecated
+build/endif_comment
+build/forward_decl
+build/include_order
+build/include_what_you_use
+build/printf_format
+build/storage_class
+legal/copyright
+readability/boost
+readability/braces
+readability/casting
+readability/check
+readability/constructors
+readability/fn_size
+readability/function
+readability/multiline_comment
+readability/multiline_string
+readability/streams
+readability/todo
+readability/utf8
+runtime/arrays
+runtime/casting
+runtime/deprecated_fn
+runtime/explicit
+runtime/int
+runtime/memset
+runtime/mutex
+runtime/nonconf
+runtime/printf
+runtime/printf_format
+runtime/references
+runtime/rtti
+runtime/sizeof
+runtime/string
+runtime/virtual
+runtime/vlog
+whitespace/blank_line
+whitespace/braces
+whitespace/comma
+whitespace/comments
+whitespace/end_of_line
+whitespace/ending_newline
+whitespace/indent
+whitespace/labels
+whitespace/line_length
+whitespace/newline
+whitespace/operators
+whitespace/parens
+whitespace/tab
+whitespace/todo
+""".split()
+
+
+class SourceFileProcessor(object):
+  """
+  Utility class that can run through a directory structure, find all relevant
+  files and invoke a custom check on the files.
+  """
+
+  def Run(self, path):
+    all_files = []
+    for file in self.GetPathsToSearch():
+      all_files += self.FindFilesIn(join(path, file))
+    if not self.ProcessFiles(all_files):
+      return False
+    return True
+
+  def IgnoreDir(self, name):
+    return name.startswith('.') or name == 'data'
+
+  def IgnoreFile(self, name):
+    return name.startswith('.')
+
+  def FindFilesIn(self, path):
+    result = []
+    for (root, dirs, files) in os.walk(path):
+      for ignored in [x for x in dirs if self.IgnoreDir(x)]:
+        dirs.remove(ignored)
+      for file in files:
+        if not self.IgnoreFile(file) and self.IsRelevant(file):
+          result.append(join(root, file))
+    return result
+
+
+class CppLintProcessor(SourceFileProcessor):
+  """
+  Lint files to check that they follow the google code style.
+  """
+
+  def IsRelevant(self, name):
+    return name.endswith('.cc') or name.endswith('.h')
+
+  def IgnoreDir(self, name):
+    return (super(CppLintProcessor, self).IgnoreDir(name)
+              or (name == 'third_party'))
+
+  IGNORE_LINT = ['flag-definitions.h']
+  
+  def IgnoreFile(self, name):
+    return (super(CppLintProcessor, self).IgnoreFile(name)
+              or (name in CppLintProcessor.IGNORE_LINT))
+
+  def GetPathsToSearch(self):
+    return ['src', 'public', 'samples', join('test', 'cctest')]
+
+  def ProcessFiles(self, files):
+    filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES])
+    command = ['cpplint.py', '--filter', filt] + join(files)
+    process = subprocess.Popen(command)
+    return process.wait() == 0
+
+
+COPYRIGHT_HEADER_PATTERN = re.compile(
+    r'Copyright [\d-]*2008 the V8 project authors. All rights reserved.')
+
+class SourceProcessor(SourceFileProcessor):
+  """
+  Check that all files include a copyright notice.
+  """
+
+  RELEVANT_EXTENSIONS = ['.js', '.cc', '.h', '.py', '.c', 'SConscript',
+      'SConstruct', '.status']
+  def IsRelevant(self, name):
+    for ext in SourceProcessor.RELEVANT_EXTENSIONS:
+      if name.endswith(ext):
+        return True
+    return False
+
+  def GetPathsToSearch(self):
+    return ['.']
+
+  def IgnoreDir(self, name):
+    return (super(SourceProcessor, self).IgnoreDir(name)
+              or (name == 'third_party')
+              or (name == 'obj'))
+
+  IGNORE_COPYRIGHTS = ['earley-boyer.js', 'raytrace.js', 'crypto.js',
+      'libraries.cc', 'libraries-empty.cc']
+  IGNORE_TABS = IGNORE_COPYRIGHTS + ['unicode-test.js',
+      'html-comments.js']
+
+  def ProcessContents(self, name, contents):
+    result = True
+    base = basename(name)
+    if not base in SourceProcessor.IGNORE_TABS:
+      if '\t' in contents:
+        print "%s contains tabs" % name
+        result = False
+    if not base in SourceProcessor.IGNORE_COPYRIGHTS:
+      if not COPYRIGHT_HEADER_PATTERN.search(contents):
+        print "%s is missing a correct copyright header." % name
+        result = False
+    return result
+
+  def ProcessFiles(self, files):
+    success = True
+    for file in files:
+      try:
+        handle = open(file)
+        contents = handle.read()
+        success = self.ProcessContents(file, contents) and success
+      finally:
+        handle.close()
+    return success
+
+
+def GetOptions():
+  result = optparse.OptionParser()
+  result.add_option('--no-lint', help="Do not run cpplint", default=False,
+                    action="store_true")
+  return result
+
+
+def Main():
+  workspace = abspath(join(dirname(sys.argv[0]), '..'))
+  parser = GetOptions()
+  (options, args) = parser.parse_args()
+  success = True
+  if not options.no_lint:
+    success = CppLintProcessor().Run(workspace) and success
+  success = SourceProcessor().Run(workspace) and success
+  if success:
+    return 0
+  else:
+    return 1
+
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/regexp2000/tools/splaytree.py b/regexp2000/tools/splaytree.py
new file mode 100644 (file)
index 0000000..4353b64
--- /dev/null
@@ -0,0 +1,219 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+class Node(object):
+  """Nodes in the splay tree."""
+
+  def __init__(self, key, value):
+    self.key = key
+    self.value = value
+    self.left = None
+    self.right = None
+
+
+class SplayTree(object):
+  """The splay tree itself is just a reference to the root of the tree."""
+
+  def __init__(self):
+    """Create a new SplayTree."""
+    self.root = None
+
+  def IsEmpty(self):
+    """Is the SplayTree empty?"""
+    return not self.root
+
+  def Insert(self, key, value):
+    """Insert a new node in the SplayTree."""
+    # If the tree is empty, insert the new node.
+    if self.IsEmpty():
+      self.root = Node(key, value)
+      return
+    # Splay on the key to move the last node on the search path for
+    # the key to the root of the tree.
+    self.Splay(key)
+    # Ignore repeated insertions with the same key.
+    if self.root.key == key:
+      return
+    # Insert the new node.
+    node = Node(key, value)
+    if key > self.root.key:
+      node.left = self.root
+      node.right = self.root.right
+      self.root.right = None
+    else:
+      node.right = self.root
+      node.left = self.root.left
+      self.root.left = None
+    self.root = node
+
+  def Remove(self, key):
+    """Remove the node with the given key from the SplayTree."""
+    # Raise exception for key that is not found if the tree is empty.
+    if self.IsEmpty():
+      raise 'KeyNotFound'
+    # Splay on the key to move the node with the given key to the top.
+    self.Splay(key)
+    # Raise exception for key that is not found.
+    if self.root.key != key:
+      raise 'KeyNotFound'
+    removed = self.root
+    # Link out the root node.
+    if not self.root.left:
+      # No left child, so the new tree is just the right child.
+      self.root = self.root.right
+    else:
+      # Left child exists.
+      right = self.root.right
+      # Make the original left child the new root.
+      self.root = self.root.left
+      # Splay to make sure that the new root has an empty right child.
+      self.Splay(key)
+      # Insert the original right child as the right child of the new
+      # root.
+      self.root.right = right
+    return removed
+
+  def Find(self, key):
+    """Returns the node with the given key or None if no such node exists."""
+    if self.IsEmpty():
+      return None
+    self.Splay(key)
+    if self.root.key == key:
+      return self.root
+    return None
+
+  def FindMax(self):
+    """Returns the node with the largest key value."""
+    if self.IsEmpty():
+      return None
+    current = self.root
+    while current.right != None:
+      current = current.right
+    return current
+
+  # Returns the node with the smallest key value.
+  def FindMin(self):
+    if self.IsEmpty():
+      return None
+    current = self.root
+    while current.left != None:
+      current = current.left
+    return current
+
+  def FindGreatestsLessThan(self, key):
+    """Returns node with greatest key less than or equal to the given key."""
+    if self.IsEmpty():
+      return None
+    # Splay on the key to move the node with the given key or the last
+    # node on the search path to the top of the tree.
+    self.Splay(key)
+    # Now the result is either the root node or the greatest node in
+    # the left subtree.
+    if self.root.key <= key:
+      return self.root
+    else:
+      tmp = self.root
+      self.root = self.root.left
+      result = self.FindMax()
+      self.root = tmp
+      return result
+
+  def ExportValueList(self):
+    """Returns a list containing all the values of the nodes in the tree."""
+    result = []
+    nodes_to_visit = [self.root]
+    while len(nodes_to_visit) > 0:
+      node = nodes_to_visit.pop()
+      if not node:
+        continue
+      result.append(node.value)
+      nodes_to_visit.append(node.left)
+      nodes_to_visit.append(node.right)
+    return result
+
+  def Splay(self, key):
+    """Perform splay operation.
+
+    Perform the splay operation for the given key. Moves the node with
+    the given key to the top of the tree.  If no node has the given
+    key, the last node on the search path is moved to the top of the
+    tree.
+
+    This uses the simplified top-down splaying algorithm from:
+
+    "Self-adjusting Binary Search Trees" by Sleator and Tarjan
+
+    """
+    if self.IsEmpty():
+      return
+    # Create a dummy node.  The use of the dummy node is a bit
+    # counter-intuitive: The right child of the dummy node will hold
+    # the L tree of the algorithm.  The left child of the dummy node
+    # will hold the R tree of the algorithm.  Using a dummy node, left
+    # and right will always be nodes and we avoid special cases.
+    dummy = left = right = Node(None, None)
+    current = self.root
+    while True:
+      if key < current.key:
+        if not current.left:
+          break
+        if key < current.left.key:
+          # Rotate right.
+          tmp = current.left
+          current.left = tmp.right
+          tmp.right = current
+          current = tmp
+          if not current.left:
+            break
+        # Link right.
+        right.left = current
+        right = current
+        current = current.left
+      elif key > current.key:
+        if not current.right:
+          break
+        if key > current.right.key:
+          # Rotate left.
+          tmp = current.right
+          current.right = tmp.left
+          tmp.left = current
+          current = tmp
+          if not current.right:
+            break
+        # Link left.
+        left.right = current
+        left = current
+        current = current.right
+      else:
+        break
+    # Assemble.
+    left.right = current.left
+    right.left = current.right
+    current.left = dummy.right
+    current.right = dummy.left
+    self.root = current
diff --git a/regexp2000/tools/test.py b/regexp2000/tools/test.py
new file mode 100755 (executable)
index 0000000..30f0f34
--- /dev/null
@@ -0,0 +1,1255 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import imp
+import optparse
+import os
+from os.path import join, dirname, abspath, basename, isdir, exists
+import platform
+import re
+import signal
+import subprocess
+import sys
+import tempfile
+import time
+import threading
+import utils
+from Queue import Queue, Empty
+
+
+VERBOSE = False
+
+
+# ---------------------------------------------
+# --- P r o g r e s s   I n d i c a t o r s ---
+# ---------------------------------------------
+
+
+class ProgressIndicator(object):
+
+  def __init__(self, cases):
+    self.cases = cases
+    self.queue = Queue(len(cases))
+    for case in cases:
+      self.queue.put_nowait(case)
+    self.succeeded = 0
+    self.remaining = len(cases)
+    self.total = len(cases)
+    self.failed = [ ]
+    self.terminate = False
+    self.lock = threading.Lock()
+
+  def PrintFailureHeader(self, test):
+    if test.IsNegative():
+      negative_marker = '[negative] '
+    else:
+      negative_marker = ''
+    print "=== %(label)s %(negative)s===" % {
+      'label': test.GetLabel(),
+      'negative': negative_marker
+    }
+    print "Path: %s" % "/".join(test.path)
+
+  def Run(self, tasks):
+    self.Starting()
+    threads = []
+    # Spawn N-1 threads and then use this thread as the last one.
+    # That way -j1 avoids threading altogether which is a nice fallback
+    # in case of threading problems.
+    for i in xrange(tasks - 1):
+      thread = threading.Thread(target=self.RunSingle, args=[])
+      threads.append(thread)
+      thread.start()
+    try:
+      self.RunSingle()
+      # Wait for the remaining threads
+      for thread in threads:
+        # Use a timeout so that signals (ctrl-c) will be processed.
+        thread.join(timeout=10000000)
+    except Exception, e:
+      # If there's an exception we schedule an interruption for any
+      # remaining threads.
+      self.terminate = True
+      # ...and then reraise the exception to bail out
+      raise
+    self.Done()
+    return not self.failed
+
+  def RunSingle(self):
+    while not self.terminate:
+      try:
+        test = self.queue.get_nowait()
+      except Empty:
+        return
+      case = test.case
+      self.lock.acquire()
+      self.AboutToRun(case)
+      self.lock.release()
+      try:
+        start = time.time()
+        output = case.Run()
+        case.duration = (time.time() - start)
+      except IOError, e:
+        assert self.terminate
+        return
+      if self.terminate:
+        return
+      self.lock.acquire()
+      if output.UnexpectedOutput():
+        self.failed.append(output)
+      else:
+        self.succeeded += 1
+      self.remaining -= 1
+      self.HasRun(output)
+      self.lock.release()
+
+
+def EscapeCommand(command):
+  parts = []
+  for part in command:
+    if ' ' in part:
+      # Escape spaces.  We may need to escape more characters for this
+      # to work properly.
+      parts.append('"%s"' % part)
+    else:
+      parts.append(part)
+  return " ".join(parts)
+
+
+class SimpleProgressIndicator(ProgressIndicator):
+
+  def Starting(self):
+    print 'Running %i tests' % len(self.cases)
+
+  def Done(self):
+    print
+    for failed in self.failed:
+      self.PrintFailureHeader(failed.test)
+      if failed.output.stderr:
+        print "--- stderr ---"
+        print failed.output.stderr.strip()
+      if failed.output.stdout:
+        print "--- stdout ---"
+        print failed.output.stdout.strip()
+      print "Command: %s" % EscapeCommand(failed.command)
+    if len(self.failed) == 0:
+      print "==="
+      print "=== All tests succeeded"
+      print "==="
+    else:
+      print
+      print "==="
+      print "=== %i tests failed" % len(self.failed)
+      print "==="
+
+
+class VerboseProgressIndicator(SimpleProgressIndicator):
+
+  def AboutToRun(self, case):
+    print 'Starting %s...' % case.GetLabel()
+    sys.stdout.flush()
+
+  def HasRun(self, output):
+    if output.UnexpectedOutput():
+      outcome = 'FAIL'
+    else:
+      outcome = 'pass'
+    print 'Done running %s: %s' % (output.test.GetLabel(), outcome)
+
+
+class DotsProgressIndicator(SimpleProgressIndicator):
+
+  def AboutToRun(self, case):
+    pass
+
+  def HasRun(self, output):
+    total = self.succeeded + len(self.failed)
+    if (total > 1) and (total % 50 == 1):
+      sys.stdout.write('\n')
+    if output.UnexpectedOutput():
+      sys.stdout.write('F')
+      sys.stdout.flush()
+    else:
+      sys.stdout.write('.')
+      sys.stdout.flush()
+
+
+class CompactProgressIndicator(ProgressIndicator):
+
+  def __init__(self, cases, templates):
+    super(CompactProgressIndicator, self).__init__(cases)
+    self.templates = templates
+    self.last_status_length = 0
+    self.start_time = time.time()
+
+  def Starting(self):
+    pass
+
+  def Done(self):
+    self.PrintProgress('Done')
+
+  def AboutToRun(self, case):
+    self.PrintProgress(case.GetLabel())
+
+  def HasRun(self, output):
+    if output.UnexpectedOutput():
+      self.ClearLine(self.last_status_length)
+      self.PrintFailureHeader(output.test)
+      stdout = output.output.stdout.strip()
+      if len(stdout):
+        print self.templates['stdout'] % stdout
+      stderr = output.output.stderr.strip()
+      if len(stderr):
+        print self.templates['stderr'] % stderr
+      print "Command: %s" % EscapeCommand(output.command)
+
+  def Truncate(self, str, length):
+    if length and (len(str) > (length - 3)):
+      return str[:(length-3)] + "..."
+    else:
+      return str
+
+  def PrintProgress(self, name):
+    self.ClearLine(self.last_status_length)
+    elapsed = time.time() - self.start_time
+    status = self.templates['status_line'] % {
+      'passed': self.succeeded,
+      'remaining': (((self.total - self.remaining) * 100) // self.total),
+      'failed': len(self.failed),
+      'test': name,
+      'mins': int(elapsed) / 60,
+      'secs': int(elapsed) % 60
+    }
+    status = self.Truncate(status, 78)
+    self.last_status_length = len(status)
+    print status,
+    sys.stdout.flush()
+
+
+class ColorProgressIndicator(CompactProgressIndicator):
+
+  def __init__(self, cases):
+    templates = {
+      'status_line': "[%(mins)02i:%(secs)02i|\033[34m%%%(remaining) 4d\033[0m|\033[32m+%(passed) 4d\033[0m|\033[31m-%(failed) 4d\033[0m]: %(test)s",
+      'stdout': "\033[1m%s\033[0m",
+      'stderr': "\033[31m%s\033[0m",
+    }
+    super(ColorProgressIndicator, self).__init__(cases, templates)
+
+  def ClearLine(self, last_line_length):
+    print "\033[1K\r",
+
+
+class MonochromeProgressIndicator(CompactProgressIndicator):
+
+  def __init__(self, cases):
+    templates = {
+      'status_line': "[%(mins)02i:%(secs)02i|%%%(remaining) 4d|+%(passed) 4d|-%(failed) 4d]: %(test)s",
+      'stdout': '%s',
+      'stderr': '%s',
+      'clear': lambda last_line_length: ("\r" + (" " * last_line_length) + "\r"),
+      'max_length': 78
+    }
+    super(MonochromeProgressIndicator, self).__init__(cases, templates)
+
+  def ClearLine(self, last_line_length):
+    print ("\r" + (" " * last_line_length) + "\r"),
+
+
+PROGRESS_INDICATORS = {
+  'verbose': VerboseProgressIndicator,
+  'dots': DotsProgressIndicator,
+  'color': ColorProgressIndicator,
+  'mono': MonochromeProgressIndicator
+}
+
+
+# -------------------------
+# --- F r a m e w o r k ---
+# -------------------------
+
+
+class CommandOutput(object):
+
+  def __init__(self, exit_code, stdout, stderr):
+    self.exit_code = exit_code
+    self.stdout = stdout
+    self.stderr = stderr
+
+
+class TestCase(object):
+
+  def __init__(self, context, path):
+    self.path = path
+    self.context = context
+    self.failed = None
+    self.duration = None
+
+  def IsNegative(self):
+    return False
+
+  def CompareTime(self, other):
+    return cmp(other.duration, self.duration)
+
+  def DidFail(self, output):
+    if self.failed is None:
+      self.failed = self.IsFailureOutput(output)
+    return self.failed
+
+  def IsFailureOutput(self, output):
+    return output.exit_code != 0
+
+  def GetSource(self):
+    return "(no source available)"
+
+  def Run(self):
+    command = self.GetCommand()
+    full_command = self.context.processor(command)
+    output = Execute(full_command, self.context, self.context.timeout)
+    return TestOutput(self, full_command, output)
+
+
+class TestOutput(object):
+
+  def __init__(self, test, command, output):
+    self.test = test
+    self.command = command
+    self.output = output
+
+  def UnexpectedOutput(self):
+    if self.HasFailed():
+      outcome = FAIL
+    else:
+      outcome = PASS
+    return not outcome in self.test.outcomes
+
+  def HasFailed(self):
+    execution_failed = self.test.DidFail(self.output)
+    if self.test.IsNegative():
+      return not execution_failed
+    else:
+      return execution_failed
+
+
+def KillProcessWithID(pid):
+  if platform.system() == 'Windows':
+    os.popen('taskkill /T /F /PID %d' % pid)
+  else:
+    os.kill(pid, signal.SIGTERM)
+
+
+MAX_SLEEP_TIME = 0.1
+INITIAL_SLEEP_TIME = 0.0001
+SLEEP_TIME_FACTOR = 1.25
+
+
+def RunProcess(context, timeout, args, **rest):
+  if context.verbose: print "#", " ".join(args)
+  popen_args = args
+  if platform.system() == 'Windows':
+    popen_args = '"' + subprocess.list2cmdline(args) + '"'
+  process = subprocess.Popen(
+    shell = (platform.system() == 'Windows'),
+    args = popen_args,
+    **rest
+  )
+  # Compute the end time - if the process crosses this limit we
+  # consider it timed out.
+  if timeout is None: end_time = None
+  else: end_time = time.time() + timeout
+  timed_out = False
+  # Repeatedly check the exit code from the process in a
+  # loop and keep track of whether or not it times out.
+  exit_code = None
+  sleep_time = INITIAL_SLEEP_TIME
+  while exit_code is None:
+    if (not end_time is None) and (time.time() >= end_time):
+      # Kill the process and wait for it to exit.
+      KillProcessWithID(process.pid)
+      exit_code = process.wait()
+      timed_out = True
+    else:
+      exit_code = process.poll()
+      time.sleep(sleep_time)
+      sleep_time = sleep_time * SLEEP_TIME_FACTOR
+      if sleep_time > MAX_SLEEP_TIME:
+        sleep_time = MAX_SLEEP_TIME
+  return (process, exit_code, timed_out)
+
+
+def PrintError(str):
+  sys.stderr.write(str)
+  sys.stderr.write('\n')
+
+
+def Execute(args, context, timeout=None):
+  (fd_out, outname) = tempfile.mkstemp()
+  (fd_err, errname) = tempfile.mkstemp()
+  (process, exit_code, timed_out) = RunProcess(
+    context,
+    timeout,
+    args = args,
+    stdout = fd_out,
+    stderr = fd_err,
+  )
+  os.close(fd_out)
+  os.close(fd_err)
+  output = file(outname).read()
+  errors = file(errname).read()
+  def CheckedUnlink(name):
+    try:
+      os.unlink(name)
+    except OSError, e:
+      PrintError(str(e))
+  CheckedUnlink(outname)
+  CheckedUnlink(errname)
+  return CommandOutput(exit_code, output, errors)
+
+
+def ExecuteNoCapture(args, context, timeout=None):
+  (process, exit_code, timed_out) = RunProcess(
+    context,
+    timeout,
+    args = args,
+  )
+  return CommandOutput(exit_code, "", "")
+
+
+def CarCdr(path):
+  if len(path) == 0:
+    return (None, [ ])
+  else:
+    return (path[0], path[1:])
+
+
+class TestConfiguration(object):
+
+  def __init__(self, context, root):
+    self.context = context
+    self.root = root
+
+  def Contains(self, path, file):
+    if len(path) > len(file):
+      return False
+    for i in xrange(len(path)):
+      if not path[i].match(file[i]):
+        return False
+    return True
+
+  def GetTestStatus(self, sections, defs):
+    pass
+
+
+class TestSuite(object):
+
+  def __init__(self, name):
+    self.name = name
+
+  def GetName(self):
+    return self.name
+
+
+class TestRepository(TestSuite):
+
+  def __init__(self, path):
+    normalized_path = abspath(path)
+    super(TestRepository, self).__init__(basename(normalized_path))
+    self.path = normalized_path
+    self.is_loaded = False
+    self.config = None
+
+  def GetConfiguration(self, context):
+    if self.is_loaded:
+      return self.config
+    self.is_loaded = True
+    file = None
+    try:
+      (file, pathname, description) = imp.find_module('testcfg', [ self.path ])
+      module = imp.load_module(self.path, file, pathname, description)
+      self.config = module.GetConfiguration(context, self.path)
+    finally:
+      if file:
+        file.close()
+    return self.config
+
+  def GetBuildRequirements(self, path, context):
+    return self.GetConfiguration(context).GetBuildRequirements()
+
+  def ListTests(self, current_path, path, context, mode):
+    return self.GetConfiguration(context).ListTests(current_path, path, mode)
+
+  def GetTestStatus(self, context, sections, defs):
+    self.GetConfiguration(context).GetTestStatus(sections, defs)
+
+
+class LiteralTestSuite(TestSuite):
+
+  def __init__(self, tests):
+    super(LiteralTestSuite, self).__init__('root')
+    self.tests = tests
+
+  def GetBuildRequirements(self, path, context):
+    (name, rest) = CarCdr(path)
+    result = [ ]
+    for test in self.tests:
+      if not name or name.match(test.GetName()):
+        result += test.GetBuildRequirements(rest, context)
+    return result
+
+  def ListTests(self, current_path, path, context, mode):
+    (name, rest) = CarCdr(path)
+    result = [ ]
+    for test in self.tests:
+      test_name = test.GetName()
+      if not name or name.match(test_name):
+        full_path = current_path + [test_name]
+        result += test.ListTests(full_path, path, context, mode)
+    return result
+
+  def GetTestStatus(self, context, sections, defs):
+    for test in self.tests:
+      test.GetTestStatus(context, sections, defs)
+
+
+PREFIX = {'debug': '_g', 'release': ''}
+
+
+class Context(object):
+
+  def __init__(self, workspace, buildspace, verbose, vm, timeout, processor):
+    self.workspace = workspace
+    self.buildspace = buildspace
+    self.verbose = verbose
+    self.vm_root = vm
+    self.timeout = timeout
+    self.processor = processor
+
+  def GetVm(self, mode):
+    name = self.vm_root + PREFIX[mode]
+    if platform.system() == 'Windows':
+      return name + '.exe'
+    else:
+      return name
+
+def RunTestCases(all_cases, progress, tasks):
+  def DoSkip(case):
+    return SKIP in c.outcomes or SLOW in c.outcomes
+  cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
+  progress = PROGRESS_INDICATORS[progress](cases_to_run)
+  return progress.Run(tasks)
+
+
+def BuildRequirements(context, requirements, mode, scons_flags):
+  command_line = (['scons', '-Y', context.workspace, 'mode=' + ",".join(mode)]
+                  + requirements
+                  + scons_flags)
+  output = ExecuteNoCapture(command_line, context)
+  return output.exit_code == 0
+
+
+# -------------------------------------------
+# --- T e s t   C o n f i g u r a t i o n ---
+# -------------------------------------------
+
+
+SKIP = 'skip'
+FAIL = 'fail'
+PASS = 'pass'
+OKAY = 'okay'
+TIMEOUT = 'timeout'
+CRASH = 'crash'
+SLOW = 'slow'
+
+
+class Expression(object):
+  pass
+
+
+class Constant(Expression):
+
+  def __init__(self, value):
+    self.value = value
+
+  def Evaluate(self, env, defs):
+    return self.value
+
+
+class Variable(Expression):
+
+  def __init__(self, name):
+    self.name = name
+
+  def GetOutcomes(self, env, defs):
+    if self.name in env: return ListSet([env[self.name]])
+    else: return Nothing()
+
+
+class Outcome(Expression):
+
+  def __init__(self, name):
+    self.name = name
+
+  def GetOutcomes(self, env, defs):
+    if self.name in defs:
+      return defs[self.name].GetOutcomes(env, defs)
+    else:
+      return ListSet([self.name])
+
+
+class Set(object):
+  pass
+
+
+class ListSet(Set):
+
+  def __init__(self, elms):
+    self.elms = elms
+
+  def __str__(self):
+    return "ListSet%s" % str(self.elms)
+
+  def Intersect(self, that):
+    if not isinstance(that, ListSet):
+      return that.Intersect(self)
+    return ListSet([ x for x in self.elms if x in that.elms ])
+
+  def Union(self, that):
+    if not isinstance(that, ListSet):
+      return that.Union(self)
+    return ListSet(self.elms + [ x for x in that.elms if x not in self.elms ])
+
+  def IsEmpty(self):
+    return len(self.elms) == 0
+
+
+class Everything(Set):
+
+  def Intersect(self, that):
+    return that
+
+  def Union(self, that):
+    return self
+
+  def IsEmpty(self):
+    return False
+
+
+class Nothing(Set):
+
+  def Intersect(self, that):
+    return self
+
+  def Union(self, that):
+    return that
+
+  def IsEmpty(self):
+    return True
+
+
+class Operation(Expression):
+
+  def __init__(self, left, op, right):
+    self.left = left
+    self.op = op
+    self.right = right
+
+  def Evaluate(self, env, defs):
+    if self.op == '||' or self.op == ',':
+      return self.left.Evaluate(env, defs) or self.right.Evaluate(env, defs)
+    elif self.op == 'if':
+      return False
+    elif self.op == '==':
+      inter = self.left.GetOutcomes(env, defs).Intersect(self.right.GetOutcomes(env, defs))
+      return not inter.IsEmpty()
+    else:
+      assert self.op == '&&'
+      return self.left.Evaluate(env, defs) and self.right.Evaluate(env, defs)
+
+  def GetOutcomes(self, env, defs):
+    if self.op == '||' or self.op == ',':
+      return self.left.GetOutcomes(env, defs).Union(self.right.GetOutcomes(env, defs))
+    elif self.op == 'if':
+      if self.right.Evaluate(env, defs): return self.left.GetOutcomes(env, defs)
+      else: return Nothing()
+    else:
+      assert self.op == '&&'
+      return self.left.GetOutcomes(env, defs).Intersect(self.right.GetOutcomes(env, defs))
+
+
+def IsAlpha(str):
+  for char in str:
+    if not (char.isalpha() or char.isdigit() or char == '_'):
+      return False
+  return True
+
+
+class Tokenizer(object):
+  """A simple string tokenizer that chops expressions into variables,
+  parens and operators"""
+
+  def __init__(self, expr):
+    self.index = 0
+    self.expr = expr
+    self.length = len(expr)
+    self.tokens = None
+
+  def Current(self, length = 1):
+    if not self.HasMore(length): return ""
+    return self.expr[self.index:self.index+length]
+
+  def HasMore(self, length = 1):
+    return self.index < self.length + (length - 1)
+
+  def Advance(self, count = 1):
+    self.index = self.index + count
+
+  def AddToken(self, token):
+    self.tokens.append(token)
+
+  def SkipSpaces(self):
+    while self.HasMore() and self.Current().isspace():
+      self.Advance()
+
+  def Tokenize(self):
+    self.tokens = [ ]
+    while self.HasMore():
+      self.SkipSpaces()
+      if not self.HasMore():
+        return None
+      if self.Current() == '(':
+        self.AddToken('(')
+        self.Advance()
+      elif self.Current() == ')':
+        self.AddToken(')')
+        self.Advance()
+      elif self.Current() == '$':
+        self.AddToken('$')
+        self.Advance()
+      elif self.Current() == ',':
+        self.AddToken(',')
+        self.Advance()
+      elif IsAlpha(self.Current()):
+        buf = ""
+        while self.HasMore() and IsAlpha(self.Current()):
+          buf += self.Current()
+          self.Advance()
+        self.AddToken(buf)
+      elif self.Current(2) == '&&':
+        self.AddToken('&&')
+        self.Advance(2)
+      elif self.Current(2) == '||':
+        self.AddToken('||')
+        self.Advance(2)
+      elif self.Current(2) == '==':
+        self.AddToken('==')
+        self.Advance(2)
+      else:
+        return None
+    return self.tokens
+
+
+class Scanner(object):
+  """A simple scanner that can serve out tokens from a given list"""
+
+  def __init__(self, tokens):
+    self.tokens = tokens
+    self.length = len(tokens)
+    self.index = 0
+
+  def HasMore(self):
+    return self.index < self.length
+
+  def Current(self):
+    return self.tokens[self.index]
+
+  def Advance(self):
+    self.index = self.index + 1
+
+
+def ParseAtomicExpression(scan):
+  if scan.Current() == "true":
+    scan.Advance()
+    return Constant(True)
+  elif scan.Current() == "false":
+    scan.Advance()
+    return Constant(False)
+  elif IsAlpha(scan.Current()):
+    name = scan.Current()
+    scan.Advance()
+    return Outcome(name.lower())
+  elif scan.Current() == '$':
+    scan.Advance()
+    if not IsAlpha(scan.Current()):
+      return None
+    name = scan.Current()
+    scan.Advance()
+    return Variable(name.lower())
+  elif scan.Current() == '(':
+    scan.Advance()
+    result = ParseLogicalExpression(scan)
+    if (not result) or (scan.Current() != ')'):
+      return None
+    scan.Advance()
+    return result
+  else:
+    return None
+
+
+BINARIES = ['==']
+def ParseOperatorExpression(scan):
+  left = ParseAtomicExpression(scan)
+  if not left: return None
+  while scan.HasMore() and (scan.Current() in BINARIES):
+    op = scan.Current()
+    scan.Advance()
+    right = ParseOperatorExpression(scan)
+    if not right:
+      return None
+    left = Operation(left, op, right)
+  return left
+
+
+def ParseConditionalExpression(scan):
+  left = ParseOperatorExpression(scan)
+  if not left: return None
+  while scan.HasMore() and (scan.Current() == 'IF'):
+    scan.Advance()
+    right = ParseOperatorExpression(scan)
+    if not right:
+      return None
+    left=  Operation(left, 'if', right)
+  return left
+
+
+LOGICALS = ["&&", "||", ","]
+def ParseLogicalExpression(scan):
+  left = ParseConditionalExpression(scan)
+  if not left: return None
+  while scan.HasMore() and (scan.Current() in LOGICALS):
+    op = scan.Current()
+    scan.Advance()
+    right = ParseConditionalExpression(scan)
+    if not right:
+      return None
+    left = Operation(left, op, right)
+  return left
+
+
+def ParseCondition(expr):
+  """Parses a logical expression into an Expression object"""
+  tokens = Tokenizer(expr).Tokenize()
+  if not tokens:
+    print "Malformed expression: '%s'" % expr
+    return None
+  scan = Scanner(tokens)
+  ast = ParseLogicalExpression(scan)
+  if not ast:
+    print "Malformed expression: '%s'" % expr
+    return None
+  return ast
+
+
+class ClassifiedTest(object):
+
+  def __init__(self, case, outcomes):
+    self.case = case
+    self.outcomes = outcomes
+
+
+class Configuration(object):
+  """The parsed contents of a configuration file"""
+
+  def __init__(self, sections, defs):
+    self.sections = sections
+    self.defs = defs
+
+  def ClassifyTests(self, cases, env):
+    sections = [s for s in self.sections if s.condition.Evaluate(env, self.defs)]
+    all_rules = reduce(list.__add__, [s.rules for s in sections], [])
+    unused_rules = set(all_rules)
+    result = [ ]
+    all_outcomes = set([])
+    for case in cases:
+      matches = [ r for r in all_rules if r.Contains(case.path) ]
+      outcomes = set([])
+      for rule in matches:
+        outcomes = outcomes.union(rule.GetOutcomes(env, self.defs))
+        unused_rules.discard(rule)
+      if not outcomes:
+        outcomes = [PASS]
+      case.outcomes = outcomes
+      all_outcomes = all_outcomes.union(outcomes)
+      result.append(ClassifiedTest(case, outcomes))
+    return (result, list(unused_rules), all_outcomes)
+
+
+class Section(object):
+  """A section of the configuration file.  Sections are enabled or
+  disabled prior to running the tests, based on their conditions"""
+
+  def __init__(self, condition):
+    self.condition = condition
+    self.rules = [ ]
+
+  def AddRule(self, rule):
+    self.rules.append(rule)
+
+
+class Rule(object):
+  """A single rule that specifies the expected outcome for a single
+  test."""
+
+  def __init__(self, raw_path, path, value):
+    self.raw_path = raw_path
+    self.path = path
+    self.value = value
+
+  def GetOutcomes(self, env, defs):
+    set = self.value.GetOutcomes(env, defs)
+    assert isinstance(set, ListSet)
+    return set.elms
+
+  def Contains(self, path):
+    if len(self.path) > len(path):
+      return False
+    for i in xrange(len(self.path)):
+      if not self.path[i].match(path[i]):
+        return False
+    return True
+
+
+HEADER_PATTERN = re.compile(r'\[([^]]+)\]')
+RULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)')
+DEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$')
+PREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w\_\.\-\/]+)$')
+
+
+def ReadConfigurationInto(path, sections, defs):
+  current_section = Section(Constant(True))
+  sections.append(current_section)
+  prefix = []
+  for line in utils.ReadLinesFrom(path):
+    header_match = HEADER_PATTERN.match(line)
+    if header_match:
+      condition_str = header_match.group(1).strip()
+      condition = ParseCondition(condition_str)
+      new_section = Section(condition)
+      sections.append(new_section)
+      current_section = new_section
+      continue
+    rule_match = RULE_PATTERN.match(line)
+    if rule_match:
+      path = prefix + SplitPath(rule_match.group(1).strip())
+      value_str = rule_match.group(2).strip()
+      value = ParseCondition(value_str)
+      if not value:
+        return False
+      current_section.AddRule(Rule(rule_match.group(1), path, value))
+      continue
+    def_match = DEF_PATTERN.match(line)
+    if def_match:
+      name = def_match.group(1).lower()
+      value = ParseCondition(def_match.group(2).strip())
+      if not value:
+        return False
+      defs[name] = value
+      continue
+    prefix_match = PREFIX_PATTERN.match(line)
+    if prefix_match:
+      prefix = SplitPath(prefix_match.group(1).strip())
+      continue
+    print "Malformed line: '%s'." % line
+    return False
+  return True
+
+
+# ---------------
+# --- M a i n ---
+# ---------------
+
+
+ARCH_GUESS = utils.GuessArchitecture()
+
+
+def BuildOptions():
+  result = optparse.OptionParser()
+  result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)",
+      default='release')
+  result.add_option("-v", "--verbose", help="Verbose output",
+      default=False, action="store_true")
+  result.add_option("-S", dest="scons_flags", help="Flag to pass through to scons",
+      default=[], action="append")
+  result.add_option("-p", "--progress",
+      help="The style of progress indicator (verbose, dots, color, mono)",
+      choices=PROGRESS_INDICATORS.keys(), default="mono")
+  result.add_option("--no-build", help="Don't build requirements",
+      default=False, action="store_true")
+  result.add_option("--report", help="Print a summary of the tests to be run",
+      default=False, action="store_true")
+  result.add_option("-s", "--suite", help="A test suite",
+      default=[], action="append")
+  result.add_option("-t", "--timeout", help="Timeout in seconds",
+      default=60, type="int")
+  result.add_option("--arch", help='The architecture to run tests for',
+      default='none')
+  result.add_option("--simulator", help="Run tests with architecture simulator",
+      default='none')
+  result.add_option("--special-command", default=None)
+  result.add_option("--cat", help="Print the source of the tests",
+      default=False, action="store_true")
+  result.add_option("--warn-unused", help="Report unused rules",
+      default=False, action="store_true")
+  result.add_option("-j", help="The number of parallel tasks to run",
+      default=1, type="int")
+  result.add_option("--time", help="Print timing information after running",
+      default=False, action="store_true")
+  return result
+
+
+def ProcessOptions(options):
+  global VERBOSE
+  VERBOSE = options.verbose
+  options.mode = options.mode.split(',')
+  for mode in options.mode:
+    if not mode in ['debug', 'release']:
+      print "Unknown mode %s" % mode
+      return False
+  if options.simulator != 'none':
+    # Simulator argument was set. Make sure arch and simulator agree.
+    if options.simulator != options.arch:
+      if options.arch == 'none':
+        options.arch = options.simulator
+      else:
+        print "Architecture %s does not match sim %s" %(options.arch, options.simulator)
+        return False
+    # Ensure that the simulator argument is handed down to scons.
+    options.scons_flags.append("simulator=" + options.simulator)
+  else:
+    # If options.arch is not set by the command line and no simulator setting
+    # was found, set the arch to the guess.
+    if options.arch == 'none':
+      options.arch = ARCH_GUESS
+  return True
+
+
+REPORT_TEMPLATE = """\
+Total: %(total)i tests
+ * %(skipped)4d tests will be skipped
+ * %(nocrash)4d tests are expected to be flaky but not crash
+ * %(pass)4d tests are expected to pass
+ * %(fail_ok)4d tests are expected to fail that we won't fix
+ * %(fail)4d tests are expected to fail that we should fix\
+"""
+
+def PrintReport(cases):
+  def IsFlaky(o):
+    return (PASS in o) and (FAIL in o) and (not CRASH in o) and (not OKAY in o)
+  def IsFailOk(o):
+    return (len(o) == 2) and (FAIL in o) and (OKAY in o)
+  unskipped = [c for c in cases if not SKIP in c.outcomes]
+  print REPORT_TEMPLATE % {
+    'total': len(cases),
+    'skipped': len(cases) - len(unskipped),
+    'nocrash': len([t for t in unskipped if IsFlaky(t.outcomes)]),
+    'pass': len([t for t in unskipped if list(t.outcomes) == [PASS]]),
+    'fail_ok': len([t for t in unskipped if IsFailOk(t.outcomes)]),
+    'fail': len([t for t in unskipped if list(t.outcomes) == [FAIL]])
+  }
+
+
+class Pattern(object):
+
+  def __init__(self, pattern):
+    self.pattern = pattern
+    self.compiled = None
+
+  def match(self, str):
+    if not self.compiled:
+      pattern = "^" + self.pattern.replace('*', '.*') + "$"
+      self.compiled = re.compile(pattern)
+    return self.compiled.match(str)
+
+  def __str__(self):
+    return self.pattern
+
+
+def SplitPath(s):
+  stripped = [ c.strip() for c in s.split('/') ]
+  return [ Pattern(s) for s in stripped if len(s) > 0 ]
+
+
+def GetSpecialCommandProcessor(value):
+  if (not value) or (value.find('@') == -1):
+    def ExpandCommand(args):
+      return args
+    return ExpandCommand
+  else:
+    pos = value.find('@')
+    prefix = value[:pos].split()
+    suffix = value[pos+1:].split()
+    def ExpandCommand(args):
+      return prefix + args + suffix
+    return ExpandCommand
+
+
+BUILT_IN_TESTS = ['mjsunit', 'cctest', 'message']
+
+
+def GetSuites(test_root):
+  def IsSuite(path):
+    return isdir(path) and exists(join(path, 'testcfg.py'))
+  return [ f for f in os.listdir(test_root) if IsSuite(join(test_root, f)) ]
+
+
+def FormatTime(d):
+  millis = round(d * 1000) % 1000
+  return time.strftime("%M:%S.", time.gmtime(d)) + ("%03i" % millis)
+
+
+def Main():
+  parser = BuildOptions()
+  (options, args) = parser.parse_args()
+  if not ProcessOptions(options):
+    parser.print_help()
+    return 1
+
+  workspace = abspath(join(dirname(sys.argv[0]), '..'))
+  suites = GetSuites(join(workspace, 'test'))
+  repositories = [TestRepository(join(workspace, 'test', name)) for name in suites]
+  repositories += [TestRepository(a) for a in options.suite]
+
+  root = LiteralTestSuite(repositories)
+  if len(args) == 0:
+    paths = [SplitPath(t) for t in BUILT_IN_TESTS]
+  else:
+    paths = [ ]
+    for arg in args:
+      path = SplitPath(arg)
+      paths.append(path)
+
+  # First build the required targets
+  buildspace = abspath('.')
+  context = Context(workspace, buildspace, VERBOSE,
+                    join(buildspace, 'shell'),
+                    options.timeout,
+                    GetSpecialCommandProcessor(options.special_command))
+  if options.j != 1:
+    options.scons_flags += ['-j', str(options.j)]
+  if not options.no_build:
+    reqs = [ ]
+    for path in paths:
+      reqs += root.GetBuildRequirements(path, context)
+    reqs = list(set(reqs))
+    if len(reqs) > 0:
+      if not BuildRequirements(context, reqs, options.mode, options.scons_flags):
+        return 1
+
+  # Get status for tests
+  sections = [ ]
+  defs = { }
+  root.GetTestStatus(context, sections, defs)
+  config = Configuration(sections, defs)
+
+  # List the tests
+  all_cases = [ ]
+  all_unused = [ ]
+  unclassified_tests = [ ]
+  globally_unused_rules = None
+  for path in paths:
+    for mode in options.mode:
+      env = {
+        'mode': mode,
+        'system': platform.system().lower(),
+        'arch': options.arch
+      }
+      test_list = root.ListTests([], path, context, mode)
+      unclassified_tests += test_list
+      (cases, unused_rules, all_outcomes) = config.ClassifyTests(test_list, env)
+      if globally_unused_rules is None:
+        globally_unused_rules = set(unused_rules)
+      else:
+        globally_unused_rules = globally_unused_rules.intersection(unused_rules)
+      all_cases += cases
+      all_unused.append(unused_rules)
+
+  if options.cat:
+    visited = set()
+    for test in unclassified_tests:
+      key = tuple(test.path)
+      if key in visited:
+        continue
+      visited.add(key)
+      print "--- begin source: %s ---" % test.GetLabel()
+      source = test.GetSource().strip()
+      print source
+      print "--- end source: %s ---" % test.GetLabel()
+    return 0
+
+  if options.warn_unused:
+    for rule in globally_unused_rules:
+      print "Rule for '%s' was not used." % '/'.join([str(s) for s in rule.path])
+
+  if options.report:
+    PrintReport(all_cases)
+
+  result = None
+  if len(all_cases) == 0:
+    print "No tests to run."
+    return 0
+  else:
+    try:
+      start = time.time()
+      if RunTestCases(all_cases, options.progress, options.j):
+        result = 0
+      else:
+        result = 1
+      duration = time.time() - start
+    except KeyboardInterrupt:
+      print "Interrupted"
+      return 1
+
+  if options.time:
+    # Write the times to stderr to make it easy to separate from the
+    # test output.
+    print
+    sys.stderr.write("--- Total time: %s ---\n" % FormatTime(duration))
+    timed_tests = [ t.case for t in all_cases if not t.case.duration is None ]
+    timed_tests.sort(lambda a, b: a.CompareTime(b))
+    index = 1
+    for entry in timed_tests[:20]:
+      t = FormatTime(entry.duration)
+      sys.stderr.write("%4i (%s) %s\n" % (index, t, entry.GetLabel()))
+      index += 1
+
+  return result
+
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/regexp2000/tools/tickprocessor.py b/regexp2000/tools/tickprocessor.py
new file mode 100644 (file)
index 0000000..e3df951
--- /dev/null
@@ -0,0 +1,206 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import csv, splaytree, sys
+
+
+class CodeEntry(object):
+
+  def __init__(self, start_addr, name):
+    self.start_addr = start_addr
+    self.tick_count = 0
+    self.name = name
+
+  def IncrementTickCount(self):
+    self.tick_count += 1
+
+  def SetStartAddress(self, start_addr):
+    self.start_addr = start_addr
+
+  def ToString(self):
+    return self.name
+
+  def IsSharedLibraryEntry(self):
+    return False
+
+
+class SharedLibraryEntry(CodeEntry):
+
+  def __init__(self, start_addr, name):
+    CodeEntry.__init__(self, start_addr, name)
+
+  def IsSharedLibraryEntry(self):
+    return True
+
+
+class JSCodeEntry(CodeEntry):
+
+  def __init__(self, start_addr, name, type, size):
+    CodeEntry.__init__(self, start_addr, name)
+    self.type = type
+    self.size = size
+
+  def ToString(self):
+    name = self.name
+    if name == '': name = '<anonymous>'
+    return self.type + ': ' + name
+
+
+class TickProcessor(object):
+
+  def __init__(self):
+    self.log_file = ''
+    self.deleted_code = []
+    self.vm_extent = {}
+    self.js_entries = splaytree.SplayTree()
+    self.cpp_entries = splaytree.SplayTree()
+    self.total_number_of_ticks = 0
+    self.number_of_library_ticks = 0
+    self.unaccounted_number_of_ticks = 0
+    self.excluded_number_of_ticks = 0
+
+  def ProcessLogfile(self, filename, included_state = None):
+    self.log_file = filename
+    self.included_state = included_state
+    try:
+      logfile = open(filename, 'rb')
+    except IOError:
+      sys.exit("Could not open logfile: " + filename)
+    try:
+      logreader = csv.reader(logfile)
+      for row in logreader:
+        if row[0] == 'tick':
+          self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]))
+        elif row[0] == 'code-creation':
+          self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4])
+        elif row[0] == 'code-move':
+          self.ProcessCodeMove(int(row[1], 16), int(row[2], 16))
+        elif row[0] == 'code-delete':
+          self.ProcessCodeDelete(int(row[1], 16))
+        elif row[0] == 'shared-library':
+          self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16))
+          self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16))
+    finally:
+      logfile.close()
+
+  def AddSharedLibraryEntry(self, filename, start, end):
+    # Mark the pages used by this library.
+    i = start
+    while i < end:
+      page = i >> 12
+      self.vm_extent[page] = 1
+      i += 4096
+    # Add the library to the entries so that ticks for which we do not
+    # have symbol information is reported as belonging to the library.
+    self.cpp_entries.Insert(start, SharedLibraryEntry(start, filename))
+
+  def ParseVMSymbols(self, filename, start, end):
+    return
+
+  def ProcessCodeCreation(self, type, addr, size, name):
+    self.js_entries.Insert(addr, JSCodeEntry(addr, name, type, size))
+
+  def ProcessCodeMove(self, from_addr, to_addr):
+    try:
+      removed_node = self.js_entries.Remove(from_addr)
+      removed_node.value.SetStartAddress(to_addr);
+      self.js_entries.Insert(to_addr, removed_node.value)
+    except 'KeyNotFound':
+      print('Code move event for unknown code: 0x%x' % from_addr)
+
+  def ProcessCodeDelete(self, from_addr):
+    try:
+      removed_node = self.js_entries.Remove(from_addr)
+      self.deleted_code.append(removed_node.value)
+    except 'KeyNotFound':
+      print('Code delete event for unknown code: 0x%x' % from_addr)
+
+  def IncludeTick(self, pc, sp, state):
+    return (self.included_state is None) or (self.included_state == state)
+
+  def ProcessTick(self, pc, sp, state):
+    if not self.IncludeTick(pc, sp, state):
+      self.excluded_number_of_ticks += 1;
+      return
+    self.total_number_of_ticks += 1
+    page = pc >> 12
+    if page in self.vm_extent:
+      entry = self.cpp_entries.FindGreatestsLessThan(pc).value
+      if entry.IsSharedLibraryEntry():
+        self.number_of_library_ticks += 1
+      entry.IncrementTickCount()
+      return
+    max = self.js_entries.FindMax()
+    min = self.js_entries.FindMin()
+    if max != None and pc < max.key and pc > min.key:
+      self.js_entries.FindGreatestsLessThan(pc).value.IncrementTickCount()
+      return
+    self.unaccounted_number_of_ticks += 1
+
+  def PrintResults(self):
+    print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d excluded).' %
+          (self.log_file,
+           self.total_number_of_ticks,
+           self.unaccounted_number_of_ticks,
+           self.excluded_number_of_ticks))
+    if self.total_number_of_ticks > 0:
+      js_entries = self.js_entries.ExportValueList()
+      js_entries.extend(self.deleted_code)
+      cpp_entries = self.cpp_entries.ExportValueList()
+      # Print the library ticks.
+      self.PrintHeader('Shared libraries')
+      self.PrintEntries(cpp_entries, lambda e:e.IsSharedLibraryEntry())
+      # Print the JavaScript ticks.
+      self.PrintHeader('JavaScript')
+      self.PrintEntries(js_entries, lambda e:not e.IsSharedLibraryEntry())
+      # Print the C++ ticks.
+      self.PrintHeader('C++')
+      self.PrintEntries(cpp_entries, lambda e:not e.IsSharedLibraryEntry())
+
+  def PrintHeader(self, header_title):
+    print('\n [%s]:' % header_title)
+    print('   total  nonlib   name')
+
+  def PrintEntries(self, entries, condition):
+    number_of_accounted_ticks = self.total_number_of_ticks - self.unaccounted_number_of_ticks
+    number_of_non_library_ticks = number_of_accounted_ticks - self.number_of_library_ticks
+    entries.sort(key=lambda e:e.tick_count, reverse=True)
+    for entry in entries:
+      if entry.tick_count > 0 and condition(entry):
+        total_percentage = entry.tick_count * 100.0 / number_of_accounted_ticks
+        if entry.IsSharedLibraryEntry():
+          non_library_percentage = 0
+        else:
+          non_library_percentage = entry.tick_count * 100.0 / number_of_non_library_ticks
+        print('  %(total)5.1f%% %(nonlib)6.1f%%   %(name)s' % {
+          'total' : total_percentage,
+          'nonlib' : non_library_percentage,
+          'name' : entry.ToString()
+        })
+
+if __name__ == '__main__':
+  sys.exit('You probably want to run windows-tick-processor.py or linux-tick-processor.py.')
diff --git a/regexp2000/tools/utils.py b/regexp2000/tools/utils.py
new file mode 100644 (file)
index 0000000..e10bb7b
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import platform
+import re
+
+
+# Reads a .list file into an array of strings
+def ReadLinesFrom(name):
+  list = []
+  for line in open(name):
+    if '#' in line:
+      line = line[:line.find('#')]
+    line = line.strip()
+    if len(line) == 0:
+      continue
+    list.append(line)
+  return list
+
+  
+def GuessArchitecture():
+  id = platform.machine()
+  if id.startswith('arm'):
+    return 'arm'
+  elif (not id) or (not re.match('(x|i[3-6])86', id) is None):
+    return 'ia32'
+  else:
+    return None
diff --git a/regexp2000/tools/v8.xcodeproj/project.pbxproj b/regexp2000/tools/v8.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..6a04153
--- /dev/null
@@ -0,0 +1,1480 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 45;
+       objects = {
+
+/* Begin PBXAggregateTarget section */
+               7BF891930E73098D000BAF8A /* All */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = 7BF8919F0E7309BE000BAF8A /* Build configuration list for PBXAggregateTarget "All" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               7BF8919B0E7309AD000BAF8A /* PBXTargetDependency */,
+                               7BF891970E73099F000BAF8A /* PBXTargetDependency */,
+                               7BF891990E73099F000BAF8A /* PBXTargetDependency */,
+                               896FD03E0E78D731003DFB6A /* PBXTargetDependency */,
+                               896FD0400E78D735003DFB6A /* PBXTargetDependency */,
+                       );
+                       name = All;
+                       productName = All;
+               };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+               8900116C0E71CA2300F91F35 /* libraries.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8900116B0E71CA2300F91F35 /* libraries.cc */; };
+               893CCE640E71D83700357A03 /* code-stubs.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1110E719B8F00D62E90 /* code-stubs.cc */; };
+               89495E480E79FC23001F68C3 /* compilation-cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89495E460E79FC23001F68C3 /* compilation-cache.cc */; };
+               89495E490E79FC23001F68C3 /* compilation-cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89495E460E79FC23001F68C3 /* compilation-cache.cc */; };
+               896FD03A0E78D717003DFB6A /* libv8-arm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89F23C870E78D5B2006B2466 /* libv8-arm.a */; };
+               897F767F0E71B690007ACF34 /* shell.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1B50E719C0900D62E90 /* shell.cc */; };
+               897F76840E71B6B1007ACF34 /* libjscre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 897FF1BF0E719CB600D62E90 /* libjscre.a */; };
+               897F76850E71B6B1007ACF34 /* libv8.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8970F2F00E719FB2006AE7B5 /* libv8.a */; };
+               897FF1C40E719D6B00D62E90 /* pcre_compile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0EA0E719B3500D62E90 /* pcre_compile.cpp */; };
+               897FF1C50E719D6E00D62E90 /* pcre_exec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0EB0E719B3500D62E90 /* pcre_exec.cpp */; };
+               897FF1C60E719D7100D62E90 /* pcre_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0ED0E719B3500D62E90 /* pcre_tables.cpp */; };
+               897FF1C70E719D7300D62E90 /* pcre_ucp_searchfuncs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0EE0E719B3500D62E90 /* pcre_ucp_searchfuncs.cpp */; };
+               897FF1C80E719D7600D62E90 /* pcre_xclass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0EF0E719B3500D62E90 /* pcre_xclass.cpp */; };
+               89A88DEC0E71A5FF0043BA31 /* accessors.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0F60E719B8F00D62E90 /* accessors.cc */; };
+               89A88DED0E71A6000043BA31 /* allocation.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0F80E719B8F00D62E90 /* allocation.cc */; };
+               89A88DEE0E71A6010043BA31 /* api.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0FA0E719B8F00D62E90 /* api.cc */; };
+               89A88DEF0E71A60A0043BA31 /* assembler-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1010E719B8F00D62E90 /* assembler-ia32.cc */; };
+               89A88DF00E71A60A0043BA31 /* assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1030E719B8F00D62E90 /* assembler.cc */; };
+               89A88DF10E71A60B0043BA31 /* ast.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1050E719B8F00D62E90 /* ast.cc */; };
+               89A88DF20E71A60C0043BA31 /* bootstrapper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1070E719B8F00D62E90 /* bootstrapper.cc */; };
+               89A88DF40E71A6160043BA31 /* builtins-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF10A0E719B8F00D62E90 /* builtins-ia32.cc */; };
+               89A88DF50E71A6170043BA31 /* builtins.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF10B0E719B8F00D62E90 /* builtins.cc */; };
+               89A88DF60E71A61C0043BA31 /* checks.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF10F0E719B8F00D62E90 /* checks.cc */; };
+               89A88DF70E71A6240043BA31 /* codegen-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1150E719B8F00D62E90 /* codegen-ia32.cc */; };
+               89A88DF80E71A6260043BA31 /* codegen.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1170E719B8F00D62E90 /* codegen.cc */; };
+               89A88DF90E71A6430043BA31 /* compiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1190E719B8F00D62E90 /* compiler.cc */; };
+               89A88DFA0E71A6440043BA31 /* contexts.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF11C0E719B8F00D62E90 /* contexts.cc */; };
+               89A88DFB0E71A6440043BA31 /* conversions.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF11F0E719B8F00D62E90 /* conversions.cc */; };
+               89A88DFC0E71A6460043BA31 /* counters.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1210E719B8F00D62E90 /* counters.cc */; };
+               89A88DFD0E71A6470043BA31 /* cpu-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1240E719B8F00D62E90 /* cpu-ia32.cc */; };
+               89A88DFE0E71A6480043BA31 /* dateparser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1260E719B8F00D62E90 /* dateparser.cc */; };
+               89A88DFF0E71A6530043BA31 /* debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1280E719B8F00D62E90 /* debug.cc */; };
+               89A88E000E71A6540043BA31 /* disasm-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF12B0E719B8F00D62E90 /* disasm-ia32.cc */; };
+               89A88E010E71A6550043BA31 /* disassembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF12D0E719B8F00D62E90 /* disassembler.cc */; };
+               89A88E020E71A65A0043BA31 /* dtoa-config.c in Sources */ = {isa = PBXBuildFile; fileRef = 897FF12F0E719B8F00D62E90 /* dtoa-config.c */; };
+               89A88E030E71A65B0043BA31 /* execution.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1300E719B8F00D62E90 /* execution.cc */; };
+               89A88E040E71A65D0043BA31 /* factory.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1320E719B8F00D62E90 /* factory.cc */; };
+               89A88E050E71A65D0043BA31 /* flags.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1350E719B8F00D62E90 /* flags.cc */; };
+               89A88E060E71A6600043BA31 /* frames-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1390E719B8F00D62E90 /* frames-ia32.cc */; };
+               89A88E070E71A6610043BA31 /* frames.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF13C0E719B8F00D62E90 /* frames.cc */; };
+               89A88E080E71A6620043BA31 /* global-handles.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF13E0E719B8F00D62E90 /* global-handles.cc */; };
+               89A88E090E71A6640043BA31 /* handles.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1420E719B8F00D62E90 /* handles.cc */; };
+               89A88E0A0E71A6650043BA31 /* hashmap.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1440E719B8F00D62E90 /* hashmap.cc */; };
+               89A88E0B0E71A66C0043BA31 /* heap.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1470E719B8F00D62E90 /* heap.cc */; };
+               89A88E0C0E71A66D0043BA31 /* ic-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF14A0E719B8F00D62E90 /* ic-ia32.cc */; };
+               89A88E0D0E71A66E0043BA31 /* ic.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF14C0E719B8F00D62E90 /* ic.cc */; };
+               89A88E0E0E71A66F0043BA31 /* jsregexp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF14E0E719B8F00D62E90 /* jsregexp.cc */; };
+               89A88E0F0E71A6740043BA31 /* log.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1520E719B8F00D62E90 /* log.cc */; };
+               89A88E100E71A6770043BA31 /* macro-assembler-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1560E719B8F00D62E90 /* macro-assembler-ia32.cc */; };
+               89A88E110E71A6780043BA31 /* mark-compact.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1590E719B8F00D62E90 /* mark-compact.cc */; };
+               89A88E120E71A67A0043BA31 /* messages.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF15C0E719B8F00D62E90 /* messages.cc */; };
+               89A88E130E71A6860043BA31 /* objects-debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1600E719B8F00D62E90 /* objects-debug.cc */; };
+               89A88E140E71A6870043BA31 /* objects.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1620E719B8F00D62E90 /* objects.cc */; };
+               89A88E150E71A68C0043BA31 /* parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1640E719B8F00D62E90 /* parser.cc */; };
+               89A88E160E71A68E0043BA31 /* platform-macos.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1670E719B8F00D62E90 /* platform-macos.cc */; };
+               89A88E170E71A6950043BA31 /* prettyprinter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16B0E719B8F00D62E90 /* prettyprinter.cc */; };
+               89A88E180E71A6960043BA31 /* property.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16D0E719B8F00D62E90 /* property.cc */; };
+               89A88E190E71A6970043BA31 /* rewriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16F0E719B8F00D62E90 /* rewriter.cc */; };
+               89A88E1A0E71A69B0043BA31 /* runtime.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1710E719B8F00D62E90 /* runtime.cc */; };
+               89A88E1B0E71A69D0043BA31 /* scanner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner.cc */; };
+               89A88E1C0E71A69E0043BA31 /* scopeinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1760E719B8F00D62E90 /* scopeinfo.cc */; };
+               89A88E1D0E71A6A00043BA31 /* scopes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1780E719B8F00D62E90 /* scopes.cc */; };
+               89A88E1E0E71A6A30043BA31 /* serialize.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF17A0E719B8F00D62E90 /* serialize.cc */; };
+               89A88E1F0E71A6B40043BA31 /* snapshot-common.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1820E719B8F00D62E90 /* snapshot-common.cc */; };
+               89A88E200E71A6B60043BA31 /* snapshot-empty.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1830E719B8F00D62E90 /* snapshot-empty.cc */; };
+               89A88E210E71A6B70043BA31 /* spaces.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1860E719B8F00D62E90 /* spaces.cc */; };
+               89A88E220E71A6BC0043BA31 /* string-stream.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1880E719B8F00D62E90 /* string-stream.cc */; };
+               89A88E230E71A6BE0043BA31 /* stub-cache-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18B0E719B8F00D62E90 /* stub-cache-ia32.cc */; };
+               89A88E240E71A6BF0043BA31 /* stub-cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18C0E719B8F00D62E90 /* stub-cache.cc */; };
+               89A88E250E71A6C20043BA31 /* token.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18E0E719B8F00D62E90 /* token.cc */; };
+               89A88E260E71A6C90043BA31 /* top.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1900E719B8F00D62E90 /* top.cc */; };
+               89A88E270E71A6CB0043BA31 /* unicode.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1930E719B8F00D62E90 /* unicode.cc */; };
+               89A88E280E71A6CC0043BA31 /* usage-analyzer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1950E719B8F00D62E90 /* usage-analyzer.cc */; };
+               89A88E290E71A6CE0043BA31 /* utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1970E719B8F00D62E90 /* utils.cc */; };
+               89A88E2A0E71A6D00043BA31 /* v8-counters.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1990E719B8F00D62E90 /* v8-counters.cc */; };
+               89A88E2B0E71A6D10043BA31 /* v8.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19B0E719B8F00D62E90 /* v8.cc */; };
+               89A88E2C0E71A6D20043BA31 /* v8threads.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19D0E719B8F00D62E90 /* v8threads.cc */; };
+               89A88E2D0E71A6D50043BA31 /* variables.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19F0E719B8F00D62E90 /* variables.cc */; };
+               89A88E2E0E71A6D60043BA31 /* zone.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1A20E719B8F00D62E90 /* zone.cc */; };
+               89F23C3F0E78D5B2006B2466 /* accessors.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0F60E719B8F00D62E90 /* accessors.cc */; };
+               89F23C400E78D5B2006B2466 /* allocation.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0F80E719B8F00D62E90 /* allocation.cc */; };
+               89F23C410E78D5B2006B2466 /* api.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0FA0E719B8F00D62E90 /* api.cc */; };
+               89F23C430E78D5B2006B2466 /* assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1030E719B8F00D62E90 /* assembler.cc */; };
+               89F23C440E78D5B2006B2466 /* ast.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1050E719B8F00D62E90 /* ast.cc */; };
+               89F23C450E78D5B2006B2466 /* bootstrapper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1070E719B8F00D62E90 /* bootstrapper.cc */; };
+               89F23C470E78D5B2006B2466 /* builtins.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF10B0E719B8F00D62E90 /* builtins.cc */; };
+               89F23C480E78D5B2006B2466 /* checks.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF10F0E719B8F00D62E90 /* checks.cc */; };
+               89F23C490E78D5B2006B2466 /* code-stubs.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1110E719B8F00D62E90 /* code-stubs.cc */; };
+               89F23C4B0E78D5B2006B2466 /* codegen.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1170E719B8F00D62E90 /* codegen.cc */; };
+               89F23C4C0E78D5B2006B2466 /* compiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1190E719B8F00D62E90 /* compiler.cc */; };
+               89F23C4D0E78D5B2006B2466 /* contexts.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF11C0E719B8F00D62E90 /* contexts.cc */; };
+               89F23C4E0E78D5B2006B2466 /* conversions.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF11F0E719B8F00D62E90 /* conversions.cc */; };
+               89F23C4F0E78D5B2006B2466 /* counters.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1210E719B8F00D62E90 /* counters.cc */; };
+               89F23C510E78D5B2006B2466 /* dateparser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1260E719B8F00D62E90 /* dateparser.cc */; };
+               89F23C520E78D5B2006B2466 /* debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1280E719B8F00D62E90 /* debug.cc */; };
+               89F23C540E78D5B2006B2466 /* disassembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF12D0E719B8F00D62E90 /* disassembler.cc */; };
+               89F23C550E78D5B2006B2466 /* dtoa-config.c in Sources */ = {isa = PBXBuildFile; fileRef = 897FF12F0E719B8F00D62E90 /* dtoa-config.c */; };
+               89F23C560E78D5B2006B2466 /* execution.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1300E719B8F00D62E90 /* execution.cc */; };
+               89F23C570E78D5B2006B2466 /* factory.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1320E719B8F00D62E90 /* factory.cc */; };
+               89F23C580E78D5B2006B2466 /* flags.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1350E719B8F00D62E90 /* flags.cc */; };
+               89F23C5A0E78D5B2006B2466 /* frames.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF13C0E719B8F00D62E90 /* frames.cc */; };
+               89F23C5B0E78D5B2006B2466 /* global-handles.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF13E0E719B8F00D62E90 /* global-handles.cc */; };
+               89F23C5C0E78D5B2006B2466 /* handles.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1420E719B8F00D62E90 /* handles.cc */; };
+               89F23C5D0E78D5B2006B2466 /* hashmap.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1440E719B8F00D62E90 /* hashmap.cc */; };
+               89F23C5E0E78D5B2006B2466 /* heap.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1470E719B8F00D62E90 /* heap.cc */; };
+               89F23C600E78D5B2006B2466 /* ic.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF14C0E719B8F00D62E90 /* ic.cc */; };
+               89F23C610E78D5B2006B2466 /* jsregexp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF14E0E719B8F00D62E90 /* jsregexp.cc */; };
+               89F23C620E78D5B2006B2466 /* libraries.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8900116B0E71CA2300F91F35 /* libraries.cc */; };
+               89F23C630E78D5B2006B2466 /* log.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1520E719B8F00D62E90 /* log.cc */; };
+               89F23C650E78D5B2006B2466 /* mark-compact.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1590E719B8F00D62E90 /* mark-compact.cc */; };
+               89F23C660E78D5B2006B2466 /* messages.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF15C0E719B8F00D62E90 /* messages.cc */; };
+               89F23C670E78D5B2006B2466 /* objects-debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1600E719B8F00D62E90 /* objects-debug.cc */; };
+               89F23C680E78D5B2006B2466 /* objects.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1620E719B8F00D62E90 /* objects.cc */; };
+               89F23C690E78D5B2006B2466 /* parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1640E719B8F00D62E90 /* parser.cc */; };
+               89F23C6A0E78D5B2006B2466 /* platform-macos.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1670E719B8F00D62E90 /* platform-macos.cc */; };
+               89F23C6B0E78D5B2006B2466 /* prettyprinter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16B0E719B8F00D62E90 /* prettyprinter.cc */; };
+               89F23C6C0E78D5B2006B2466 /* property.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16D0E719B8F00D62E90 /* property.cc */; };
+               89F23C6D0E78D5B2006B2466 /* rewriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16F0E719B8F00D62E90 /* rewriter.cc */; };
+               89F23C6E0E78D5B2006B2466 /* runtime.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1710E719B8F00D62E90 /* runtime.cc */; };
+               89F23C6F0E78D5B2006B2466 /* scanner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner.cc */; };
+               89F23C700E78D5B2006B2466 /* scopeinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1760E719B8F00D62E90 /* scopeinfo.cc */; };
+               89F23C710E78D5B2006B2466 /* scopes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1780E719B8F00D62E90 /* scopes.cc */; };
+               89F23C720E78D5B2006B2466 /* serialize.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF17A0E719B8F00D62E90 /* serialize.cc */; };
+               89F23C730E78D5B2006B2466 /* snapshot-common.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1820E719B8F00D62E90 /* snapshot-common.cc */; };
+               89F23C740E78D5B2006B2466 /* snapshot-empty.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1830E719B8F00D62E90 /* snapshot-empty.cc */; };
+               89F23C750E78D5B2006B2466 /* spaces.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1860E719B8F00D62E90 /* spaces.cc */; };
+               89F23C760E78D5B2006B2466 /* string-stream.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1880E719B8F00D62E90 /* string-stream.cc */; };
+               89F23C780E78D5B2006B2466 /* stub-cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18C0E719B8F00D62E90 /* stub-cache.cc */; };
+               89F23C790E78D5B2006B2466 /* token.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18E0E719B8F00D62E90 /* token.cc */; };
+               89F23C7A0E78D5B2006B2466 /* top.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1900E719B8F00D62E90 /* top.cc */; };
+               89F23C7B0E78D5B2006B2466 /* unicode.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1930E719B8F00D62E90 /* unicode.cc */; };
+               89F23C7C0E78D5B2006B2466 /* usage-analyzer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1950E719B8F00D62E90 /* usage-analyzer.cc */; };
+               89F23C7D0E78D5B2006B2466 /* utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1970E719B8F00D62E90 /* utils.cc */; };
+               89F23C7E0E78D5B2006B2466 /* v8-counters.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1990E719B8F00D62E90 /* v8-counters.cc */; };
+               89F23C7F0E78D5B2006B2466 /* v8.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19B0E719B8F00D62E90 /* v8.cc */; };
+               89F23C800E78D5B2006B2466 /* v8threads.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19D0E719B8F00D62E90 /* v8threads.cc */; };
+               89F23C810E78D5B2006B2466 /* variables.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF19F0E719B8F00D62E90 /* variables.cc */; };
+               89F23C820E78D5B2006B2466 /* zone.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1A20E719B8F00D62E90 /* zone.cc */; };
+               89F23C8E0E78D5B6006B2466 /* shell.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1B50E719C0900D62E90 /* shell.cc */; };
+               89F23C900E78D5B6006B2466 /* libjscre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 897FF1BF0E719CB600D62E90 /* libjscre.a */; };
+               89F23C970E78D5E3006B2466 /* assembler-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF0FE0E719B8F00D62E90 /* assembler-arm.cc */; };
+               89F23C980E78D5E7006B2466 /* builtins-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1090E719B8F00D62E90 /* builtins-arm.cc */; };
+               89F23C990E78D5E9006B2466 /* codegen-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1140E719B8F00D62E90 /* codegen-arm.cc */; };
+               89F23C9A0E78D5EC006B2466 /* cpu-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1230E719B8F00D62E90 /* cpu-arm.cc */; };
+               89F23C9B0E78D5EE006B2466 /* disasm-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF12A0E719B8F00D62E90 /* disasm-arm.cc */; };
+               89F23C9C0E78D5F1006B2466 /* frames-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1370E719B8F00D62E90 /* frames-arm.cc */; };
+               89F23C9D0E78D5FB006B2466 /* ic-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1490E719B8F00D62E90 /* ic-arm.cc */; };
+               89F23C9E0E78D5FD006B2466 /* macro-assembler-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */; };
+               89F23C9F0E78D604006B2466 /* simulator-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */; };
+               89F23CA00E78D609006B2466 /* stub-cache-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+               7BF891960E73099F000BAF8A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 8970F2EF0E719FB2006AE7B5;
+                       remoteInfo = v8;
+               };
+               7BF891980E73099F000BAF8A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 897F76790E71B4CC007ACF34;
+                       remoteInfo = v8_shell;
+               };
+               7BF8919A0E7309AD000BAF8A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 897FF1BE0E719CB600D62E90;
+                       remoteInfo = jscre;
+               };
+               896FD03B0E78D71F003DFB6A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 89F23C3C0E78D5B2006B2466;
+                       remoteInfo = "v8-arm";
+               };
+               896FD03D0E78D731003DFB6A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 89F23C3C0E78D5B2006B2466;
+                       remoteInfo = "v8-arm";
+               };
+               896FD03F0E78D735003DFB6A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 89F23C880E78D5B6006B2466;
+                       remoteInfo = "v8_shell-arm";
+               };
+               897F76800E71B6AC007ACF34 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 897FF1BE0E719CB600D62E90;
+                       remoteInfo = jscre;
+               };
+               897F76820E71B6AC007ACF34 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 8970F2EF0E719FB2006AE7B5;
+                       remoteInfo = v8;
+               };
+               89F23C8A0E78D5B6006B2466 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 8915B8680E719336009C4E19 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 897FF1BE0E719CB600D62E90;
+                       remoteInfo = jscre;
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+               8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; };
+               89495E460E79FC23001F68C3 /* compilation-cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "compilation-cache.cc"; sourceTree = "<group>"; };
+               89495E470E79FC23001F68C3 /* compilation-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "compilation-cache.h"; sourceTree = "<group>"; };
+               8964482B0E9C00F700E7C516 /* codegen-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-ia32.h"; sourceTree = "<group>"; };
+               896448BC0E9D530500E7C516 /* codegen-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-arm.h"; sourceTree = "<group>"; };
+               8970F2F00E719FB2006AE7B5 /* libv8.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libv8.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               897F767A0E71B4CC007ACF34 /* v8_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = v8_shell; sourceTree = BUILT_PRODUCTS_DIR; };
+               897FF0D40E719A8500D62E90 /* v8-debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "v8-debug.h"; sourceTree = "<group>"; };
+               897FF0D50E719A8500D62E90 /* v8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v8.h; sourceTree = "<group>"; };
+               897FF0E00E719B3500D62E90 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
+               897FF0E10E719B3500D62E90 /* dtoa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dtoa.c; sourceTree = "<group>"; };
+               897FF0E30E719B3500D62E90 /* ASCIICType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCIICType.h; sourceTree = "<group>"; };
+               897FF0E40E719B3500D62E90 /* AUTHORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS; sourceTree = "<group>"; };
+               897FF0E50E719B3500D62E90 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
+               897FF0E60E719B3500D62E90 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
+               897FF0E70E719B3500D62E90 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
+               897FF0E80E719B3500D62E90 /* pcre.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pcre.h; sourceTree = "<group>"; };
+               897FF0E90E719B3500D62E90 /* pcre_chartables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcre_chartables.c; sourceTree = "<group>"; };
+               897FF0EA0E719B3500D62E90 /* pcre_compile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pcre_compile.cpp; sourceTree = "<group>"; };
+               897FF0EB0E719B3500D62E90 /* pcre_exec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pcre_exec.cpp; sourceTree = "<group>"; };
+               897FF0EC0E719B3500D62E90 /* pcre_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pcre_internal.h; sourceTree = "<group>"; };
+               897FF0ED0E719B3500D62E90 /* pcre_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pcre_tables.cpp; sourceTree = "<group>"; };
+               897FF0EE0E719B3500D62E90 /* pcre_ucp_searchfuncs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pcre_ucp_searchfuncs.cpp; sourceTree = "<group>"; };
+               897FF0EF0E719B3500D62E90 /* pcre_xclass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pcre_xclass.cpp; sourceTree = "<group>"; };
+               897FF0F00E719B3500D62E90 /* ucpinternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucpinternal.h; sourceTree = "<group>"; };
+               897FF0F10E719B3500D62E90 /* ucptable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ucptable.cpp; sourceTree = "<group>"; };
+               897FF0F60E719B8F00D62E90 /* accessors.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = accessors.cc; sourceTree = "<group>"; };
+               897FF0F70E719B8F00D62E90 /* accessors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = accessors.h; sourceTree = "<group>"; };
+               897FF0F80E719B8F00D62E90 /* allocation.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = allocation.cc; sourceTree = "<group>"; };
+               897FF0F90E719B8F00D62E90 /* allocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = allocation.h; sourceTree = "<group>"; };
+               897FF0FA0E719B8F00D62E90 /* api.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = api.cc; sourceTree = "<group>"; };
+               897FF0FB0E719B8F00D62E90 /* api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = api.h; sourceTree = "<group>"; };
+               897FF0FC0E719B8F00D62E90 /* arguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arguments.h; sourceTree = "<group>"; };
+               897FF0FD0E719B8F00D62E90 /* assembler-arm-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-arm-inl.h"; sourceTree = "<group>"; };
+               897FF0FE0E719B8F00D62E90 /* assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "assembler-arm.cc"; sourceTree = "<group>"; };
+               897FF0FF0E719B8F00D62E90 /* assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-arm.h"; sourceTree = "<group>"; };
+               897FF1000E719B8F00D62E90 /* assembler-ia32-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-ia32-inl.h"; sourceTree = "<group>"; };
+               897FF1010E719B8F00D62E90 /* assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "assembler-ia32.cc"; sourceTree = "<group>"; };
+               897FF1020E719B8F00D62E90 /* assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "assembler-ia32.h"; sourceTree = "<group>"; };
+               897FF1030E719B8F00D62E90 /* assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assembler.cc; sourceTree = "<group>"; };
+               897FF1040E719B8F00D62E90 /* assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assembler.h; sourceTree = "<group>"; };
+               897FF1050E719B8F00D62E90 /* ast.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ast.cc; sourceTree = "<group>"; };
+               897FF1060E719B8F00D62E90 /* ast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ast.h; sourceTree = "<group>"; };
+               897FF1070E719B8F00D62E90 /* bootstrapper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bootstrapper.cc; sourceTree = "<group>"; };
+               897FF1080E719B8F00D62E90 /* bootstrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bootstrapper.h; sourceTree = "<group>"; };
+               897FF1090E719B8F00D62E90 /* builtins-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "builtins-arm.cc"; sourceTree = "<group>"; };
+               897FF10A0E719B8F00D62E90 /* builtins-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "builtins-ia32.cc"; sourceTree = "<group>"; };
+               897FF10B0E719B8F00D62E90 /* builtins.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = builtins.cc; sourceTree = "<group>"; };
+               897FF10C0E719B8F00D62E90 /* builtins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtins.h; sourceTree = "<group>"; };
+               897FF10D0E719B8F00D62E90 /* char-predicates-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "char-predicates-inl.h"; sourceTree = "<group>"; };
+               897FF10E0E719B8F00D62E90 /* char-predicates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "char-predicates.h"; sourceTree = "<group>"; };
+               897FF10F0E719B8F00D62E90 /* checks.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = checks.cc; sourceTree = "<group>"; };
+               897FF1100E719B8F00D62E90 /* checks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = checks.h; sourceTree = "<group>"; };
+               897FF1110E719B8F00D62E90 /* code-stubs.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "code-stubs.cc"; sourceTree = "<group>"; };
+               897FF1120E719B8F00D62E90 /* code-stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "code-stubs.h"; sourceTree = "<group>"; };
+               897FF1130E719B8F00D62E90 /* code.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = code.h; sourceTree = "<group>"; };
+               897FF1140E719B8F00D62E90 /* codegen-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "codegen-arm.cc"; sourceTree = "<group>"; };
+               897FF1150E719B8F00D62E90 /* codegen-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "codegen-ia32.cc"; sourceTree = "<group>"; };
+               897FF1160E719B8F00D62E90 /* codegen-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-inl.h"; sourceTree = "<group>"; };
+               897FF1170E719B8F00D62E90 /* codegen.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = codegen.cc; sourceTree = "<group>"; };
+               897FF1180E719B8F00D62E90 /* codegen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = codegen.h; sourceTree = "<group>"; };
+               897FF1190E719B8F00D62E90 /* compiler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compiler.cc; sourceTree = "<group>"; };
+               897FF11A0E719B8F00D62E90 /* compiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compiler.h; sourceTree = "<group>"; };
+               897FF11B0E719B8F00D62E90 /* constants-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "constants-arm.h"; sourceTree = "<group>"; };
+               897FF11C0E719B8F00D62E90 /* contexts.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = contexts.cc; sourceTree = "<group>"; };
+               897FF11D0E719B8F00D62E90 /* contexts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contexts.h; sourceTree = "<group>"; };
+               897FF11E0E719B8F00D62E90 /* conversions-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "conversions-inl.h"; sourceTree = "<group>"; };
+               897FF11F0E719B8F00D62E90 /* conversions.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = conversions.cc; sourceTree = "<group>"; };
+               897FF1200E719B8F00D62E90 /* conversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conversions.h; sourceTree = "<group>"; };
+               897FF1210E719B8F00D62E90 /* counters.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = counters.cc; sourceTree = "<group>"; };
+               897FF1220E719B8F00D62E90 /* counters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = counters.h; sourceTree = "<group>"; };
+               897FF1230E719B8F00D62E90 /* cpu-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "cpu-arm.cc"; sourceTree = "<group>"; };
+               897FF1240E719B8F00D62E90 /* cpu-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "cpu-ia32.cc"; sourceTree = "<group>"; };
+               897FF1250E719B8F00D62E90 /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = "<group>"; };
+               897FF1260E719B8F00D62E90 /* dateparser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dateparser.cc; sourceTree = "<group>"; };
+               897FF1270E719B8F00D62E90 /* dateparser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dateparser.h; sourceTree = "<group>"; };
+               897FF1280E719B8F00D62E90 /* debug.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debug.cc; sourceTree = "<group>"; };
+               897FF1290E719B8F00D62E90 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
+               897FF12A0E719B8F00D62E90 /* disasm-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "disasm-arm.cc"; sourceTree = "<group>"; };
+               897FF12B0E719B8F00D62E90 /* disasm-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "disasm-ia32.cc"; sourceTree = "<group>"; };
+               897FF12C0E719B8F00D62E90 /* disasm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disasm.h; sourceTree = "<group>"; };
+               897FF12D0E719B8F00D62E90 /* disassembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = disassembler.cc; sourceTree = "<group>"; };
+               897FF12E0E719B8F00D62E90 /* disassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disassembler.h; sourceTree = "<group>"; };
+               897FF12F0E719B8F00D62E90 /* dtoa-config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dtoa-config.c"; sourceTree = "<group>"; };
+               897FF1300E719B8F00D62E90 /* execution.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = execution.cc; sourceTree = "<group>"; };
+               897FF1310E719B8F00D62E90 /* execution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = execution.h; sourceTree = "<group>"; };
+               897FF1320E719B8F00D62E90 /* factory.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = factory.cc; sourceTree = "<group>"; };
+               897FF1330E719B8F00D62E90 /* factory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = factory.h; sourceTree = "<group>"; };
+               897FF1350E719B8F00D62E90 /* flags.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flags.cc; sourceTree = "<group>"; };
+               897FF1360E719B8F00D62E90 /* flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flags.h; sourceTree = "<group>"; };
+               897FF1370E719B8F00D62E90 /* frames-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "frames-arm.cc"; sourceTree = "<group>"; };
+               897FF1380E719B8F00D62E90 /* frames-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frames-arm.h"; sourceTree = "<group>"; };
+               897FF1390E719B8F00D62E90 /* frames-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "frames-ia32.cc"; sourceTree = "<group>"; };
+               897FF13A0E719B8F00D62E90 /* frames-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frames-ia32.h"; sourceTree = "<group>"; };
+               897FF13B0E719B8F00D62E90 /* frames-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frames-inl.h"; sourceTree = "<group>"; };
+               897FF13C0E719B8F00D62E90 /* frames.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = frames.cc; sourceTree = "<group>"; };
+               897FF13D0E719B8F00D62E90 /* frames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = frames.h; sourceTree = "<group>"; };
+               897FF13E0E719B8F00D62E90 /* global-handles.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "global-handles.cc"; sourceTree = "<group>"; };
+               897FF13F0E719B8F00D62E90 /* global-handles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "global-handles.h"; sourceTree = "<group>"; };
+               897FF1400E719B8F00D62E90 /* globals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = globals.h; sourceTree = "<group>"; };
+               897FF1410E719B8F00D62E90 /* handles-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "handles-inl.h"; sourceTree = "<group>"; };
+               897FF1420E719B8F00D62E90 /* handles.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = handles.cc; sourceTree = "<group>"; };
+               897FF1430E719B8F00D62E90 /* handles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = handles.h; sourceTree = "<group>"; };
+               897FF1440E719B8F00D62E90 /* hashmap.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashmap.cc; sourceTree = "<group>"; };
+               897FF1450E719B8F00D62E90 /* hashmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hashmap.h; sourceTree = "<group>"; };
+               897FF1460E719B8F00D62E90 /* heap-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "heap-inl.h"; sourceTree = "<group>"; };
+               897FF1470E719B8F00D62E90 /* heap.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = heap.cc; sourceTree = "<group>"; };
+               897FF1480E719B8F00D62E90 /* heap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = heap.h; sourceTree = "<group>"; };
+               897FF1490E719B8F00D62E90 /* ic-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "ic-arm.cc"; sourceTree = "<group>"; };
+               897FF14A0E719B8F00D62E90 /* ic-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "ic-ia32.cc"; sourceTree = "<group>"; };
+               897FF14B0E719B8F00D62E90 /* ic-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ic-inl.h"; sourceTree = "<group>"; };
+               897FF14C0E719B8F00D62E90 /* ic.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ic.cc; sourceTree = "<group>"; };
+               897FF14D0E719B8F00D62E90 /* ic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ic.h; sourceTree = "<group>"; };
+               897FF14E0E719B8F00D62E90 /* jsregexp.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsregexp.cc; sourceTree = "<group>"; };
+               897FF14F0E719B8F00D62E90 /* jsregexp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsregexp.h; sourceTree = "<group>"; };
+               897FF1500E719B8F00D62E90 /* list-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "list-inl.h"; sourceTree = "<group>"; };
+               897FF1510E719B8F00D62E90 /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = list.h; sourceTree = "<group>"; };
+               897FF1520E719B8F00D62E90 /* log.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log.cc; sourceTree = "<group>"; };
+               897FF1530E719B8F00D62E90 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; };
+               897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "macro-assembler-arm.cc"; sourceTree = "<group>"; };
+               897FF1550E719B8F00D62E90 /* macro-assembler-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "macro-assembler-arm.h"; sourceTree = "<group>"; };
+               897FF1560E719B8F00D62E90 /* macro-assembler-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "macro-assembler-ia32.cc"; sourceTree = "<group>"; };
+               897FF1570E719B8F00D62E90 /* macro-assembler-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "macro-assembler-ia32.h"; sourceTree = "<group>"; };
+               897FF1580E719B8F00D62E90 /* macro-assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "macro-assembler.h"; sourceTree = "<group>"; };
+               897FF1590E719B8F00D62E90 /* mark-compact.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "mark-compact.cc"; sourceTree = "<group>"; };
+               897FF15A0E719B8F00D62E90 /* mark-compact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mark-compact.h"; sourceTree = "<group>"; };
+               897FF15B0E719B8F00D62E90 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = "<group>"; };
+               897FF15C0E719B8F00D62E90 /* messages.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = messages.cc; sourceTree = "<group>"; };
+               897FF15D0E719B8F00D62E90 /* messages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = messages.h; sourceTree = "<group>"; };
+               897FF15E0E719B8F00D62E90 /* mksnapshot.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mksnapshot.cc; sourceTree = "<group>"; };
+               897FF15F0E719B8F00D62E90 /* natives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = natives.h; sourceTree = "<group>"; };
+               897FF1600E719B8F00D62E90 /* objects-debug.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "objects-debug.cc"; sourceTree = "<group>"; };
+               897FF1610E719B8F00D62E90 /* objects-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "objects-inl.h"; sourceTree = "<group>"; };
+               897FF1620E719B8F00D62E90 /* objects.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = objects.cc; sourceTree = "<group>"; };
+               897FF1630E719B8F00D62E90 /* objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objects.h; sourceTree = "<group>"; };
+               897FF1640E719B8F00D62E90 /* parser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parser.cc; sourceTree = "<group>"; };
+               897FF1650E719B8F00D62E90 /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+               897FF1660E719B8F00D62E90 /* platform-linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "platform-linux.cc"; sourceTree = "<group>"; };
+               897FF1670E719B8F00D62E90 /* platform-macos.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "platform-macos.cc"; sourceTree = "<group>"; };
+               897FF1680E719B8F00D62E90 /* platform-nullos.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "platform-nullos.cc"; sourceTree = "<group>"; };
+               897FF1690E719B8F00D62E90 /* platform-win32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "platform-win32.cc"; sourceTree = "<group>"; };
+               897FF16A0E719B8F00D62E90 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = platform.h; sourceTree = "<group>"; };
+               897FF16B0E719B8F00D62E90 /* prettyprinter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = prettyprinter.cc; sourceTree = "<group>"; };
+               897FF16C0E719B8F00D62E90 /* prettyprinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = prettyprinter.h; sourceTree = "<group>"; };
+               897FF16D0E719B8F00D62E90 /* property.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = property.cc; sourceTree = "<group>"; };
+               897FF16E0E719B8F00D62E90 /* property.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = property.h; sourceTree = "<group>"; };
+               897FF16F0E719B8F00D62E90 /* rewriter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rewriter.cc; sourceTree = "<group>"; };
+               897FF1700E719B8F00D62E90 /* rewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rewriter.h; sourceTree = "<group>"; };
+               897FF1710E719B8F00D62E90 /* runtime.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = runtime.cc; sourceTree = "<group>"; };
+               897FF1720E719B8F00D62E90 /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runtime.h; sourceTree = "<group>"; };
+               897FF1730E719B8F00D62E90 /* scanner.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scanner.cc; sourceTree = "<group>"; };
+               897FF1740E719B8F00D62E90 /* scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner.h; sourceTree = "<group>"; };
+               897FF1750E719B8F00D62E90 /* SConscript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SConscript; sourceTree = "<group>"; };
+               897FF1760E719B8F00D62E90 /* scopeinfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scopeinfo.cc; sourceTree = "<group>"; };
+               897FF1770E719B8F00D62E90 /* scopeinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scopeinfo.h; sourceTree = "<group>"; };
+               897FF1780E719B8F00D62E90 /* scopes.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scopes.cc; sourceTree = "<group>"; };
+               897FF1790E719B8F00D62E90 /* scopes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scopes.h; sourceTree = "<group>"; };
+               897FF17A0E719B8F00D62E90 /* serialize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = serialize.cc; sourceTree = "<group>"; };
+               897FF17B0E719B8F00D62E90 /* serialize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = serialize.h; sourceTree = "<group>"; };
+               897FF17C0E719B8F00D62E90 /* shell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shell.h; sourceTree = "<group>"; };
+               897FF17D0E719B8F00D62E90 /* simulator-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "simulator-arm.cc"; sourceTree = "<group>"; };
+               897FF17E0E719B8F00D62E90 /* simulator-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "simulator-arm.h"; sourceTree = "<group>"; };
+               897FF17F0E719B8F00D62E90 /* simulator-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "simulator-ia32.cc"; sourceTree = "<group>"; };
+               897FF1800E719B8F00D62E90 /* simulator-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "simulator-ia32.h"; sourceTree = "<group>"; };
+               897FF1810E719B8F00D62E90 /* smart-pointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "smart-pointer.h"; sourceTree = "<group>"; };
+               897FF1820E719B8F00D62E90 /* snapshot-common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "snapshot-common.cc"; sourceTree = "<group>"; };
+               897FF1830E719B8F00D62E90 /* snapshot-empty.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "snapshot-empty.cc"; sourceTree = "<group>"; };
+               897FF1840E719B8F00D62E90 /* snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = snapshot.h; sourceTree = "<group>"; };
+               897FF1850E719B8F00D62E90 /* spaces-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "spaces-inl.h"; sourceTree = "<group>"; };
+               897FF1860E719B8F00D62E90 /* spaces.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spaces.cc; sourceTree = "<group>"; };
+               897FF1870E719B8F00D62E90 /* spaces.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spaces.h; sourceTree = "<group>"; };
+               897FF1880E719B8F00D62E90 /* string-stream.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "string-stream.cc"; sourceTree = "<group>"; };
+               897FF1890E719B8F00D62E90 /* string-stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "string-stream.h"; sourceTree = "<group>"; };
+               897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "stub-cache-arm.cc"; sourceTree = "<group>"; };
+               897FF18B0E719B8F00D62E90 /* stub-cache-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "stub-cache-ia32.cc"; sourceTree = "<group>"; };
+               897FF18C0E719B8F00D62E90 /* stub-cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "stub-cache.cc"; sourceTree = "<group>"; };
+               897FF18D0E719B8F00D62E90 /* stub-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "stub-cache.h"; sourceTree = "<group>"; };
+               897FF18E0E719B8F00D62E90 /* token.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = token.cc; sourceTree = "<group>"; };
+               897FF18F0E719B8F00D62E90 /* token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = token.h; sourceTree = "<group>"; };
+               897FF1900E719B8F00D62E90 /* top.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = top.cc; sourceTree = "<group>"; };
+               897FF1910E719B8F00D62E90 /* top.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = top.h; sourceTree = "<group>"; };
+               897FF1920E719B8F00D62E90 /* unicode-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "unicode-inl.h"; sourceTree = "<group>"; };
+               897FF1930E719B8F00D62E90 /* unicode.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unicode.cc; sourceTree = "<group>"; };
+               897FF1940E719B8F00D62E90 /* unicode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unicode.h; sourceTree = "<group>"; };
+               897FF1950E719B8F00D62E90 /* usage-analyzer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "usage-analyzer.cc"; sourceTree = "<group>"; };
+               897FF1960E719B8F00D62E90 /* usage-analyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "usage-analyzer.h"; sourceTree = "<group>"; };
+               897FF1970E719B8F00D62E90 /* utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utils.cc; sourceTree = "<group>"; };
+               897FF1980E719B8F00D62E90 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
+               897FF1990E719B8F00D62E90 /* v8-counters.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "v8-counters.cc"; sourceTree = "<group>"; };
+               897FF19A0E719B8F00D62E90 /* v8-counters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "v8-counters.h"; sourceTree = "<group>"; };
+               897FF19B0E719B8F00D62E90 /* v8.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = v8.cc; sourceTree = "<group>"; };
+               897FF19C0E719B8F00D62E90 /* v8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v8.h; sourceTree = "<group>"; };
+               897FF19D0E719B8F00D62E90 /* v8threads.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = v8threads.cc; sourceTree = "<group>"; };
+               897FF19E0E719B8F00D62E90 /* v8threads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v8threads.h; sourceTree = "<group>"; };
+               897FF19F0E719B8F00D62E90 /* variables.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = variables.cc; sourceTree = "<group>"; };
+               897FF1A00E719B8F00D62E90 /* variables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = variables.h; sourceTree = "<group>"; };
+               897FF1A10E719B8F00D62E90 /* zone-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "zone-inl.h"; sourceTree = "<group>"; };
+               897FF1A20E719B8F00D62E90 /* zone.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = zone.cc; sourceTree = "<group>"; };
+               897FF1A30E719B8F00D62E90 /* zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zone.h; sourceTree = "<group>"; };
+               897FF1A60E719BC100D62E90 /* apinatives.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = apinatives.js; sourceTree = "<group>"; };
+               897FF1A70E719BC100D62E90 /* array.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = array.js; sourceTree = "<group>"; };
+               897FF1A80E719BC100D62E90 /* date-delay.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "date-delay.js"; sourceTree = "<group>"; };
+               897FF1A90E719BC100D62E90 /* debug-delay.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "debug-delay.js"; sourceTree = "<group>"; };
+               897FF1AA0E719BC100D62E90 /* math.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = math.js; sourceTree = "<group>"; };
+               897FF1AB0E719BC100D62E90 /* messages.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = messages.js; sourceTree = "<group>"; };
+               897FF1AC0E719BC100D62E90 /* mirror-delay.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "mirror-delay.js"; sourceTree = "<group>"; };
+               897FF1AD0E719BC100D62E90 /* regexp-delay.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "regexp-delay.js"; sourceTree = "<group>"; };
+               897FF1AE0E719BC100D62E90 /* runtime.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = runtime.js; sourceTree = "<group>"; };
+               897FF1AF0E719BC100D62E90 /* string.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = string.js; sourceTree = "<group>"; };
+               897FF1B00E719BC100D62E90 /* uri.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = uri.js; sourceTree = "<group>"; };
+               897FF1B10E719BC100D62E90 /* v8natives.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = v8natives.js; sourceTree = "<group>"; };
+               897FF1B50E719C0900D62E90 /* shell.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shell.cc; sourceTree = "<group>"; };
+               897FF1B60E719C2300D62E90 /* js2c.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = js2c.py; sourceTree = "<group>"; };
+               897FF1B70E719C2E00D62E90 /* macros.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = macros.py; path = ../src/macros.py; sourceTree = "<group>"; };
+               897FF1BF0E719CB600D62E90 /* libjscre.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjscre.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               89B12E8D0E7FF2A40080BA62 /* presubmit.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = presubmit.py; sourceTree = "<group>"; };
+               89F23C870E78D5B2006B2466 /* libv8-arm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libv8-arm.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+               89F23C950E78D5B6006B2466 /* v8_shell-arm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "v8_shell-arm"; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               8970F2EE0E719FB2006AE7B5 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               897F76780E71B4CC007ACF34 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               897F76840E71B6B1007ACF34 /* libjscre.a in Frameworks */,
+                               897F76850E71B6B1007ACF34 /* libv8.a in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               897FF1BD0E719CB600D62E90 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               89F23C830E78D5B2006B2466 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               89F23C8F0E78D5B6006B2466 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               89F23C900E78D5B6006B2466 /* libjscre.a in Frameworks */,
+                               896FD03A0E78D717003DFB6A /* libv8-arm.a in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               8915B8660E719336009C4E19 = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0CF0E71996900D62E90 /* v8 */,
+                               897FF1C00E719CB600D62E90 /* Products */,
+                       );
+                       sourceTree = "<group>";
+               };
+               897FF0CF0E71996900D62E90 /* v8 */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0D10E71999E00D62E90 /* include */,
+                               897FF0D00E71999800D62E90 /* src */,
+                               897FF1B30E719BCE00D62E90 /* samples */,
+                               897FF1B40E719BE800D62E90 /* tools */,
+                       );
+                       name = v8;
+                       path = ..;
+                       sourceTree = "<group>";
+               };
+               897FF0D00E71999800D62E90 /* src */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0D70E719AB300D62E90 /* C++ */,
+                               897FF0D80E719ABA00D62E90 /* js */,
+                               897FF0DE0E719B3400D62E90 /* third_party */,
+                               89A9C1630E71C8E300BE6CCA /* generated */,
+                       );
+                       path = src;
+                       sourceTree = "<group>";
+               };
+               897FF0D10E71999E00D62E90 /* include */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0D40E719A8500D62E90 /* v8-debug.h */,
+                               897FF0D50E719A8500D62E90 /* v8.h */,
+                       );
+                       path = include;
+                       sourceTree = "<group>";
+               };
+               897FF0D70E719AB300D62E90 /* C++ */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0F60E719B8F00D62E90 /* accessors.cc */,
+                               897FF0F70E719B8F00D62E90 /* accessors.h */,
+                               897FF0F80E719B8F00D62E90 /* allocation.cc */,
+                               897FF0F90E719B8F00D62E90 /* allocation.h */,
+                               897FF0FA0E719B8F00D62E90 /* api.cc */,
+                               897FF0FB0E719B8F00D62E90 /* api.h */,
+                               897FF0FC0E719B8F00D62E90 /* arguments.h */,
+                               897FF0FD0E719B8F00D62E90 /* assembler-arm-inl.h */,
+                               897FF0FE0E719B8F00D62E90 /* assembler-arm.cc */,
+                               897FF0FF0E719B8F00D62E90 /* assembler-arm.h */,
+                               897FF1000E719B8F00D62E90 /* assembler-ia32-inl.h */,
+                               897FF1010E719B8F00D62E90 /* assembler-ia32.cc */,
+                               897FF1020E719B8F00D62E90 /* assembler-ia32.h */,
+                               897FF1030E719B8F00D62E90 /* assembler.cc */,
+                               897FF1040E719B8F00D62E90 /* assembler.h */,
+                               897FF1050E719B8F00D62E90 /* ast.cc */,
+                               897FF1060E719B8F00D62E90 /* ast.h */,
+                               897FF1070E719B8F00D62E90 /* bootstrapper.cc */,
+                               897FF1080E719B8F00D62E90 /* bootstrapper.h */,
+                               897FF1090E719B8F00D62E90 /* builtins-arm.cc */,
+                               897FF10A0E719B8F00D62E90 /* builtins-ia32.cc */,
+                               897FF10B0E719B8F00D62E90 /* builtins.cc */,
+                               897FF10C0E719B8F00D62E90 /* builtins.h */,
+                               897FF10D0E719B8F00D62E90 /* char-predicates-inl.h */,
+                               897FF10E0E719B8F00D62E90 /* char-predicates.h */,
+                               897FF10F0E719B8F00D62E90 /* checks.cc */,
+                               897FF1100E719B8F00D62E90 /* checks.h */,
+                               897FF1110E719B8F00D62E90 /* code-stubs.cc */,
+                               897FF1120E719B8F00D62E90 /* code-stubs.h */,
+                               897FF1130E719B8F00D62E90 /* code.h */,
+                               897FF1140E719B8F00D62E90 /* codegen-arm.cc */,
+                               896448BC0E9D530500E7C516 /* codegen-arm.h */,
+                               897FF1150E719B8F00D62E90 /* codegen-ia32.cc */,
+                               8964482B0E9C00F700E7C516 /* codegen-ia32.h */,
+                               897FF1160E719B8F00D62E90 /* codegen-inl.h */,
+                               897FF1170E719B8F00D62E90 /* codegen.cc */,
+                               897FF1180E719B8F00D62E90 /* codegen.h */,
+                               89495E460E79FC23001F68C3 /* compilation-cache.cc */,
+                               89495E470E79FC23001F68C3 /* compilation-cache.h */,
+                               897FF1190E719B8F00D62E90 /* compiler.cc */,
+                               897FF11A0E719B8F00D62E90 /* compiler.h */,
+                               897FF11B0E719B8F00D62E90 /* constants-arm.h */,
+                               897FF11C0E719B8F00D62E90 /* contexts.cc */,
+                               897FF11D0E719B8F00D62E90 /* contexts.h */,
+                               897FF11E0E719B8F00D62E90 /* conversions-inl.h */,
+                               897FF11F0E719B8F00D62E90 /* conversions.cc */,
+                               897FF1200E719B8F00D62E90 /* conversions.h */,
+                               897FF1210E719B8F00D62E90 /* counters.cc */,
+                               897FF1220E719B8F00D62E90 /* counters.h */,
+                               897FF1230E719B8F00D62E90 /* cpu-arm.cc */,
+                               897FF1240E719B8F00D62E90 /* cpu-ia32.cc */,
+                               897FF1250E719B8F00D62E90 /* cpu.h */,
+                               897FF1260E719B8F00D62E90 /* dateparser.cc */,
+                               897FF1270E719B8F00D62E90 /* dateparser.h */,
+                               897FF1280E719B8F00D62E90 /* debug.cc */,
+                               897FF1290E719B8F00D62E90 /* debug.h */,
+                               897FF12A0E719B8F00D62E90 /* disasm-arm.cc */,
+                               897FF12B0E719B8F00D62E90 /* disasm-ia32.cc */,
+                               897FF12C0E719B8F00D62E90 /* disasm.h */,
+                               897FF12D0E719B8F00D62E90 /* disassembler.cc */,
+                               897FF12E0E719B8F00D62E90 /* disassembler.h */,
+                               897FF12F0E719B8F00D62E90 /* dtoa-config.c */,
+                               897FF1300E719B8F00D62E90 /* execution.cc */,
+                               897FF1310E719B8F00D62E90 /* execution.h */,
+                               897FF1320E719B8F00D62E90 /* factory.cc */,
+                               897FF1330E719B8F00D62E90 /* factory.h */,
+                               897FF1350E719B8F00D62E90 /* flags.cc */,
+                               897FF1360E719B8F00D62E90 /* flags.h */,
+                               897FF1370E719B8F00D62E90 /* frames-arm.cc */,
+                               897FF1380E719B8F00D62E90 /* frames-arm.h */,
+                               897FF1390E719B8F00D62E90 /* frames-ia32.cc */,
+                               897FF13A0E719B8F00D62E90 /* frames-ia32.h */,
+                               897FF13B0E719B8F00D62E90 /* frames-inl.h */,
+                               897FF13C0E719B8F00D62E90 /* frames.cc */,
+                               897FF13D0E719B8F00D62E90 /* frames.h */,
+                               897FF13E0E719B8F00D62E90 /* global-handles.cc */,
+                               897FF13F0E719B8F00D62E90 /* global-handles.h */,
+                               897FF1400E719B8F00D62E90 /* globals.h */,
+                               897FF1410E719B8F00D62E90 /* handles-inl.h */,
+                               897FF1420E719B8F00D62E90 /* handles.cc */,
+                               897FF1430E719B8F00D62E90 /* handles.h */,
+                               897FF1440E719B8F00D62E90 /* hashmap.cc */,
+                               897FF1450E719B8F00D62E90 /* hashmap.h */,
+                               897FF1460E719B8F00D62E90 /* heap-inl.h */,
+                               897FF1470E719B8F00D62E90 /* heap.cc */,
+                               897FF1480E719B8F00D62E90 /* heap.h */,
+                               897FF1490E719B8F00D62E90 /* ic-arm.cc */,
+                               897FF14A0E719B8F00D62E90 /* ic-ia32.cc */,
+                               897FF14B0E719B8F00D62E90 /* ic-inl.h */,
+                               897FF14C0E719B8F00D62E90 /* ic.cc */,
+                               897FF14D0E719B8F00D62E90 /* ic.h */,
+                               897FF14E0E719B8F00D62E90 /* jsregexp.cc */,
+                               897FF14F0E719B8F00D62E90 /* jsregexp.h */,
+                               897FF1500E719B8F00D62E90 /* list-inl.h */,
+                               897FF1510E719B8F00D62E90 /* list.h */,
+                               897FF1520E719B8F00D62E90 /* log.cc */,
+                               897FF1530E719B8F00D62E90 /* log.h */,
+                               897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */,
+                               897FF1550E719B8F00D62E90 /* macro-assembler-arm.h */,
+                               897FF1560E719B8F00D62E90 /* macro-assembler-ia32.cc */,
+                               897FF1570E719B8F00D62E90 /* macro-assembler-ia32.h */,
+                               897FF1580E719B8F00D62E90 /* macro-assembler.h */,
+                               897FF1590E719B8F00D62E90 /* mark-compact.cc */,
+                               897FF15A0E719B8F00D62E90 /* mark-compact.h */,
+                               897FF15B0E719B8F00D62E90 /* memory.h */,
+                               897FF15C0E719B8F00D62E90 /* messages.cc */,
+                               897FF15D0E719B8F00D62E90 /* messages.h */,
+                               897FF15E0E719B8F00D62E90 /* mksnapshot.cc */,
+                               897FF15F0E719B8F00D62E90 /* natives.h */,
+                               897FF1600E719B8F00D62E90 /* objects-debug.cc */,
+                               897FF1610E719B8F00D62E90 /* objects-inl.h */,
+                               897FF1620E719B8F00D62E90 /* objects.cc */,
+                               897FF1630E719B8F00D62E90 /* objects.h */,
+                               897FF1640E719B8F00D62E90 /* parser.cc */,
+                               897FF1650E719B8F00D62E90 /* parser.h */,
+                               897FF1660E719B8F00D62E90 /* platform-linux.cc */,
+                               897FF1670E719B8F00D62E90 /* platform-macos.cc */,
+                               897FF1680E719B8F00D62E90 /* platform-nullos.cc */,
+                               897FF1690E719B8F00D62E90 /* platform-win32.cc */,
+                               897FF16A0E719B8F00D62E90 /* platform.h */,
+                               897FF16B0E719B8F00D62E90 /* prettyprinter.cc */,
+                               897FF16C0E719B8F00D62E90 /* prettyprinter.h */,
+                               897FF16D0E719B8F00D62E90 /* property.cc */,
+                               897FF16E0E719B8F00D62E90 /* property.h */,
+                               897FF16F0E719B8F00D62E90 /* rewriter.cc */,
+                               897FF1700E719B8F00D62E90 /* rewriter.h */,
+                               897FF1710E719B8F00D62E90 /* runtime.cc */,
+                               897FF1720E719B8F00D62E90 /* runtime.h */,
+                               897FF1730E719B8F00D62E90 /* scanner.cc */,
+                               897FF1740E719B8F00D62E90 /* scanner.h */,
+                               897FF1750E719B8F00D62E90 /* SConscript */,
+                               897FF1760E719B8F00D62E90 /* scopeinfo.cc */,
+                               897FF1770E719B8F00D62E90 /* scopeinfo.h */,
+                               897FF1780E719B8F00D62E90 /* scopes.cc */,
+                               897FF1790E719B8F00D62E90 /* scopes.h */,
+                               897FF17A0E719B8F00D62E90 /* serialize.cc */,
+                               897FF17B0E719B8F00D62E90 /* serialize.h */,
+                               897FF17C0E719B8F00D62E90 /* shell.h */,
+                               897FF17D0E719B8F00D62E90 /* simulator-arm.cc */,
+                               897FF17E0E719B8F00D62E90 /* simulator-arm.h */,
+                               897FF17F0E719B8F00D62E90 /* simulator-ia32.cc */,
+                               897FF1800E719B8F00D62E90 /* simulator-ia32.h */,
+                               897FF1810E719B8F00D62E90 /* smart-pointer.h */,
+                               897FF1820E719B8F00D62E90 /* snapshot-common.cc */,
+                               897FF1830E719B8F00D62E90 /* snapshot-empty.cc */,
+                               897FF1840E719B8F00D62E90 /* snapshot.h */,
+                               897FF1850E719B8F00D62E90 /* spaces-inl.h */,
+                               897FF1860E719B8F00D62E90 /* spaces.cc */,
+                               897FF1870E719B8F00D62E90 /* spaces.h */,
+                               897FF1880E719B8F00D62E90 /* string-stream.cc */,
+                               897FF1890E719B8F00D62E90 /* string-stream.h */,
+                               897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
+                               897FF18B0E719B8F00D62E90 /* stub-cache-ia32.cc */,
+                               897FF18C0E719B8F00D62E90 /* stub-cache.cc */,
+                               897FF18D0E719B8F00D62E90 /* stub-cache.h */,
+                               897FF18E0E719B8F00D62E90 /* token.cc */,
+                               897FF18F0E719B8F00D62E90 /* token.h */,
+                               897FF1900E719B8F00D62E90 /* top.cc */,
+                               897FF1910E719B8F00D62E90 /* top.h */,
+                               897FF1920E719B8F00D62E90 /* unicode-inl.h */,
+                               897FF1930E719B8F00D62E90 /* unicode.cc */,
+                               897FF1940E719B8F00D62E90 /* unicode.h */,
+                               897FF1950E719B8F00D62E90 /* usage-analyzer.cc */,
+                               897FF1960E719B8F00D62E90 /* usage-analyzer.h */,
+                               897FF1970E719B8F00D62E90 /* utils.cc */,
+                               897FF1980E719B8F00D62E90 /* utils.h */,
+                               897FF1990E719B8F00D62E90 /* v8-counters.cc */,
+                               897FF19A0E719B8F00D62E90 /* v8-counters.h */,
+                               897FF19B0E719B8F00D62E90 /* v8.cc */,
+                               897FF19C0E719B8F00D62E90 /* v8.h */,
+                               897FF19D0E719B8F00D62E90 /* v8threads.cc */,
+                               897FF19E0E719B8F00D62E90 /* v8threads.h */,
+                               897FF19F0E719B8F00D62E90 /* variables.cc */,
+                               897FF1A00E719B8F00D62E90 /* variables.h */,
+                               897FF1A10E719B8F00D62E90 /* zone-inl.h */,
+                               897FF1A20E719B8F00D62E90 /* zone.cc */,
+                               897FF1A30E719B8F00D62E90 /* zone.h */,
+                       );
+                       name = "C++";
+                       sourceTree = "<group>";
+               };
+               897FF0D80E719ABA00D62E90 /* js */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF1A60E719BC100D62E90 /* apinatives.js */,
+                               897FF1A70E719BC100D62E90 /* array.js */,
+                               897FF1A80E719BC100D62E90 /* date-delay.js */,
+                               897FF1A90E719BC100D62E90 /* debug-delay.js */,
+                               897FF1AA0E719BC100D62E90 /* math.js */,
+                               897FF1AB0E719BC100D62E90 /* messages.js */,
+                               897FF1AC0E719BC100D62E90 /* mirror-delay.js */,
+                               897FF1AD0E719BC100D62E90 /* regexp-delay.js */,
+                               897FF1AE0E719BC100D62E90 /* runtime.js */,
+                               897FF1AF0E719BC100D62E90 /* string.js */,
+                               897FF1B00E719BC100D62E90 /* uri.js */,
+                               897FF1B10E719BC100D62E90 /* v8natives.js */,
+                       );
+                       name = js;
+                       sourceTree = "<group>";
+               };
+               897FF0DE0E719B3400D62E90 /* third_party */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0DF0E719B3400D62E90 /* dtoa */,
+                               897FF0E20E719B3500D62E90 /* jscre */,
+                       );
+                       path = third_party;
+                       sourceTree = "<group>";
+               };
+               897FF0DF0E719B3400D62E90 /* dtoa */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0E00E719B3500D62E90 /* COPYING */,
+                               897FF0E10E719B3500D62E90 /* dtoa.c */,
+                       );
+                       path = dtoa;
+                       sourceTree = "<group>";
+               };
+               897FF0E20E719B3500D62E90 /* jscre */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF0E30E719B3500D62E90 /* ASCIICType.h */,
+                               897FF0E40E719B3500D62E90 /* AUTHORS */,
+                               897FF0E50E719B3500D62E90 /* config.h */,
+                               897FF0E60E719B3500D62E90 /* COPYING */,
+                               897FF0E70E719B3500D62E90 /* LICENSE */,
+                               897FF0E80E719B3500D62E90 /* pcre.h */,
+                               897FF0E90E719B3500D62E90 /* pcre_chartables.c */,
+                               897FF0EA0E719B3500D62E90 /* pcre_compile.cpp */,
+                               897FF0EB0E719B3500D62E90 /* pcre_exec.cpp */,
+                               897FF0EC0E719B3500D62E90 /* pcre_internal.h */,
+                               897FF0ED0E719B3500D62E90 /* pcre_tables.cpp */,
+                               897FF0EE0E719B3500D62E90 /* pcre_ucp_searchfuncs.cpp */,
+                               897FF0EF0E719B3500D62E90 /* pcre_xclass.cpp */,
+                               897FF0F00E719B3500D62E90 /* ucpinternal.h */,
+                               897FF0F10E719B3500D62E90 /* ucptable.cpp */,
+                       );
+                       path = jscre;
+                       sourceTree = "<group>";
+               };
+               897FF1B30E719BCE00D62E90 /* samples */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF1B50E719C0900D62E90 /* shell.cc */,
+                       );
+                       path = samples;
+                       sourceTree = "<group>";
+               };
+               897FF1B40E719BE800D62E90 /* tools */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF1B60E719C2300D62E90 /* js2c.py */,
+                               897FF1B70E719C2E00D62E90 /* macros.py */,
+                               89B12E8D0E7FF2A40080BA62 /* presubmit.py */,
+                       );
+                       path = tools;
+                       sourceTree = "<group>";
+               };
+               897FF1C00E719CB600D62E90 /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               897FF1BF0E719CB600D62E90 /* libjscre.a */,
+                               8970F2F00E719FB2006AE7B5 /* libv8.a */,
+                               897F767A0E71B4CC007ACF34 /* v8_shell */,
+                               89F23C870E78D5B2006B2466 /* libv8-arm.a */,
+                               89F23C950E78D5B6006B2466 /* v8_shell-arm */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               89A9C1630E71C8E300BE6CCA /* generated */ = {
+                       isa = PBXGroup;
+                       children = (
+                               8900116B0E71CA2300F91F35 /* libraries.cc */,
+                       );
+                       path = generated;
+                       sourceTree = CONFIGURATION_TEMP_DIR;
+               };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+               8970F2EF0E719FB2006AE7B5 /* v8 */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 8970F2F70E719FC1006AE7B5 /* Build configuration list for PBXNativeTarget "v8" */;
+                       buildPhases = (
+                               89EA6FB50E71AA1F00F59E1B /* ShellScript */,
+                               8970F2ED0E719FB2006AE7B5 /* Sources */,
+                               8970F2EE0E719FB2006AE7B5 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = v8;
+                       productName = v8;
+                       productReference = 8970F2F00E719FB2006AE7B5 /* libv8.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               897F76790E71B4CC007ACF34 /* v8_shell */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 897F767E0E71B4EA007ACF34 /* Build configuration list for PBXNativeTarget "v8_shell" */;
+                       buildPhases = (
+                               897F76770E71B4CC007ACF34 /* Sources */,
+                               897F76780E71B4CC007ACF34 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               897F76810E71B6AC007ACF34 /* PBXTargetDependency */,
+                               897F76830E71B6AC007ACF34 /* PBXTargetDependency */,
+                       );
+                       name = v8_shell;
+                       productName = v8_shell;
+                       productReference = 897F767A0E71B4CC007ACF34 /* v8_shell */;
+                       productType = "com.apple.product-type.tool";
+               };
+               897FF1BE0E719CB600D62E90 /* jscre */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 897FF1C30E719CB600D62E90 /* Build configuration list for PBXNativeTarget "jscre" */;
+                       buildPhases = (
+                               897FF1BC0E719CB600D62E90 /* Sources */,
+                               897FF1BD0E719CB600D62E90 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = jscre;
+                       productName = jscre;
+                       productReference = 897FF1BF0E719CB600D62E90 /* libjscre.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               89F23C3C0E78D5B2006B2466 /* v8-arm */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 89F23C840E78D5B2006B2466 /* Build configuration list for PBXNativeTarget "v8-arm" */;
+                       buildPhases = (
+                               89F23C3D0E78D5B2006B2466 /* ShellScript */,
+                               89F23C3E0E78D5B2006B2466 /* Sources */,
+                               89F23C830E78D5B2006B2466 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "v8-arm";
+                       productName = "v8-arm";
+                       productReference = 89F23C870E78D5B2006B2466 /* libv8-arm.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               89F23C880E78D5B6006B2466 /* v8_shell-arm */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 89F23C920E78D5B6006B2466 /* Build configuration list for PBXNativeTarget "v8_shell-arm" */;
+                       buildPhases = (
+                               89F23C8D0E78D5B6006B2466 /* Sources */,
+                               89F23C8F0E78D5B6006B2466 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               89F23C890E78D5B6006B2466 /* PBXTargetDependency */,
+                               896FD03C0E78D71F003DFB6A /* PBXTargetDependency */,
+                       );
+                       name = "v8_shell-arm";
+                       productName = "v8_shell-arm";
+                       productReference = 89F23C950E78D5B6006B2466 /* v8_shell-arm */;
+                       productType = "com.apple.product-type.tool";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               8915B8680E719336009C4E19 /* Project object */ = {
+                       isa = PBXProject;
+                       buildConfigurationList = 8915B86B0E719336009C4E19 /* Build configuration list for PBXProject "v8" */;
+                       compatibilityVersion = "Xcode 3.1";
+                       hasScannedForEncodings = 0;
+                       mainGroup = 8915B8660E719336009C4E19;
+                       productRefGroup = 897FF1C00E719CB600D62E90 /* Products */;
+                       projectDirPath = "";
+                       projectRoot = ..;
+                       targets = (
+                               7BF891930E73098D000BAF8A /* All */,
+                               897FF1BE0E719CB600D62E90 /* jscre */,
+                               8970F2EF0E719FB2006AE7B5 /* v8 */,
+                               897F76790E71B4CC007ACF34 /* v8_shell */,
+                               89F23C3C0E78D5B2006B2466 /* v8-arm */,
+                               89F23C880E78D5B6006B2466 /* v8_shell-arm */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               89EA6FB50E71AA1F00F59E1B /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "set -ex\nJS_FILES=\"runtime.js\"\\\n\" v8natives.js\"\\\n\" array.js\"\\\n\" string.js\"\\\n\" uri.js\"\\\n\" math.js\"\\\n\" messages.js\"\\\n\" apinatives.js\"\\\n\" debug-delay.js\"\\\n\" mirror-delay.js\"\\\n\" date-delay.js\"\\\n\" regexp-delay.js\"\\\n\" macros.py\"\n\nV8ROOT=\"${SRCROOT}/..\"\n\nSRC_DIR=\"${V8ROOT}/src\"\n\nNATIVE_JS_FILES=\"\"\n\nfor i in ${JS_FILES} ; do\n  NATIVE_JS_FILES+=\"${SRC_DIR}/${i} \"\ndone\n\nV8_GENERATED_SOURCES_DIR=\"${CONFIGURATION_TEMP_DIR}/generated\"\nmkdir -p \"${V8_GENERATED_SOURCES_DIR}\"\n\nLIBRARIES_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries.cc\"\nLIBRARIES_EMPTY_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries-empty.cc\"\n\npython \"${V8ROOT}/tools/js2c.py\" \\\n  \"${LIBRARIES_CC}.new\" \\\n  \"${LIBRARIES_EMPTY_CC}.new\" \\\n  \"CORE\" \\\n  ${NATIVE_JS_FILES}\n\n# Only use the new files if they're different from the existing files (if any),\n# preserving the existing files' timestamps when there are no changes.  This\n# minimizes unnecessary build activity for a no-change build.\n\nif ! diff -q \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\" >& /dev/null ; then\n  mv \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\"\nelse\n  rm \"${LIBRARIES_CC}.new\"\nfi\n\nif ! diff -q \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\" >& /dev/null ; then\n  mv \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\"\nelse\n  rm \"${LIBRARIES_EMPTY_CC}.new\"\nfi\n";
+               };
+               89F23C3D0E78D5B2006B2466 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "set -ex\nJS_FILES=\"runtime.js\"\\\n\" v8natives.js\"\\\n\" array.js\"\\\n\" string.js\"\\\n\" uri.js\"\\\n\" math.js\"\\\n\" messages.js\"\\\n\" apinatives.js\"\\\n\" debug-delay.js\"\\\n\" mirror-delay.js\"\\\n\" date-delay.js\"\\\n\" regexp-delay.js\"\\\n\" macros.py\"\n\nV8ROOT=\"${SRCROOT}/..\"\n\nSRC_DIR=\"${V8ROOT}/src\"\n\nNATIVE_JS_FILES=\"\"\n\nfor i in ${JS_FILES} ; do\n  NATIVE_JS_FILES+=\"${SRC_DIR}/${i} \"\ndone\n\nV8_GENERATED_SOURCES_DIR=\"${CONFIGURATION_TEMP_DIR}/generated\"\nmkdir -p \"${V8_GENERATED_SOURCES_DIR}\"\n\nLIBRARIES_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries.cc\"\nLIBRARIES_EMPTY_CC=\"${V8_GENERATED_SOURCES_DIR}/libraries-empty.cc\"\n\npython \"${V8ROOT}/tools/js2c.py\" \\\n  \"${LIBRARIES_CC}.new\" \\\n  \"${LIBRARIES_EMPTY_CC}.new\" \\\n  \"CORE\" \\\n  ${NATIVE_JS_FILES}\n\n# Only use the new files if they're different from the existing files (if any),\n# preserving the existing files' timestamps when there are no changes.  This\n# minimizes unnecessary build activity for a no-change build.\n\nif ! diff -q \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\" >& /dev/null ; then\n  mv \"${LIBRARIES_CC}.new\" \"${LIBRARIES_CC}\"\nelse\n  rm \"${LIBRARIES_CC}.new\"\nfi\n\nif ! diff -q \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\" >& /dev/null ; then\n  mv \"${LIBRARIES_EMPTY_CC}.new\" \"${LIBRARIES_EMPTY_CC}\"\nelse\n  rm \"${LIBRARIES_EMPTY_CC}.new\"\nfi\n";
+               };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               8970F2ED0E719FB2006AE7B5 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               89A88DEC0E71A5FF0043BA31 /* accessors.cc in Sources */,
+                               89A88DED0E71A6000043BA31 /* allocation.cc in Sources */,
+                               89A88DEE0E71A6010043BA31 /* api.cc in Sources */,
+                               89A88DEF0E71A60A0043BA31 /* assembler-ia32.cc in Sources */,
+                               89A88DF00E71A60A0043BA31 /* assembler.cc in Sources */,
+                               89A88DF10E71A60B0043BA31 /* ast.cc in Sources */,
+                               89A88DF20E71A60C0043BA31 /* bootstrapper.cc in Sources */,
+                               89A88DF40E71A6160043BA31 /* builtins-ia32.cc in Sources */,
+                               89A88DF50E71A6170043BA31 /* builtins.cc in Sources */,
+                               89A88DF60E71A61C0043BA31 /* checks.cc in Sources */,
+                               893CCE640E71D83700357A03 /* code-stubs.cc in Sources */,
+                               89A88DF70E71A6240043BA31 /* codegen-ia32.cc in Sources */,
+                               89A88DF80E71A6260043BA31 /* codegen.cc in Sources */,
+                               89495E480E79FC23001F68C3 /* compilation-cache.cc in Sources */,
+                               89A88DF90E71A6430043BA31 /* compiler.cc in Sources */,
+                               89A88DFA0E71A6440043BA31 /* contexts.cc in Sources */,
+                               89A88DFB0E71A6440043BA31 /* conversions.cc in Sources */,
+                               89A88DFC0E71A6460043BA31 /* counters.cc in Sources */,
+                               89A88DFD0E71A6470043BA31 /* cpu-ia32.cc in Sources */,
+                               89A88DFE0E71A6480043BA31 /* dateparser.cc in Sources */,
+                               89A88DFF0E71A6530043BA31 /* debug.cc in Sources */,
+                               89A88E000E71A6540043BA31 /* disasm-ia32.cc in Sources */,
+                               89A88E010E71A6550043BA31 /* disassembler.cc in Sources */,
+                               89A88E020E71A65A0043BA31 /* dtoa-config.c in Sources */,
+                               89A88E030E71A65B0043BA31 /* execution.cc in Sources */,
+                               89A88E040E71A65D0043BA31 /* factory.cc in Sources */,
+                               89A88E050E71A65D0043BA31 /* flags.cc in Sources */,
+                               89A88E060E71A6600043BA31 /* frames-ia32.cc in Sources */,
+                               89A88E070E71A6610043BA31 /* frames.cc in Sources */,
+                               89A88E080E71A6620043BA31 /* global-handles.cc in Sources */,
+                               89A88E090E71A6640043BA31 /* handles.cc in Sources */,
+                               89A88E0A0E71A6650043BA31 /* hashmap.cc in Sources */,
+                               89A88E0B0E71A66C0043BA31 /* heap.cc in Sources */,
+                               89A88E0C0E71A66D0043BA31 /* ic-ia32.cc in Sources */,
+                               89A88E0D0E71A66E0043BA31 /* ic.cc in Sources */,
+                               89A88E0E0E71A66F0043BA31 /* jsregexp.cc in Sources */,
+                               8900116C0E71CA2300F91F35 /* libraries.cc in Sources */,
+                               89A88E0F0E71A6740043BA31 /* log.cc in Sources */,
+                               89A88E100E71A6770043BA31 /* macro-assembler-ia32.cc in Sources */,
+                               89A88E110E71A6780043BA31 /* mark-compact.cc in Sources */,
+                               89A88E120E71A67A0043BA31 /* messages.cc in Sources */,
+                               89A88E130E71A6860043BA31 /* objects-debug.cc in Sources */,
+                               89A88E140E71A6870043BA31 /* objects.cc in Sources */,
+                               89A88E150E71A68C0043BA31 /* parser.cc in Sources */,
+                               89A88E160E71A68E0043BA31 /* platform-macos.cc in Sources */,
+                               89A88E170E71A6950043BA31 /* prettyprinter.cc in Sources */,
+                               89A88E180E71A6960043BA31 /* property.cc in Sources */,
+                               89A88E190E71A6970043BA31 /* rewriter.cc in Sources */,
+                               89A88E1A0E71A69B0043BA31 /* runtime.cc in Sources */,
+                               89A88E1B0E71A69D0043BA31 /* scanner.cc in Sources */,
+                               89A88E1C0E71A69E0043BA31 /* scopeinfo.cc in Sources */,
+                               89A88E1D0E71A6A00043BA31 /* scopes.cc in Sources */,
+                               89A88E1E0E71A6A30043BA31 /* serialize.cc in Sources */,
+                               89A88E1F0E71A6B40043BA31 /* snapshot-common.cc in Sources */,
+                               89A88E200E71A6B60043BA31 /* snapshot-empty.cc in Sources */,
+                               89A88E210E71A6B70043BA31 /* spaces.cc in Sources */,
+                               89A88E220E71A6BC0043BA31 /* string-stream.cc in Sources */,
+                               89A88E230E71A6BE0043BA31 /* stub-cache-ia32.cc in Sources */,
+                               89A88E240E71A6BF0043BA31 /* stub-cache.cc in Sources */,
+                               89A88E250E71A6C20043BA31 /* token.cc in Sources */,
+                               89A88E260E71A6C90043BA31 /* top.cc in Sources */,
+                               89A88E270E71A6CB0043BA31 /* unicode.cc in Sources */,
+                               89A88E280E71A6CC0043BA31 /* usage-analyzer.cc in Sources */,
+                               89A88E290E71A6CE0043BA31 /* utils.cc in Sources */,
+                               89A88E2A0E71A6D00043BA31 /* v8-counters.cc in Sources */,
+                               89A88E2B0E71A6D10043BA31 /* v8.cc in Sources */,
+                               89A88E2C0E71A6D20043BA31 /* v8threads.cc in Sources */,
+                               89A88E2D0E71A6D50043BA31 /* variables.cc in Sources */,
+                               89A88E2E0E71A6D60043BA31 /* zone.cc in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               897F76770E71B4CC007ACF34 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               897F767F0E71B690007ACF34 /* shell.cc in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               897FF1BC0E719CB600D62E90 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               897FF1C40E719D6B00D62E90 /* pcre_compile.cpp in Sources */,
+                               897FF1C50E719D6E00D62E90 /* pcre_exec.cpp in Sources */,
+                               897FF1C60E719D7100D62E90 /* pcre_tables.cpp in Sources */,
+                               897FF1C70E719D7300D62E90 /* pcre_ucp_searchfuncs.cpp in Sources */,
+                               897FF1C80E719D7600D62E90 /* pcre_xclass.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               89F23C3E0E78D5B2006B2466 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               89F23C3F0E78D5B2006B2466 /* accessors.cc in Sources */,
+                               89F23C400E78D5B2006B2466 /* allocation.cc in Sources */,
+                               89F23C410E78D5B2006B2466 /* api.cc in Sources */,
+                               89F23C970E78D5E3006B2466 /* assembler-arm.cc in Sources */,
+                               89F23C430E78D5B2006B2466 /* assembler.cc in Sources */,
+                               89F23C440E78D5B2006B2466 /* ast.cc in Sources */,
+                               89F23C450E78D5B2006B2466 /* bootstrapper.cc in Sources */,
+                               89F23C980E78D5E7006B2466 /* builtins-arm.cc in Sources */,
+                               89F23C470E78D5B2006B2466 /* builtins.cc in Sources */,
+                               89F23C480E78D5B2006B2466 /* checks.cc in Sources */,
+                               89F23C490E78D5B2006B2466 /* code-stubs.cc in Sources */,
+                               89F23C990E78D5E9006B2466 /* codegen-arm.cc in Sources */,
+                               89F23C4B0E78D5B2006B2466 /* codegen.cc in Sources */,
+                               89495E490E79FC23001F68C3 /* compilation-cache.cc in Sources */,
+                               89F23C4C0E78D5B2006B2466 /* compiler.cc in Sources */,
+                               89F23C4D0E78D5B2006B2466 /* contexts.cc in Sources */,
+                               89F23C4E0E78D5B2006B2466 /* conversions.cc in Sources */,
+                               89F23C4F0E78D5B2006B2466 /* counters.cc in Sources */,
+                               89F23C9A0E78D5EC006B2466 /* cpu-arm.cc in Sources */,
+                               89F23C510E78D5B2006B2466 /* dateparser.cc in Sources */,
+                               89F23C520E78D5B2006B2466 /* debug.cc in Sources */,
+                               89F23C9B0E78D5EE006B2466 /* disasm-arm.cc in Sources */,
+                               89F23C540E78D5B2006B2466 /* disassembler.cc in Sources */,
+                               89F23C550E78D5B2006B2466 /* dtoa-config.c in Sources */,
+                               89F23C560E78D5B2006B2466 /* execution.cc in Sources */,
+                               89F23C570E78D5B2006B2466 /* factory.cc in Sources */,
+                               89F23C580E78D5B2006B2466 /* flags.cc in Sources */,
+                               89F23C9C0E78D5F1006B2466 /* frames-arm.cc in Sources */,
+                               89F23C5A0E78D5B2006B2466 /* frames.cc in Sources */,
+                               89F23C5B0E78D5B2006B2466 /* global-handles.cc in Sources */,
+                               89F23C5C0E78D5B2006B2466 /* handles.cc in Sources */,
+                               89F23C5D0E78D5B2006B2466 /* hashmap.cc in Sources */,
+                               89F23C5E0E78D5B2006B2466 /* heap.cc in Sources */,
+                               89F23C9D0E78D5FB006B2466 /* ic-arm.cc in Sources */,
+                               89F23C600E78D5B2006B2466 /* ic.cc in Sources */,
+                               89F23C610E78D5B2006B2466 /* jsregexp.cc in Sources */,
+                               89F23C620E78D5B2006B2466 /* libraries.cc in Sources */,
+                               89F23C630E78D5B2006B2466 /* log.cc in Sources */,
+                               89F23C9E0E78D5FD006B2466 /* macro-assembler-arm.cc in Sources */,
+                               89F23C650E78D5B2006B2466 /* mark-compact.cc in Sources */,
+                               89F23C660E78D5B2006B2466 /* messages.cc in Sources */,
+                               89F23C670E78D5B2006B2466 /* objects-debug.cc in Sources */,
+                               89F23C680E78D5B2006B2466 /* objects.cc in Sources */,
+                               89F23C690E78D5B2006B2466 /* parser.cc in Sources */,
+                               89F23C6A0E78D5B2006B2466 /* platform-macos.cc in Sources */,
+                               89F23C6B0E78D5B2006B2466 /* prettyprinter.cc in Sources */,
+                               89F23C6C0E78D5B2006B2466 /* property.cc in Sources */,
+                               89F23C6D0E78D5B2006B2466 /* rewriter.cc in Sources */,
+                               89F23C6E0E78D5B2006B2466 /* runtime.cc in Sources */,
+                               89F23C6F0E78D5B2006B2466 /* scanner.cc in Sources */,
+                               89F23C700E78D5B2006B2466 /* scopeinfo.cc in Sources */,
+                               89F23C710E78D5B2006B2466 /* scopes.cc in Sources */,
+                               89F23C720E78D5B2006B2466 /* serialize.cc in Sources */,
+                               89F23C9F0E78D604006B2466 /* simulator-arm.cc in Sources */,
+                               89F23C730E78D5B2006B2466 /* snapshot-common.cc in Sources */,
+                               89F23C740E78D5B2006B2466 /* snapshot-empty.cc in Sources */,
+                               89F23C750E78D5B2006B2466 /* spaces.cc in Sources */,
+                               89F23C760E78D5B2006B2466 /* string-stream.cc in Sources */,
+                               89F23CA00E78D609006B2466 /* stub-cache-arm.cc in Sources */,
+                               89F23C780E78D5B2006B2466 /* stub-cache.cc in Sources */,
+                               89F23C790E78D5B2006B2466 /* token.cc in Sources */,
+                               89F23C7A0E78D5B2006B2466 /* top.cc in Sources */,
+                               89F23C7B0E78D5B2006B2466 /* unicode.cc in Sources */,
+                               89F23C7C0E78D5B2006B2466 /* usage-analyzer.cc in Sources */,
+                               89F23C7D0E78D5B2006B2466 /* utils.cc in Sources */,
+                               89F23C7E0E78D5B2006B2466 /* v8-counters.cc in Sources */,
+                               89F23C7F0E78D5B2006B2466 /* v8.cc in Sources */,
+                               89F23C800E78D5B2006B2466 /* v8threads.cc in Sources */,
+                               89F23C810E78D5B2006B2466 /* variables.cc in Sources */,
+                               89F23C820E78D5B2006B2466 /* zone.cc in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               89F23C8D0E78D5B6006B2466 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               89F23C8E0E78D5B6006B2466 /* shell.cc in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               7BF891970E73099F000BAF8A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 8970F2EF0E719FB2006AE7B5 /* v8 */;
+                       targetProxy = 7BF891960E73099F000BAF8A /* PBXContainerItemProxy */;
+               };
+               7BF891990E73099F000BAF8A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 897F76790E71B4CC007ACF34 /* v8_shell */;
+                       targetProxy = 7BF891980E73099F000BAF8A /* PBXContainerItemProxy */;
+               };
+               7BF8919B0E7309AD000BAF8A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 897FF1BE0E719CB600D62E90 /* jscre */;
+                       targetProxy = 7BF8919A0E7309AD000BAF8A /* PBXContainerItemProxy */;
+               };
+               896FD03C0E78D71F003DFB6A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 89F23C3C0E78D5B2006B2466 /* v8-arm */;
+                       targetProxy = 896FD03B0E78D71F003DFB6A /* PBXContainerItemProxy */;
+               };
+               896FD03E0E78D731003DFB6A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 89F23C3C0E78D5B2006B2466 /* v8-arm */;
+                       targetProxy = 896FD03D0E78D731003DFB6A /* PBXContainerItemProxy */;
+               };
+               896FD0400E78D735003DFB6A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 89F23C880E78D5B6006B2466 /* v8_shell-arm */;
+                       targetProxy = 896FD03F0E78D735003DFB6A /* PBXContainerItemProxy */;
+               };
+               897F76810E71B6AC007ACF34 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 897FF1BE0E719CB600D62E90 /* jscre */;
+                       targetProxy = 897F76800E71B6AC007ACF34 /* PBXContainerItemProxy */;
+               };
+               897F76830E71B6AC007ACF34 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 8970F2EF0E719FB2006AE7B5 /* v8 */;
+                       targetProxy = 897F76820E71B6AC007ACF34 /* PBXContainerItemProxy */;
+               };
+               89F23C890E78D5B6006B2466 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 897FF1BE0E719CB600D62E90 /* jscre */;
+                       targetProxy = 89F23C8A0E78D5B6006B2466 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+               7BF891940E73098D000BAF8A /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = All;
+                       };
+                       name = Debug;
+               };
+               7BF891950E73098D000BAF8A /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = All;
+                       };
+                       name = Release;
+               };
+               8915B8690E719336009C4E19 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               COPY_PHASE_STRIP = NO;
+                               GCC_CW_ASM_SYNTAX = NO;
+                               GCC_C_LANGUAGE_STANDARD = ansi;
+                               GCC_DYNAMIC_NO_PIC = YES;
+                               GCC_ENABLE_CPP_EXCEPTIONS = NO;
+                               GCC_ENABLE_CPP_RTTI = NO;
+                               GCC_ENABLE_PASCAL_STRINGS = NO;
+                               GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                                       DEBUG,
+                                       _GLIBCXX_CONCEPT_CHECKS,
+                                       _GLIBCXX_DEBUG,
+                                       _GLIBCXX_DEBUG_PEDANTIC,
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+                               GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+                               OTHER_CFLAGS = (
+                                       "$(OTHER_CFLAGS)",
+                                       "-fstack-protector",
+                                       "-fstack-protector-all",
+                               );
+                               PREBINDING = NO;
+                               SYMROOT = ../xcodebuild;
+                               USE_HEADERMAP = NO;
+                               WARNING_CFLAGS = (
+                                       "$(WARNING_CFLAGS)",
+                                       "-Wall",
+                                       "-Wendif-labels",
+                               );
+                       };
+                       name = Debug;
+               };
+               8915B86A0E719336009C4E19 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               DEAD_CODE_STRIPPING = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               DEPLOYMENT_POSTPROCESSING = YES;
+                               GCC_CW_ASM_SYNTAX = NO;
+                               GCC_C_LANGUAGE_STANDARD = ansi;
+                               GCC_DYNAMIC_NO_PIC = YES;
+                               GCC_ENABLE_CPP_EXCEPTIONS = NO;
+                               GCC_ENABLE_CPP_RTTI = NO;
+                               GCC_ENABLE_PASCAL_STRINGS = NO;
+                               GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+                               GCC_OPTIMIZATION_LEVEL = 2;
+                               GCC_PRECOMPILE_PREFIX_HEADER = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                                       NDEBUG,
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+                               GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+                               PREBINDING = NO;
+                               STRIP_STYLE = all;
+                               SYMROOT = ../xcodebuild;
+                               USE_HEADERMAP = NO;
+                               WARNING_CFLAGS = (
+                                       "$(WARNING_CFLAGS)",
+                                       "-Wall",
+                                       "-Wendif-labels",
+                               );
+                       };
+                       name = Release;
+               };
+               8970F2F10E719FB2006AE7B5 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEPLOYMENT_POSTPROCESSING = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                                       ENABLE_DISASSEMBLER,
+                                       ENABLE_LOGGING_AND_PROFILING,
+                               );
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = v8;
+                               STRIP_STYLE = debugging;
+                       };
+                       name = Debug;
+               };
+               8970F2F20E719FB2006AE7B5 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEPLOYMENT_POSTPROCESSING = NO;
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = v8;
+                               STRIP_STYLE = debugging;
+                       };
+                       name = Release;
+               };
+               897F767C0E71B4CC007ACF34 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = v8_shell;
+                       };
+                       name = Debug;
+               };
+               897F767D0E71B4CC007ACF34 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = v8_shell;
+                       };
+                       name = Release;
+               };
+               897FF1C10E719CB600D62E90 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEPLOYMENT_POSTPROCESSING = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                                       SUPPORT_UTF8,
+                                       SUPPORT_UCP,
+                                       NO_RECURSE,
+                               );
+                               PRODUCT_NAME = jscre;
+                               STRIP_STYLE = debugging;
+                       };
+                       name = Debug;
+               };
+               897FF1C20E719CB600D62E90 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEPLOYMENT_POSTPROCESSING = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                                       SUPPORT_UTF8,
+                                       SUPPORT_UCP,
+                                       NO_RECURSE,
+                               );
+                               PRODUCT_NAME = jscre;
+                               STRIP_STYLE = debugging;
+                       };
+                       name = Release;
+               };
+               89F23C850E78D5B2006B2466 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEPLOYMENT_POSTPROCESSING = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                                       ARM,
+                                       ENABLE_DISASSEMBLER,
+                                       ENABLE_LOGGING_AND_PROFILING,
+                               );
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = "v8-arm";
+                               STRIP_STYLE = debugging;
+                       };
+                       name = Debug;
+               };
+               89F23C860E78D5B2006B2466 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEPLOYMENT_POSTPROCESSING = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS)",
+                                       ARM,
+                               );
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = "v8-arm";
+                               STRIP_STYLE = debugging;
+                       };
+                       name = Release;
+               };
+               89F23C930E78D5B6006B2466 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = "v8_shell-arm";
+                       };
+                       name = Debug;
+               };
+               89F23C940E78D5B6006B2466 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               HEADER_SEARCH_PATHS = ../src;
+                               PRODUCT_NAME = "v8_shell-arm";
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               7BF8919F0E7309BE000BAF8A /* Build configuration list for PBXAggregateTarget "All" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               7BF891940E73098D000BAF8A /* Debug */,
+                               7BF891950E73098D000BAF8A /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               8915B86B0E719336009C4E19 /* Build configuration list for PBXProject "v8" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               8915B8690E719336009C4E19 /* Debug */,
+                               8915B86A0E719336009C4E19 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               8970F2F70E719FC1006AE7B5 /* Build configuration list for PBXNativeTarget "v8" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               8970F2F10E719FB2006AE7B5 /* Debug */,
+                               8970F2F20E719FB2006AE7B5 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               897F767E0E71B4EA007ACF34 /* Build configuration list for PBXNativeTarget "v8_shell" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               897F767C0E71B4CC007ACF34 /* Debug */,
+                               897F767D0E71B4CC007ACF34 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               897FF1C30E719CB600D62E90 /* Build configuration list for PBXNativeTarget "jscre" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               897FF1C10E719CB600D62E90 /* Debug */,
+                               897FF1C20E719CB600D62E90 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               89F23C840E78D5B2006B2466 /* Build configuration list for PBXNativeTarget "v8-arm" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               89F23C850E78D5B2006B2466 /* Debug */,
+                               89F23C860E78D5B2006B2466 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               89F23C920E78D5B6006B2466 /* Build configuration list for PBXNativeTarget "v8_shell-arm" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               89F23C930E78D5B6006B2466 /* Debug */,
+                               89F23C940E78D5B6006B2466 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 8915B8680E719336009C4E19 /* Project object */;
+}
diff --git a/regexp2000/tools/visual_studio/README.txt b/regexp2000/tools/visual_studio/README.txt
new file mode 100644 (file)
index 0000000..4aaefd6
--- /dev/null
@@ -0,0 +1,65 @@
+This directory contains Microsoft Visual Studio project files for including v8
+in a Visual Studio/Visual C++ Express solution. All these project files have
+been created for use with Microsoft Visual Studio 2005. They can however also
+be used in both Visual Studio 2008 and Visual C++ 2008 Express Edition. When
+using the project files in the 2008 editions minor upgrades to the files will
+be performed by Visual Studio.
+
+v8_base.vcproj
+--------------
+Base V8 library containing all the V8 code but no JavaScript library code. This
+includes third party code for regular expression handling (jscre) and
+string/number convertions (dtoa).
+
+v8.vcproj
+---------
+V8 library containing all the V8 and JavaScript library code embedded as source
+which is compiled as V8 is running.
+
+v8_mksnapshot.vcproj
+--------------------
+Executable v8_mksnapshot.exe for building a heap snapshot from a running V8.
+
+v8_snapshot.vcproj
+------------------
+V8 library containing all the V8 and JavaScript library code embedded as a heap
+snapshot instead of source to be compiled as V8 is running. Using this library
+provides significantly faster startup time than v8.vcproj.
+
+The property sheets common.vsprops, debug.vsprops and release.vsprops contains
+most of the configuration options and are inhireted by the project files
+described above. The location of the output directory used are defined in
+common.vsprops.
+
+With regard to Platform SDK version V8 has no specific requriments and builds
+with either what is supplied with Visual Studio 2005 or the latest Platform SDK
+from Microsoft.
+
+When adding these projects to a solution the following dependencies needs to be
+in place:
+
+  v8.vcproj depends on v8_base.vcproj
+  v8_mksnapshot.vcproj depends on v8.vcproj
+  v8_snapshot.vcproj depends on v8_mksnapshot.vcproj and v8_base.vcproj
+
+A project which uses V8 should then depend on v8_snapshot.vcproj.
+
+If V8 without snapshot if preferred only v8_base.vcproj and v8.vcproj are
+required and a project which uses V8 should depend on v8.vcproj.
+
+Two sample project files are available as well. These are v8_shell_sample.vcproj
+for building the sample in samples\shell.cc and v8_process_sample.vcproj for
+building the sample in samples\process.cc. Add either of these (or both) to a
+solution with v8_base, v8, v8_mksnapshot and v8_snapshot set up as described
+above and have them depend on v8_snapshot.
+
+Finally a sample Visual Studio solution file for is provided. This solution file
+includes the two sample projects together with the V8 projects and with the
+dependencies configured as described above.
+
+Python requirements
+-------------------
+When using the Microsoft Visual Studio project files Python version 2.4 or later
+is required. Make sure that python.exe is on the path before running Visual
+Studio. The use of Python is in the command script js2c.cmd which is used in the
+Custom Build Step for v8natives.js in the v8.vcproj project.
diff --git a/regexp2000/tools/visual_studio/common.vsprops b/regexp2000/tools/visual_studio/common.vsprops
new file mode 100644 (file)
index 0000000..7e18f17
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="essential"
+       OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+       IntermediateDirectory="$(SolutionDir)$(ConfigurationName)\obj\$(ProjectName)"
+       CharacterSet="1"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               AdditionalIncludeDirectories="$(ProjectDir)\..\..\src;$(IntDir)\DerivedSources"
+               PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_USE_32BIT_TIME_T;_HAS_EXCEPTIONS=0;PCRE_STATIC;ENABLE_LOGGING_AND_PROFILING"
+               MinimalRebuild="false"
+               ExceptionHandling="0"
+               RuntimeTypeInfo="false"
+               WarningLevel="3"
+               WarnAsError="true"
+               Detect64BitPortabilityProblems="false"
+               DebugInformationFormat="3"
+               DisableSpecificWarnings="4355;4800"
+               EnableFunctionLevelLinking="true"
+       />
+       <Tool
+               Name="VCLibrarianTool"
+               OutputFile="$(OutDir)\lib\$(ProjectName).lib"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               GenerateDebugInformation="true"
+               MapFileName="$(OutDir)\$(TargetName).map"
+               ImportLibrary="$(OutDir)\lib\$(TargetName).lib"
+               TargetMachine="1"
+               FixedBaseAddress="1"
+               AdditionalOptions="/IGNORE:4221 /NXCOMPAT"
+       />
+</VisualStudioPropertySheet>
diff --git a/regexp2000/tools/visual_studio/d8.vcproj b/regexp2000/tools/visual_studio/d8.vcproj
new file mode 100644 (file)
index 0000000..ac38bf3
--- /dev/null
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8,00"
+       Name="d8"
+       ProjectGUID="{7E4C7D2D-A4B9-40B9-8192-22654E626F6C}"
+       RootNamespace="d8"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <File
+                       RelativePath="..\..\src\d8.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\src\d8.h"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\src\d8.js"
+                       >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                               Description="Processing js files..."
+                                               CommandLine=".\d8js2c.cmd ..\..\src &quot;$(IntDir)\DerivedSources&quot;"
+                                                                                               Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                               Description="Processing js files..."
+                                               CommandLine=".\d8js2c.cmd ..\..\src &quot;$(IntDir)\DerivedSources&quot;"
+                                               Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc"
+                                       />
+                               </FileConfiguration>
+               </File>
+               <Filter
+                       Name="generated files"
+                       >
+                       <File
+                               RelativePath="$(IntDir)\DerivedSources\natives.cc"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/visual_studio/d8js2c.cmd b/regexp2000/tools/visual_studio/d8js2c.cmd
new file mode 100644 (file)
index 0000000..04d8e26
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+set SOURCE_DIR=%1\r
+set TARGET_DIR=%2\r
+set PYTHON="..\..\..\third_party\python_24\python.exe"\r
+if not exist %PYTHON% set PYTHON=python.exe\r
+%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc D8 %SOURCE_DIR%\macros.py %SOURCE_DIR%\d8.js\r
diff --git a/regexp2000/tools/visual_studio/debug.vsprops b/regexp2000/tools/visual_studio/debug.vsprops
new file mode 100644 (file)
index 0000000..0abf924
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="debug"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               Optimization="0"
+               PreprocessorDefinitions="DEBUG;_DEBUG;ENABLE_DISASSEMBLER"
+               RuntimeLibrary="1"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               LinkIncremental="2"
+       />
+</VisualStudioPropertySheet>
diff --git a/regexp2000/tools/visual_studio/js2c.cmd b/regexp2000/tools/visual_studio/js2c.cmd
new file mode 100644 (file)
index 0000000..b6a46a2
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off
+set SOURCE_DIR=%1
+set TARGET_DIR=%2
+set PYTHON="..\..\..\third_party\python_24\python.exe"
+if not exist %PYTHON% set PYTHON=python.exe
+%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc CORE %SOURCE_DIR%\macros.py %SOURCE_DIR%\runtime.js %SOURCE_DIR%\v8natives.js %SOURCE_DIR%\array.js %SOURCE_DIR%\string.js %SOURCE_DIR%\uri.js %SOURCE_DIR%\math.js %SOURCE_DIR%\messages.js %SOURCE_DIR%\apinatives.js %SOURCE_DIR%\debug-delay.js %SOURCE_DIR%\mirror-delay.js %SOURCE_DIR%\date-delay.js %SOURCE_DIR%\regexp-delay.js
diff --git a/regexp2000/tools/visual_studio/release.vsprops b/regexp2000/tools/visual_studio/release.vsprops
new file mode 100644 (file)
index 0000000..d7b26bc
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="release"
+       >
+       <Tool
+               Name="VCCLCompilerTool"
+               RuntimeLibrary="0"
+               Optimization="2"
+               InlineFunctionExpansion="2"
+               EnableIntrinsicFunctions="true"
+               FavorSizeOrSpeed="0"
+               OmitFramePointers="true"
+               StringPooling="true"
+       />
+       <Tool
+               Name="VCLinkerTool"
+               LinkIncremental="1"
+               OptimizeReferences="2"
+               OptimizeForWindows98="1"
+               EnableCOMDATFolding="2"
+       />
+</VisualStudioPropertySheet>
diff --git a/regexp2000/tools/visual_studio/v8.sln b/regexp2000/tools/visual_studio/v8.sln
new file mode 100644 (file)
index 0000000..a8a8f9c
--- /dev/null
@@ -0,0 +1,92 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_base", "v8_base.vcproj", "{EC8B7909-62AF-470D-A75D-E1D89C837142}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8", "v8.vcproj", "{21E22961-22BF-4493-BD3A-868F93DA5179}"
+       ProjectSection(ProjectDependencies) = postProject
+               {EC8B7909-62AF-470D-A75D-E1D89C837142} = {EC8B7909-62AF-470D-A75D-E1D89C837142}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_mksnapshot", "v8_mksnapshot.vcproj", "{865575D0-37E2-405E-8CBA-5F6C485B5A26}"
+       ProjectSection(ProjectDependencies) = postProject
+               {21E22961-22BF-4493-BD3A-868F93DA5179} = {21E22961-22BF-4493-BD3A-868F93DA5179}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_snapshot", "v8_snapshot.vcproj", "{C0334F9A-1168-4101-9DD8-C30FB252D435}"
+       ProjectSection(ProjectDependencies) = postProject
+               {865575D0-37E2-405E-8CBA-5F6C485B5A26} = {865575D0-37E2-405E-8CBA-5F6C485B5A26}
+               {EC8B7909-62AF-470D-A75D-E1D89C837142} = {EC8B7909-62AF-470D-A75D-E1D89C837142}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_shell_sample", "v8_shell_sample.vcproj", "{2DE20FFA-6F5E-48D9-84D8-09B044A5B119}"
+       ProjectSection(ProjectDependencies) = postProject
+               {C0334F9A-1168-4101-9DD8-C30FB252D435} = {C0334F9A-1168-4101-9DD8-C30FB252D435}
+       EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E131F77D-B713-48F3-B86D-097ECDCC4C3A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_process_sample", "v8_process_sample.vcproj", "{EF019874-D38A-40E3-B17C-DB5923F0A79C}"
+       ProjectSection(ProjectDependencies) = postProject
+               {C0334F9A-1168-4101-9DD8-C30FB252D435} = {C0334F9A-1168-4101-9DD8-C30FB252D435}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_cctest", "v8_cctest.vcproj", "{97ECC711-7430-4FC4-90FD-004DA880E72A}"
+       ProjectSection(ProjectDependencies) = postProject
+               {C0334F9A-1168-4101-9DD8-C30FB252D435} = {C0334F9A-1168-4101-9DD8-C30FB252D435}
+       EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AD933CE2-1303-448E-89C8-60B1FDD18EC3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d8", "d8.vcproj", "{7E4C7D2D-A4B9-40B9-8192-22654E626F6C}"
+       ProjectSection(ProjectDependencies) = postProject
+               {C0334F9A-1168-4101-9DD8-C30FB252D435} = {C0334F9A-1168-4101-9DD8-C30FB252D435}
+       EndProjectSection
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Win32 = Debug|Win32
+               Release|Win32 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Win32.ActiveCfg = Debug|Win32
+               {21E22961-22BF-4493-BD3A-868F93DA5179}.Debug|Win32.Build.0 = Debug|Win32
+               {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Win32.ActiveCfg = Release|Win32
+               {21E22961-22BF-4493-BD3A-868F93DA5179}.Release|Win32.Build.0 = Release|Win32
+               {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Debug|Win32.ActiveCfg = Debug|Win32
+               {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Debug|Win32.Build.0 = Debug|Win32
+               {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Release|Win32.ActiveCfg = Release|Win32
+               {2DE20FFA-6F5E-48D9-84D8-09B044A5B119}.Release|Win32.Build.0 = Release|Win32
+               {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Debug|Win32.ActiveCfg = Debug|Win32
+               {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Debug|Win32.Build.0 = Debug|Win32
+               {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Release|Win32.ActiveCfg = Release|Win32
+               {7E4C7D2D-A4B9-40B9-8192-22654E626F6C}.Release|Win32.Build.0 = Release|Win32
+               {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Debug|Win32.ActiveCfg = Debug|Win32
+               {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Debug|Win32.Build.0 = Debug|Win32
+               {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Release|Win32.ActiveCfg = Release|Win32
+               {865575D0-37E2-405E-8CBA-5F6C485B5A26}.Release|Win32.Build.0 = Release|Win32
+               {97ECC711-7430-4FC4-90FD-004DA880E72A}.Debug|Win32.ActiveCfg = Debug|Win32
+               {97ECC711-7430-4FC4-90FD-004DA880E72A}.Debug|Win32.Build.0 = Debug|Win32
+               {97ECC711-7430-4FC4-90FD-004DA880E72A}.Release|Win32.ActiveCfg = Release|Win32
+               {97ECC711-7430-4FC4-90FD-004DA880E72A}.Release|Win32.Build.0 = Release|Win32
+               {C0334F9A-1168-4101-9DD8-C30FB252D435}.Debug|Win32.ActiveCfg = Debug|Win32
+               {C0334F9A-1168-4101-9DD8-C30FB252D435}.Debug|Win32.Build.0 = Debug|Win32
+               {C0334F9A-1168-4101-9DD8-C30FB252D435}.Release|Win32.ActiveCfg = Release|Win32
+               {C0334F9A-1168-4101-9DD8-C30FB252D435}.Release|Win32.Build.0 = Release|Win32
+               {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Win32.ActiveCfg = Debug|Win32
+               {EC8B7909-62AF-470D-A75D-E1D89C837142}.Debug|Win32.Build.0 = Debug|Win32
+               {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Win32.ActiveCfg = Release|Win32
+               {EC8B7909-62AF-470D-A75D-E1D89C837142}.Release|Win32.Build.0 = Release|Win32
+               {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Debug|Win32.ActiveCfg = Debug|Win32
+               {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Debug|Win32.Build.0 = Debug|Win32
+               {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Release|Win32.ActiveCfg = Release|Win32
+               {EF019874-D38A-40E3-B17C-DB5923F0A79C}.Release|Win32.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(NestedProjects) = preSolution
+               {2DE20FFA-6F5E-48D9-84D8-09B044A5B119} = {E131F77D-B713-48F3-B86D-097ECDCC4C3A}
+               {97ECC711-7430-4FC4-90FD-004DA880E72A} = {AD933CE2-1303-448E-89C8-60B1FDD18EC3}
+               {EF019874-D38A-40E3-B17C-DB5923F0A79C} = {E131F77D-B713-48F3-B86D-097ECDCC4C3A}
+       EndGlobalSection
+EndGlobal
diff --git a/regexp2000/tools/visual_studio/v8.vcproj b/regexp2000/tools/visual_studio/v8.vcproj
new file mode 100644 (file)
index 0000000..212fd07
--- /dev/null
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="v8"
+       ProjectGUID="{21E22961-22BF-4493-BD3A-868F93DA5179}"
+       RootNamespace="v8"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               LinkLibraryDependencies="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               LinkLibraryDependencies="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="js"
+                       >
+                       <File
+                               RelativePath="..\..\src\apinatives.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\array.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\date-delay.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\debug-delay.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\macros.py"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\math.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\messages.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\mirror-delay.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\regexp-delay.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\runtime.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\string.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\uri.js"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\v8natives.js"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                               Description="Processing js files..."
+                                               CommandLine=".\js2c.cmd ..\..\src &quot;$(IntDir)\DerivedSources&quot;"
+                                               AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js"
+                                               Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCustomBuildTool"
+                                               Description="Processing js files..."
+                                               CommandLine=".\js2c.cmd ..\..\src &quot;$(IntDir)\DerivedSources&quot;"
+                                               AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js"
+                                               Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc"
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="generated files"
+                       >
+                       <File
+                               RelativePath="$(IntDir)\DerivedSources\natives.cc"
+                               >
+                       </File>
+               </Filter>
+               <File
+                       RelativePath="..\..\src\snapshot-empty.cc"
+                       >
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/visual_studio/v8_base.vcproj b/regexp2000/tools/visual_studio/v8_base.vcproj
new file mode 100644 (file)
index 0000000..37e604d
--- /dev/null
@@ -0,0 +1,931 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="v8_base"
+       ProjectGUID="{EC8B7909-62AF-470D-A75D-E1D89C837142}"
+       RootNamespace="v8_base"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="jscre"
+                       >
+                       <File
+                               RelativePath="..\..\src\third_party\jscre\pcre_compile.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\src\third_party\jscre\pcre_exec.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\src\third_party\jscre\pcre_internal.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\third_party\jscre\pcre_tables.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\src\third_party\jscre\pcre_ucp_searchfuncs.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\src\third_party\jscre\pcre_xclass.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               UndefinePreprocessorDefinitions="DEBUG"
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="dtoa"
+                       >
+                       <File
+                               RelativePath="..\..\src\dtoa-config.c"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               DisableSpecificWarnings="4018;4244"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               DisableSpecificWarnings="4018;4244"
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="src"
+                       >
+                       <File
+                               RelativePath="..\..\src\accessors.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\accessors.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\allocation.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\allocation.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\api.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\api.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\arguments.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\assembler-arm-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\assembler-arm.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\assembler-ia32-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\assembler-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\assembler-ia32.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\assembler.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\assembler.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ast.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ast.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\bootstrapper.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\bootstrapper.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\builtins-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\builtins.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\builtins.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\char-predicates-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\char-predicates.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\checks.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\checks.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\code-stubs.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\code-stubs.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\code.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\codegen-arm.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\codegen-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\codegen-ia32.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\codegen-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\codegen.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\codegen.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\compilation-cache.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\compilation-cache.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\compiler.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\compiler.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\contexts.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\contexts.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\conversions-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\conversions.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\conversions.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\counters.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\counters.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\cpu-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\cpu.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\dateparser.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\dateparser.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\debug.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\debug.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\disassembler.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\disassembler.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\execution.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\execution.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\factory.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\factory.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\flags.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\flags.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames-arm-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames-arm.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames-ia32-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames-ia32.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\frames.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\global-handles.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\global-handles.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\globals.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\handles-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\handles.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\handles.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\hashmap.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\hashmap.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\heap-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\heap.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\heap.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ic-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ic-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ic.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\ic.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\interceptors.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\jsregexp.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\jsregexp.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\list-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\list.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\log.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\log.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\macro-assembler-arm.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\macro-assembler-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\macro-assembler-ia32.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\macro-assembler.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\mark-compact.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\mark-compact.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\memory.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\messages.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\messages.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\natives.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\objects-debug.cc"
+                               >
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\src\objects-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\objects.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\objects.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\parser.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\parser.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\platform-win32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\platform.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\prettyprinter.cc"
+                               >
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\..\src\prettyprinter.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\property.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\property.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\rewriter.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\rewriter.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\runtime.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\runtime.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\scanner.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\scanner.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\scopeinfo.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\scopeinfo.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\scopes.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\scopes.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\serialize.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\serialize.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\shell.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\snapshot-common.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\snapshot.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\spaces-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\spaces.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\spaces.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\string-stream.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\string-stream.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\stub-cache-ia32.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\stub-cache.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\stub-cache.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\token.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\token.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\top.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\top.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\unicode-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\unicode.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\usage-analyzer.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\usage-analyzer.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\utils.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\utils.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\v8-counters.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\v8-counters.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\v8.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\v8.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\v8threads.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\v8threads.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\variables.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\variables.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\zone-inl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\zone.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\zone.h"
+                               >
+                       </File>
+                       <Filter
+                               Name="third party"
+                               >
+                               <File
+                                       RelativePath="..\..\src\disasm-ia32.cc"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath="..\..\src\disasm.h"
+                                       >
+                               </File>
+                       </Filter>
+                       <Filter
+                               Name="generated files"
+                               >
+                               <File
+                                       RelativePath="..\..\src\unicode.cc"
+                                       >
+                               </File>
+                       </Filter>
+               </Filter>
+               <Filter
+                       Name="include"
+                       >
+                       <File
+                               RelativePath="..\..\include\debug.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\include\v8.h"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/visual_studio/v8_cctest.vcproj b/regexp2000/tools/visual_studio/v8_cctest.vcproj
new file mode 100644 (file)
index 0000000..5c14b9b
--- /dev/null
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8,00"
+       Name="v8_cctest"
+       ProjectGUID="{97ECC711-7430-4FC4-90FD-004DA880E72A}"
+       RootNamespace="v8_cctest"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <File
+                       RelativePath="..\..\test\cctest\cctest.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-api.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-assembler-ia32.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-ast.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-compiler.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-conversions.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-debug.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-decls.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-disasm-ia32.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-flags.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-hashmap.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-heap.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-lock.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-mark-compact.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-platform-win32.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-serialize.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-spaces.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-strings.cc"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\test\cctest\test-utils.cc"
+                       >
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/visual_studio/v8_mksnapshot.vcproj b/regexp2000/tools/visual_studio/v8_mksnapshot.vcproj
new file mode 100644 (file)
index 0000000..daa73f7
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="v8_mksnapshot"
+       ProjectGUID="{865575D0-37E2-405E-8CBA-5F6C485B5A26}"
+       RootNamespace="v8_mksnapshot"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <File
+                       RelativePath="..\..\src\mksnapshot.cc"
+                       >
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/visual_studio/v8_process_sample.vcproj b/regexp2000/tools/visual_studio/v8_process_sample.vcproj
new file mode 100644 (file)
index 0000000..219b0cd
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="v8_process_sample"
+       ProjectGUID="{EF019874-D38A-40E3-B17C-DB5923F0A79C}"
+       RootNamespace="v8_process_sample"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <File
+                       RelativePath="..\..\samples\process.cc"
+                       >
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/visual_studio/v8_shell_sample.vcproj b/regexp2000/tools/visual_studio/v8_shell_sample.vcproj
new file mode 100644 (file)
index 0000000..28249d8
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="v8_shell_sample"
+       ProjectGUID="{2DE20FFA-6F5E-48D9-84D8-09B044A5B119}"
+       RootNamespace="v8_shell_sample"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <File
+                       RelativePath="..\..\samples\shell.cc"
+                       >
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/visual_studio/v8_snapshot.vcproj b/regexp2000/tools/visual_studio/v8_snapshot.vcproj
new file mode 100644 (file)
index 0000000..8a17a1f
--- /dev/null
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="v8_snapshot"
+       ProjectGUID="{C0334F9A-1168-4101-9DD8-C30FB252D435}"
+       RootNamespace="v8_snapshot"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets=".\common.vsprops;.\debug.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               LinkLibraryDependencies="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="4"
+                       InheritedPropertySheets=".\common.vsprops;.\release.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLibrarianTool"
+                               LinkLibraryDependencies="true"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="generated files"
+                       >
+                       <File
+                               RelativePath="$(IntDir)\..\v8\DerivedSources\natives-empty.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="$(IntDir)\DerivedSources\snapshot.cc"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories="$(SolutionDir)..\v8\src"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                               AdditionalIncludeDirectories="$(SolutionDir)..\v8\src"
+                                       />
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <File
+                       RelativePath="$(OutDir)\v8_mksnapshot.exe"
+                       >
+                       <FileConfiguration
+                               Name="Debug|Win32"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                                       Description="Building snapshot..."
+                                       CommandLine="$(OutDir)\v8_mksnapshot.exe $(IntDir)\DerivedSources\snapshot.cc&#x0D;&#x0A;"
+                                       AdditionalDependencies="$(OutDir)\v8_mksnapshot.exe"
+                                       Outputs="$(IntDir)\DerivedSources\snapshot.cc"
+                               />
+                       </FileConfiguration>
+                       <FileConfiguration
+                               Name="Release|Win32"
+                               >
+                               <Tool
+                                       Name="VCCustomBuildTool"
+                                       Description="Building snapshot..."
+                                       CommandLine="$(OutDir)\v8_mksnapshot.exe $(IntDir)\DerivedSources\snapshot.cc&#x0D;&#x0A;"
+                                       AdditionalDependencies="$(OutDir)\v8_mksnapshot.exe"
+                                       Outputs="$(IntDir)\DerivedSources\snapshot.cc"
+                               />
+                       </FileConfiguration>
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/regexp2000/tools/windows-tick-processor.py b/regexp2000/tools/windows-tick-processor.py
new file mode 100755 (executable)
index 0000000..4b1c3f1
--- /dev/null
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# Usage: process-ticks.py <binary> <logfile>
+#
+# Where <binary> is the binary program name (eg, v8_shell.exe) and
+# <logfile> is the log file name (eg, v8.log).
+#
+# This tick processor expects to find a map file for the binary named
+# binary.map if the binary is named binary.exe. The tick processor
+# only works for statically linked executables - no information about
+# shared libraries is logged from v8 on Windows.
+
+import os, re, sys, tickprocessor, getopt
+
+class WindowsTickProcessor(tickprocessor.TickProcessor):
+
+  def Unmangle(self, name):
+    """Performs very simple unmangling of C++ names.
+
+    Does not handle arguments and template arguments. The mangled names have
+    the form:
+
+       ?LookupInDescriptor@JSObject@internal@v8@@...arguments info...
+
+    """
+    # Name is mangled if it starts with a question mark.
+    is_mangled = re.match("^\?(.*)", name)
+    if is_mangled:
+      substrings = is_mangled.group(1).split('@')
+      try:
+        # The function name is terminated by two @s in a row.  Find the
+        # substrings that are part of the function name.
+        index = substrings.index('')
+        substrings = substrings[0:index]
+      except ValueError:
+        # If we did not find two @s in a row, the mangled name is not in
+        # the format we expect and we give up.
+        return name
+      substrings.reverse()
+      function_name = "::".join(substrings)
+      return function_name
+    return name
+
+
+  def ParseMapFile(self, filename):
+    """Parse map file and add symbol information to the cpp entries."""
+    # Locate map file.
+    has_dot = re.match('^([a-zA-F0-9_-]*)[\.]?.*$', filename)
+    if has_dot:
+      map_file_name = has_dot.group(1) + '.map'
+      try:
+        map_file = open(map_file_name, 'rb')
+      except IOError:
+        sys.exit("Could not open map file: " + map_file_name)
+    else:
+      sys.exit("Could not find map file for executable: " + filename)
+    try:
+      max_addr = 0
+      min_addr = 2**30
+      # Process map file and search for function entries.
+      row_regexp = re.compile(' 0001:[0-9a-fA-F]{8}\s*([_\?@$0-9a-zA-Z]*)\s*([0-9a-fA-F]{8}).*')
+      for line in map_file:
+        row = re.match(row_regexp, line)
+        if row:
+          addr = int(row.group(2), 16)
+          if addr > max_addr:
+            max_addr = addr
+          if addr < min_addr:
+            min_addr = addr
+          mangled_name = row.group(1)
+          name = self.Unmangle(mangled_name)
+          self.cpp_entries.Insert(addr, tickprocessor.CodeEntry(addr, name));
+      i = min_addr
+      # Mark the pages for which there are functions in the map file.
+      while i < max_addr:
+        page = i >> 12
+        self.vm_extent[page] = 1
+        i += 4096
+    finally:
+      map_file.close()
+
+def Usage():
+  print("Usage: windows-tick-processor.py binary logfile-name");
+  sys.exit(2)
+
+def Main():
+  # parse command line options
+  state = None;
+  try:
+    opts, args = getopt.getopt(sys.argv[1:], "jgco", ["js", "gc", "compiler", "other"])
+  except getopt.GetoptError:
+    usage()
+  # process options.
+  for key, value in opts:
+    if key in ("-j", "--js"):
+      state = 0
+    if key in ("-g", "--gc"):
+      state = 1
+    if key in ("-c", "--compiler"):
+      state = 2
+    if key in ("-o", "--other"):
+      state = 3
+  # do the processing.
+  if len(args) != 2:
+      Usage();
+  tickprocessor = WindowsTickProcessor()
+  tickprocessor.ParseMapFile(args[0])
+  tickprocessor.ProcessLogfile(args[1], state)
+  tickprocessor.PrintResults()
+
+if __name__ == '__main__':
+  Main()